Реализация секундомера
- Войдите на сайт для отправки комментариев
Пнд, 01/06/2020 - 18:16
Здравствуйте. У меня есть задача по реализации секундомера, использующая ЖД дисплей и две кнопки. Первая кнопка отвечает за старт секундомера и его остановку(повторное нажатие), вторая отвечает за сброс времени.Также необходимо выводить текущий режим работы(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 ");
}
}
Вижу такой метод - вывести паузу на экран один раз и поставить флаг.
не понял в чем проблема. Режимы Пауза и Ресет управляются разными кнопками. непонятно как Пауза мешает вывести Ресет
Видимо ввести еще одно состояние: 0 - резет, 1 - старт, 2 - пауза
ЗЫ: дребезг контактов вообще не подавляется?
Видимо ввести еще одно состояние: 0 - резет, 1 - старт, 2 - пауза
имхо, ресет не является третим состоянием. Это независимый модификатор, который можно применить как состоянию "пауза", так и к состоянию "счет"
имхо, ресет не является третим состоянием. Это независимый модификатор, который можно применить как состоянию "пауза", так и к состоянию "счет"
Ага. Ресет - это состояние Стоп с обнулением данных. По идее не должно иметь значение, из какого состояния его вызвали.
У него же ресет взводит переменную state в единицу (стр. 084), а на следующей итерации в строке 045 секундомер тут же снова стартует. Соответственно, ресет у него с экрана исчезает раньше, чем успевает прочитаться )
Кнопка 1 - старт/ стоп
После старта 2 кнопка работает как пауза /продолжение
В режиме остановки - 2 кнопка как сброс
В режиме пауза нажатие кнопки 1 ни к чему не приводит
Т е всего 1 переменная с тремя режимами
немношка дедокода тебе в ленту
Измени только пины дисплея и кнопок на нужные
/* 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(); }справишься, поди. Не поймешь чонить - спроси меня как, я тебе за пицот р. всё растолкую.