Живее всех живых

Это не про Владимира Ильича (в смысле — про Ленина). В далёкие годы был такой мем про вождя мирового пролетариата.

Живее всех живых — это про последовательный порт. Разумеется, это сказано в контексте работы с микроконтроллерами.

Не смотря на присутствие в обиходе множества самых разных интерфейсов для передачи данных на все случаи жизни, древний как… не важно!… последовательный порт ещё ого-го какой востребованный!

Несколько дней назад я отлаживал одну штукенцию, в которой мне нужно было мониторить температуру. Измерение температуры осуществляется один раз в секунду. Значение температуры укладывается в двухбайтовое знаковое целочисленное число — int16_t. Вот это-то число и надо было передавать в комп чтобы отображать на экране.

Вот, так выглядит результат работы:

Вроде всё хорошо, но температура измеряется с десятыми-сотыми долями градуса и, следовательно, должна также и отображаться. То есть целое число не совсем подходит. Переходить на «плавучку» (числа с плавающей точкой) очень не хотелось. Но решение даже искать не пришлось.

Я так много раз уже делал — измерял микроконтроллером температуру, но не в градусах, а в дека- или сантиградусах. Ну, то есть в 10 или в 100 раз более мелких единицах. Какая разница — в каком формате выражается температура микроконтроллере и бежит по линиям передачи данных! А вот при поступлении таких значений температуры в комп, её нужно «очеловечить», то есть превратить в нормальные градусы и десятые-сотые доли градуса.

Поэтому в данном случае внутри микроконтроллера и по последовательному порту температура передавалась в значении в 16 раз большем. То есть +20°C выражались числом 320, +30°С — числом 480, минус 10°С — числом -160. Ну, понятно. Ну, мне так было удобнее обрабатывать температуру внутри микроконтроллера.

В общем, в комп должны были поступать двухбайтовые целые числа, которые нужно было немножко масштабировать и отобразить на экране. Не сложно. Если бы я продолжал работать под Виндовсом, я бы взял какую-нибудь программу для СОМ-порта и … печально созерцал бы получаемые HEX-коды.

Но я уже забыл как выглядит этот Виндовс! А кроме того в Линуксе у меня всегда есть Python. Ну и что мне мешает сделать себе приятно?

Ниже находится текст простой проги, которая принимает по последовательному порту двухбайтовые посылки и после несложной их обработки выводит в консоль температуру в человеческом формате. Ничто не мешает переделать прогу для получения других сущностей — например,  напряжения или мощности. Поэтому это даже не совсем прога, а скорее шаблон для построения на скорую руку таких программ. Ну вы поняли!

#!/usr/bin/env python3
# coding:utf-8

''' get_t.py '''

import struct
import serial

PORT = "/dev/ttyS0"  # "/dev/ttyUSB0" и другие наименования портов
BAUD = 115200
TIMEOUT = 0.1 # Секунды

if __name__ == "__main__":
  try :
    ser = serial.Serial(PORT)
  except:
    print("Не могу открыть порт {}".format(PORT))
    exit(0)

  # Параметры последовательного порта
  ser.baudrate = BAUD
  ser.timeout  = TIMEOUT
  ser.bytesize = serial.EIGHTBITS
  ser.parity   = serial.PARITY_NONE
  ser.stopbits = serial.STOPBITS_ONE

  while True:
    packet = ser.read(2)
    if len(packet) == 2: # Только двухбайтовые пакеты
      values = struct.unpack("<h", packet)
      t = values[0] / 16  # Обратное масштабирование
      print("t = {:.1f}°C".format(t))

Это не коммерческая прога, поэтому в ней нет штатного выхода. Для её остановки нужно нажать Ctrl-C.

При создании подобных программ на Питоне у меня есть утилита mkpy (я её описывал где-то в этом блоге и приводил исходный текст). Эта утилита создает питоновский файл и сразу же присваивает ему атрибуты исполнительного файла. Таким образом, мне не надо специально прописывать имя самого Питона. Я просто набираю имя проги и Линукс (точнее оболочка, bash) сам знает что ему делать.

Оператор ser.read(2) возвращает байтовый массив, состоящий из двух байт. Этот массив я скармливаю функции unpack из модуля struct. Функция берёт из этого массива первые два байта (а других там, собственно, и нет!) и превращает их в целое 16-битное число. Функция универсальная, рассчитана на то, что пакет packet может содержать не только одно двухбайтное целое число, а в нем могут быть и другие числа и строки. Поэтому функция unpack возвращает кортеж значений.

В нашем случае кортеж состоит из одного числа. Но это всё равно кортеж. К членам кортежа можно добраться через их индексы, наподобие доступа к элементам массива в языке Си. При обратном масштабировании значения температуры мы берём первый (с индексом 0) элемент кортежа и делим его на 16. После чего выводим в консоль.

Вот и вся прога!

В первых, это совсем не сложно. А во вторых от такого подхода к решению задачи получаешь истинное удовольствие.
И зачем мне Винда? 😦 Не понимаю…

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google photo

Для комментария используется ваша учётная запись Google. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s