Последовательный вывод Arduino вышел из-под контроля!

У меня возникла небольшая проблема, которую я не могу решить. Я использую Arduino Uno для печати инкрементной, но предопределённой длины окружности колеса. Всё работает прекрасно, за исключением того, что во время выполнения выдаётся отрицательное значение, которое затем становится положительным и т.д. Не будучи точным, вывод выглядит примерно так:

1.85, 3.71, 5.56, 7.41, 9.27, 11.15....

Когда это кратное достигает 32,00 или больше, оно затем отсчитывается отрицательно до нуля, а затем снова положительно до 32,00.

Я не совсем понимаю, почему так происходит, поэтому надеюсь, что кто-нибудь из вас сможет прояснить ситуацию. Код такой:

#include <Arduino.h>

int InterruptPin = 2;
int circ = 1854; //mtrs
int km = 0;


void calculate(){
    km = km + circ;
    //float temp = km / 1000;
    float temp = (float)km / (float)1000;
    Serial.println(temp);
}


void setup(){
    pinMode(InterruptPin, INPUT);
    attachInterrupt(digitalPinToInterrupt(2), calculate, RISING);
    Serial.begin(9600);
}


void loop(){

}

, 👍2


1 ответ


Лучший ответ:

4

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

km = km + circ;

Это приводит к переполнению значения через некоторое время.

Когда вы объявляете int km;, то int на Arduino Uno равно int16_t, то есть его максимальное положительное значение равно 2^15 - 1 = 32767. Поскольку circ — константа 1854, после выполнения ISR в общей сложности CEIL(32767 / 1854) = 18 раз, km станет больше этого максимального положительного значения. Таким образом, происходит целочисленное переполнение, которое возвращает вас к максимальному отрицательному значению int16_t. (См. https://en.wikipedia.org/wiki/Integer_overflow)

Возможно, вы захотите использовать uint32_t или аналогичный из stdint.h, если хотите охватить более широкий диапазон значений. Однако, я думаю, ваш базовый алгоритм несовершенен, поскольку даже в этом случае km переполнится через некоторое время. Вам необходимо сбросить его в какой-то момент или хранить только количество оборотов, что гораздо меньше. Если вы хотите получить пройденное расстояние, нужно взять количество оборотов и умножить его на длину окружности.

Кроме того, не следует использовать печать Serial в процедуре обработки прерываний! Кроме того, следует объявить используемые переменные прерываний как volatile. Подробнее см. в этой статье.

,