Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Help! Timer0 в ATmega168PA отказывается повиноваться
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
DVF
В расположенном ниже примере кода Timer0, настроенный на режим компаратора по OCR0A не генерит прерывание, как и было задумано. Для этого в цикле мониторится флаг прерывания этого компаратора с последующим его сбросом. Но не пашет чего-это.
CODE
///--- TIMER0 initialize - prescale:1024 --------------
///--- quartz 8MHz
///--- WGM: CTC
///--- desired value: 10mSec
///--- actual value: 10,048mSec (-0,5%)
void timer0_init()
{
STOP_TIMER0(); //stop
//TCNT0 = 0x32; //set count
OCR0A = 0x4E; //set count limite
OCR0B = 0x4E; //set count limite
TCCR0A = 0x02; // WGM: CTC
}

void devices_init()
{
CLI();
ports_init();
ADC_init();
timer0_init();

MCUCR = 0x00;
EICRA = 0x00; // Extended ext ints
EIMSK = 0x00;


PCMSK0 = 0x00;
PCMSK1 = 0x00;
PCMSK2 = 0x00;
PCICR = 0x00;
PRR = 0xEF; // отключение питания от всей периферии
SEI();
}

void main()
{
devices_init(); // Инициализация контроллера (здесь спрятан и вызов инициализации timer0)
POWER_TIMER0_EN(); // Разрешаем питание на Timer0 (PRR &= ~(1<<PRTIM0))
INT_TIMER0_CTCA_DISBL(); // Запрет прерываний от Timer0 (TIMSK0 &= ~(1<<OCIE0A))
START_TIMER0_PRSCL1024(); // Запустк Timer0 (TCCR0B |= (1<<CS02) | (1<<CS00))

while( 1 )
{
if( OCF0A ) // Обнаружение флага компаратора OCF0A Timer0
{
FLAG_TIMER0_CLINE(); // Сбрасываем флаг Timer0 (TIFR0 |= (1<<OCF0A))

switch( LED_Level ) // Включение св.диода с необходимой интенсивностью
{
case 1:
LED_1LEVEL_SCAN_ON();
break;
case 2:
LED_2LEVEL_SCAN_ON();
break;
case 3:
LED_3LEVEL_SCAN_ON();
break;
}

Data_ADSC = 1; // Значение бита ADSC регистра для дальнейшего слежения в while( Data_ADSC ).
// В обработчике прерывания от ADC переменная Data_ADSC обнуляется
POWER_ADC_SUP(); // Подаем питание на ADC (PRR &= ~(1<<PRADC))
ADC_EN(); // Разрешаем работу ADC (ADCSRA |= (1<<ADEN))
ADC_INTERRUPT_EN(); // Разрешаем прерывание от ADC (ADCSRA |= (1<<ADIE))
ADC_START_CONV(); // Запуск измерения (ADCSRA |= (1<<ADSC))
while( Data_ADSC )
{
;
}

LED_LEVEL_SCAN_OFF(); // Выключение св.диода.

if( ADC_Data > 0x99 )
{
LED_NORM_ON();
}
else
{
LED_NORM_ERR_OFF();
}

}
}
}

Само прерывание ADC не примечательно:
Код
#pragma vector = ADC_vect
__interrupt void ADC_interrupt(void)
{
  ADC_Data = ADCH;
  Data_ADSC = 0;
}

На строки подачи питания на АЦП и т.п. просьба не обращать внимание - в будущем планируется вести измерение в режиме ADC Noise Reduction.
На скриншоте видно, что св.диод практически постоянно во включенном состоянии (низкий уровень Digital1). Получается, что светит он на время измерения, далее гашение на короткий отрезок и опять вход в измерение, как-будто флаг Timer0, настроенного на 10мс опять установлен.
Нажмите для просмотра прикрепленного файла
Палыч
Цитата(DVF @ Apr 23 2012, 10:41) *
if( OCF0A ) // Обнаружение флага компаратора OCF0A Timer0
.........
как-будто флаг Timer0, настроенного на 10мс опять установлен.

Чего же Вы хотели с таким-то условием?
DVF
Виноват. Буду пробовать с if( TIFR0 & (1<<OCF0A) )
Действительно, так правильно. Теперь следующий шаг, на котором у меня опять затык - это перевод МК в режим ADC Noise Reduction: не уходит после строки SLEEP_MODE_EN(); в спячку.
CODE

void ADC_init()
{
ADCSRA = (1<<ADPS2) | (1<<ADPS1); // ADC отключен. Предделение тактовой 64 (время конвертации 104uS)
ADMUX = (1<<ADLAR); // Аналоговый вход 0, Выравнивание результатов ADC в лево
DIDR0 = (1<<ADC0D); // Отключение цифрового буфера от входа 0 ADC
ACSR = (1<<ACD); // Отключение питания от компаратора
ADCSRB = 0x00; // ADC: Free Running mode
}

void devices_init()
{
CLI();
ports_init();
ADC_init();
timer0_init();

MCUCR = 0x00;
EICRA = 0x00; // Extended ext ints
EIMSK = 0x00;


PCMSK0 = 0x00;
PCMSK1 = 0x00;
PCMSK2 = 0x00;
PCICR = 0x00;
PRR = 0xEF; // отключение питания от всей периферии
SEI();
}

#pragma vector = ADC_vect
__interrupt void ADC_interrupt(void)
{
SLEEP_MODE_DIS(); // Запрет на "сон"
ADC_Data = ADCH;
}

void main()
{
devices_init(); // Инициализация контроллера (здесь спрятан и вызов инициализации timer0)
POWER_TIMER0_EN(); // Разрешаем питание на Timer0 (PRR &= ~(1<<PRTIM0))
INT_TIMER0_CTCA_DISBL(); // Запрет прерываний от Timer0 (TIMSK0 &= ~(1<<OCIE0A))
START_TIMER0_PRSCL1024(); // Запустк Timer0 (TCCR0B |= (1<<CS02) | (1<<CS00))

while( 1 )
{
if( TIFR0 & (1<<OCF0A) ) // Обнаружение флага компаратора OCF0A Timer0
{
FLAG_TIMER0_CLINE(); // Сбрасываем флаг Timer0 (TIFR0 |= (1<<OCF0A))

switch( LED_Level ) // Включение св.диода с необходимой интенсивностью
{
case 1: LED_1LEVEL_SCAN_ON();
break;
case 2: LED_2LEVEL_SCAN_ON();
break;
case 3: LED_3LEVEL_SCAN_ON();
break;
}

POWER_ADC_SUP(); // Подаем питание на ADC (PRR &= ~(1<<PRADC))
ADC_EN(); // Разрешаем работу ADC (ADCSRA |= (1<<ADEN))
ADC_INTERRUPT_EN(); // Разрешаем прерывание от ADC (ADCSRA |= (1<<ADIE))
ADC_NOISE_REDUCTION_MODE(); // Устанавливаем режим ADC Noise Reduction (SMCR |= (1<<SM0))
SLEEP_MODE_EN(); // Запускаем режим сна (SMCR |= (1<<SE))

LED_LEVEL_SCAN_OFF(); // Выключение св.диода.

if( ADC_Data > 0x99 )
{
LED_NORM_ON();
}
else
{
LED_NORM_ERR_OFF();
}

}
}
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.