🔍 Возможные проблемы:
Неправильная очистка флага прерывания (IR):
c
Copy
Edit
LPC_TIM2->IR |= BIT(4);
Регистр IR является регистрoм типа write-1-to-clear, поэтому правильный способ очистки флага должен выглядеть так:
c
Copy
Edit
LPC_TIM2->IR = BIT(4);
То же самое касается BIT(5). Использование |= может случайно установить другие биты, если в регистре IR уже есть значения.
Избыточное использование volatile для tm2_cr0 и tm2_cr1:
c
Copy
Edit
static volatile uint32_t tm2_cr0;
Ключевое слово volatile используется, когда значение переменной может изменяться извне (например, оборудованием или другим прерыванием). В данном случае это лишнее — переменные используются только внутри ISR и не изменяются снаружи. Лучше так:
c
Copy
Edit
static uint32_t tm2_cr0;
Проблемы синхронизации при чтении CR0, CR1:
Регистр CRx может изменяться динамически, особенно если источник сигнала внешний. Если прерывание задерживается, разность между CRx и tm2_crx может быть большой, что приведёт к ошибочному увеличению счётчика.
Ошибка в логике FIN_MIN_PERIOD:
Неизвестно, чему равен FIN_MIN_PERIOD. Если значение слишком большое или тип данных выбран неверно, сравнение может быть некорректным и импульсы не будут считаться.
Нет защиты от переполнения CR0/CR1:
Регистр CR0 и CR1 имеют ограниченную длину (например, 32 бита), и могут переполниться. Сравнение:
c
Copy
Edit
if (LPC_TIM2->CR0 - tm2_cr0 >= FIN_MIN_PERIOD)
работает корректно, если переменные типа uint32_t, но важно удостовериться, что логика переполнения учитывается.
Слишком длинный код внутри обработчика прерывания (ISR):
В ISR не рекомендуется выполнять много логики — здесь происходят сравнения, присваивания, инкременты... Если ISR работает слишком долго, можно потерять последующие прерывания.
✅ Рекомендуемая версия обработчика:
c
Copy
Edit
void TIMER2_IRQHandler(void)
{
static uint32_t tm2_cr0;
static uint32_t tm2_cr1;
// Обработка канала 0 (CR0)
if (LPC_TIM2->IR & BIT(4)) {
LPC_TIM2->IR = BIT(4); // Очистка флага
uint32_t now = LPC_TIM2->CR0;
if ((now - tm2_cr0) >= FIN_MIN_PERIOD) {
tm2_cr0 = now;
vars.fcntr[0]++;
}
}
// Обработка канала 1 (CR1)
if (LPC_TIM2->IR & BIT(5)) {
LPC_TIM2->IR = BIT(5); // Очистка флага
uint32_t now = LPC_TIM2->CR1;
if ((now - tm2_cr1) >= FIN_MIN_PERIOD) {
tm2_cr1 = now;
vars.fcntr[1]++;
}
}
}