保姆级教程:用Python在Jetson Nano上玩转串口,轻松控制STM32(附完整代码)
从零开始Jetson Nano与STM32的串口通信实战指南在嵌入式开发领域Jetson Nano凭借其强大的AI计算能力和丰富的接口资源成为连接物理世界与数字世界的理想桥梁。而STM32系列单片机则以其稳定性和灵活性在工业控制、物联网终端等领域占据重要地位。本文将带你从硬件连接到软件调试一步步实现这两个平台之间的串口通信。1. 硬件准备与环境搭建1.1 所需硬件清单在开始之前请确保你已准备好以下硬件设备Jetson Nano开发板建议使用4GB内存版本STM32开发板本文以STM32F4系列为例USB转TTL串口模块用于调试和监控杜邦线若干建议使用不同颜色区分功能稳压电源或USB供电线提示购买杜邦线时建议选择母对母、公对母、公对公各一组以适应不同开发板的接口需求。1.2 Jetson Nano串口配置Jetson Nano默认启用了串口控制台功能我们需要先禁用这一设置sudo systemctl stop nvgetty sudo systemctl disable nvgetty然后修改/boot/extlinux/extlinux.conf文件找到包含consolettyTHS1的行并删除它。保存后重启系统使更改生效。1.3 STM32开发环境准备对于STM32开发我们推荐使用以下工具链STM32CubeIDE官方集成开发环境包含HAL库和LL库STM32CubeMX图形化配置工具可自动生成初始化代码OpenOCD用于调试和烧录程序安装完成后创建一个新项目并配置USART外设选择正确的MCU型号在Pinout视图中启用USART2配置参数波特率1152008位数据位无校验1位停止位生成代码2. 硬件连接详解2.1 引脚对应关系Jetson Nano的40针GPIO接口中串口引脚位于第8和第10针Jetson Nano引脚功能STM32对应引脚6GNDGND8TXDUSART2_RX10RXDUSART2_TX2.2 连接注意事项电平匹配Jetson Nano的串口为3.3V电平与STM32F4系列兼容无需电平转换防短路措施连接前务必断电操作避免误接导致硬件损坏信号完整性长距离通信时建议使用屏蔽线并考虑添加终端电阻注意错误的接线可能导致设备损坏。务必再三确认连接正确后再通电。3. Python串口通信实现3.1 pyserial库安装与基础使用在Jetson Nano上安装pyserial库pip install pyserial创建一个简单的串口测试脚本serial_test.pyimport serial import time def main(): try: # 配置串口参数 ser serial.Serial( port/dev/ttyTHS1, baudrate115200, bytesizeserial.EIGHTBITS, parityserial.PARITY_NONE, stopbitsserial.STOPBITS_ONE, timeout1 ) if ser.is_open: print(串口已打开) while True: # 发送数据 send_data Hello STM32\n ser.write(send_data.encode(utf-8)) print(f发送: {send_data.strip()}) # 接收数据 if ser.in_waiting 0: received_data ser.read(ser.in_waiting) print(f接收: {received_data.decode(utf-8).strip()}) time.sleep(1) except Exception as e: print(f发生错误: {str(e)}) finally: if ser in locals() and ser.is_open: ser.close() print(串口已关闭) if __name__ __main__: main()3.2 常见问题排查当通信不成功时可以按照以下步骤排查检查物理连接确认GND已正确连接确认TX-RX交叉连接检查线缆是否完好验证串口配置波特率双方必须一致数据位、停止位、校验位设置匹配流控设置通常为None权限问题ls -l /dev/ttyTHS1如果显示权限不足可以添加当前用户到dialout组sudo usermod -a -G dialout $(whoami)然后注销重新登录。4. STM32固件开发4.1 使用HAL库实现串口通信在STM32CubeIDE中我们可以利用HAL库快速实现串口功能。以下是关键代码片段/* 在main.c中添加以下变量 */ uint8_t rxBuffer[128]; uint8_t txBuffer[128]; uint8_t receivedFlag 0; /* 在main函数初始化部分添加 */ HAL_UART_Receive_IT(huart2, rxBuffer, 1); /* 添加回调函数 */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart-Instance USART2) { // 设置接收完成标志 receivedFlag 1; // 重新启动接收 HAL_UART_Receive_IT(huart2, rxBuffer, 1); } } /* 在主循环中添加处理逻辑 */ while (1) { if(receivedFlag) { receivedFlag 0; // 回传接收到的数据 sprintf((char*)txBuffer, Echo: %c\n, rxBuffer[0]); HAL_UART_Transmit(huart1, txBuffer, strlen((char*)txBuffer), HAL_MAX_DELAY); } }4.2 调试技巧使用逻辑分析仪可以捕获实际的串口信号验证时序和电平分段测试先单独测试STM32与PC的通信再测试Jetson与PC的通信最后两者对接添加状态指示灯利用LED指示通信状态便于快速诊断5. 高级应用与性能优化5.1 数据帧协议设计简单的文本协议虽然易于调试但在实际应用中我们通常需要设计更健壮的通信协议# Python端帧处理示例 def build_frame(command, data): header b\xAA\x55 length len(data).to_bytes(2, little) checksum (sum(data) 0xFF).to_bytes(1, little) return header length command data checksum def parse_frame(raw_data): if len(raw_data) 5: return None if raw_data[0] ! 0xAA or raw_data[1] ! 0x55: return None length int.from_bytes(raw_data[2:4], little) if len(raw_data) 4 length 1: return None command raw_data[4] data raw_data[5:5length] checksum raw_data[-1] if sum(data) 0xFF ! checksum: return None return (command, data)5.2 多线程处理为提高通信效率可以在Python端使用多线程分离发送和接收逻辑import threading class SerialManager: def __init__(self, port, baudrate): self.ser serial.Serial(port, baudrate, timeout1) self.receive_thread threading.Thread(targetself._receive_loop) self.running False def start(self): self.running True self.receive_thread.start() def stop(self): self.running False self.receive_thread.join() self.ser.close() def send(self, data): self.ser.write(data) def _receive_loop(self): while self.running: if self.ser.in_waiting 0: data self.ser.read(self.ser.in_waiting) print(fReceived: {data.hex()}) time.sleep(0.01)5.3 性能优化建议缓冲区管理合理设置接收缓冲区大小避免内存浪费或数据丢失超时设置根据实际通信频率调整超时参数错误处理添加重试机制和错误计数器提高系统鲁棒性在实际项目中我发现最常遇到的问题是波特率不匹配和接线错误。特别是在使用不同厂家的开发板时务必仔细核对技术文档。另一个实用技巧是在通信开始时加入握手协议确保双方都已准备好再进行数据传输。