Микроконтроллеры, АЦП, память и т.д Темы касающиеся микроконтроллеров разных производителей, памяти, АЦП/ЦАП, периферийных модулей... |
01.12.2010, 11:25
|
|
Частый гость
Регистрация: 07.10.2007
Сообщений: 14
Сказал спасибо: 5
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Прерывания таймера
Уважаемые форумчане, прошу вашей помощи, уже голову сломал почему не работает должным образом прерывания от таймера.
Вообщем по порядку:
Пишу программу на atmega128. Среда разработки - AVR Studio + WinAVR.
Проблема в следующем - есть прервания от таймера с переодичностью 5мс. В обработчике прерываний инкрементируется переменная, которая затем проверяется в главном цикле программы. По положительному результату проверки вызывается функция в которой делается довольно долгое действие (несколько десятков мс).
Так вот, получается что величина переодичности изменяется на велечину этой задержки.
Специально создал простенькую программу, листинг которой приведу ниже:
Код:
|
#include ‹util/delay.h›
#include ‹avr/io.h›
#include ‹avr/interrupt.h›
//объявляем глобальную переменную
volatile uint8_t t = 0;
//инициализируем таймер, тиканье с периодом 5мс (частота кварца 16МГц)
void InitTimer(void)
{
cli();
OCR1A=1249;
TCNT1=0;
TCCR1C=0x00;
TCCR1A=0x00;
TCCR1B=0x0B;
TIMSK=TIMSK | (1‹‹OCIE1A);
sei();
}
//тут меняем пин порта B и делаем тупую задержку
void test (void)
{
PORTB = ~PORTB;
_delay_ms(20);
}
//в прерывании таймера только инкрементируем переменную
ISR(TIMER1_COMPA_vect)
{
t++;
}
int main(void)
{
DDRB |= 0b10000000;
PORTB |= 0b10000000;
InitTimer();
while(1){
ждем 5*20=100мс
if (t==20){
test();
t=0;
}
}
} |
По идеи изменения порта B должны происходить каждые 100мс, но на самом деле происходят 100+20=120мс.
|
|
|
|
01.12.2010, 11:36
|
|
Частый гость
Регистрация: 20.07.2006
Сообщений: 37
Сказал спасибо: 2
Сказали Спасибо 7 раз(а) в 4 сообщении(ях)
|
Re: Прерывания таймера
в
void test (void)
убери строку:
_delay_ms(20);
|
|
|
|
01.12.2010, 11:41
|
|
Частый гость
Регистрация: 07.10.2007
Сообщений: 14
Сказал спасибо: 5
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Прерывания таймера
Сообщение от sasareccer
|
в
void test (void)
убери строку:
_delay_ms(20);
|
Эту строку я специально поставил. Это упрощенный листинг (который тоже тестировался). А в основной программе вместо _delay_ms(20); вызываются различные функции общей длительностью порядка 20-25мс.
Если убрать эту задержку, то тогда все естественно работает нормально. Кстати забыл написать, что обработчик прерывания работает нормально, т.е тикает каждые 5 мс, и ничего ему не мешает.
|
|
|
|
01.12.2010, 11:48
|
|
Гуру портала
Регистрация: 27.10.2008
Адрес: ЕС
Сообщений: 10,835
Сказал спасибо: 919
Сказали Спасибо 4,308 раз(а) в 2,573 сообщении(ях)
|
Re: Прерывания таймера
Выбросите проверку t в основном цикле и закиньте ее в прерывание. Там поднимайте флаг (переменная boolean) и по флагу идите дальше в основном теле.
|
|
|
|
01.12.2010, 12:04
|
|
Частый гость
Регистрация: 07.10.2007
Сообщений: 14
Сказал спасибо: 5
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Прерывания таймера
Сообщение от Easyrider83
|
Выбросите проверку t в основном цикле и закиньте ее в прерывание. Там поднимайте флаг (переменная boolean) и по флагу идите дальше в основном теле.
|
Сделал по вашему совету, всеравно одно и тоже - задержка 120мс. Я уже замучился с этим бороться. (
Кстати и на реальном устройстве и в отладке AVR Studio задержка одинаковая. Из-за чего она берется я никак понять не могу.
Т.е как должно работать в идеале - каждые 100мс происходит переход на пользовательскую функцию. В этой функции может быть любая задержка ‹100мс. Контроллер обработает эту функцию, дождется следующих 100мс и заново повторит.
|
|
|
|
01.12.2010, 12:08
|
|
Частый гость
Регистрация: 20.07.2006
Сообщений: 37
Сказал спасибо: 2
Сказали Спасибо 7 раз(а) в 4 сообщении(ях)
|
Re: Прерывания таймера
если
_delay_ms(20);
так необходима, тогда просто надо поменять местами строки
test();
t=0;
и получится следующее
while(1){
//ждем 5*20=100мс
if (t==20){
t=0;
test();
}
}
Могу пояснить почему так:
Переменная t досчитала до =20, сработал if, Вы отправили на выполнение функцию test(); внутри которой есть задержка, а счетчик-то так и не обнулился, он обнулится только через "четыре раза" таймера (4х5мс), когда дойдет дело до строки t=0;, т.е. успеет посчитать до t=24, вот и получается в плюс 20мс. А если сразу после срабатывания if обнулять в первую очередь t, а потом уже делать что-то в функции test(); - то все будет OK.
Последний раз редактировалось sasareccer; 01.12.2010 в 12:15.
|
|
|
Сказали "Спасибо" sasareccer
|
|
|
01.12.2010, 12:17
|
|
Частый гость
Регистрация: 07.10.2007
Сообщений: 14
Сказал спасибо: 5
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Прерывания таймера
[QUOTE=sasareccer;286114]если
_delay_ms(20);
так необходима, тогда просто надо поменять местами строки
test();
t=0;
QUOTE]
Спасибо за подсказку, действительно не просчитал что t обнуляется потом. НО(!) сейчас переделал и всеравно 120мс.
|
|
|
|
01.12.2010, 12:29
|
|
Частый гость
Регистрация: 07.10.2007
Сообщений: 14
Сказал спасибо: 5
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Прерывания таймера
sasareccer все нормально, это я поспешил просто проверить результат. Что то я конкретно ступил, наверное сказывается усталость. )
Действительно в не том месте обнулял переменную, а начал грешить на контроллер,программатор и компилятор )))
Еще раз спасибо!
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 20:22.
|
|