Реализация секундомера

Temp
Offline
Зарегистрирован: 01.06.2020

Здравствуйте. У меня есть задача по реализации секундомера, использующая ЖД дисплей и две кнопки. Первая кнопка отвечает за старт секундомера и его остановку(повторное нажатие), вторая отвечает за сброс времени.Также необходимо выводить текущий режим работы(Start/Pause/Reset)

Проблема заключается в режиме работа пауза. Поскольку я не могу использовать сторонние библиотеки(наподобе Bounce / Button), то состояние кнопки я проверяю через флаг и digitalRead. В таком случае получается, что если секундомер не работает - он на паузе, поэтому не получается вывести Reset. Как можно переформулировать условие, чтобы пауза и сброс мирно сосуществовали?

Код прилагаю
 

int state = 1;
bool flag = false;
bool resetFlag = false;
long start;
long finish;
long elaps;
float h, m, s, ms;
unsigned long over;
// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  // set up the LCD's number of columns and rows:
   pinMode(8, INPUT);
  Serial.begin(9600);
  pinMode(9, INPUT);
  lcd.begin(16, 2);
 lcd.setCursor(0,0);
  // Print a message to the LCD.
  lcd.print("Reset");
  lcd.setCursor(0, 1);
lcd.print(h, 0); 
lcd.print("h "); 
lcd.print(m, 0);
lcd.print("m ");
lcd.print(s, 0);
lcd.print("s ");
  lcd.print(ms,0);
    lcd.print("ms ");
}

void loop() {
  if(digitalRead(8) == HIGH && !flag){
	flag = true;
    state++;
    if(state > 2) state = 1;
  }
  if(digitalRead(8) == LOW && flag){
    flag = false;
  }
  
  if(state == 1){
    start = millis();
    elaps+= start - finish;
    h = int(elaps / 3600000);
	over = elaps % 3600000;
m = int(over / 60000);
over = over % 60000;
s = int(over / 1000);
ms = over % 1000;
// показать результаты
lcd.setCursor(0,0);
lcd.print("Start");
lcd.setCursor(0, 1);
lcd.print(h, 0); 
lcd.print("h "); 
lcd.print(m, 0);
lcd.print("m ");
lcd.print(s, 0);
lcd.print("s ");
if (h < 10)
{
lcd.print(ms, 0);
lcd.print("ms ");
}
    finish = start;
    
  }
  if(state == 2) {
    finish = millis();
    lcd.setCursor(0,0);
    lcd.print("Pause");
  }
 
  
  if(digitalRead(9) == HIGH && !resetFlag){
    start = 0;
    finish = 0;
    elaps = 0;
    over = 0;
    state = 1;
    lcd.clear();
    over = 0;
     flag = false;
 
    h=m=s=ms = 0.0;
    lcd.setCursor(0,0);
    lcd.print("     ");
    lcd.setCursor(0,0);
    lcd.print("Reset");
    lcd.setCursor(0, 1);
	lcd.print(h, 0); 
	lcd.print("h "); 
	lcd.print(m, 0);
	lcd.print("m ");
	lcd.print(s, 0);
	lcd.print("s ");
   	lcd.print(ms,0);
    lcd.print("ms ");
  
  }

}
 

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Вижу такой метод - вывести паузу на экран один раз и поставить флаг.

b707
Offline
Зарегистрирован: 26.05.2017

не понял в чем проблема. Режимы Пауза и Ресет управляются разными кнопками. непонятно как Пауза мешает вывести Ресет

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Видимо ввести еще одно состояние: 0 - резет, 1 - старт, 2 - пауза

ЗЫ: дребезг контактов вообще не подавляется?

b707
Offline
Зарегистрирован: 26.05.2017

v258 пишет:

Видимо ввести еще одно состояние: 0 - резет, 1 - старт, 2 - пауза

имхо, ресет не является третим состоянием. Это независимый модификатор, который можно применить как состоянию "пауза", так и к состоянию "счет"

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

b707 пишет:

имхо, ресет не является третим состоянием. Это независимый модификатор, который можно применить как состоянию "пауза", так и к состоянию "счет"

Ага. Ресет - это состояние Стоп с обнулением данных. По идее не должно иметь значение, из какого состояния его вызвали.

У него же ресет взводит переменную state в единицу (стр. 084), а на следующей итерации в строке 045 секундомер тут же снова стартует. Соответственно, ресет у него с экрана исчезает раньше, чем успевает прочитаться )

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Кнопка 1 - старт/ стоп
После старта 2 кнопка работает как пауза /продолжение
В режиме остановки - 2 кнопка как сброс
В режиме пауза нажатие кнопки 1 ни к чему не приводит
Т е всего 1 переменная с тремя режимами

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

немношка дедокода тебе в ленту

Измени только пины дисплея и кнопок на нужные


/*
    Name:       Secundomer.ino
    Created:	02.06.2020 6:35:43
    Author:     DtS
*/

#include <LiquidCrystal.h>

// #interface

//  -----------  TTimer  -----------------

struct TTimer {
protected:
    bool    FActive : 1;
    bool    FChanged : 1;
    uint8_t FHour : 6;
    
    uint8_t FMin;
    uint8_t FSec;

    uint32_t FLastTick;
    char*    FOutString;
public:
    TTimer() {
        FOutString = new char[10];
        Reset();
    }

    ~TTimer() {
        if (FOutString!=NULL) delete[] FOutString;
    }

    void Reset() {
        FHour = FMin = FSec = 0;
        Stop();
    }

    void Start(void) { 
        FLastTick = millis();
        FActive = true;
    }

    inline void Stop(void) { FActive = false; }

    const char* const ToString() {
        FChanged = false;
        sprintf(FOutString, "%02d:%02d:%02d", FHour, FMin, FSec);
        return FOutString;
    }

    void Tick() {
        if (!FActive) return;
        uint32_t now = millis();
        if (now - FLastTick < 1000) return;
        FLastTick = now;
        FChanged = true;
        FSec++;
        if (FSec > 59) {
            FMin++;
            FSec = 0;
        }
        if (FMin > 59) {
            FMin = 0;
            FHour++;
        }
        if (FHour > 23) FHour = 0;
    }

    inline bool isActive() const { return FActive; }

    inline bool isChanged() const { return FChanged; }
};

// -------------  TTimer ends  --------------------

const uint8_t btnStop = A0;   // кнопки с этих пинов на землю  Start/Stop
const uint8_t btnReset = 3;   // Reset

const uint8_t ACTIVE_BTN_LEVEL = LOW;

enum class TProgState :uint8_t { Unknown = 0, Stop, Run };

TProgState ProgState = TProgState::Unknown;

LiquidCrystal Screen(8, 9, 4, 5, 6, 7);

TTimer Timer;

// #implementation

void Display() {
    Screen.clear();
    Screen.print(Timer.ToString());
    Screen.setCursor(0, 1);

    switch (ProgState)
    {
    case TProgState::Unknown:
        Screen.clear();
        Screen.print("Error");
        break;
    
    case TProgState::Stop:
        Screen.print("Stop");
        break;

    case TProgState::Run:
        Screen.print("Running");
        break;

    default:
        break;
    }
}


void SetState(const TProgState ANewState) {
    if (ProgState == ANewState) return;

    ProgState = ANewState;

     switch (ProgState)
     {

     case TProgState::Stop:
         Timer.Stop();
         break;

     case TProgState::Run:
         Timer.Start();
         break;

     default:
         break;
     }

     Display();
}

bool ReadButton(const uint8_t APin) {
    uint8_t cnt = 0;
    for (uint8_t i = 0; i < 16; i++) {
        if (digitalRead(APin) == ACTIVE_BTN_LEVEL) cnt++;
        delay(1);
    }

    return (cnt > 12);
}


void setup()
{
    Serial.begin(115200);
    pinMode(btnStop, INPUT_PULLUP);
    pinMode(btnReset, INPUT_PULLUP);
    Screen.begin(16, 2);
    Screen.clear();
    SetState(TProgState::Stop);
}

void loop()
{
    Timer.Tick();

    if (ReadButton(btnStop)) {

        if (Timer.isActive())
            SetState(TProgState::Stop);
        else
            SetState(TProgState::Run);
        delay(500);
    }

    if (ReadButton(btnReset)) {
        Timer.Reset();
        SetState(TProgState::Stop);
        delay(500);
    }

    if (Timer.isChanged()) Display();

}

справишься, поди.  Не поймешь чонить - спроси меня как, я тебе за пицот р. всё растолкую.