发布时间:2026/8/2 13:54:51
串口通信从入门到实战:STM32与Python完整开发指南 在嵌入式开发和硬件通信中串口通信是最基础也是最常用的通信方式之一。无论是单片机与PC通信还是设备间的数据交换串口都扮演着重要角色。本文将从零开始带你快速掌握串口通信的核心原理、配置方法和实战应用让你在3分钟内搭建起可运行的串口通信系统。1. 串口通信基础概念1.1 什么是串口通信串口通信Serial Communication是指数据按位顺序依次传输的通信方式。与并行通信相比串口通信只需要少数几条线就可以实现系统间的数据交换具有布线简单、成本低、传输距离远等优点。串口通信通常包含两种类型同步串行通信和异步串行通信。在嵌入式领域最常用的是异步串行通信也就是我们常说的UARTUniversal Asynchronous Receiver/Transmitter。1.2 串口通信的核心参数要成功建立串口通信必须正确配置以下几个关键参数波特率Baud Rate数据传输速率表示每秒传输的符号数常见值有9600、115200等数据位Data Bits每个数据包包含的数据位数通常是7或8位停止位Stop Bits表示数据包结束的位数通常是1位或2位校验位Parity Bit用于错误检测可选无校验、奇校验或偶校验1.3 串口通信的应用场景串口通信广泛应用于各种场景单片机与PC机之间的数据传输工业控制设备的通信传感器数据采集嵌入式系统调试和日志输出物联网设备通信2. 硬件连接与接口标准2.1 RS-232标准RS-232是最经典的串口通信标准使用DB9或DB25接口。虽然现在很多设备已经不再使用传统的RS-232接口但其通信原理仍然是理解串口通信的基础。RS-232接口的主要引脚定义TX引脚3数据发送端RX引脚2数据接收端GND引脚5信号地线2.2 TTL电平串口在现代嵌入式系统中更常用的是TTL电平的串口通信。TTL电平使用0V表示逻辑03.3V或5V表示逻辑1可以直接与单片机GPIO引脚连接。2.3 USB转串口模块由于现代电脑大多不再配备原生串口USB转串口模块成为连接PC与嵌入式设备的重要桥梁。常见的芯片有CH340、CP2102、FT232等。3. 串口通信协议详解3.1 数据帧结构串口通信的数据以帧为单位进行传输每帧数据包含以下部分起始位 | 数据位7-8位 | 校验位可选 | 停止位1-2位起始位总是逻辑0表示一帧数据的开始数据位实际要传输的数据从低位到高位依次传输校验位用于简单的错误检测停止位总是逻辑1表示一帧数据的结束3.2 通信流程串口通信的基本流程如下发送端将并行数据转换为串行数据添加起始位、校验位和停止位组成数据帧按照设定的波特率逐位发送接收端检测起始位开始接收数据验证校验位如果启用检查数据完整性将串行数据转换为并行数据供处理器使用4. STM32串口通信实战4.1 环境准备开发板STM32F103C8T6蓝色药丸板开发环境STM32CubeIDE串口模块USB转TTL模块CH340芯片连接线杜邦线若干4.2 硬件连接将USB转TTL模块与STM32开发板正确连接TTL模块的TX引脚 → STM32的PA10引脚USART1_RXTTL模块的RX引脚 → STM32的PA9引脚USART1_TXTTL模块的GND引脚 → STM32的GND引脚4.3 STM32CubeMX配置使用STM32CubeMX进行外设配置打开STM32CubeMX选择对应的STM32型号在Pinout视图中使能USART1配置USART1参数Mode: AsynchronousBaud Rate: 115200Word Length: 8 BitsParity: NoneStop Bits: 1Oversampling: 16生成代码工程4.4 核心代码实现在生成的工程中添加串口通信代码// 文件路径Core/Src/main.c #include main.h #include string.h UART_HandleTypeDef huart1; // 重定向printf到串口 int _write(int file, char *ptr, int len) { HAL_UART_Transmit(huart1, (uint8_t*)ptr, len, HAL_MAX_DELAY); return len; } // 串口接收回调函数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart-Instance USART1) { // 处理接收到的数据 uint8_t received_data; HAL_UART_Receive_IT(huart1, received_data, 1); printf(Received: %c\n, received_data); } } int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); printf(STM32 UART Communication Demo Started!\r\n); uint8_t receive_buffer; HAL_UART_Receive_IT(huart1, receive_buffer, 1); while (1) { // 每隔1秒发送测试数据 printf(Hello from STM32!\r\n); HAL_Delay(1000); } }4.5 串口初始化配置// 文件路径Core/Src/usart.c static 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(); } }5. Python串口通信上位机开发5.1 安装pyserial库pip install pyserial5.2 Python串口通信代码# 文件路径serial_monitor.py import serial import time import threading class SerialMonitor: def __init__(self, portCOM3, baudrate115200): self.ser serial.Serial( portport, baudratebaudrate, bytesizeserial.EIGHTBITS, parityserial.PARITY_NONE, stopbitsserial.STOPBITS_ONE, timeout1 ) self.running True def read_serial(self): 读取串口数据的线程函数 while self.running: if self.ser.in_waiting 0: data self.ser.readline().decode(utf-8).strip() if data: print(fReceived: {data}) time.sleep(0.01) def send_data(self, data): 发送数据到串口 if isinstance(data, str): data data.encode(utf-8) self.ser.write(data b\r\n) print(fSent: {data.decode(utf-8)}) def start_monitor(self): 启动串口监视器 print(Serial Monitor Started!) print(Press CtrlC to stop) # 启动读取线程 read_thread threading.Thread(targetself.read_serial) read_thread.daemon True read_thread.start() try: while True: # 可以在这里添加发送逻辑 user_input input(Enter message to send (or quit to exit): ) if user_input.lower() quit: break self.send_data(user_input) except KeyboardInterrupt: print(\nStopping monitor...) finally: self.running False self.ser.close() if __name__ __main__: # 根据实际情况修改端口号 monitor SerialMonitor(portCOM3, baudrate115200) monitor.start_monitor()5.3 自动检测可用串口import serial.tools.list_ports def list_serial_ports(): 列出所有可用的串口 ports serial.tools.list_ports.comports() available_ports [] for port, desc, hwid in sorted(ports): print(f{port}: {desc} [{hwid}]) available_ports.append(port) return available_ports # 使用示例 if __name__ __main__: ports list_serial_ports() if ports: print(f可用串口: {ports}) else: print(未找到可用串口)6. 常见问题与解决方案6.1 通信失败排查步骤当串口通信出现问题时可以按照以下步骤排查检查硬件连接确认TX、RX交叉连接设备A的TX接设备B的RX检查GND是否共地确认电源供电正常检查参数配置确认双方波特率一致检查数据位、停止位、校验位设置验证流控制设置软件层面检查确认串口未被其他程序占用检查驱动程序是否正常安装验证代码中的端口号是否正确6.2 常见错误代码及解决# 常见的串口错误处理 try: ser serial.Serial(COM3, 115200, timeout1) except serial.SerialException as e: print(f串口打开失败: {e}) # 可能的原因端口不存在、权限不足、端口被占用6.3 数据丢失或乱码问题数据丢失的常见原因及解决方案波特率不匹配重新校准波特率确保发送接收方一致缓冲区溢出增加读取频率或增大缓冲区电磁干扰使用屏蔽线缩短传输距离接地问题确保所有设备共地7. 串口通信高级应用7.1 自定义通信协议在实际项目中通常需要定义自己的通信协议来确保数据的可靠性# 简单的帧结构设计 class SerialProtocol: def __init__(self): self.START_BYTE 0xAA self.END_BYTE 0x55 def pack_data(self, command, data): 打包数据帧 frame bytearray() frame.append(self.START_BYTE) # 起始字节 frame.append(command) # 命令字 frame.append(len(data)) # 数据长度 frame.extend(data) # 数据内容 # 计算校验和 checksum sum(frame) 0xFF frame.append(checksum) # 校验和 frame.append(self.END_BYTE) # 结束字节 return bytes(frame) def unpack_data(self, frame): 解包数据帧 if (frame[0] ! self.START_BYTE or frame[-1] ! self.END_BYTE): return None # 帧格式错误 received_checksum frame[-2] calculated_checksum sum(frame[:-2]) 0xFF if received_checksum ! calculated_checksum: return None # 校验和错误 return { command: frame[1], length: frame[2], data: frame[3:3frame[2]] }7.2 多线程串口通信对于需要同时处理多个任务的应用程序使用多线程可以提高效率import threading import queue import time class ThreadedSerialCommunication: def __init__(self, port, baudrate115200): self.serial_port serial.Serial(port, baudrate, timeout1) self.receive_queue queue.Queue() self.send_queue queue.Queue() self.running True def receiver_thread(self): 接收线程 while self.running: if self.serial_port.in_waiting 0: try: data self.serial_port.readline() if data: self.receive_queue.put(data) except serial.SerialException: break time.sleep(0.01) def sender_thread(self): 发送线程 while self.running: try: if not self.send_queue.empty(): data self.send_queue.get() self.serial_port.write(data) except serial.SerialException: break time.sleep(0.01) def start_communication(self): 启动通信线程 receiver threading.Thread(targetself.receiver_thread) sender threading.Thread(targetself.sender_thread) receiver.daemon True sender.daemon True receiver.start() sender.start()7.3 数据可视化显示将串口接收的数据实时显示在图形界面上import matplotlib.pyplot as plt import matplotlib.animation as animation from collections import deque class SerialPlotter: def __init__(self, max_points100): self.max_points max_points self.data_buffer deque([0] * max_points, maxlenmax_points) self.fig, self.ax plt.subplots() self.line, self.ax.plot(range(max_points), list(self.data_buffer)) def update_plot(self, new_value): 更新绘图数据 self.data_buffer.append(new_value) self.line.set_ydata(self.data_buffer) return self.line, def start_animation(self): 启动实时动画 ani animation.FuncAnimation( self.fig, self.update_plot, interval50, blitTrue ) plt.show()8. 不同平台的串口通信实现8.1 C# 串口通信实现using System; using System.IO.Ports; using System.Threading; public class SerialPortExample { private SerialPort serialPort; public SerialPortExample(string portName, int baudRate) { serialPort new SerialPort(portName, baudRate); serialPort.DataReceived new SerialDataReceivedEventHandler(DataReceivedHandler); } public void OpenConnection() { try { serialPort.Open(); Console.WriteLine(串口连接成功); } catch (Exception ex) { Console.WriteLine($串口连接失败: {ex.Message}); } } private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) { SerialPort sp (SerialPort)sender; string data sp.ReadExisting(); Console.WriteLine($接收到数据: {data}); } public void SendData(string data) { if (serialPort.IsOpen) { serialPort.WriteLine(data); Console.WriteLine($发送数据: {data}); } } public void CloseConnection() { if (serialPort.IsOpen) { serialPort.Close(); } } } // 使用示例 class Program { static void Main() { SerialPortExample example new SerialPortExample(COM3, 115200); example.OpenConnection(); example.SendData(Hello from C#); Thread.Sleep(2000); example.CloseConnection(); } }8.2 LabVIEW与单片机串口通信在LabVIEW中实现串口通信的基本步骤前面板设计添加字符串显示控件接收数据显示添加字符串输入控件发送数据输入添加数值控件波特率设置添加布尔按钮连接/断开控制程序框图设计使用VISA配置串口函数使用VISA写入函数发送数据使用VISA读取函数接收数据使用While循环实现持续通信添加错误处理机制8.3 Kotlin Android串口通信在Android应用中实现串口通信class SerialHelper(private val context: Context) { private var serialPort: SerialPort? null private var inputStream: InputStream? null private var outputStream: OutputStream? null private var readThread: Thread? null private var isReading false fun openSerialPort(device: File, baudrate: Int): Boolean { return try { serialPort SerialPort(device, baudrate, 0) inputStream serialPort!!.inputStream outputStream serialPort!!.outputStream startReading() true } catch (e: Exception) { Log.e(SerialHelper, 打开串口失败, e) false } } private fun startReading() { isReading true readThread Thread { val buffer ByteArray(1024) while (isReading) { try { val size inputStream!!.read(buffer) if (size 0) { val data String(buffer, 0, size) // 处理接收到的数据 Log.d(SerialHelper, 收到数据: $data) } } catch (e: Exception) { Log.e(SerialHelper, 读取数据异常, e) } } } readThread!!.start() } fun sendData(data: String) { try { outputStream!!.write(data.toByteArray()) outputStream!!.flush() } catch (e: Exception) { Log.e(SerialHelper, 发送数据失败, e) } } fun closeSerialPort() { isReading false readThread?.interrupt() serialPort?.close() } }9. 性能优化与最佳实践9.1 波特率选择策略选择合适的波特率对通信质量至关重要低速应用传感器数据9600-19200 bps中速应用一般控制38400-115200 bps高速应用图像传输230400-921600 bps选择原则在满足数据传输需求的前提下尽量选择较低的波特率以提高通信稳定性。9.2 错误检测与纠正提高通信可靠性的方法校验和验证每帧数据添加校验和超时重传设置合理的超时时间数据确认机制接收方确认收到数据数据重发机制发送失败时自动重发9.3 资源管理最佳实践# 使用上下文管理器确保资源正确释放 class SafeSerial: def __init__(self, port, baudrate): self.port port self.baudrate baudrate self.ser None def __enter__(self): self.ser serial.Serial(self.port, self.baudrate, timeout1) return self.ser def __exit__(self, exc_type, exc_val, exc_tb): if self.ser and self.ser.is_open: self.ser.close() # 使用示例 with SafeSerial(COM3, 115200) as ser: ser.write(bHello World) response ser.readline() print(fResponse: {response})串口通信作为嵌入式系统中最基础的通信方式掌握其原理和实现方法对嵌入式开发者至关重要。通过本文的讲解和示例你应该能够快速搭建起可用的串口通信系统并根据实际需求进行功能扩展。在实际项目中记得充分考虑通信的可靠性和错误处理确保系统的稳定运行。

相关新闻

2026/8/2 13:54:51

软件支持体系全解析:技术维护、社区生态与商业保障

1. 从“支持”二字说起:软件生态的基石与价值当我们谈论一款软件时,“支持”这个词往往被轻描淡写地带过,但它却是决定软件生命力、用户体验和项目成败的隐形骨架。它远不止是客服电话或一个FAQ页面那么简单。在我过去十多年的技术选型、项目…

2026/8/2 13:54:50

3分钟掌握全网视频资源下载:res-downloader终极指南

3分钟掌握全网视频资源下载:res-downloader终极指南 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader 还在为无法保…

2026/8/2 13:49:50

如何让Windows性能飙升45%:AtlasOS终极优化方案完整指南

如何让Windows性能飙升45%:AtlasOS终极优化方案完整指南 【免费下载链接】Atlas 🚀 An open and lightweight modification to Windows, designed to optimize performance, privacy and usability. 项目地址: https://gitcode.com/GitHub_Trending/at…

2026/8/2 15:35:11

Unity测试框架:C语言单元测试的终极指南

Unity测试框架:C语言单元测试的终极指南 【免费下载链接】Unity Simple unit testing for C 项目地址: https://gitcode.com/gh_mirrors/un/Unity Unity是一个专为C语言设计的轻量级单元测试框架,特别适合嵌入式系统和跨平台开发。这个简单的C语言…

2026/8/2 15:35:11

免费开源下载加速神器:AB Download Manager终极使用指南

免费开源下载加速神器:AB Download Manager终极使用指南 【免费下载链接】ab-download-manager A Download Manager that speeds up your downloads 项目地址: https://gitcode.com/GitHub_Trending/ab/ab-download-manager 在现代数字生活中,高效…

2026/8/2 15:35:11

Grove LCD RGB背光屏:I2C控制与Arduino项目实战

1. 项目概述:点亮你的创意,从这块彩屏开始 如果你玩过Arduino或者树莓派,大概率会对那些单色、蓝底或者绿底的字符液晶屏(LCD)有印象。它们能显示文字,但背景光通常是固定的颜色,看久了难免有些…

2026/8/2 15:35:11

2026最新音频转文字软件哪个好用?亲测4款实用工具,均有免费额度

简短结论 针对2026年学生群体的课堂记录、复习备考、论文访谈需求,本次亲测的4款带免费额度的音频转文字软件各有适配场景。仅需基础转写可选通义听悟、觅讯,需要离线转写可选录音转文字助手,听脑AI更适合需要把录音整理成复习材料、访谈初稿…

2026/8/2 15:35:11

DOI与PMID:学术文献的身份证与社保号,科研效率提升必备

1. 从一篇文献的“身份证”说起 如果你刚开始接触学术研究,或者需要查阅一些专业的医学、生物学论文,大概率会碰到两个看起来像乱码的字符串:一个是以“10.”开头,长得像网址的“DOI”,另一个是纯数字组成的“PMID”。…

2026/8/2 15:30:10

电子墨水屏驱动全解析:从SPI通信到低功耗显示优化实践

1. 项目概述:7.3英寸电子纸HAT (G) 是什么? 如果你玩过树莓派、Arduino或者STM32,肯定对各种各样的显示屏不陌生。从LCD到OLED,选择很多,但它们都有一个共同点:需要持续供电才能显示内容。一旦断电&#xf…

2026/8/2 0:02:18

如何用免费工具突破游戏窗口限制:SRWE完整使用指南

如何用免费工具突破游戏窗口限制:SRWE完整使用指南 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 你是否遇到过这样的困扰?想为心爱的游戏截图,却发现游戏不支持自定义分辨率…

2026/8/2 0:02:18

如何用免费工具突破游戏窗口限制:SRWE完整使用指南

如何用免费工具突破游戏窗口限制:SRWE完整使用指南 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 你是否遇到过这样的困扰?想为心爱的游戏截图,却发现游戏不支持自定义分辨率…

2026/8/2 1:52:02

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/1 0:03:49

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/2 8:56:50

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…