Шальные руки голове покоя не дают.
в процессе экспериментов выяснилось, что функция
dtostrf превосходно округляет сама.
также выяснилось, что при расчете скорости в м/с
V = S / T при большом значении T, зачастую получаем на выходе 0.
проблему решил умножением S на 1000, с последующим умножением на 0.001 результата масштабной скорости
Arduino код:
V = S * 1000.0 / T;
sV = V * units[selected_unit][1].toFloat() * scale[selected_scale][1].toInt() * 0.001;
Ну и универсальности хочется... Добавил кнопку выбора количества знаков после запятой при выводе результата.
Ниже два скетча. Первый без кнопки, количество знаков задается в переменной
Arduino код:
int decimals = 1;
переставил датчики на 2-й и 3-й выходы
схема
скетч v2.10 - без кнопки
Arduino код:
/*
scale speed meter v2.10 2016.09.14 13:14 GMT
*/
#include <LiquidCrystal.h> // Добавляем библиотеку LCD
#include <EEPROM.h> // Добавляем библиотеку работы с энергонезависимой памятью
// Добавляем библиотеку антидребезга кнопок
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
Main code by Thomas O Fredericks (tof@t-o-f.info)
Previous contributions by Eric Lowry, Jim Schimpf and Tom Harkaway
[url]https://github.com/thomasfredericks/Bounce2/archive/master.zip[/url]
* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <Bounce2.h>
// переменные, которые можно менять
int S = 70; //дистанция (расстояние между датчиками) в миллиметрах
int resultDelay = 5000; // время показа результата измерений в миллисекундах
int animationDelay = 50; // время задержки анимации в миллисекундах
unsigned long timeoutDelay = 160000; // время ожидания срабатывания второго датчика в миллисекундах
// флаги
unsigned long flagLeft = 0; // время срабатывания левого датчика
unsigned long flagRight = 0; // время срабатывания правого датчика
unsigned long flagShow = 0; //время окончания отображения результатов
unsigned long flagAnimation = 0; //время отображения следующего символа при анимации
// переменные для расчетов
unsigned long timeStart;//время срабатывания первого датчика
unsigned long timeStop;//время срабатывания второго датчика
long T; //интервал в милисекундах
float V; //скорость в м/с
float sV; //масштабная скорость
int selected_scale = EEPROM.read(0); // ключ массива выбранного масштаба
int selected_unit = EEPROM.read(1); // ключ массива выбранных единиц измерения
int decimals = 1; // точности отображения результата
// массивы, которые можно дополнять или изменять
const String scale[][2] = {{" HO", "87"}, {" TT", "120"}, {" N", "160"}}; // массив масштабов (отображение на экране, множитель)
const String units[][2] = {{"KPH", "3.6"}, {"MPH", "2.23694"}}; // массив единиц измерения (отображение на экране, коэффициент перевода из метров в секунду)
LiquidCrystal lcd(4, 5, 6, 7, 8, 9); // (RS, E, DB4, DB5, DB6, DB7) инициализируем дисплей
int ir_left = 2; // вход лекого датчика
int ir_right = 3; // вход правого датчика
int scalePin = 10; // вход кноки выбора масштаба
int unitsPin = 11; // вход кнопки выбора единиц измерения скорости
int decimalsPin = 12; // вход кнопки выбора точночти отображения результатов
Bounce scaleBouncer = Bounce(); // объект-обработчик антидребезга кнопки выбра масштаба
Bounce unitsBouncer = Bounce(); // объект-обработчик антидребезга кнопки выбора единиц измерения
// переменные для анимации
int r;
char c;
void setup() {
lcd.begin(16, 2);
pinMode(ir_left, INPUT);
pinMode(ir_right, INPUT);
pinMode(scalePin, INPUT);
pinMode(unitsPin, INPUT);
// параметры обработчика антидребезга
scaleBouncer.attach(scalePin);
scaleBouncer.interval(5);
unitsBouncer.attach(unitsPin);
unitsBouncer.interval(5);
}
// расчет скорости
void calculateSpeed(int selected_unit, int selected_scale, int decimals){
T = (timeStop - timeStart);
V = S * 1000.0 / T;
sV = V * units[selected_unit][1].toFloat() * scale[selected_scale][1].toInt() * 0.001;
char buffer[12];
String tmpStr = dtostrf(sV, 12, decimals, buffer);
lcd.setCursor(0, 0);
lcd.print(tmpStr);
flagShow = millis() + resultDelay;
timeStart = 0;
timeStop = 0;
}
//рисуем бегущую строку
void animation() {
lcd.setCursor(r, 1);
lcd.print(c);
if(flagRight > 0) {
r++;
if(r > 11){
r = 1;
if(c == '>') {
c = ' ';
}
else {
c = '>';
}
}
}
else if(flagLeft > 0) {
r--;
if(r < 1){
r = 11;
if(c == '<') {
c = ' ';
}
else {
c = '<';
}
}
}
flagAnimation = millis() + animationDelay;
}
void loop() {
if(selected_scale > sizeof(scale)/sizeof(scale[0])-1) {
// если считанное значение больше, чем количество элементов в массиве масштабов - обнуляем значение
selected_scale = 0;
EEPROM.write(0, 0);
}
if(selected_unit > sizeof(units)/sizeof(units[0])-1) {
// если считанное значение больше, чем количество элементов в массиве единиц измерения скоростей - обнуляем значение
selected_unit = 0;
EEPROM.write(1, 0);
}
// если флаг отображения результатов меньше текущего времени выполняем код, в противном случае продолжаем отображать результаты измерений
if(flagShow < millis()) {
flagShow = 0;
// если сработал один датчик, но за время timeoutDelay не сработал второй - выводим TIME OUT
if(timeStart > 0 && timeStart + timeoutDelay < millis()) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" TIME OUT ");
flagShow = millis() + resultDelay;
timeStart = 0;
timeStop = 0;
flagLeft = 0;
flagRight = 0;
flagAnimation = 0;
}
// если одновременно сработали оба датчика, но не выставлены флаги начала измерения - выводим ошибку
else if(digitalRead(ir_right) == LOW && digitalRead(ir_left) == LOW && flagLeft == 0 && flagRight == 0) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" ERROR ");
flagShow = millis() + 1000;
}
// если нет сигнала от обоих датчиков и не выставлены флаги обоих датчиков - система готова к измерениям
else if(digitalRead(ir_right) == HIGH && digitalRead(ir_left) == HIGH && flagLeft == 0 && flagRight == 0) {
// если была нажата кнопка масштаба
if(scaleBouncer.update()){
if(scaleBouncer.read() == HIGH) {
selected_scale++;
if(selected_scale > sizeof(scale)/sizeof(scale[0])-1){
selected_scale = 0;
}
}
}
// если была нажата кнопка единиц измерения
if (unitsBouncer.update()){
if(unitsBouncer.read() == HIGH) {
selected_unit++;
if(selected_unit > sizeof(units)/sizeof(units[0])-1){
selected_unit = 0;
}
}
}
// если была нажата кнопка единиц измерения
if (unitsBouncer.update()){
if(unitsBouncer.read() == HIGH) {
selected_unit++;
if(selected_unit > sizeof(units)/sizeof(units[0])-1){
selected_unit = 0;
}
}
}
char buffer[12];
String tmpStr = dtostrf(0.000, 12, decimals, buffer);
lcd.setCursor(0, 0);
lcd.print(tmpStr);
lcd.setCursor(13, 0);
lcd.print(units[selected_unit][0]);
lcd.setCursor(13, 1);
lcd.print(scale[selected_scale][0]);
lcd.setCursor(1, 1);
lcd.print("READY ");
}
// если измерения не началось и сработал один из датчиков при этом нет флага второго датчика - начинаем замер
else if(timeStart == 0 && ((digitalRead(ir_right) == LOW && flagLeft == 0) || (digitalRead(ir_left) == LOW && flagRight == 0))) {
timeStart = millis();
if(digitalRead(ir_right) == LOW){
flagRight = millis();
c = '>';
r = 1;
}
else {
flagLeft = millis();
c = '<';
r = 11;
}
lcd.setCursor(1, 1);
lcd.print(" ");
animation();
}
// если сработал один из датчиков и выставлен флаг второго - заканчиваем измерения и производим расчет скорости
else if((digitalRead(ir_right) == LOW && flagLeft > 0) || (digitalRead(ir_left) == LOW && flagRight > 0)) {
timeStop = millis();
flagLeft = 0;
flagRight = 0;
flagAnimation = 0;
EEPROM.update(0, selected_scale);
EEPROM.update(1, selected_unit);
lcd.setCursor(1, 1);
lcd.print("RESULT ");
calculateSpeed(selected_unit, selected_scale, decimals);
}
// если настало время рисовать новый символ при анимации
else if(flagAnimation < millis()){
animation();
}
}
}
во втором варианте, (v3.10) выбор кнопкой от одного до трех знаков