Эксперимент 51. Секундомер

В прошлом эксперименте мы получили секундомер, который умеет отсчитывать время, но еще не поддается управлению. В этом эксперименте мы добавим ему кнопку для запуска и остановки.

Схема эксперимента

Рисунок 1. Монтажная схема эксперимента для дисплея с 8 выводами

Рисунок 2. Монтажная схема эксперимента для дисплея с 11 выводами

Программный код эксперимента

Exp51.ino
  1. #include <SPI.h>
  2. #include <Adafruit_ST7735.h>
  3. #include "LittleFS_ImageReader.h"
  4.  
  5. #define PIN_CS 2
  6. #define PIN_DC 4
  7. #define PIN_RST 5
  8.  
  9. Adafruit_ST7735 tft = Adafruit_ST7735(PIN_CS, PIN_DC, PIN_RST);
  10. LittleFS_ImageReader reader;
  11.  
  12. class Stopwatch {
  13. private:
  14. unsigned int hours = 0;
  15. unsigned int mins = 0;
  16. unsigned int secs = 0;
  17. unsigned long start_time = 0;
  18. bool state = 0;
  19. unsigned int backcolor = tft.color565(255, 251, 240);
  20. unsigned int fontcolor = tft.color565(39, 40, 51);
  21.  
  22. public:
  23. void init() {
  24. tft.fillScreen(backcolor);
  25. reader.drawBMP("/time.bmp", tft, 0, 0);
  26. drawInit();
  27. }
  28.  
  29. void drawInit() {
  30. drawValue(8, 125, 3, 0);
  31. drawValue(55, 125, 3, 0);
  32. drawValue(98, 132, 2, 0);
  33.  
  34. tft.setTextColor(fontcolor);
  35.  
  36. tft.setCursor(41, 125);
  37. tft.setTextSize(3);
  38. tft.print(":");
  39.  
  40. tft.setCursor(88, 132);
  41. tft.setTextSize(2);
  42. tft.print(":");
  43. }
  44.  
  45. void drawValue(int x, int y, int size, int value) {
  46. tft.fillRect(x, y, 6 * size * 2, 8 * size -2, backcolor);
  47.  
  48. tft.setCursor(x, y);
  49. tft.setTextColor(fontcolor);
  50. tft.setTextSize(size);
  51.  
  52. if (value < 10) tft.print(0);
  53. tft.print(value);
  54. }
  55.  
  56. void tick() {
  57. if (state) {
  58. unsigned long diff = millis() - start_time;
  59. int hours_cur = diff / (1000 * 60 * 60);
  60. diff = diff % (1000 * 60 * 60);
  61. int mins_cur = diff / (1000 * 60);
  62. diff = diff % (1000 * 60);
  63. int secs_cur = diff / (1000);
  64.  
  65. if (hours_cur != hours) {
  66. hours = hours_cur;
  67. drawValue(8, 125, 3, hours);
  68. }
  69.  
  70. if (mins_cur != mins) {
  71. mins = mins_cur;
  72. drawValue(55, 125, 3, mins);
  73. }
  74.  
  75. if (secs_cur != secs) {
  76. secs = secs_cur;
  77. drawValue(98, 132, 2, secs);
  78. }
  79. }
  80. }
  81.  
  82. void startStop() {
  83. state = !state;
  84. if (state) start_time = millis();
  85. }
  86. };
  87.  
  88. class Button {
  89. private:
  90. int pin;
  91. bool pressState;
  92. bool oldState;
  93.  
  94. public:
  95. Button(int _pin, bool _pressState) {
  96. pin = _pin;
  97. pinMode(pin, INPUT);
  98. pressState = _pressState;
  99. oldState = not _pressState;
  100. }
  101.  
  102. bool onPress() {
  103. bool state = digitalRead(pin);
  104. if (state != oldState){
  105. oldState = state;
  106. if (state == pressState) return true;
  107. }
  108. return false;
  109. }
  110. };
  111.  
  112. Stopwatch stopwatch;
  113. Button btn(16, HIGH);
  114.  
  115. void setup() {
  116. os_update_cpu_frequency(160);
  117. LittleFS.begin();
  118. tft.initR(INITR_BLACKTAB);
  119. tft.setRotation(2);
  120. stopwatch.init();
  121. }
  122.  
  123. void loop() {
  124. if (btn.onPress()) stopwatch.startStop();
  125. stopwatch.tick();
  126. }

К коду из прошлого эксперимента мы добавили класс кнопки, который уже использовали ранее здесь. Создаем объект кнопки на выводе 16 с логической 1 в нажатом состоянии:

  1. Button btn(16, HIGH);

В основном цикле проверяем не нажата ли кнопка. Если нажатие зафиксировано, то изменяем состояние секундомера (запускаем, если не запущен. Останавливаем, если запущен):

  1. if (btn.onPress()) stopwatch.startStop();

Теперь состоянием таймера можно управлять с помощью кнопки.