MicroPython Basics: Stream vs Block I/O Devices Explained
This tutorial explains MicroPython select poll() I/O multiplexing and demonstrates serial port event monitoring, data reading and exception handling.
【Preliminary Note】The original hardware example in this article was written based on the RP2040. The actual hardware used in this hands-on demonstration features the W55RP20 as the main controller chip. The circuit logic and UF2 flashing operation principles are universally applicable, with only the main controller model differing. The original chip model mentioned in the circuit descriptions below is provided for reference purposes only.
1. select module
2. Use the select module to monitor serial port events
MiniUSB data cable to connect the Fengya No. 1 Board - Universal Compatible Expansion Board 's UART0 USB port to the USB port on the computer:select module to monitor the active status of the serial port is as follows:machine. UART to create a serial port object, and configure parameters such as baud rate, data bits, and parity bits.a poll object: Use select. poll () to create a poll object for polling and registering serial port events.poll object, and monitor the POLLIN event, which means that when there is data readable on the serial port, the polling mechanism will be triggered.poll. poll () to perform polling and wait for I/O events of the serial port device. The polling method will block until there is data readable on the serial port or return after a timeout.poll () returns an event, the program can use uart. read () to read and process the serial port data.select module to monitor serial port events and read data, handle events such as serial port errors and device disconnection, and store the received data in a buffer. The code will also clear the buffer when it is full to ensure that no data overflow occurs.elegance-devkit v1\Demo\10 UART_SelectRead:# Python env : MicroPython v1.23.0
# -*- coding: utf-8 -*-
# @Time : 2024/6/27 上午12:08
# @Author : 李清水
# @File : main.py
# @Description : Select类实验,主要完成使用select模块进行串口状态读取和数据接收等操作
# ======================================== 导入相关模块 ========================================
# 硬件相关的模块
from machine import UART, Pin
# 时间相关的模块
import time
# 导入select模块
import select
# ======================================== 全局变量 ============================================
# 创建一个串口数据缓冲区
uart_buffer = []
# 串口数据缓冲区最大长度
uart_buffer_max_len = 100
# ======================================== 功能函数 ============================================
def handle_uart_error(event: int) -> None:
"""
处理串口错误事件。
当串口发生错误时,调用该方法进行错误处理。它会尝试重置串口连接,
并重新初始化串口设置以确保通信恢复正常。
Args:
event (int): 事件类型标识。只有当事件类型为 `POLLERR` 时才会调用该函数。
"""
if event & select.POLLERR:
print("UART error occurred, resetting UART")
# 错误时熄灭LED指示灯
LED.off()
# 可能的恢复操作,关闭串口然后重新初始化
uart.deinit()
# 等待1秒后重新初始化
time.sleep(1)
uart.init(bits=8, parity=None, stop=1, tx=0, rx=1, timeout=5)
# 重新亮起LED,表示恢复工作
LED.on()
def handle_uart_disconnect(event: int) -> None:
"""
处理串口断开事件。
当串口连接断开时,调用该方法进行断开处理。它会停止串口操作并熄灭LED指示灯,
同时准备好重新连接串口。
Args:
event (int): 事件类型标识。只有当事件类型为 `POLLHUP` 时才会调用该函数。
"""
if event & select.POLLHUP:
print("UART disconnected, resetting UART")
# 断开时熄灭LED
LED.off()
# 停止串口操作
uart.deinit()
# 等待1秒,准备重新连接
time.sleep(1)
# ======================================== 自定义类 ============================================
# ======================================== 初始化配置 ==========================================
# 上电延时3s
time.sleep(3)
# 打印调试消息
print("FreakStudio: Using select module to read UART data")
# 创建串口对象,设置波特率为9600
uart: UART = UART(0, 9600)
# 初始化uart对象,数据位为8,无校验位,停止位为1
# 设置输入引脚为GPIO1,输出引脚为GPIO2
# GPIO1和GPIO2短接,串口0自发自收
# 设置串口超时时间为5ms
uart.init(bits=8,
parity=None,
stop=1,
tx=0,
rx=1,
timeout=5)
# 设置GPIO 25为LED输出引脚,下拉电阻使能
LED: Pin = Pin(25, Pin.OUT, Pin.PULL_DOWN)
# 创建一个轮询对象,用于监视串口的活动状态
uart_read_poll: select.poll = select.poll()
# 将串口对象注册到轮询对象中
# select.POLLIN 是一个常量,表示可读事件
# select.POLLERR 是一个常量,表示错误事件
# select.POLLHUP 是一个常量,表示设备断开事件
# 当串口设备上有数据可读时,uart_read_poll 对象会被触发
uart_read_poll.register(uart, select.POLLIN | select.POLLERR | select.POLLHUP)
# ======================================== 主程序 ============================================
while True:
# 点亮LED灯
LED.on()
# 使用Python的select模块中的poll方法来监听串口事件
# poll方法会阻塞等待,直到串口上有数据可以接收
# 设定超时时间为50ms,50ms内无事件发生则返回
events = uart_read_poll.poll(50)
# events是一个包含设备对象的列表,包括fd属性和events属性
print('events =', events)
# 如果有事件发生,处理这些事件
if events:
# 循环遍历事件列表
for event in events:
# 打印发生事件的设备和事件类型
print(" fd attributes/the name of the device : ",event[0])
print(" events property/the trigger type of the event : ",event[1])
# 若是uart对象有事件发生,则处理该事件
if event[0] == uart:
# 调用handle_uart_error方法处理串口错误事件
handle_uart_error(event[1])
# 调用handle_uart_disconnect方法处理串口断开事件
handle_uart_disconnect(event[1])
# 若是uart对象有可读数据,则读取并打印接收到的数据
if event[1] & select.POLLIN:
# 尝试读取串口数据
try:
# 读取一个字节的串口数据
data = uart.read(1)
# 打印接收到的数据
print("uart recv data = ", data)
# 将数据添加到缓冲区
uart_buffer.append(data)
# 可以选择在此处处理或分析接收到的数据
# ...
# 若缓冲区数据满时,执行清空操作
if len(uart_buffer) >= uart_buffer_max_len:
# 清空缓冲区
uart_buffer.clear()
# 熄灭LED灯表示数据已读取完毕
LED.off()
except Exception as e:
print("uart read error: ", e)UART to create a serial port object and configure an LED.select. poll object uart_read_poll is created, which is used to monitor the active status of the serial port, including:POLLIN: Readable event, indicating that there is data available to be read from the serial port.POLLERR: An error event, indicating that an error has occurred in the serial port device. POLLERR event indicates that some kind of error has occurred in the device (such as a serial port line error or a device driver error), which may result in the failure to perform normal data read or write operations.POLLHUP: Disconnection event, indicating that the serial port device is disconnected (e. g., the serial port cable is unplugged or the virtual serial port on the computer closes the connection). Note that in MicroPython for Raspberry Pi Pico, the serial port will not automatically send a disconnection notification when the serial port device is disconnected, and the operating system itself does not actively detect the physical disconnection of the serial port; only when a USB-based virtual serial port device is disconnected may the POLLERR or POLLHUP event be triggered.uart_read_poll. register method to register the serial port object with the poll object, so as to monitor these events;In the main loop, uart_read_poll. poll (50) is used to listen for serial port events. The poll method will block until an event is triggered, or return if no event occurs within 50 milliseconds. Here, events is a list containing device objects, and the event objects as elements in the list are in the form of tuples, namely (fd attribute - device name, events attribute - event type).events list and checks the device and event type for each entry:POLLERR): If a serial port error is detected, the handle_uart_error function will be called to handle the error. This function will attempt to reset the serial port connection and reinitialize the serial port settings.POLLHUP): If a serial port device disconnection is detected, call the handle_uart_disconnect function to stop serial port operations and prepare for reconnection.POLLIN): If there is data available to read on the serial port, the system will attempt to read one byte of data and add it to the buffer. The received data will be printed out.uart_buffer. To prevent buffer overflow, a maximum length uart_buffer_max_len is set, and the buffer will be cleared once the amount of data in it exceeds this maximum value.LED acts as an indicator light to show the status of the system:the LED will light up.the LED will turn off, indicating that the data reading has been finished.Pico, open the terminal, and send data via the XCOM serial port assistant. The operation status is as follows:events = [(UART(0, baudrate=9600, bits=8, parity=None, stop=1, tx=0, rx=1, txbuf=256, rxbuf=256, timeout=5, timeout_char=2, invert=None), 1)]
fd attributes/the name of the device : UART(0, baudrate=9600, bits=8, parity=None, stop=1, tx=0, rx=1, txbuf=256, rxbuf=256, timeout=5, timeout_char=2, invert=None)
events property/the trigger type of the event : 1
uart recv data = b'a'events), device name, event type, and the data received via the serial port (uart recv data = b'a').