реклама на сайте
подробности

 
 
> вызвать прерывание каждые 50мсек
romez777
сообщение Nov 19 2004, 07:54
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077



Приветствую.

Продолжаю разборки с atmega162. Вот такой кусок кода, использующий прерывание и таймер (использую WinAVR и AVRstudio для отладки):

#include <inttypes.h>
#include <interrupt.h>
#include <io.h>
#include <sig-avr.h>

SIGNAL(SIG_OUTPUT_COMPARE1A)
{
// далее обработка ......
// .........
}

void Timer1_Init(void)
{
SREG = (1 << SREG_I); // enable global interrupt
TCCR1A = 0x00;
TCCR1B = 0x04; // set prescale
TCCR1B = (1 << CS10) | (1 << WGM12);

TIMSK = (1 << OCIE1A);

// load value
TCNT1H = 0xFE;
TCNT1L = 0x7A;

// set compare register for 50ms
OCR1AH = 0x01;
OCR1AL = 0x86;
}

int main(void)
{
Timer1_Init();

// DDRB = 0xFF;
while (1)
;
return 1;
}

На первый взгляд все правильно, но не сдается мне что не получаю я задержки в 50мсек, а проверить в симуляторе, как предложил IgorKossak, не могу (симулятор не позволяет).

Вообщем, я окончательно запутался smile.gif
Go to the top of the page
 
+Quote Post
2 страниц V   1 2 >  
Start new topic
Ответов (1 - 14)
Alex2172
сообщение Nov 19 2004, 08:13
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 242
Регистрация: 25-08-04
Пользователь №: 537



А осциллографа то нет под рукой? (Ну или хотябы светодиода)
Go to the top of the page
 
+Quote Post
romez777
сообщение Nov 19 2004, 08:25
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077



Цитата(Alex2172 @ Nov 19 2004, 11:13 AM)
А осциллографа то нет под рукой? (Ну или хотябы светодиода)

осциллографа нет, в на глаз IMHO сложно заметить мерцание светодиода каждые 50мсек smile.gif
Go to the top of the page
 
+Quote Post
Styv
сообщение Nov 19 2004, 08:59
Сообщение #4


Частый гость
**

Группа: Свой
Сообщений: 133
Регистрация: 16-08-04
Пользователь №: 504



Попробуй подели генерируемую частоту (~50мс) на 20 и подай этот сигнал на светодиод. Будет мигать с частотой 1 Гц (1с), а это уже можно на глаз определить - сам так делал.
А если нодо определить болле точно, то без осцила не обойтись!
Или замени осцил например компом: подавай свой сигнал на LPT-порт и смотри с помощью ентой проги твой сигнал
Прикрепленные файлы
Прикрепленный файл  dlpt.zip ( 431.38 килобайт ) Кол-во скачиваний: 92
 
Go to the top of the page
 
+Quote Post
KRS
сообщение Nov 19 2004, 11:15
Сообщение #5


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



А зачем при инициализации таймера в TCNT писать 0xFE7A?
Это конечно понятно что это -0x186 но зачем это делать?

И еще при инициализации корректнее с начала выставлять OCR и TCNT и самым последним писать TCCR1B иначе можно получить ложное прерываение
Go to the top of the page
 
+Quote Post
lamerok
сообщение Nov 19 2004, 11:55
Сообщение #6


Частый гость
**

Группа: Свой
Сообщений: 135
Регистрация: 22-06-04
Из: Челябинск
Пользователь №: 88



Код
void InitTimer (void)
{
 
TCCR1A = 0;
 TCCR1B = ((1<<CS10)|(1<<CS12)); //делим на 1024;
 TCNT1H = TCNT1L = 0;
 
 TIFR  |= (1<<OCF1B);
 Temp.B[0]=TCNT1L;
 Temp.B[1]=TCNT1H;
 Temp.I += PERIOD;
 OCR1BH = TimerOn2Char1.B[1];
 OCR1BL = TimerOn2Char1.B[0];
 TIMSK |= (1<<OCIE1B);  /*разрешаем прерывание по сравнению для таймера на 2 символов*/            
 
}
Go to the top of the page
 
+Quote Post
lamerok
сообщение Nov 19 2004, 12:07
Сообщение #7


Частый гость
**

Группа: Свой
Сообщений: 135
Регистрация: 22-06-04
Из: Челябинск
Пользователь №: 88



Блин нечаяно нажалось, первое не смотрите....
Вот это код будет все время генерить период в сколько надо, задается PERIODом
Код
#define PERIOD 0x186

#pragma  vector = TIMER1_COMPB_vect
__interrupt void CompareB(void)
{
 union  {unsigned char B[2];unsigned int I} Temp;

 Temp.B[0]=TCNT1L;
 Temp.B[1]=TCNT1H;
 Temp.I +=PERIOD;
 OCR1BH = Temp.B[1];
 OCR1BL = Temp.B[0];
 TIFR  |= (1<<OCF1B);

}



void InitTimer (void)
{

union {unsigned char B[2];unsigned int I} Temp;

Temp.I = 0;


TCCR1A = 0;
TCCR1B = ((1<<CS10)|(1<<CS12)); //делим на 1024;
TIFR  |= (1<<OCF1B);

Temp.I = PERIOD;

TCNT1H = TCNT1L = 0;
OCR1BH = Temp.B[1];
OCR1BL = Temp.B[0];
 
TIMSK |= (1<<OCIE1B);
           

}
Go to the top of the page
 
+Quote Post
lamerok
сообщение Nov 19 2004, 12:10
Сообщение #8


Частый гость
**

Группа: Свой
Сообщений: 135
Регистрация: 22-06-04
Из: Челябинск
Пользователь №: 88



Еще поправим маленько. Вечер глучу малость blink.gif
Код
#pragma  vector = TIMER1_COMPB_vect
__interrupt void CompareB(void)
{
union  {unsigned char B[2];unsigned int I} Temp;

Temp.B[0]=OCR1BL;
Temp.B[1]=OCR1BH;
Temp.I +=PERIOD;
OCR1BH = Temp.B[1];
OCR1BL = Temp.B[0];
TIFR  |= (1<<OCF1B);

}

Вот теперь точно все правильно smile.gif :P
Go to the top of the page
 
+Quote Post
romez777
сообщение Nov 22 2004, 00:08
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077



Цитата(KRS @ Nov 19 2004, 02:15 PM)
А зачем при инициализации таймера в TCNT писать 0xFE7A?
Это конечно понятно что это -0x186 но зачем это делать?

И еще при инициализации корректнее с начала выставлять OCR и TCNT и самым последним писать TCCR1B иначе можно получить ложное прерываение

Приветствую.

Так вот с этим пунктом у меня и была изначально непонятность... Я считал, что в TCNT _обязательно_ нужно заносить инициализационное значение для отсчета тиков (c output compare либо без него). А потом - либо по переполнению, либо при match значения в OCR регистре.

Так получается, что если работаем в compare режиме, то TCNT уже обнулен и начинает считать сам по себе, без моего вмешательства? И мне достаточно только проинициализировать OCR ?
Go to the top of the page
 
+Quote Post
romez777
сообщение Nov 22 2004, 02:14
Сообщение #10


Местный
***

Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077



Цитата(lamerok @ Nov 19 2004, 03:07 PM)
Блин нечаяно нажалось, первое не смотрите....
Вот это код будет все время генерить период в сколько надо, задается PERIODом

Приветствую.

Спасибо за пример. Есть вопросы по нему:

1) почему используется union а не structure. Это связано с особенностями генерации кода или только в целях экономии памяти?
2) зачем устанавливать принудительно OCF1B, как я понял этот флаг выставится сам при возникновении события совпадения ? И опять же при отладен в студии, этот флаг не выставляется (баг студии?)...
3) почему используется B-compare канал, а не A ?
4) при прогоне и отладке этого кода в AVR studio я не наблюдаю увеличения счетчика в TCNT...
Go to the top of the page
 
+Quote Post
KRS
сообщение Nov 22 2004, 10:27
Сообщение #11


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(romez777 @ Nov 22 2004, 03:08 AM)
Так получается, что если работаем в compare режиме, то TCNT уже обнулен и начинает считать сам по себе, без моего вмешательства? И мне достаточно только проинициализировать OCR ?


4) при прогоне и отладке этого кода в AVR studio я не наблюдаю увеличения счетчика в TCNT...

Изначально TCNT=0. при работе Clear Timer on Compare or CTC mode таймер считает от 0 до OCR1A потом сбрасывается. Действительно нужно проинициализироать только OCR. И запустить таймер в нужном режиме и прерывание будет выполнятся переодически

По поводу величения счетчика в TCNT в AVR studio - это скорее всего из-за прескалера в 1024 надо ждать 1024 такта

А вообще на мой взглад у lamerok слишком навороченный пример.

Я бы написал так
инициализация таймера

OCR1A=Fclk / 20; // 20 HZ
TCCR1B= (1 << CS10) | (1 << WGM12);
TIMSK = (1 << OCIE1A);

после этого разрешить прерывания и обработчик будет вызываться каждые 50 мсек (20HZ)! в обработчике регистры таймера трогать не надо.
Go to the top of the page
 
+Quote Post
romez777
сообщение Nov 22 2004, 10:48
Сообщение #12


Местный
***

Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077



Цитата(KRS @ Nov 22 2004, 01:27 PM)
Изначально TCNT=0. при работе Clear Timer on Compare or CTC mode таймер считает от 0 до OCR1A потом сбрасывается. Действительно нужно проинициализироать только OCR. И запустить таймер в нужном режиме и прерывание будет выполнятся переодически

По поводу величения счетчика в TCNT в AVR studio - это скорее всего из-за прескалера в 1024 надо ждать 1024 такта

А вообще на мой взглад у lamerok слишком навороченный пример.

Я бы написал так
инициализация таймера

OCR1A=Fclk / 20; // 20 HZ
TCCR1B= (1 << CS10) | (1 << WGM12);
TIMSK = (1 << OCIE1A);

после этого разрешить прерывания и обработчик будет вызываться каждые 50 мсек (20HZ)! в обработчике регистры таймера трогать не надо.

Таймер заработал в режиме compare, при достижении значения в OCR, вызывается ISR.

Но вот такой момент: в процедуре обработки прерывания таймер продолжает тикать. И если значение в счетчике достигает OCR, то ISR уже не вызывется smile.gif

IMHO это неправильно и таймер нужно остановить после вызова ISR?

Вот нынешний код:

SIGNAL(SIG_OUTPUT_COMPARE1A)
{
//...
}

void Timer1_Init(void)
{
union {
unsigned char B[2];
unsigned int I;
} Temp;

Temp.I = 0;

TCCR1A = 0;
TCCR1B = (1 << CS11) | (1 << WGM12);

Temp.I = PERIOD;

TCNT1L = 0;
TCNT1H = 0;

OCR1AH = Temp.B[1];
OCR1AL = Temp.B[0];

TIMSK |= (1 << OCIE1A);
}

int main(void)
{
Timer1_Init();
sei();

while (1)
;

return 1;
}
Go to the top of the page
 
+Quote Post
KRS
сообщение Nov 22 2004, 11:19
Сообщение #13


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(romez777 @ Nov 22 2004, 01:48 PM)
Но вот такой момент: в процедуре обработки прерывания таймер продолжает тикать. И если значение в счетчике достигает OCR, то ISR уже не вызывется smile.gif

Так и должно быть! Таймер должен тикать иначе прерывание будет вызваться реже чем 50 мс! А вот если значение в счетчике достигнет OCR то после выхода из прерывания (разрешения прерываний) прерывание вызовется сново, т.к флаг очищается при входе в обработчик. Но в любом случае обработчик прерывания который работает больше 50 мс это не правильно.
Go to the top of the page
 
+Quote Post
romez777
сообщение Nov 22 2004, 11:52
Сообщение #14


Местный
***

Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077



Цитата(KRS @ Nov 22 2004, 02:19 PM)
Так и должно быть! Таймер должен тикать иначе прерывание будет вызваться реже чем 50 мс! А вот если значение в счетчике достигнет OCR то после выхода из прерывания (разрешения прерываний) прерывание вызовется сново, т.к флаг очищается при входе в обработчик. Но в любом случае обработчик прерывания который работает больше 50 мс это не правильно.

Приветствую.

А если в обработчике стоит цикл while (...) {...} и нет гарантии что он будет работать меньше 50 мс, как быть? Отказываться от while и искать другую концепцию?
Go to the top of the page
 
+Quote Post
KRS
сообщение Nov 22 2004, 12:04
Сообщение #15


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(romez777 @ Nov 22 2004, 02:52 PM)
Цитата(KRS @ Nov 22 2004, 02:19 PM)
Так и должно быть! Таймер должен тикать иначе прерывание будет вызваться реже чем 50 мс! А вот если значение в счетчике достигнет OCR то после выхода из прерывания (разрешения прерываний) прерывание вызовется сново, т.к флаг очищается при входе в обработчик. Но в любом случае обработчик прерывания который работает больше 50 мс это не правильно.

Приветствую.

А если в обработчике стоит цикл while (...) {...} и нет гарантии что он будет работать меньше 50 мс, как быть? Отказываться от while и искать другую концепцию?

А как можно делать действие каждые 50 мс если длительность самого дейстивя больше 50 мс? они же будут перекрываться.
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 03:55
Рейтинг@Mail.ru


Страница сгенерированна за 0.01482 секунд с 7
ELECTRONIX ©2004-2016