Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слеваПредыдущая версия
Следующая версия
Предыдущая версия
products:laboratory_iot_c:exp50 [2024/12/13 15:34] – [Класс Stopwatch] labuser30products:laboratory_iot_c:exp50 [2024/12/13 17:12] (текущий) – [Программный код эксперимента] labuser30
Строка 32: Строка 32:
  
   public:   public:
-    // Функция инициализации вместо конструктора, которым мы не можем воспользоваться,+    // Метод инициализации вместо конструктора, которым мы не можем воспользоваться,
     // т.к. нам нужен уже инициализированный объект дисплея     // т.к. нам нужен уже инициализированный объект дисплея
     void init() {       void init() {  
       tft.fillScreen(backcolor); // Закрашиваем дисплей цветом фона       tft.fillScreen(backcolor); // Закрашиваем дисплей цветом фона
       reader.drawBMP("/time.bmp", tft, 0, 0); // Выводим изображение секундомера       reader.drawBMP("/time.bmp", tft, 0, 0); // Выводим изображение секундомера
-      draw_init(); // Вызов функции отображения начального значения- нулей+      drawInit(); // Вызов функции отображения начального значения- нулей
     }      } 
  
-    // Функция вывода начального значения секундомера — нулей +    // Метод вывода начального значения секундомера — нулей 
-    void draw_init() { +    void drawInit() { 
-      draw_value(8, 125, 3, 0);  // Выводим на дисплей 0 часов +      drawValue(8, 125, 3, 0);  // Выводим на дисплей 0 часов 
-      draw_value(55, 125, 3, 0); // Выводим на дисплей 0 минут +      drawValue(55, 125, 3, 0); // Выводим на дисплей 0 минут 
-      draw_value(98, 132, 2, 0); // Выводим на дисплей 0 секунд+      drawValue(98, 132, 2, 0); // Выводим на дисплей 0 секунд
  
       tft.setTextColor(fontcolor); // Задаем цвет текста       tft.setTextColor(fontcolor); // Задаем цвет текста
Строка 57: Строка 57:
     }     }
  
-    // Функция отображения на дисплее значений +    // Метод отображения на дисплее значений 
-    void draw_value(int x, int y, int size, int value) {+    void drawValue(int x, int y, int size, int value) {
       // Перед выводом на дисплей новых данных закрашиваем старые прямоугольником с цветом фона       // Перед выводом на дисплей новых данных закрашиваем старые прямоугольником с цветом фона
       tft.fillRect(x, y, 6 * size * 2, 8 * size -2, backcolor);       tft.fillRect(x, y, 6 * size * 2, 8 * size -2, backcolor);
Строка 71: Строка 71:
     }     }
  
-    // Основная функция секундомера, отсчет времени+    // Основной метод секундомера, отсчет времени
     void tick() {     void tick() {
       if (state) { // отсчет производим только, если секундомер запущен       if (state) { // отсчет производим только, если секундомер запущен
         // Находим разницу в миллисекундах между текущим временем и временем запуска         // Находим разницу в миллисекундах между текущим временем и временем запуска
-        unsigned long diff = millis();+        unsigned long diff = millis() - start_time;
         int hours_cur = diff / (1000 * 60 * 60); // Деление без остатка. Находим сколько целых часов прошло         int hours_cur = diff / (1000 * 60 * 60); // Деление без остатка. Находим сколько целых часов прошло
         diff = diff % (1000 * 60 * 60); // Находим остаток после деления на часы и сохраняем в diff         diff = diff % (1000 * 60 * 60); // Находим остаток после деления на часы и сохраняем в diff
Строка 85: Строка 85:
         if (hours_cur != hours) {         if (hours_cur != hours) {
             hours = hours_cur;              hours = hours_cur; 
-            draw_value(8, 125, 3, hours);+            drawValue(8, 125, 3, hours);
         }         }
  
Строка 91: Строка 91:
         if (mins_cur != mins) {         if (mins_cur != mins) {
           mins = mins_cur;           mins = mins_cur;
-          draw_value(55, 125, 3, mins);+          drawValue(55, 125, 3, mins);
         }         }
                  
Строка 97: Строка 97:
         if (secs_cur != secs) {         if (secs_cur != secs) {
           secs = secs_cur;           secs = secs_cur;
-          draw_value(98, 132, 2, secs);+          drawValue(98, 132, 2, secs);
         }         }
       }       }
     }     }
  
-     // Функция запуска и остановки секундомера+     // Метод запуска и остановки секундомера
     void startStop() {     void startStop() {
       state = !state; // Инвертируем состояние секундомера       state = !state; // Инвертируем состояние секундомера
Строка 110: Строка 110:
 </code> </code>
  
-Класс содержит конструктор ''__init__'' и методы: +Класс содержит методы: 
-  * ''draw_init'' — отображает начальное значение таймера, нули, как в прошлом эксперименте. +  * ''init'' — используется вместо конструктора и вызывается в функции  ''setup()''. 
-  * ''start_stop'' — запускает и останавливает секундомер.  +  * ''drawInit'' — отображает начальное значение таймера, нули, как в прошлом эксперименте. 
-  * ''draw_value'' — выводит значение часов минут или секунд. В качестве параметров принимает координаты, размер шрифта и значение.+  * ''startStop'' — запускает и останавливает секундомер.  
 +  * ''drawValue'' — выводит значение часов минут или секунд. В качестве параметров принимает координаты, размер шрифта и значение.
   * ''tick'' — системная функция секундомера. Она определяет сколько часов, минут и секунд прошло с момента его запуска. Эту функцию необходимо вызывать постоянно.   * ''tick'' — системная функция секундомера. Она определяет сколько часов, минут и секунд прошло с момента его запуска. Эту функцию необходимо вызывать постоянно.
  
 Код класса снабжен комментариями, подробно описывающими почти каждую строку. Кроме этого дадим несколько пояснений. Когда мы говорим "Сохраняем время запуска секундомера", то имеется в виду, что мы сохраняем значение количества миллисекунд с момента запуска микроконтроллера. И все упоминания времени следует читать в этом ключе. Код класса снабжен комментариями, подробно описывающими почти каждую строку. Кроме этого дадим несколько пояснений. Когда мы говорим "Сохраняем время запуска секундомера", то имеется в виду, что мы сохраняем значение количества миллисекунд с момента запуска микроконтроллера. И все упоминания времени следует читать в этом ключе.
- 
-Функция ''diff = time.ticks_diff(time.ticks_ms(), self.start_time)'' нужна для нахождения разницы между  количеством миллисекунд, прошедших со старта микроконтроллера при запуске секундомера и сейчас. Несмотря на то, что это есть обычное число, которое можно было бы вычесть обычным знаком минус, лучше это делать с помощью данной функции. Дело в том, что это значение может переполниться и обнулиться и начать считать "по второму кругу". Тогда простое вычитание даст ошибку. Только функция ''ticks_diff'' гарантирует правильное значение. 
  
 Заострим внимание на вычислении количества часов: Заострим внимание на вычислении количества часов:
-<code python+<code arduino
-hours = diff // (1000 * 60 * 60) +int hours_cur = diff / (1000 * 60 * 60); 
-diff = diff % (1000 * 60 * 60)+diff = diff % (1000 * 60 * 60);
 </code> </code>
  
-Оператор ''%%//%%'' — это оператор деления без остатка. Например 5 %%//%% 2 = 2. А остаток 0.5 был отброшен.+Оператор ''%%/%%'' — это оператор деления без остатка. Например 5 %%/%% 2 = 2. А остаток 0.5 был отброшен.
 А оператор ''%'' — напротив возвращает только остаток от деления. 5 % 2 = 0.5 А оператор ''%'' — напротив возвращает только остаток от деления. 5 % 2 = 0.5
  
 Сначала мы вычисляем целое количество часов, а потом мы вычисляем по сути сколько осталось после выделения целого количества часов. После этого там останется значение меньше одного часа. Его мы уже будем делить на минуты. А после вычитания минут будем определять сколько осталось секунд. Сначала мы вычисляем целое количество часов, а потом мы вычисляем по сути сколько осталось после выделения целого количества часов. После этого там останется значение меньше одного часа. Его мы уже будем делить на минуты. А после вычитания минут будем определять сколько осталось секунд.
  
-Теперь сделаем программу с использованием данного класса+Теперь сделаем программу с использованием данного класса.
  
 ==== Программный код эксперимента ==== ==== Программный код эксперимента ====
  
-<file python Exp50.py[enable_line_numbers="2", start_line_numbers_at="1"]> +<file arduino Exp50.ino[enable_line_numbers="2", start_line_numbers_at="1"]> 
-from machine import Pin, SPI +#include <SPI.h> 
-from tft import TFT_GREEN +#include <Adafruit_ST7735.h> 
-import font +#include "LittleFS_ImageReader.h" 
-import time +
-_init() +
-machine.freq(160000000)+
  
 +#define PIN_CS  2
 +#define PIN_DC  4
 +#define PIN_RST 5
  
-dc  Pin(4Pin.OUT)  +Adafruit_ST7735 tft Adafruit_ST7735(PIN_CS,  PIN_DCPIN_RST); 
-cs  = Pin(2Pin.OUT+LittleFS_ImageReader reader;
-rst = Pin(5, Pin.OUT)+
  
-spi SPI(1, baudrate=40000000, polarity=0, phase=0) +class Stopwatch { 
-tft TFT_GREEN(128160spidccs, rst, rotate=0)+  private: 
 +    unsigned int hours 0;  
 +    unsigned int mins 0;  
 +    unsigned int secs = 0;   
 +    unsigned long start_time = 0; 
 +    bool state 0;  
 +    unsigned int backcolor = tft.color565(255251240);  
 +    unsigned int fontcolor = tft.color565(394051);   
  
-tft.initr(tft.BGRtft.initr(tft.RGB#Если вместо синего цвета отображается красный, а вместо красного синий +  public: 
-tft.clear(tft.rgbcolor(255,251,240))  +    void init() {   
-tft.draw_bmp(0,0,'time.bmp')+      tft.fillScreen(backcolor) 
 +      reader.drawBMP("/time.bmp"tft, 0, 0)
 +      drawInit();  
 +    } 
  
 +    void drawInit() {
 +      drawValue(8, 125, 3, 0);  
 +      drawValue(55, 125, 3, 0); 
 +      drawValue(98, 132, 2, 0);
  
-class Stopwatch: +      tft.setTextColor(fontcolor) 
-    def __init__(self): +       
-        self.hours = 0 +      tft.setCursor(41125) 
-        self.mins = 0 +      tft.setTextSize(3); 
-        self.secs = 0 +      tft.print(":");
-        self.start_time = 0 +
-        self.state = 0 +
-        self.backcolor = tft.rgbcolor(255,251,240+
-        self.fontcolor = tft.rgbcolor(39,40,51+
-        self.draw_init()+
  
 +      tft.setCursor(88, 132);  
 +      tft.setTextSize(2); 
 +      tft.print(":");
 +    }
  
-    def draw_init(self): +    void drawValue(int xint yint sizeint value{ 
-        self.draw_value(9813220+      tft.fillRect(xy6 * size * 28 * size -2backcolor);
-        self.draw_value(5512530) +
-        self.draw_value(5, 125, 30)+
  
-        tft.text(41125, ":", font.terminalfont, self.fontcolor, 3+      tft.setCursor(xy);   
-        tft.text(90, 130, ":", font.terminalfont, self.fontcolor, 2)+      tft.setTextColor(fontcolor); 
 +      tft.setTextSize(size);
  
 +      if (value < 10) tft.print(0);
 +      tft.print(value); 
 +    }
  
-    def tick(self): +    void tick() { 
-        if self.state: +      if (state) {  
-            diff = time.ticks_diff(time.ticks_ms(), self.start_time) +        unsigned long diff = millis() start_time; 
-            hours = diff // (1000 * 60 * 60) +        int hours_cur = diff / (1000 * 60 * 60) 
-            diff = diff % (1000 * 60 * 60) +        diff = diff % (1000 * 60 * 60) 
-            mins = diff // (1000 * 60) +        int mins_cur = diff / (1000 * 60) 
-            diff = diff % (1000 * 60) +        diff = diff % (1000 * 60) 
-            secs = diff // (1000)+        int secs_cur = diff / (1000)
  
-            if secs != self.secs: +        if (hours_cur != hours{ 
-                self.secs = secs +            hours hours_cur;  
-                self.draw_value(98, 132, 2, secs) +            drawValue(8, 125, 3, hours)
- +        }
-            if mins !self.mins: +
-                self.mins = mins +
-                self.draw_value(55, 125, 3, mins)+
  
-            if hours != self.hours: +        if (mins_cur != mins) { 
-                self.hours hours +          mins mins_cur; 
-                self.draw_value(5, 125, 3, hours)+          drawValue(55, 125, 3, mins)
 +        }
                  
 +        if (secs_cur != secs) {
 +          secs = secs_cur;
 +          drawValue(98, 132, 2, secs);
 +        }
 +      }
 +    }
  
-    def start_stop(self): +    void startStop() { 
-        if self.state: +      state = !state 
-            self.state = +      if (statestart_time millis() 
-        else: +    } 
-            self.state = 1 +};
-            self.start_time = time.ticks_ms() +
- +
- +
-    def draw_value(self, x, y, size, value): +
-        tft.rect(x+2, y, 6 * size * 2, 8 * size -2, self.backcolor) +
- +
-        if value < 10: +
-            value = '0' + str(value) +
-        else: +
-            value str(value) +
- +
-        tft.text(x, y, value, font.terminalfont, self.fontcolor, size) +
- +
- +
-class Button: +
-    def __init__(self, p, pressSate): +
-        self.pin = Pin(p, Pin.IN) +
-        self.pressSate = pressSate +
-        self.oldState = not pressSate +
-  +
-    def onPress(self): +
-        state = self.pin.value() +
-        if state != self.oldState: +
-            self.oldState = state +
-            if state == self.pressSate: +
-                return True +
-        return False+
  
 +Stopwatch stopwatch;
  
-stopwatch = Stopwatch() +void setup() { 
-stopwatch.start_stop()+  os_update_cpu_frequency(160); 
 +  LittleFS.begin(); 
 +  tft.initR(INITR_BLACKTAB); 
 +  tft.setRotation(2);  
 +   
 +  stopwatch.init(); 
 +  stopwatch.startStop()
 +}
  
-while True: +void loop() { 
-    stopwatch.tick()+  stopwatch.tick()
 +}
 </file> </file>
  
-Код эксперимента должен быть понятен. Сначала как обычно подключаем библиотеки, настраиваем SPI и дисплей. Потом код класса секундомера и в конце мы создаем объект секундомера +Код эксперимента должен быть понятен. Сначала как обычно подключаем библиотеки и дисплей. Потом код класса секундомера и в конце мы создаем объект секундомера. 
-<code python[enable_line_numbers="2", start_line_numbers_at="98"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="88"]> 
-stopwatch = Stopwatch()+Stopwatch stopwatch;
 </code> </code>
  
-Запускаем его +Инициализируем и запускаем его. 
-<code python[enable_line_numbers="2", start_line_numbers_at="99"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="96"]> 
-stopwatch.start_stop()+  stopwatch.init(); 
 +  stopwatch.startStop();
 </code> </code>
  
-И в бесконечном цикле вызываем его метод ''tick()''. В нем он занимается отслеживаем времени и отображением изменений на дисплее +И в бесконечном цикле вызываем его метод ''tick()''. В нем он занимается отслеживаем времени и отображением изменений на дисплее. 
-<code python[enable_line_numbers="2", start_line_numbers_at="101"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="101"]> 
-while True: +  stopwatch.tick();
-    stopwatch.tick()+
 </code> </code>
  
 Теперь наш секундомер умеет считать время. Но еще не слушается управления. В следующем эксперименте мы добавим управление с помощью кнопки и получим полноценный секундомер. Теперь наш секундомер умеет считать время. Но еще не слушается управления. В следующем эксперименте мы добавим управление с помощью кнопки и получим полноценный секундомер.