1. Python串口通信基础入门第一次接触串口通信时我完全被那些专业术语搞懵了。什么波特率、数据位、停止位听起来就像天书一样。但实际用起来才发现Python的serial库把这些复杂概念都封装得特别友好。就像用USB线连接手机和电脑那么简单串口通信其实就是让计算机和设备通过几根电线聊天。安装pyserial库只需要一行命令pip install pyserial记得我第一次用这个库时犯了个低级错误——没注意Python版本。pyserial要求Python 3.6如果你还在用Python 2.7肯定会遇到各种奇怪问题。安装完成后导入库的姿势也很重要import serial import serial.tools.list_ports # 这个后面会用到2. 硬件连接与串口配置去年给工厂做自动化改造时我遇到过最头疼的问题就是串口死活连不上。后来发现是USB转串口线的驱动没装好。所以在写代码前一定要先确认硬件连接正常。Windows设备管理器里能看到COM口Linux下可以用ls /dev/tty*查看。配置串口就像给两个说不同语言的人当翻译参数必须对得上ser serial.Serial( portCOM3, # Windows下是COMxLinux是/dev/ttyUSBx baudrate115200, # 这个必须和设备一致 bytesize8, # 数据位默认8位就够用 parityN, # 校验位N无校验E偶校验O奇校验 stopbits1, # 停止位 timeout1 # 读超时时间(秒) )有次调试电机控制器数据老是乱码折腾半天才发现波特率设成了9600而设备实际是115200。所以记住波特率是串口通信的生命线常见值有9600、19200、38400、57600、115200等越高传输越快但距离越短。3. 数据收发实战技巧3.1 基础读写操作收发数据就像用对讲机要遵守说完等回应的原则。我常用的几个方法# 发送数据必须是bytes类型 ser.write(bHello Motor) # 发送ASCII ser.write(bytes.fromhex(01 03 00 01 00 01 D5 CA)) # 发送16进制 # 读取数据 data ser.read(10) # 读10个字节 line ser.readline() # 读一行(直到\n) all_data ser.read_all() # 读取全部缓存特别提醒很多电机控制器用的是Modbus RTU协议指令都是16进制格式。比如读取寄存器0x0001的值cmd bytes.fromhex(01 03 00 01 00 01 D5 CA) ser.write(cmd) response ser.read(8) # 典型响应长度3.2 异常处理必备我踩过最痛的坑就是程序崩溃后串口没关闭下次运行就报串口被占用。所以一定要用try-finallytry: ser serial.Serial(COM3, 115200) # 你的操作代码... finally: ser.close() # 确保串口一定会关闭更完善的方案是使用with语句with serial.Serial(COM3, 115200) as ser: ser.write(bSTART) # 不需要手动close4. 驱动电机控制实战4.1 直流电机控制通过串口控制电机本质上就是发送特定指令。比如这个案例控制电机启停和转速def control_motor(ser, speed50, direction1): # 速度限制在0-100 speed max(0, min(100, speed)) # 方向0停止1正转2反转 cmd fMOTOR {direction} {speed}\n.encode() ser.write(cmd) # 等待电机响应 response ser.readline() return response.decode().strip()实际工业设备通常会使用更专业的协议。比如某品牌步进电机的控制指令# 设置转速为300rpm ser.write(bytes.fromhex(01 06 00 20 01 2C 78 47)) # 启动电机 ser.write(bytes.fromhex(01 06 00 00 00 01 48 0A))4.2 反馈控制实现真正实用的系统需要闭环控制。比如通过编码器读取实际转速再调整PWM输出def speed_control(target_rpm): Kp 0.5 # 比例系数 current_rpm 0 with serial.Serial(COM4, 115200) as ser: while True: # 读取编码器值假设协议是GETSPEED ser.write(bGETSPEED\n) current_rpm float(ser.readline()) # 计算误差并调整 error target_rpm - current_rpm adjustment int(Kp * error) # 发送新PWM值 ser.write(fPWM {adjustment}\n.encode()) time.sleep(0.1) # 控制周期5. 高级技巧与调试心得5.1 自动检测串口每次换电脑都要改COM口号太麻烦我封装了这个自动检测函数def find_serial_device(keywordCH340): 通过设备描述查找串口 ports serial.tools.list_ports.comports() for port in ports: if keyword in port.description: return port.device raise Exception(未找到指定串口设备)5.2 数据可视化监控用matplotlib实时显示电机转速变化import matplotlib.pyplot as plt from collections import deque # 初始化数据缓冲区 history deque(maxlen100) plt.ion() # 开启交互模式 with serial.Serial(find_serial_device(), 115200) as ser: while True: ser.write(bGETSPEED\n) rpm float(ser.readline()) history.append(rpm) # 更新曲线 plt.clf() plt.plot(history) plt.pause(0.01)5.3 常见问题排查数据乱码检查波特率、数据位、停止位是否一致发送无响应确认RTS/DTR流控设置尝试交换TX/RX线间歇性断开可能是USB供电不足换带外接电源的HUB延迟严重调小timeout值或使用read_all()非阻塞读取有次现场调试电机时好时坏最后发现是485总线的终端电阻没接。所以硬件问题也不能忽视6. 项目案例智能窗帘控制系统去年用这套技术做了个自动窗帘项目核心代码如下class CurtainController: def __init__(self, port): self.ser serial.Serial(port, 9600) self.position 0 # 0-100%开度 def move_to(self, target): steps abs(target - self.position) * 10 direction 1 if target self.position else 0 cmd bytes([0xAA, 0x01, direction, steps 0xFF, steps 8]) self.ser.write(cmd) self.position target def auto_adjust(self, light_sensor): 根据光照自动调节 while True: light light_sensor.read() target min(100, max(0, (light - 200) / 5)) # 简单映射 self.move_to(int(target)) time.sleep(60)这个系统通过光敏电阻采集光照强度自动控制步进电机调节窗帘开合度。关键点是电机每转对应固定步数通过绝对位置控制避免累积误差加入手动override功能实际部署时还加了太阳能供电和无线模块但串口通信始终是核心控制通道。