Различия

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

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

Следующая версия
Предыдущая версия
products:laboratory_iot:exp50 [2020/06/01 18:40] – создано labuser29products:laboratory_iot:exp50 [2021/07/21 16:47] (текущий) – [Программный код эксперимента] labuser29
Строка 9: Строка 9:
 Системная библиотека ''time'' предлагает функцию ''ticks_ms()'', которая возвращает количество миллисекунд с начала запуска микроконтроллера. Это значение обновляется аппаратно по прерыванию от таймера, который настроен точно и не зависит от действий программы. Поэтому лучше ориентироваться именно на это значение. Системная библиотека ''time'' предлагает функцию ''ticks_ms()'', которая возвращает количество миллисекунд с начала запуска микроконтроллера. Это значение обновляется аппаратно по прерыванию от таймера, который настроен точно и не зависит от действий программы. Поэтому лучше ориентироваться именно на это значение.
  
-При запуске таймера мы будем запоминать текущее значение ''ticks_ms()'' и следить за его изменением+При запуске таймера мы будем запоминать текущее значение ''ticks_ms()'' и следить за его изменением.
  
 ==== Схема эксперимента ==== ==== Схема эксперимента ====
  
 {{ :products:esp-iot:exp24.1_mont.png?direct&600 |}} {{ :products:esp-iot:exp24.1_mont.png?direct&600 |}}
-//Рисунок 1. Монтажная схема эксперимента//+//Рисунок 1. Монтажная схема эксперимента для дисплея с 8 выводами//
  
 +{{ :products:esp-iot:exp24.1_mont_11pin.png?direct&600 |}}
 +//Рисунок 2. Монтажная схема эксперимента для дисплея с 11 выводами//
 +==== Класс Stopwatch====
 +
 +<code python [enable_line_numbers="2", start_line_numbers_at="1"]>
 +class Stopwatch:
 +    def __init__(self):
 +        self.hours = 0 # Значение часов
 +        self.mins = 0 # Значение минут
 +        self.secs = 0 # Значение секунд
 +        self.start_time = 0 # Время запуска
 +        self.state = 0 # Состояние. 0 - секундомер не запущен, 1 - запущен
 +        self.backcolor = tft.rgbcolor(255,251,240) # Цвет фона
 +        self.fontcolor = tft.rgbcolor(39,40,51) # Цвет шрифта
 +        self.draw_init() # Вызов функции отображения начального значения- нулей
 +
 +    # Функция вывода начального значения секундомера- нулей
 +    def draw_init(self):
 +        self.draw_value(98, 132, 2, 0) # Выводим на дисплей 0 секунд
 +        self.draw_value(55, 125, 3, 0) # Выводим на дисплей 0 минут
 +        self.draw_value(5, 125, 3, 0) # Выводим на дисплей 0 часов
 +
 +        # Выводим разделитель часов и минут
 +        tft.text(41, 125, ":", font.terminalfont, self.fontcolor, 3) 
 +        # Выводим разделитель минут и секунд
 +        tft.text(90, 130, ":", font.terminalfont, self.fontcolor, 2)
 +
 +
 +    # Основная функция секундомера, отсчет времени
 +    def tick(self):
 +        if self.state: # отсчет производим только, если секундомер запущен
 +            # Находим разницу в миллисекундах между текущим временем и временем запуска
 +            diff = time.ticks_diff(time.ticks_ms(), self.start_time)
 +            hours = diff // (1000 * 60 * 60) # Деление без остатка. Находим сколько целых часов прошло
 +            diff = diff % (1000 * 60 * 60) # Находим остаток после деления на часы и сохраняем в diff
 +            mins = diff // (1000 * 60) # Деление без остатка. Находим сколько целых минут прошло
 +            diff = diff % (1000 * 60) # Находим остаток после деления на минуты и сохраняем в diff
 +            secs = diff // (1000) # Деление без остатка. Находим сколько целых секунд прошло
 +
 +            # Если сохраненное ранее значение секунд отличается от вычисленных- обновляем и выводим на дисплей
 +            if secs != self.secs:
 +                self.secs = secs
 +                self.draw_value(98, 132, 2, secs)
 +           
 +            # Если сохраненное ранее значение минут отличается от вычисленных- обновляем и выводим на дисплей
 +            if mins != self.mins:
 +                self.mins = mins
 +                self.draw_value(55, 125, 3, mins)
 +
 +            # Если сохраненное ранее значение часов отличается от вычисленных- обновляем и выводим на дисплей
 +            if hours != self.hours:
 +                self.hours = hours
 +                self.draw_value(5, 125, 3, hours)
 +        
 +
 +    # Функция запуска и остановки секундомера
 +    def start_stop(self):
 +        if self.state: # Если секундомер запущен- останавливаем
 +            self.state = 0
 +        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)
 +
 +        # Если значение для вывода менее 10, то добавляем ведущий ноль, чтобы всегда было 2 знака
 +        # конвертируем значение из числа в строку
 +        if value < 10:
 +            value = '0' + str(value)
 +        else:
 +            value = str(value)
 +
 +        # Выводим значение в виде строки на дисплей в нужном месте нужным цветом и размером
 +        tft.text(x, y, value, font.terminalfont, self.fontcolor, size)
 +</code>
 +
 +Класс содержит конструктор ''__init__'' и методы:
 +  * ''draw_init'' — отображает начальное значение таймера, нули, как в прошлом эксперименте.
 +  * ''start_stop'' — запускает и останавливает секундомер. 
 +  * ''draw_value'' — выводит значение часов минут или секунд. В качестве параметров принимает координаты, размер шрифта и значение.
 +  * ''tick'' — системная функция секундомера. Она определяет сколько часов, минут и секунд прошло с момента его запуска. Эту функцию необходимо вызывать постоянно.
 +
 +Код класса снабжен комментариями, подробно описывающими почти каждую строку. Кроме этого дадим несколько пояснений. Когда мы говорим "Сохраняем время запуска секундомера", то имеется в виду, что мы сохраняем значение количества миллисекунд с момента запуска микроконтроллера. И все упоминания времени следует читать в этом ключе.
 +
 +Функция ''diff = time.ticks_diff(time.ticks_ms(), self.start_time)'' нужна для нахождения разницы между  количеством миллисекунд, прошедших со старта микроконтроллера при запуске секундомера и сейчас. Несмотря на то, что это есть обычное число, которое можно было бы вычесть обычным знаком минус, лучше это делать с помощью данной функции. Дело в том, что это значение может переполниться и обнулиться и начать считать "по второму кругу". Тогда простое вычитание даст ошибку. Только функция ''ticks_diff'' гарантирует правильное значение.
 +
 +Заострим внимание на вычислении количества часов:
 +<code python>
 +hours = diff // (1000 * 60 * 60)
 +diff = diff % (1000 * 60 * 60)
 +</code>
 +
 +Оператор ''%%//%%'' — это оператор деления без остатка. Например 5 %%//%% 2 = 2. А остаток 0.5 был отброшен.
 +А оператор ''%'' — напротив возвращает только остаток от деления. 5 % 2 = 0.5
 +
 +Сначала мы вычисляем целое количество часов, а потом мы вычисляем по сути сколько осталось после выделения целого количества часов. После этого там останется значение меньше одного часа. Его мы уже будем делить на минуты. А после вычитания минут будем определять сколько осталось секунд.
 +
 +Теперь сделаем программу с использованием данного класса
 +
 +==== Программный код эксперимента ====
 +
 +<file python Exp50.py[enable_line_numbers="2", start_line_numbers_at="1"]>
 +from machine import Pin, SPI
 +from tft import TFT_GREEN
 +import font
 +import time
 +_init()
 +machine.freq(160000000)
 +
 +
 +dc  = Pin(4, Pin.OUT) 
 +cs  = Pin(2, Pin.OUT)
 +rst = Pin(5, Pin.OUT)
 +
 +spi = SPI(1, baudrate=40000000, polarity=0, phase=0)
 +tft = TFT_GREEN(128, 160, spi, dc, cs, rst, rotate=0)
 +
 +tft.initr(tft.BGR) # tft.initr(tft.RGB) #Если вместо синего цвета отображается красный, а вместо красного синий
 +tft.clear(tft.rgbcolor(255,251,240)) 
 +tft.draw_bmp(0,0,'time.bmp')
 +
 +
 +class Stopwatch:
 +    def __init__(self):
 +        self.hours = 0
 +        self.mins = 0
 +        self.secs = 0
 +        self.start_time = 0
 +        self.state = 0
 +        self.backcolor = tft.rgbcolor(255,251,240)
 +        self.fontcolor = tft.rgbcolor(39,40,51)
 +        self.draw_init()
 +
 +
 +    def draw_init(self):
 +        self.draw_value(98, 132, 2, 0)
 +        self.draw_value(55, 125, 3, 0)
 +        self.draw_value(5, 125, 3, 0)
 +
 +        tft.text(41, 125, ":", font.terminalfont, self.fontcolor, 3)
 +        tft.text(90, 130, ":", font.terminalfont, self.fontcolor, 2)
 +
 +
 +    def tick(self):
 +        if self.state:
 +            diff = time.ticks_diff(time.ticks_ms(), self.start_time)
 +            hours = diff // (1000 * 60 * 60)
 +            diff = diff % (1000 * 60 * 60)
 +            mins = diff // (1000 * 60)
 +            diff = diff % (1000 * 60)
 +            secs = diff // (1000)
 +
 +            if secs != self.secs:
 +                self.secs = secs
 +                self.draw_value(98, 132, 2, secs)
 +
 +            if mins != self.mins:
 +                self.mins = mins
 +                self.draw_value(55, 125, 3, mins)
 +
 +            if hours != self.hours:
 +                self.hours = hours
 +                self.draw_value(5, 125, 3, hours)
 +        
 +
 +    def start_stop(self):
 +        if self.state:
 +            self.state = 0
 +        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.start_stop()
 +
 +while True:
 +    stopwatch.tick()
 +</file>
 +
 +Код эксперимента должен быть понятен. Сначала как обычно подключаем библиотеки, настраиваем SPI и дисплей. Потом код класса секундомера и в конце мы создаем объект секундомера
 +<code python[enable_line_numbers="2", start_line_numbers_at="98"]>
 +stopwatch = Stopwatch()
 +</code>
 +
 +Запускаем его
 +<code python[enable_line_numbers="2", start_line_numbers_at="99"]>
 +stopwatch.start_stop()
 +</code>
 +
 +И в бесконечном цикле вызываем его метод ''tick()''. В нем он занимается отслеживаем времени и отображением изменений на дисплее
 +<code python[enable_line_numbers="2", start_line_numbers_at="101"]>
 +while True:
 +    stopwatch.tick()
 +</code>
 +
 +Теперь наш секундомер умеет считать время. Но еще не слушается управления. В следующем эксперименте мы добавим управление с помощью кнопки и получим полноценный секундомер.