- Русские Блоги
- Инструмент для последовательного порта Python, хост-компьютер с последовательным портом
- Python использует Pyserial последовательный порт библиотеки для разработки последовательных инструментов
- Python & Arduino. Просто, быстро и красиво
- Оборудование
- Скетч для Arduino
- Код для компьютера
- Установка
- Интерфейс
- Исходный код
Русские Блоги
Инструмент для последовательного порта Python, хост-компьютер с последовательным портом
Python использует Pyserial последовательный порт библиотеки для разработки последовательных инструментов
Я уже публиковал код пользовательского интерфейса инструмента последовательного порта, созданный с помощью библиотеки tkinter. Ниже приведен логический код последовательного порта python, который организован в модули и может быть сохранен и использован в любое время. Некоторые функции названы по-китайски, просто чтобы проверить, можно ли запустить китайскую функцию, и выясняется, что она может работать нормально. Вы также можете изменить имя функции
1. Пример кода (MyPySerial.py)
# !/usr/bin/python 3.6.5 # coding=utf-8 import serial import serial.tools.list_ports import threading ''' 1. Сканирование списка последовательных портов 2. Откройте последовательный порт 3. Записать данные в последовательный порт 4. Считать данные с последовательного порта 5. Закройте последовательный порт инициализация инициализирует последовательный порт -> Создать тему: 1. Если последовательный порт не открыт, он используется для сканирования последовательного порта в режиме реального времени, чтобы определить, установлено ли новое устройство Вставлено новое устройство: добавьте в список устройств и обновите список устройств пользовательского интерфейса, чтобы предоставить параметры Нет новых устройств: продолжить сканирование 2. Если последовательный порт открыт, он используется для мониторинга того, получил ли последовательный порт данные Если это так, прочитайте данные и отправьте их в пользовательский интерфейс Если нет, продолжайте сканирование Параметры: главное окно, список портов, окно получения Возврат: экземпляр потока (используется для закрытия потока перед закрытием окна) открыть Открыть последовательный порт -> Параметры: номер порта, скорость передачи, период ожидания Возврат: Экземпляр последовательного порта (успешно открыт) / Нет (не удалось открыть) закрыть закрыть последовательный порт -> Параметры: экземпляр последовательного порта Возврат: 0 (успешно закрыто) / -1 (закрыто не удалось) написать написать данные читать читать данные ''' SERIAL_IS_OPEN = False # Стандартный последовательный порт закрыт port_name_list = [] # Список имен портов port_com_list = [] # Список номеров портов MySerial = None # Открытый последовательный порт def Сканирование последовательного порта(): port_list = list(serial.tools.list_ports.comports()) if len(port_list) > 0: return port_list else: return None def Откройте последовательный порт(port="COM4", bps=115200, timex=5): try: # Откройте последовательный порт ser = serial.Serial(port, bps, timeout=timex) if ser.is_open: global SERIAL_IS_OPEN SERIAL_IS_OPEN = True print("--- последовательный порт открыт ---") return ser except Exception as e: print("--- Открытое исключение ---:", e) return None def отправить данные(ser, text, code="utf-8"): try: result = ser.write(text.encode(code)) if result == len(text): print("--- Успешно отправлено ---:", text) return result else: print("--- Ошибка отправки ---:", "data len:", len(text), "send len:", result) return None except Exception as e: print("--- отправка исключения ---:", e) def Читать данные(ser, code="utf-8"): if ser.in_waiting: str = ser.read(ser.in_waiting).decode(code) print("--- Читать данные ---:", str) return str else: return None def Закройте последовательный порт(ser): if ser.is_open: try: global SERIAL_IS_OPEN SERIAL_IS_OPEN = False ser.close() print("--- Последовательный порт закрыт ---") return 0 except Exception as e: print("--- Закрыть исключение ---:", e) return -1 else: print("--- Ошибка ---: последовательный порт не открыт!") return -1 class SERIAL: def __init__(self): self.ser = None self.get_str = '' self.master = None self.show_com = None self.read_text_win = None self.serialThread = None def serial_thread(self, master, list_port, text_read): global SERIAL_IS_OPEN, port_name_list, port_com_list global MySerial while True: if SERIAL_IS_OPEN: self.get_str = Читать данные(MySerial) if self.get_str: # print(self.get_str) text_read.insert(tk.END, self.get_str) master.update() else: port_list = Сканирование последовательного порта() if len(port_name_list) is not len(port_list): # Только судить о длине списка, который не является надежным. Необходимо изменить, чтобы сделать содержимое списка более надежным port_name_list.clear() port_com_list.clear() for i in range(0, len(port_list)): port_name_list.append(port_list[i].description) port_com_list.append(port_list[i].device) list_port["values"] = port_name_list if list_port.get() is "": # Если список портов в текущем пользовательском интерфейсе пуст, укажите для отображения первый list_port.current(0) master.update() @classmethod def init(cls, master, list_port, text_read): cls.master = master cls.show_com = list_port cls.read_text_win = text_read cls.serialThread = threading.Thread(target=cls.serial_thread, args=(SERIAL, cls.master, cls.show_com, cls.read_text_win)) cls.serialThread.start() return cls.serialThread @classmethod def open(cls, port=None, bps=115200, timex=5): global port_name_list, port_com_list, MySerial if not port: port_name = cls.show_com.get() index = port_name_list.index(port_name) MySerial = Откройте последовательный порт(port_com_list[index], bps, timex) else: MySerial = Откройте последовательный порт(port, bps, timex) @staticmethod def write(text, coding="gbk"): global MySerial, SERIAL_IS_OPEN if SERIAL_IS_OPEN: отправить данные(MySerial, text, coding) @staticmethod def read(coding="gbk"): global MySerial, SERIAL_IS_OPEN str = None if SERIAL_IS_OPEN: str = Читать данные(MySerial, coding) return str @staticmethod def close(): global MySerial, SERIAL_IS_OPEN if SERIAL_IS_OPEN and MySerial: Закройте последовательный порт(MySerial) if __name__ == "__main__": import tkinter as tk from tkinter import ttk root = tk.Tk() root.title(«Тестовое окно») root.geometry("300x300") list_box = ttk.Combobox(root, width=22, textvariable=port_name_list, state="readonly") list_box.place(x=10, y=10) text_box = tk.Text(root, width=25, heigh=10) text_box.place(x=10, y=50) def open_serial(): SERIAL.open() def send_date(): SERIAL.write("hello python serial\n", coding="gbk") def close_serial(): SERIAL.close() SERIAL.init(root, list_box, text_box) button0 = tk.Button(root, text=«Откройте последовательный порт», command=open_serial) button0.place(x=10, y=200) button1 = tk.Button(root, text="отправить данные", command=send_date) button1.place(x=70, y=200) button2 = tk.Button(root, text=«Закрыть последовательный порт», command=close_serial) button2.place(x=130, y=200) root.mainloop()
2. Протестируйте окно интерфейса
Как использовать тестовое окно:
- Скопируйте пример кода напрямую и сохраните его как: MyPySerial.py file
- Запустите файл, чтобы открыть тестовое окно
- Выберите порт CH340, откройте последовательный порт
- «Send data» отправит «hello python serial \ n» на последовательный порт
- Короткое замыкание «tx» и «rx» последовательного порта CH340 для приема и передачи отправленных данных в текстовый элемент управления
- Закройте последовательный порт
Примечание. Этот пример вернется к потоку в init и должен быть закрыт сам по себе. Главный поток python закрыт, но дочерний поток не будет закрыт автоматически.
Python & Arduino. Просто, быстро и красиво
Очень часто, у начинающих и не только разработчиков возникают вопросы. Как управлять с Arduino с компьютера? А если компьютер — не Raspberry Pi, а обычный домашний компьютер? А если не хочется мучится с ESP8266 и управлять через веб интерфейс? Неужели надо каждый раз открывать Arduino IDE и отправлять команды через Монитор порта? Именно о том, как создать своё собственное приложение с графическим интерфейсом для управления Arduino я сейчас и расскажу.
Оборудование
Недавно я заполучил очень интересную плату: Arduino SS Micro. Эта плата, внешне напоминающая Digispark Attiny 85, тем не менее является китайской версией Arduino Micro, с выведенным выходом USB.
Подробно рассказывать о ней я не буду, ведь это уже сделал пользователь YouTube с ником iomoio, и его обзор можно посмотреть здесь.
Как мне кажется — это довольно крутое и удобное устройство для небольших домашних проектов, ведь у проводов есть супер-свойство: теряться в самый неподходящий момент.
В качестве управляющего компьютера был использован MacBook Pro с операционной системой macOS Mojave, но не надо закрывать статью, если вы используете Windows или Linux — всё описанное в статье будет работать без изменений на любой операционной системе.
Скетч для Arduino
В качестве примера будет использоваться скетч, включающий и выключающий светодиод, по команде из Serial-порта.
Светодиод в Arduino SS Micro висит на порте SS, и поэтому он автоматически выключается. Не смотря на это, стандартный пример Blink — мигающий светодиод работает.
char inChar; #define LED_PIN SS void setup() < pinMode(LED_PIN, OUTPUT); // Инициализация светодиода Serial.begin(115200); // Инициализация Serial - порта >void loop() < if (Serial.available() >0) < inChar = Serial.read(); if (inChar=='e') // e - Enable - включить < digitalWrite(LED_PIN,HIGH); >> else if (inChar=='d') // d - Disable - выключить < digitalWrite(LED_PIN,LOW); >else if (inChar=='b') // b - Blink - выключить режим мигания < while (true)< digitalWrite(LED_PIN,HIGH); delay(1000); digitalWrite(LED_PIN,LOW); delay(1000); >> >
Если вы будете использовать другую Arduino — не забудьте сменить пин светодиода.
Код для компьютера
Одним из достоинств Python, кроме его кроссплатформенности — наличие гигантского числа библиотек. Нам понадобятся:
- PySerial — библиотека для работы с Serial-портом
- PyQT5 — библиотека для создания графического интерфейса
Установка
Для установки, воспользуемся встроенным менеджером пакетов — pip.
pip install pyserial pyqt5
Для удобства создания GUI можно установить программу QTDesigner.
Интерфейс
Поскольку данная программа предназначена скорее, для демонстрации возможностей, пользователь может выбрать порт из предложенных, а так же скорость, с которой будет происходить общение.
Исходный код
Вся работа с устройством происходит благодаря библиотеке PySerial. Но есть несколько нюансов. Например, как узнать, в какой из портов подключено устройство?
На всем прекрасно известном сайте stackoverflow, пользователь с ником Thomas предложил уже готовое решение, которое я и использовал.
def serial_ports(): """ Lists serial port names :raises EnvironmentError: On unsupported or unknown platforms :returns: A list of the serial ports available on the system """ if sys.platform.startswith('win'): ports = ['COM%s' % (i + 1) for i in range(256)] elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'): # this excludes your current terminal "/dev/tty" ports = glob.glob('/dev/tty[A-Za-z]*') elif sys.platform.startswith('darwin'): ports = glob.glob('/dev/tty.*') else: raise EnvironmentError('Unsupported platform') result = [] for port in ports: try: s = serial.Serial(port) s.close() result.append(port) except (OSError, serial.SerialException): pass return result
Кроме этого необходимо хранить список доступных скоростей:
speeds = ['1200','2400', '4800', '9600', '19200', '38400', '57600', '115200']
А теперь соберём вместе дизайн(созданный в QtDesigner и сконвертированный с помощью утилиты pyuic5 в .py файл), функции для сканирования портов и основной код программы.
Основной класс, содержащий в себе всю логику программы
class LedApp(QtWidgets.QMainWindow, design.Ui_Form): def __init__(self): super().__init__() self.setupUi(self) self.Port.addItems(serial_ports()) self.Speed.addItems(speeds) self.realport = None self.ConnectButton.clicked.connect(self.connect) self.EnableBtn.clicked.connect(self.send) def connect(self): try: self.realport = serial.Serial(self.Port.currentText(),int(self.Speed.currentText())) self.ConnectButton.setStyleSheet("background-color: green") self.ConnectButton.setText('Подключено') except Exception as e: print(e) def send(self): if self.realport: self.realport.write(b'b')
Переменные self.Port и self.Speed — это выпадающие списки, содержащие в себе значения доступных портов и скоростей.
При нажатии на кнопку self.ConnectButton вызывается функция connect, в которой производится попытка подключения к заданному порту с заданной скоростью. Если подключение успешно, то кнопка окрашивается в зелёный цвет, и меняется надпись.
Функция send отправляет в наш порт байтовую строку — заставляющую включить режим мигания.
Таким образом можно управлять различными устройствами, подключёнными к USB.
Данная статья является вводной и обзорной, более полную информацию можно найти например тут: