Прерывание по переполнению таймера срабатывает и по переполнению и по достижении половины

Здравствуйте. Это программа для расходомера на основе водяного счетчика. В счетчик поставлен ик датчик, от него идет сигнал с частотой пропорциональной расходу на 8 пин ардуино нано. В программе задействован таймер1 в режиме захвата. Проблема в том, что счетчик переполнений таймера увеличивается не только по переполнению, но и по достижению половины т.е. 32768.

//расходомер на основе водяного счетчика . один импульс - 2.442 Е-2 литра.
//сигнал поступает на пин8,считается длина периода, по нему вычисляется расход воды в л/мин.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C MyLCD(0x27, 16, 2);

volatile bool Start = 0;
volatile uint8_t T1OVF_Counter = 0; //счетчик количества прерываний по переполнению таймера1
volatile uint32_t T = 0, T2 = 0;
float Rashod = 0;
const float Imp = 3.663E+5;

ISR(TIMER1_OVF_vect)
{
  T1OVF_Counter++;
}

ISR(TIMER1_CAPT_vect)
{
  if (!Start)
  {
    TCNT1 = 0;
    Start = 1;
  }
  else
  {
    T2 = ICR1;
    T = ((uint32_t)T1OVF_Counter << 16) | T2;
    T1OVF_Counter = 0;
    Start = 0;
  }
}

void setup() {
  MyLCD.begin();
  MyLCD.setBacklight(1);
  pinMode(8, INPUT);
  TCCR1A = 0; TCCR1B |= B11000011;  //шумоподавитель вкл, передний фронт вкл, прескалер =64
  TIMSK1 |= B00100001; // вкл прерывания по переполнению и захвату
}

void loop() {
  Rashod = Imp / T;  //литров в минуту
  MyLCD.clear();
  MyLCD.setCursor(0, 0);
  MyLCD.print(T);
  MyLCD.setCursor(0, 1);
  MyLCD.print(Rashod, 4);
  MyLCD.setCursor(8, 1);
  MyLCD.print("L/MIN");
  delay(500);

}

вопросов не было видимо надо покритиковать код…
думаю так будет правильней…
ИМХО

  pinMode(8, INPUT);
  TCCR1A = 0; TCCR1B |= 0b11000011;  //шумоподавитель вкл, передний фронт вкл, прескалер =64
  TIMSK1 |= 0b00100001; // вкл прерывания по переполнению и захвату

Не критично. Что в лоб, что по лбу. В binary.h ардуины есть определения в такой записи. Например:
#define B00100001 33

А можно поподробнее, как именно это реализовано?

В строке 28 переполнение

Интересно, из каких тайных соображений счетчик переполнений выбран размера 8 бит? Прикидывали, будет ли это достаточно?

Покажите, как вы это определяете. Если код немного упростить, всё норм

Спойлер
//расходомер на основе водяного счетчика . один импульс - 2.442 Е-2 литра.
//сигнал поступает на пин8,считается длина периода, по нему вычисляется расход воды в л/мин.

volatile bool Start = 0;
volatile uint8_t T1OVF_Counter = 0; //счетчик количества прерываний по переполнению таймера1
volatile uint32_t T = 0, T2 = 0;
volatile uint16_t saveTimer;
uint16_t saveTMR1[100] = {0};
uint16_t index_saveTMR1 = 0;
uint16_t tik = 0;
uint8_t  T1OVF_MASS[100] = {0};

ISR(TIMER1_OVF_vect)
{
  T1OVF_Counter++;
}

ISR(TIMER1_CAPT_vect)
{
  if (!Start)
  {
    TCNT1 = 0;
    Start = 1;
  }
  else
  {
    T2 = ICR1;
    T = ((uint32_t)T1OVF_Counter << 16) | T2;
    T1OVF_Counter = 0;
    Start = 0;
  }
}

void setup() {
 Serial.begin(9600);
  pinMode(8, INPUT);
  TCCR1A = 0; TCCR1B |= B11000011;  //шумоподавитель вкл, передний фронт вкл, прескалер =64
  TIMSK1 |= B00100001; //B00100001; вкл прерывания по переполнению и захвату
}

void loop() {

 saveTMR1[index_saveTMR1] = TCNT1;
 T1OVF_MASS[index_saveTMR1] = T1OVF_Counter;
 tik++;
 if(tik > 1000)
 {
 index_saveTMR1++;
 tik = 0;
 }
 if(index_saveTMR1 > 99)
 {
    for(uint8_t i = 0; i < 100; i++)
    {
      Serial.print(saveTMR1[i]);
       Serial.print("   ");
      Serial.print(T1OVF_MASS[i]); 
      Serial.println();
    }
 
  for(; ;);
 }
}
Спойлер

Screenshot_90

Думаю, считает расход по формуле.
Расход у него получается неправильный, поэтому он думает что прерывание не работает.

Ну, если так, то другое дело. А то всё думаю, как такое может быть?
Хотя, хотелось бы услышать автора.))

Это, конечно, догадки - но посмотри внимательнее на его код. Диагностического вывода счетчика у него в коде нет… а значит он делает вывод об ошибке по косвенным признакам.

Согласен

на оси счетчика крутится шторка, перекрывает датчик от старого видака.

не понял почему в 28 строке перполнение. а 8 бит хватает за глаза, и 4 хватило бы

Не знаю, что тут выполнится раньше - сдвиг влево на 16 бит (с переполнением) или приведение счетчика к 32 битам:

В любом случае, я бы еще пару скобок добавил, лишними не будут::

 T = ( ((uint32_t)T1OVF_Counter)  << 16) | T2;

Вы не ответили на вопрос, как вы установили, что у вас прерывание срабатывает на 32767?

определяю так: подаю вместо датчика частоту, плавно увеличиваю. после 32767 количество посчитанных тактов перескакивает на98304, а счетчик переполнений увеличивается на 1.

А где вы это видите?

на оледе

Какая строка в скетче?

46
ну раньше еще была строка для выведения количества переполнений, потом убрал.
И ко всем: я на этом форуме 1 день, плохо ориентируюсь в интерфейсе. Если что извиняйте. да и программист я без году неделя.

Поставьте эксперимент - попробуйте увеличивать счетчик переполнений, только если TCNT1 =0 или около того

Строка 46 не показывает напрямую

Как по мне, формула стр.28 неверна. Надо по первому фронту сохранить значение ICR1, а по второму вычесть из текущего сохранённое (ИМХО, могу ошибаться)