Помогите с Timer2 и UART

Здравствуйте гуру форума. Помогите пожалуйста разобраться в проблеме. На ардуино не так давно начал работать а с прерываниями ещё не имел дело.
Устройство на Nano 328. На вывод PD3 приходит ШИМ сигнал. Нужно определить частоту и перевести её в скорость (км/ч). Далее отправить её на UART. Uart использую для теста и отладки, в дальнейшем будет ISP (модуль мср2515).
Суть программы: По прерыванию INT1 считаю количество импульсов. По прерыванию Timer2 веду отсчет времени.
Суть проблемы: не работает команда Serial.print в участке кода там где мне нужно. Зато работает там где мне не нужно. Если закомментировать Timer2 то команда Serial.print будет работать. Пробовал так же с Tmr0 и Tmr1.
В строчке кода №71 Serial.print не выполняется. Как будто её там нет. Зато в строчке 63 всё работает (вставил Serial.print для теста).
Строчка 71 будет выполняться при условии, что строка 63 не закомментирована.
В строке 25 пробовал разные конфигурации. Тесты проводил в протеусе.
Помогите пожалуйста в этой проблеме.

#include <avr/io.h>
#include <avr/interrupt.h>
// test 1
//#include <mcp2515.h>      //Library for using CAN Communication
//struct can_frame canMsg;
//MCP2515 mcp2515(10);

byte Data1 = 0; // 0 to 255
byte Data2 = 0; // 0 to 255
byte Speed = 0; // 0 to 255
unsigned long xx = 0;  //  0 to 4 294 967 295
unsigned long countin = 0;  //  0 to 4 294 967 295
unsigned long timer;    //  0 to 4 294 967 295
unsigned long Finishcountin = 0;    //  0 to 4 294 967 295
float Floy = 0;
float Speed2 = 0;
float Rkolesa = 0.32; // Радиус колеса в метрах

void setup()  
  {
cli(); // отключить глобальные прерывания
  TCCR2A = 0;
  TCCR2B = 0;
  TIMSK2 = (1 << TOIE1);              
  TCCR2B |= (1 << CS20);  
   sei();  // включить глобальные прерывания

  Serial.begin(9600);   // initialize the serial communication:
 
  //mcp2515.reset();
  //mcp2515.setBitrate(CAN_500KBPS,MCP_8MHZ); //устанавливаем скорость шины CAN 500 кбит/с и частоту кварцевого генератора 8 МГц
  //mcp2515.setNormalMode();

 attachInterrupt (1, insig, RISING); //прерывания INT1
  }

ISR(TIMER2_OVF_vect) // процедура обработки прерывания
{
    timer ++;
    
     if (timer == 40000){
     Finishcountin = 1;
     }     
}
   
   void insig()      // прерывания по INT1 
   { 
  countin ++;
   }
   

  
void loop() 
{ 
  
  Finishcountin = 0;
  countin = 0;
  timer = 0;
  Floy = 0;
  
while (Finishcountin == 0)
 {
     Serial.print(Speed); // тут переменная отправляется в порт
     delay(500);
 }

////////////////////////////
  xx = (62500*countin)/timer;  // Вычисляет частоту. В Гц
  Speed = ((2*3.14*Rkolesa*((xx/42)*60))/60)*3.6;  // Вычисляет скорость от частоты и радиуса колеса. (42 - это 42 импульса на 1 оборот)
   
  Serial.print(Speed); // тут переменная не отправляется в порт
delay(1000);
 
}

Работать где, стр71?
Не пойму, только как. Ведь переменная Finishcountin будет всегда равна 0, и будет вечный цикл стр61.

Попробуйте объявить переменную

volatile unsigned long Finishcountin = 0;

Вряд ли поможет. Компилятор прекрасно видит что переменная меняется и используется.

Период импульса вычислять прерываниями таймера и INT это моветон. Надо либо таймер в режиме захвата использовать( если частота импульсов относительно малая), либо за ед.времени подсчитывать кол-во импульсов на внешнем входе таймера(при большой частоте).
И бросьте эти лишние “для человеков” вычисления

Ресурсов надо много. Переведите кол-во импульсов сразу км/ч через коэффициент и радиус.

Не пойму, нафига печатать скорость с частотой 500мс, если она не меняется?

И еще - какой у вас примерный период внешнего ШИМ? Считать 40 тыс импульсов для обработки - не многовато ли?

42 имп/об, 0.64м диаметр. При скорости 100 км/ч получаем 1166 имп/сек.
Такие тайминги быстрей измерять именно замером периода между импульсами.
Таймер как настроен? Я по памяти не помню,просветите.

Если закомментировать (либо вообще убрать Timer2) то да, строка 71 выполняется. Вечным цикл While не будет, так как Finishcountin изменит значение в строке 42. А до этого да, он будет находится в цикле While.

Поскольку Тс обрабатывает данные скорости раз в 40 тыс импульсов, значит даже при скорости 100 кмч данные на спидометре будут обновлятся 1 раз примерно в 35 секунд . Шустрый такой спидометр, ничего не скажешь…

1 лайк

Timer2 настроен без делителя, 1/1. В данном случае это все его настройки. Так то все вычисления работают. Частоту вычисляет, скорость тоже. Но не отправляет в терминал. Что вы имели ввиду про использования одновременно IN и Timer2 ?

может вы просто недостаточно ждете? При небольших скоростях ваш код будет отправлять данные в терминал раз в 5-10 минут, надо иметь терпение…

Весь код полон каких-то нелепых ляпов. Вроде идея правильная, а реализация вся через Ж… простите…

Вы правы, абсолютно не нужно. Строчка 63 и 64 там не нужны. Но сейчас они там стоят для тестирования. Именно в этом и проблема, что строчка 64 выполняется а строчка 71 не хочет. Если сделать так что бы строка 71 выполнялась то 63-64 можно удалить

Улыбнуло)
6.28Rkolesaxx/42*3.6

Частота замера выходит не такой. Примерно 200-300 мс получилось в тестах в протеусе

Частота МК какая?

у вас как с математикой в школе было? все вычисления выше.

позвольте вам не поверить. Может вы просто не замечаете, когда оно срабатывает?
Вот смотрите - у вас печать идет оператором

Serial.print(Speed);

без пробелов, без перевода строк. То есть в терминале вы должны видеть просто непрерывный ряд цифр. В котором, по моим прикидкам, примерно на 50 выводов строки 64 приходится одно значение из строки 71. Немудренно, что вы его просто не замечаете.
Повторюсь, весь код просто как будто создан только для того, чтобы выдавать полную хрень.

1 лайк

Прощаю)) я понимаю что там не так как должно быть и как все привыкли) буду стараться изучать эти моменты. Просто до этого делал програмки для себя во Flowcode. А в ардуине недавно начал.
Насчет 5-10 минут: дело в том, что строка 69 выполняется регулярно (примерно 200-400 мс.) Т.е. программа обсчитывает всё достаточно быстро

Если 16 МГц, 8 битный счётчик переполняется 62500 раз в секунду. Переменная Finishcountin уст.в “1” 62500/40000=1.56 Гц или 0.641мс.

1 лайк

абсолютно нереальная цифра, кстати, с учетом задержки 500мс в строке 65

А мне всегда нравились эти имена переменных, типа Rkolesa, как и diametrZalupy… Ну чем плохо! И, главное, всем понятно. На самом деле ППЦ!

Да я же не спорю. Я пытаюсь донести что я вижу (по протеусу) Строка 69 то выполняется регулярно.
Сейчас делаю как вы посоветовали