Велоспидометр на ардуино

bod9I
Offline
Зарегистрирован: 23.04.2016

Подскажите пожалуйста что не так в этом скетче? Проблема в том что иногда он не хочет считать скорость. Геркон цел.

#include <EEPROM.h>   //библиотека для работы со внутренней памятью ардуино
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F, 16, 2);
unsigned long lastturn; //переменные хранения времени
float SPEED; //переменная хранения скорости в виде десятичной дроби
float DIST; //переменная хранения расстояния в виде десятичной дроби
float w_length=2.050; //длина окружности колеса в метрах


void setup() {
  Serial.begin(9600);  //открыть порт
  Wire.begin(0, 2);
  lcd.begin();
lcd.setCursor(0, 0); // 1 строка
lcd.print("Speed:");


lcd.setCursor(0, 1); // 1 строка
lcd.print("Distance:");

  digitalPinToInterrupt (12);
  attachInterrupt(12,sens,RISING); //подключить прерывание на 2 пин при повышении сигнала
  pinMode(14, OUTPUT);   //3 пин как выход
  digitalWrite(14, HIGH);  //подать 5 вольт на 3 пин
  
  DIST=(float)EEPROM.read(0)/10.0; //вспоминаем пройденное расстояние при запуске системы (деление на 10 нужно для сохранения десятых долей расстояния, см. запись)
}

void sens() {
  if (millis()-lastturn > 80) {  //защита от случайных измерений (основано на том, что велосипед не будет ехать быстрее 120 кмч)
    SPEED=w_length/((float)(millis()-lastturn)/1000)*3.6;  //расчет скорости, км/ч
    lastturn=millis();  //запомнить время последнего оборота
    DIST=DIST+w_length/1000;  //прибавляем длину колеса к дистанции при каждом обороте оного
  }
}

void loop() {
  int cel_sp=floor(SPEED);
  int sot_sp=(((float)cel_sp/1000)-floor((float)cel_sp/1000))*10;
  int des_sp=(((float)cel_sp/100)-floor((float)cel_sp/100))*10;
  int ed_sp=(((float)cel_sp/10)-floor((float)cel_sp/10))*10;
  int dr_sp=(float)(SPEED-floor(SPEED))*10;

  lcd.setCursor(6, 0); 
lcd.print(des_sp);
lcd.setCursor(7, 0); 
lcd.print(ed_sp);
lcd.setCursor(8, 0); 
lcd.print(".");
lcd.setCursor(9, 0); 
lcd.print(dr_sp);
lcd.setCursor(11, 0); 
lcd.print("km/h");
  
  int cel_di=floor(DIST);  //целые
  int sot_di=(((float)cel_di/1000)-floor((float)cel_di/1000))*10;  //сотни
  int des_di=(((float)cel_di/100)-floor((float)cel_di/100))*10;  //десятки
  int ed_di=floor(((float)((float)cel_di/10)-floor((float)cel_di/10))*10);  //единицы (с точкой)
  int dr_di=(float)(DIST-floor(DIST))*10;  //десятые части
  
lcd.setCursor(9, 1); 
lcd.print(des_di);
lcd.setCursor(10, 1); 
lcd.print(ed_di);
lcd.setCursor(11, 1); 
lcd.print(".");
lcd.setCursor(12, 1); 
lcd.print(dr_di);
lcd.setCursor(13, 1); 
lcd.print("km");

  if ((millis()-lastturn)>2000){ //если сигнала нет больше 2 секунды
    SPEED=0;  //считаем что SPEED 0
    EEPROM.write(0,(float)DIST*10.0); //записываем DIST во внутреннюю память. Сделал так хитро, потому что внутренняя память не любит частой перезаписи. Также *10, чтобы сохранить десятую долю
  }
}

Работает на ESP8266 (не спрашивайте почему) 

toc
Offline
Зарегистрирован: 09.02.2013

всё-таки почему?
фотографию вашего изобретения покажите?

toc
Offline
Зарегистрирован: 09.02.2013

что значит не хочет? на экране пишет "обиделся, выключаюсь"? или он думает что едет со скоростью 130 км/ч, а вы ему запретили считать?

sadman41
Offline
Зарегистрирован: 19.10.2016

Думаю, что стандартный прокол - попытка в обработчике обращаться к millis() и проводить вычисления. А так же считывать значения с многобайтовой неволатильной переменной без обеспечения атомарности.

toc
Offline
Зарегистрирован: 09.02.2013

bod9I, после остановки велосипеда сколько раз сохраняется дистанция во внутреннюю память, которая не любит частой перезаписи?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

sadman41 пишет:

Думаю, что стандартный прокол - попытка в обработчике обращаться к millis().

Поясни, почему нельзя обращаться? Она же вроде только отдает значение внутренней переменной. Я всегда внутри прерывания millis() использоваю, чтоб запомнить момент.  Правда, несколько раз миллис вызывать бесполезно, внутри прерывания он не меняется. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так Вы на строку №24 посмотрите. Там можно вызывать миллис, а можно и не вызывать - там пофиг. Хуже уже не будет.

sadman41
Offline
Зарегистрирован: 19.10.2016

DetSimen пишет:

Поясни, почему нельзя обращаться? Она же вроде только отдает значение внутренней переменной. Я всегда внутри прерывания millis() использоваю, чтоб запомнить момент.  

Я не написал, что нельзя. Просто вижу, что товарищ начинает накидывать в обработчик прерывания вычисления, многократное использование millis(). Как правило - вскоре после этого начинается поиск пропавших миллисекунд. Пока он не понимает, что делает - думаю, лучше отказаться от таких приемчиков.