Последовательный вывод 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(){
}
@user4163554, 👍2
1 ответ
Лучший ответ:
км никогда не сбрасывается, а постоянно увеличивается.
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. Подробнее см. в этой статье.
- Как узнать частоту дискретизации?
- Что такое Serial.begin(9600)?
- Использовать все контакты как цифровые входы/выходы
- Float печатается только 2 десятичных знака после запятой
- Arduino как USB HID
- Serial1' was not declared in this scope
- Очень простая операция Arduino Uno Serial.readString()
- AT-команда не отвечает на последовательный монитор