K210实战笔记:MicroPython解码STM32串口数据,驱动LCD实时显示
1. 硬件连接与初始化配置
第一次玩K210和STM32串口通信的时候,最让我头疼的就是引脚连接问题。STM32的串口引脚是固定的,比如USART1默认在PA9和PA10,但K210就灵活多了,几乎任意IO都可以映射为串口功能。这里我用的是一块K210开发板和正点原子的STM32F103ZET6精英板。
接线其实特别简单,只需要四根线:
- STM32的PA9(TXD)接K210的IO9(RXD)
- STM32的PA10(RXD)接K210的IO10(TXD)
- 两边的GND一定要接在一起
- 3.3V电源可以共用一个
这里有个坑我踩过:刚开始没接GND,数据死活传不过去,后来才发现共地是必须的。另外建议用杜邦线连接时尽量短一些,长线容易引入干扰。
STM32端的初始化就是标准操作,用HAL库或者标准库都行。我习惯用HAL,初始化代码大概长这样:
void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } }2. STM32数据发送实战
在STM32端发送数据其实特别简单,但有几个细节需要注意。我以发送温度值为例,实际项目里可能是各种传感器数据。
最直接的方式就是用printf:
float temp_wendu = 25.6; printf("%.2f", temp_wendu);但这里有个坑:默认情况下printf是通过串口1输出的,如果你的工程里没重定向fputc,可能会卡死。保险起见可以这样发送:
char buffer[20]; int len = sprintf(buffer, "%.2f", temp_wendu); HAL_UART_Transmit(&huart1, (uint8_t*)buffer, len, 100);实测下来发现几个经验:
- 浮点数传输建议固定小数位数,避免长度变化
- 如果传输多个数据,最好加分隔符,比如逗号
- 传输频率不要太快,K210那边处理需要时间
我后来改进的发送代码是这样的:
void send_sensor_data(float temp, float humi) { static char tx_buf[64]; int len = sprintf(tx_buf, "%.1f,%.1f\r\n", temp, humi); HAL_UART_Transmit(&huart1, (uint8_t*)tx_buf, len, 100); }加\r\n是为了方便K210那边判断数据结束,这个在调试阶段特别有用。
3. K210端串口配置详解
K210这边用MicroPython开发真的太方便了,比用C语言开发STM32舒服多了。首先要在MaixPy IDE里导入必要的模块:
from machine import UART from fpioa_manager import fm引脚映射是K210的特色功能,我们可以把任意IO配置成串口:
fm.register(9, fm.fpioa.UART1_RX, force=True) fm.register(10, fm.fpioa.UART1_TX, force=True)这里的force=True意思是强制映射,即使这个引脚之前被其他功能占用也会强行改过来。初始化串口的代码如下:
uart = UART(UART.UART1, 115200, 8, 1, 0, timeout=1000, read_buf_len=4096)参数说明:
- 115200:波特率,必须和STM32一致
- 8:数据位
- 1:停止位
- 0:无校验
- timeout:超时时间(ms)
- read_buf_len:接收缓冲区大小
这里我建议缓冲区设大一点,实测4096比较稳妥。曾经设过256,结果数据量大时就丢包。
4. 数据接收与解码处理
STM32发过来的是字节数据,K210这边需要解码才能变成可读的字符串。MicroPython处理这个特别简单:
read_data = uart.read(5) # 读取5个字节 if read_data: text = read_data.decode('utf-8') # UTF-8解码但实际项目中会遇到各种问题:
- 数据长度不固定:比如温度可能是"25.6"或"-12.3"
- 数据不完整:可能只收到部分字节
- 数据错误:传输过程中出现干扰
我的改进方案是这样的:
def read_uart(uart): buf = bytearray() while True: byte = uart.read(1) if not byte: break buf.append(byte[0]) if byte == b'\n': # 以换行符作为结束标志 break try: return buf.decode('utf-8').strip() except: return None这样就能可靠地读取一行数据了。如果数据是浮点数,还需要转换:
text = read_uart(uart) if text: try: value = float(text) except ValueError: value = 0.05. LCD实时显示实现
K210的LCD显示功能很强大,配合摄像头可以做很多有趣的应用。先初始化LCD和摄像头:
import lcd import sensor lcd.init() sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.run(1)显示数据的基本方法是在摄像头画面上叠加文字:
img = sensor.snapshot() img.draw_string(10, 10, "Temp: %.1fC" % value, color=(255,0,0), scale=2) lcd.display(img)但直接这样写会发现文字闪烁严重。优化方法是只在数据更新时刷新显示区域:
last_value = None while True: img = sensor.snapshot() value = get_sensor_value() # 获取传感器值 if value != last_value: img.draw_rectangle(0, 0, 200, 30, (0,0,0), fill=True) img.draw_string(10, 10, "Temp: %.1fC" % value, color=(0,255,0), scale=2) last_value = value lcd.display(img)这样显示就稳定多了。还可以添加更多信息,比如时间戳、单位等。
6. 多数据协议设计实战
实际项目往往需要传输多个数据,比如温湿度、气压等。这时候就需要设计简单的通信协议了。
STM32端可以这样发送:
void send_all_data(float temp, float humi, float press) { char buf[64]; sprintf(buf, "T%.1fH%.1fP%.1f\r\n", temp, humi, press); HAL_UART_Transmit(&huart1, (uint8_t*)buf, strlen(buf), 100); }K210端解析代码:
def parse_data(text): if not text or len(text) < 5: return None data = {} parts = text.split('\r\n')[0] # 去掉结尾符 i = 0 while i < len(parts): if parts[i] == 'T': i += 1 data['temp'] = float(parts[i:i+4]) i += 4 elif parts[i] == 'H': i += 1 data['humi'] = float(parts[i:i+4]) i += 4 elif parts[i] == 'P': i += 1 data['press'] = float(parts[i:i+4]) i += 4 else: i += 1 return data这种协议虽然简单,但很实用。更复杂的可以用JSON格式,不过对STM32来说处理起来有点吃力。
7. 性能优化与稳定性提升
在实际使用中,我发现几个可以优化的地方:
- 串口读取优化:
# 不好的写法 data = uart.read() # 可能阻塞 # 好的写法 data = uart.read(uart.any()) # 只读取当前缓冲区数据- 显示刷新优化:
# 只在数据变化时刷新特定区域 if new_value != old_value: img.draw_rectangle(x, y, w, h, bg_color, fill=True) img.draw_string(x, y, text, color, scale)- 错误处理增强:
try: value = float(text) except: value = 0.0 uart.write(b'ERROR\n') # 通知STM32重发- 添加心跳包检测:
last_active = time.ticks_ms() while True: if uart.any(): process_data() last_active = time.ticks_ms() elif time.ticks_diff(time.ticks_ms(), last_active) > 5000: show_error("Connection lost!")这些技巧都是我在实际项目中踩坑后总结出来的,特别是心跳包机制,在长时间运行的项目中特别重要。
