#c #embedded #avr #clock
#c #встроенный #avr #часы
Вопрос:
Я пытаюсь установить таймер для запуска прерывания 8 тыс. раз в секунду на AVR128DB48. Код инициализации, который я использую для инициализации часов, приведен ниже.
//clock init
//24Mhz/64 = 375k
//(1/375k)*top=(1/8000)
//top = 46
TCA0.SINGLE.PER = 46;
//enables overflow interrupt
TCA0.SINGLE.INTCTRL |= 0x1;
//sets clock divider to 64 enables clock
TCA0.SINGLE.CTRLA |= TCA_SINGLE_RUNSTDBY_bm | TCA_SINGLE_ENABLE_bm | (5<<1);
Это почти точно то, что в документации указано, что код инициализации должен быть. Для проверки прерывания я использую эту функцию в качестве обработчика прерываний
ISR(TCA0_OVF_vect)
{
outputval = !outputval;
if (outputval){
PORTC.OUT |= 2;
}
else{
PORTC.OUTCLR |= 2;
}
return;
}
Когда я подключаю этот вывод к своему осциллографу и измеряю частоту, он считывает выходную частоту 35 кб. Если я изменяю значение per на что угодно, оно также всегда считывает 35 кб. Я тестировал со значениями, такими как 100 и 200, все те же результаты. Я также меняю делитель тактовой частоты, и я все равно получаю тот же результат в 35 тыс. Если я не установлю бит включения, я не получу никакого вывода. Я чего-то не хватает? OVF прерывания не выполняет то, что я думаю, что он делает? Я несколько раз просматривал документацию и считаю, что все делаю правильно.
Комментарии:
1. Вам нужно очистить источник прерывания в обработчике прерывания, чтобы прерывание не повторялось немедленно?
2. @kkrambo да, это была проблема. большое вам спасибо.
3. Если проблема была решена, поделитесь решением. 🙂
Ответ №1:
Как указал kkrambo, проблема заключалась в том, что с AVR128DB48 этот флаг прерывания не сбрасывается автоматически контроллером прерываний, поэтому вам необходимо сбросить флаг в конце обработчика прерываний перед возвратом. Если вы этого не сделаете, он будет постоянно пытаться обслуживать прерывание снова и снова. Это делается путем записи 1 во флаг прерывания, который для этого периферийного устройства и для этого прерывания (OVF) выполняется следующим кодом ниже:
TCA0.SINGLE.INTFLAGS |= 0x1;
Таким образом, для пересмотренного кода для всего прерывания будет:
ISR(TCA0_OVF_vect)
{
outputval = !outputval;
if (outputval){
PORTC.OUT |= 2;
}
else{
PORTC.OUTCLR |= 2;
}
TCA0.SINGLE.INTFLAGS |= 0x1;
return;
}