Прерывание сравнения Timer2 не работает должным образом
Чтобы разобраться с этим в первую очередь: я уже посмотрел на "Timer2 does not works as it should" и "Timer2 “Clear OC2B on Compare Match” not working as expected in CTC mode", но не нашел ответы там особенно полезными.
Теперь перейдем к моей проблеме:
Я пытаюсь использовать Timer2 в режиме CTC, чтобы прерывание происходило каждые 500 мкс. Для этого у меня есть следующий код:
#include "TimerTwo.h"
TimerTwo Timer2;
ISR(TIMER2_COMPA_vect) { //ISR при сравнении совпадений A
Timer2.isrCallback();
}
void TimerTwo::initialize() {
cli();
TCCR2A = 0;// установить весь регистр TCCR2A в 0
TCCR2B = 0;// то же самое для TCCR2B
TCNT2 = 0;//инициализируем значение счетчика до 0
// установить регистр сравнения для приращения 2 кГц
OCR2A = 124;// = (16*10^6) / (2000*64) - 1 (должно быть < 256)
// включить режим CTC
TCCR2A |= _BV(WGM21);
// Установить бит CS22 для 64-кратного предварительного делителя
TCCR2B |= _BV(CS22);
// включить прерывание сравнения таймера
TIMSK2 |= _BV(OCIE2A);
sei();
}
void TimerTwo::attachInterrupt(void (*isr)()) {
TIMSK2 |= _BV(OCIE2A);
isrCallback = isr;
}
void TimerTwo::detachInterrupt() {
TIMSK2 &= ~_BV(OCIE2A);
isrCallback = nullptr;
}
и
#ifndef TIMERTWO_H
#define TIMERTWO_H
#include <Arduino.h>
class TimerTwo
{
public: //методы
void initialize();
void attachInterrupt(void (*isr)());
void detachInterrupt();
void (*isrCallback)();
};
extern TimerTwo Timer2;
#endif
Вдохновением послужила библиотека TimerOne.
Однако, когда я измеряю период на выходном выводе (который я подключил внутри какого-то другого кода), я получаю только период 1 мс. Даже если я устанавливаю ORC2A
на 63, этот факт не меняется.
У меня есть конструктор, который вызывается внутри моего setup()
, поэтому регистры не должны перезаписываться при подключении.
Я также посмотрел техническое описание ATmega328p и проверил, что все регистры установлены правильно.
Заранее спасибо за помощь. Если вам понадобится дополнительная информация, дайте мне знать.
@Lithimlin, 👍1
1 ответ
Лучший ответ:
Так что вы правы, CTC ведет себя странно. Я тоже замечал это несколько лет назад на другой плате, но я всегда подозревал асинхронный режим (я добавил 32k RTC Xtal на Arduino Mega).
Однако режим Fast PWM с OCR2A
в качестве значения TOP
, похоже, работает:
class TimerTwo
{
public: //методы
void initialize();
void attachInterrupt(void (*isr)());
void detachInterrupt();
void (*isrCallback)() = nullptr;
};
TimerTwo Timer2;
ISR(TIMER2_COMPA_vect) { //ISR при сравнении совпадений A
Timer2.isrCallback();
}
void TimerTwo::initialize() {
cli();
OCR2A = 124; // = (16*10^6) / (2000*64) - 1 (должно быть < 256)
TCCR2A = _BV(WGM21) | _BV(WGM20); // включаем быстрый режим ШИМ с верхним в OCR2A
TCCR2B = _BV(WGM22) | _BV(CS22); // Установить бит CS22 для 64-кратного предварительного делителя
TCNT2 = 0; // инициализируем значение счетчика на 0
sei();
}
void TimerTwo::attachInterrupt(void (*isr)()) {
isrCallback = isr;
TIMSK2 |= _BV(OCIE2A);
}
void TimerTwo::detachInterrupt() {
TIMSK2 &= ~_BV(OCIE2A);
isrCallback = nullptr;
}
volatile uint32_t counter = 0;
void isrHandler() {
++counter;
}
void setup() {
Serial.begin(115200);
Timer2.initialize();
Timer2.attachInterrupt(&isrHandler);
}
void loop() {
static uint32_t counter_old = 0;
Serial.println(counter - counter_old);
counter_old = counter;
delay(500);
}
EDIT: Хорошо, после некоторого изучения этой проблемы я обнаружил, что настройка режима CTC может привести к повреждению OCR2A (я полагаю?). Кажется, это работает, если изменить порядок настроек следующим образом:
TCCR2B = 0; // остановить таймер и сбросить WGM22
TCCR2A = _BV(WGM21); // включаем режим CTC с верхним в OCR2A
OCR2A = 124; // = (16*10^6) / (2000*64) - 1 (должно быть < 256)
TCNT2 = 0; //инициализируем значение счетчика до 0
TCCR2B = _BV(CS22); // Установить бит CS22 для 64 предварительного делителя (для запуска таймера)
- ATmega328P - проблема с использованием таймера 2 для генерации тона
- Точность синхронизации Arduino nano
- Интервальный таймер на Arduino: Сомнения по поводу библиотеки TimerOne
- Можно ли отсоединить прерывание на определенное время
- Заставить TCNT оставаться ниже OCRxA на ATmega328P
- Эмуляция Arduino Uno с помощью QEMU: прерывания не работают
- Arduino непрерывно считывает значение АЦП с помощью прерывания
- Генерация стабильной частоты