Ошибка подкралась незаметно. "millis()"

Тема в разделе "Arduino & Shields", создана пользователем D_REC, 31 окт 2021.

  1. D_REC

    D_REC Нерд

    Делаю проект известного блогера AlexGyver - спидометр для велосипеда.
    В программе есть условие. Если сигнала нет больше 2 секунды, то скорость равна нулю. И якобы это условие должно выполнится один раз при прохождения времени 2 секунды.
    Но когда я поставил вывод на дисплей при обнулении скорости, экран стал жутко моргать.
    Оказалось что условие выполняется тысячи раз при отсутствии сигнала больше двух секунд.

    Как обнулить скорость и вывести на экран только однократно?

    PS. в своем проекте буду использовать дисплей LCD16*2

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


    Код (C++):
    /*
    Created 2016
    by AlexGyver
    AlexGyver Home Labs Inc.
    */


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

    #include <Servo.h>   //библиотека для работы с сервоприводом
    Servo servo;  //объявить серво назвать servo
    unsigned int min_speed=0;  //минимальная отображаемая скорость, км/ч
    unsigned int max_speed=40; //максимальная отображаемая скорость, км/ч

    //-----------дисплей-----------
    #include <TM74HC595Display-old.h>
    int SCLK = 7;
    int RCLK = 6;
    int DIO = 5;
    TM74HC595Display disp(SCLK, RCLK, DIO);
    unsigned char LED_0F[29];
    //--------дисплей-------

    unsigned long lastturn, time_press; //переменные хранения времени
    float SPEED; //переменная хранения скорости в виде десятичной дроби
    float DIST; //переменная хранения расстояния в виде десятичной дроби
    float w_length=2.050; //длина окружности колеса в метрах
    boolean flag; //флажок для хранения (что выводим на дисплее, скорость или расстояние)
    boolean state, button; //флажки для обработчика нажатия кнопки

    void setup() {
      servo.write(0);
      Serial.begin(9600);  //открыть порт
      attachInterrupt(0,sens,RISING); //подключить прерывание на 2 пин при повышении сигнала
      pinMode(3, OUTPUT);   //3 пин как выход
      digitalWrite(3, HIGH);  //подать 5 вольт на 3 пин
      pinMode(8, INPUT);   //сюда подключена кнопка
      servo.attach(4);  //серво на 4 порту
      //для дисплея цифры----------
      LED_0F[0] = 0xC0; //0
      LED_0F[1] = 0xF9; //1
      LED_0F[2] = 0xA4; //2
      LED_0F[3] = 0xB0; //3
      LED_0F[4] = 0x99; //4
      LED_0F[5] = 0x92; //5
      LED_0F[6] = 0x82; //6
      LED_0F[7] = 0xF8; //7
      LED_0F[8] = 0x80; //8
      LED_0F[9] = 0x90; //9
      //--------------
      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 pos=map(SPEED, min_speed, max_speed, 180, 0); //перевести значение от минимума до максимума в угол поворота сервы (от 0 до 180)
      servo.write(pos);  //повернуть серву

      disp.digit4(DIST,50);  //вывод расстояния на дисплей


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

        if (digitalRead(8)==1) {    // Если кнопка нажата
       DIST=0;    //обнулить расстояние
      }
    }
     
     
  2. LeTaGa

    LeTaGa Нерд

    Код (C++):
    int status = 0; // в начало

    status = 0; // в функцию sens


    if(status == 0){
    if ((millis()-lastturn)>2000){  секунды
    SPEED=0; //считаем что SPEED 0
    lcd.print(SPEED,1);
    EEPROM.write(0,(float)DIST*10.0);
    status = 1;
    }
    }
     
  3. D_REC

    D_REC Нерд

    Спасибо, завтра попробую.
     
  4. Andy16

    Andy16 Гик

    А если вместо этого использовать значение SPEED?
    if(SPEED > 0){
     
  5. b707

    b707 Гуру

    А причем тут вообще это условие? - В показанном коде оно вывод на экран не меняет вовсе. А если вы уже переделали код гайвера, насажали своих ошибок - то и задавать вопрос надо по ВАШЕМУ коду, а не по коду гайвера
     
    Andrey12 нравится это.
  6. SergeiL

    SergeiL Оракул Модератор

    Так у гайвера там тоже криво.
    Его хитрость по поводу снижения количества записи в EEPROM, не работает после двух секунд стояния.
    Он начинает писать в EEPROM при каждом вызове loop(). ;)
     
    Andrey12 и DetSimen нравится это.
  7. LeTaGa

    LeTaGa Нерд

    Так там прерывание сделано. Должно что-то выводить.
    Код (C++):
     attachInterrupt(0,sens,RISING); //подключить прерывание на 2 пин при повышении сигнала
     
  8. Andy16

    Andy16 Гик

    Прерывание там, к счастью, ничего на экран не выводит. Просто считает скорость и расстояние каждый оборот колеса.
     
  9. akl

    akl Гуру

    сегментный индикатор в велокомпе решение сомнительное - аккумулятор будет жрать как не в себя. ну и к ардуине надо применять энергосбережение.
     
    SergeiL нравится это.
  10. D_REC

    D_REC Нерд



    Проверил, все отлично работает. Спасибо.
     
  11. D_REC

    D_REC Нерд

    Нет смысла записывать все что выше нуля. Задача в том, что если датчик не срабатывает более двух секунд то колесо не движется и соответственно скорость равна нулю.
     
  12. D_REC

    D_REC Нерд

    Вот для этого использую ЖК 16*2
     
  13. Andy16

    Andy16 Гик

    Я понимаю в чем задача. Я просто хотел тебе переменную сэкономить (status). Потому что она дублирует переменную SPEED.