roboforum.ru

Технический форум по робототехнике.

Прерывание от АЦП в ATMEGA8 не срабатывает

Прерывание от АЦП в ATMEGA8 не срабатывает

C-r-o-w » 23 июн 2009, 12:49

Пишу довольно большой проект. И столкнулся с проблемой. В программе используются два прерывания: при переполнении таймера0, и при завершении АЦП. Обработчик прерывания от tmr0 довольно длинный. В самом его начале запускается начало АЦП (ADSRA.6 = 1). Но атмега8 просто игнорирует прерывание от АЦП, в него она просто не залетает. В-общем, проблема свелась в следующему простому коду:
Код: Выделить всёРазвернуть
#include <mega8.h>
#include <delay.h>
#include <MyLCD.inc>

interrupt [TIM0_OVF] void timer0_ovf_isr(void);
interrupt [ADC_INT] void adc_isr(void);
void lcd_putnum(unsigned char num);
void main(void);

//======== TIMER0 INTERRUPT HANDLER ========//
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
  ADCSRA.6 = 1;
//  delay_ms(500);
}
//==== END OF TIMER0 INTERRUPT HANDLER =====//


//======== ADC INTERRUPT HANDLER ========//
interrupt [ADC_INT] void adc_isr(void)
{
  unsigned char adc_data;
  adc_data = ADCH;
  lcd_clear();
  lcd_putsf("ADC = ");
  lcd_putnum(adc_data);
  delay_ms(200);
}
//==== END OF ADC INTERRUPT HANDLER =====//


void lcd_putnum(unsigned char num)
{
unsigned char tmp1, tmp2;
tmp1 = num / 100;
tmp2 = ( num / 10 ) % 10;
if (tmp1)
  lcd_putchar(tmp1 + 48);
if ( ((!tmp2) && (tmp1)) ||(tmp2))
  lcd_putchar(tmp2 + 48);
lcd_putchar((num%100)%10 + 48);
}


void main(void)
{
DDRC  = 0b00110110;
PORTC = 0b00111110;

ADMUX  = 0b01100000;
ADCSRA = 0x8B;

TCCR0=0x03;
TIMSK=0x01;
ACSR=0x80;

lcd_init();
lcd_putsf("TEST");
delay_ms(200);
ADCSRA.6 = 1;

#asm("sei");

while (1)
  {
  }
}

При комментировании delay(500) в прерывании от таймера, прерывание от АЦП СРАБАТЫВАЕТ. При внесении же delay_ms (500), т.е. "удлинения по времени" прерывания от таймера, прерывание от АЦП игнорируется. В чем может быть дело?
P.S. Контроль данных АЦП выводится на ЛСД дисплей (100% рабочий).
P.S.S. В протеусе все эмулится нормально.

Re: Прерывание от АЦП в ATMEGA8 не срабатывает

yak-40 » 23 июн 2009, 13:09

Использовать delay в теле прерывания не есть гуд.
Да потом delay_ms(500) - это же 0,5 секунды :shock:

Re: Прерывание от АЦП в ATMEGA8 не срабатывает

SERGEY_M » 23 июн 2009, 13:12

зачем в main запуск АЦП (ADCSRA.6 = 1;), ведь он запускается таймером
а таймер тактируется от внешнего источника?

Re: Прерывание от АЦП в ATMEGA8 не срабатывает

yak-40 » 23 июн 2009, 13:17

TCCR0=0x03; - clk /64 (From prescaler)

Re: Прерывание от АЦП в ATMEGA8 не срабатывает

SERGEY_M » 23 июн 2009, 13:32

а блин... точно...
пардон, надо кофе выпить :)

Добавлено спустя 6 минут 16 секунд:
Какая тактовая у МК?

Re: Прерывание от АЦП в ATMEGA8 не срабатывает

avr123.nm.ru » 23 июн 2009, 13:43

C-r-o-w писал(а):атмега8 просто игнорирует прерывание от АЦП, в него она просто не залетает.


Механизм прерываний AVR ATmega описан на страничке 3 учебного курса по AVR - http://avr123.nm.ru/03.htm

Там сказано что AVR не помнит порядок появления накопленых прерываний (порядок установки их флагов) и поэтому обрабатывает их по порядку расположения в таблице прерываний в даташите.

Т.е. у вас перед флагом АЦП всегда есть флаг таймера (если он устанавливается за время большой паузы) - его и обрабатывает мега8.

Там же КРУПНО написано:

Делайте функции обработчики прерывания как можно короче !
Не засиживайтесь в них ...


Нужно тщательно продумывать алгоритм программы чтоб успевать обрабатывать все прерывания - т.е. не пропускать нужные события
и обрабатывать их вовремя.

Re: Прерывание от АЦП в ATMEGA8 не срабатывает

yak-40 » 23 июн 2009, 13:52

avr123.nm.ru писал(а):Т.е. у вас перед флагом АЦП всегда есть флаг таймера - его и обрабатывает мега8.

Позвольте несогласиться.
Топикстартер пишет:
C-r-o-w писал(а):При комментировании delay(500) в прерывании от таймера, прерывание от АЦП СРАБАТЫВАЕТ.

Значит дело не во флагах, а в delay-е. :)

Re: Прерывание от АЦП в ATMEGA8 не срабатывает

SERGEY_M » 23 июн 2009, 14:12

что такое delay(500), это сколько???
написали же, русским языком
Там сказано что AVR не помнит порядок появления накопленых прерываний (порядок установки их флагов) и поэтому обрабатывает их по порядку расположения в таблице прерываний в даташите.

Т.е. у вас перед флагом АЦП всегда есть флаг таймера (если он устанавливается за время большой паузы) - его и обрабатывает мега8.

т.е. таймер всегда находится в своем прерывании, т.к. за 0,5сек оно точно наступит

Re: Прерывание от АЦП в ATMEGA8 не срабатывает

avr123.nm.ru » 23 июн 2009, 14:28

yak-40 писал(а):avr123.nm.ru Позвольте несогласиться.
Топикстартер пишет:
C-r-o-w писал(а):При комментировании delay(500) в прерывании от таймера, прерывание от АЦП СРАБАТЫВАЕТ.

Значит дело не во флагах, а в delay-е. :)


Я об этом и написал. Внимательно перечитайте если интересно.

Добавлено спустя 2 минуты 31 секунду:
SERGEY_M писал(а):т.е. таймер всегда находится в своем прерывании, т.к. за 0,5сек оно точно наступит

Нет. Прога почти всегда находится в прерывании от таймера. Таймер там не находится :)

Когда прога выходит из этого прерывания то обнаруживает два флага - от таймера (который внось возник за время длинной паузы) и от АЦП и обрабоатывает ПЕРВЫЙ их них по списку в даташите.

Если в конце прерывания сделать очистку флага от таймера то вероятно прога сможет попасть в прерывание от АЦП.

Re: Прерывание от АЦП в ATMEGA8 не срабатывает

SERGEY_M » 23 июн 2009, 14:42

пардон, ну не так выразился :oops:
именно это я и хотел про таймер сказать

Re: Прерывание от АЦП в ATMEGA8 не срабатывает

C-r-o-w » 23 июн 2009, 20:37

avr123.nm.ru писал(а):Если в конце прерывания сделать очистку флага от таймера то вероятно прога сможет попасть в прерывание от АЦП.

Да, идеи теперь две: либо переносить весь обработчик таймера в мэйн и сделать там свой "переполнитель" таймера, либо в прерывании от таймера тормозить сам таймер и обнулять его... Наверно лучше первое. Спасибо всем за внимание!

Re: Прерывание от АЦП в ATMEGA8 не срабатывает

boez » 24 июн 2009, 00:51

Однозначно лучше. Много видел всякого, но delay(500) в обработчике - это жесть :)

Re: Прерывание от АЦП в ATMEGA8 не срабатывает

USER777 » 24 июн 2009, 22:26

Может из-за

Обратите внимание, что при выполнении команды "чтение-модификация-запись" с регистром ADCSRA ожидаемое прерывание может быть отключено.
http://www.gaw.ru/html.cgi/txt/doc/micros/avr/arh128/12.htm

И таймер 0 здесь вроде только 1-раз срабатывает.
А если так попробовать
Код: Выделить всёРазвернуть
#include <mega8.h>
#include <delay.h>
#include <MyLCD.inc>

interrupt [TIM0_OVF] void timer0_ovf_isr(void);
interrupt [ADC_INT] void adc_isr(void);
void lcd_putnum(unsigned char num);
void main(void);

//======== TIMER0 INTERRUPT HANDLER ========//
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
TCNT0 = 0x??;
ADCSRA = 0xCB;

//  delay_ms(500);
}
//==== END OF TIMER0 INTERRUPT HANDLER =====//


//======== ADC INTERRUPT HANDLER ========//
interrupt [ADC_INT] void adc_isr(void)
{
  unsigned char adc_data;
ADCSRA=0x00;
  adc_data = ADCH;
  lcd_clear();
  lcd_putsf("ADC = ");
  lcd_putnum(adc_data);
  delay_ms(200);
}
//==== END OF ADC INTERRUPT HANDLER =====//


void lcd_putnum(unsigned char num)
{
unsigned char tmp1, tmp2;
tmp1 = num / 100;
tmp2 = ( num / 10 ) % 10;
if (tmp1)
  lcd_putchar(tmp1 + 48);
if ( ((!tmp2) && (tmp1)) ||(tmp2))
  lcd_putchar(tmp2 + 48);
lcd_putchar((num%100)%10 + 48);
}


void main(void)
{
DDRC  = 0b00110110;
PORTC = 0b00111110;

ADCSRA=0x00;
ADMUX  = 0b01100000;
ACSR=0x80;


TCCR0=0x00;
TCNT0 = 0x??;
TCCR0=0x03;
TIMSK=0x01;


lcd_init();
lcd_putsf("TEST");
delay_ms(200);


#asm("sei");

while (1)
  {
  }
}
?
Последний раз редактировалось USER777 24 июн 2009, 22:30, всего редактировалось 2 раз(а).

Re: Прерывание от АЦП в ATMEGA8 не срабатывает

avr123.nm.ru » 24 июн 2009, 22:28

А у вас есть "чтение-модификация-запись" с регистром ADCSRA ?

Re: Прерывание от АЦП в ATMEGA8 не срабатывает

Duhas » 25 июн 2009, 18:01

ADCSRA = 0xCB;

а это кто?


Rambler\'s Top100 Mail.ru counter