
庐山派K230开发板UART串口通信实战从引脚复用、API调用到环路测试大家好我是老张一个在嵌入式行业摸爬滚打了十几年的工程师。最近在用庐山派K230开发板做项目发现很多刚入门的朋友对串口通信这块有点犯怵特别是引脚复用和MicroPython API的使用。今天我就结合自己的经验带大家从零开始手把手搞定K230上的UART串口通信最后咱们再用一个硬件环路测试来验证功能是否正常。串口UART可以说是嵌入式开发的“万能钥匙”不管是调试打印、连接传感器还是设备间通信都离不开它。掌握了串口就等于打通了开发板和外部世界沟通的桥梁。1. 串口通信基础先搞懂原理再动手在动手接线写代码之前咱们先花几分钟把串口通信的基本原理捋清楚这样后面配置起来心里才有底。1.1 串口到底是什么UART全称是“通用异步收发传输器”。说人话它就是两个设备之间用两根线TXD和RXD进行数据聊天的一种方式。它的特点是“异步”意思是通信双方不需要共用一根时钟线来同步各自用自己的时钟只要事先约定好通信速度波特率就行。这就像两个人用对讲机通话不需要看着同一个钟表只要说话速度差不多就能听懂对方在说什么。两根关键线TXD发送端数据从你这端发出去。RXD接收端数据从对方那里接收进来。这里有个超级重要的坑点两个设备要通信必须交叉连接也就是设备A的TXD要接设备B的RXD设备A的RXD要接设备B的TXD。自己接自己的话数据就“自言自语”传不出去了。1.2 串口通信的关键参数配置串口时通信双方必须约定好下面几个参数否则就是“鸡同鸭讲”收发的全是乱码波特率通信的速度单位是bps比特每秒。常见的有9600、115200、1.5M等。K230开发板的调试串口默认用的是1.5M波特率这个要特别注意和常见的115200不一样。数据位一个数据包一帧里实际有效数据的位数通常是8位一个字节。停止位用来表示一帧数据结束的标志位通常是1位。校验位用于简单的错误检测比如奇校验或偶校验。如果对数据可靠性要求不高可以不用设为None。一个完整的数据帧就是从起始位低电平开始然后是数据位接着是可选的校验位最后以停止位高电平结束。空闲时数据线保持高电平。2. K230开发板上的串口资源分布庐山派K230开发板提供了丰富的串口资源分布在不同的接口上方便我们连接各种外设。咱们得先知道哪个口对应哪个串口别接错了。2.1 40PIN排针上的串口首先看最常用的40PIN排针这里引出了UART1、UART2、UART3和UART4。具体引脚定义如下表排针引脚号芯片引脚号串口功能备注03GPIO 49UART4_RXD同时连接到摄像头接口2 (CSI2) 用作I2C通信板子内部有4.7K电阻上拉到3.3V05GPIO 48UART4_TXD同上08GPIO 03UART1_TXD-10GPIO 04UART1_RXD-11GPIO 05UART2_TXD-13GPIO 06UART2_RXD-27GPIO 41UART1_RXD同时连接到摄像头接口1 (CSI1) 用作I2C通信板子内部有4.7K电阻上拉到3.3V28GPIO 40UART1_TXD同上29GPIO 36UART4_TXD-31GPIO 37UART4_RXD-37GPIO 32UART3_TXD-40GPIO 33UART3_RXD-注意引脚有复用功能时比如同时是UART和I2C一次只能使用一种功能配置时要小心别冲突。2.2 三个带锁的GH1.25-4P接口除了排针板子上还有三个更稳固的GH1.25-4P带锁接口非常适合需要可靠连接的实际项目。这三个接口的线序定义是一致的引脚序号简称功能1V5V电源输出2RRXD串口信号接收线3TTXD串口信号发送线4GGND接地这三个接口分别对应不同的串口接口1位于两个侧按键中间标号为2对应UART2。这是最重要的外部通信接口也可以复用为I2C2。我们后面的例子主要就用它。接口2位于12V电源输入口旁边标号为3对应UART3。在最新的CanMV固件中用户可以使用它。接口3位于USB HOST接口旁边标号为0对应UART0。这个口用户无法直接调用因为它被内部系统RT-Smart占用为finsh控制台串口。如果你想看它的输出内容可以借助外部USB转串口工具连接到电脑的串口助手软件如MobaXterm参数设置为1152008N1。提示GH1.25接口插拔时需要向下按压上方卡扣才能顺利拔出千万不要用蛮力否则可能导致线缆甚至接口损坏。2.3 背面的大焊盘可焊排针处板子背面还有一些间距为2.54mm的大焊盘也标注了UART0、UART2、UART3。它们的电气连接和上面的GH1.25接口是一致的。如果你觉得GH1.25接口不方便可以直接把线焊在这些焊盘上或者用杜邦线连接。3. 实战第一步引脚复用与UART初始化K230内部集成了五个UART硬件模块。其中UART0被系统占用UART3在某些固件下可能被占用。剩下的UART1、UART2、UART4我们都可以正常使用。这里我们以最常用的UART2GH1.25接口1为例。在K230的MicroPythonCanMV中使用串口分两步引脚功能复用和UART模块初始化。3.1 引脚功能复用FPIOAK230的引脚功能非常灵活一个物理引脚可以通过FPIOA现场可编程IO阵列配置成多种功能UART、I2C、PWM等。所以使用串口前必须先把对应的GPIO引脚配置为UART功能。from machine import UART from machine import FPIOA # 创建FPIOA对象 fpioa FPIOA() # 将GPIO11配置为UART2的发送引脚(TXD) fpioa.set_function(11, FPIOA.UART2_TXD) # 将GPIO12配置为UART2的接收引脚(RXD) fpioa.set_function(12, FPIOA.UART2_RXD)代码解释from machine import ...导入必要的模块。fpioa FPIOA()创建一个FPIOA对象用来管理引脚功能。set_function(pin, function)是核心方法。第一个参数是芯片引脚号参考前面的表格第二个参数是预定义的功能常量比如FPIOA.UART2_TXD。3.2 初始化UART对象引脚配置好后就可以创建并初始化UART对象了。# 初始化UART2波特率1152008位数据位无校验1位停止位 uart UART(UART.UART2, baudrate115200, bitsUART.EIGHTBITS, parityUART.PARITY_NONE, stopUART.STOPBITS_ONE)构造函数的参数详解id: UART模块编号。有效值为UART.UART1,UART.UART2,UART.UART3,UART.UART4。必须和你前面引脚复用的UART编号一致baudrate: 波特率。默认115200可以根据需要修改但通信双方必须一致。bits: 数据位位数。可选UART.FIVEBITS,UART.SIXBITS,UART.SEVENBITS,UART.EIGHTBITS。默认8位。parity: 校验位。可选UART.PARITY_NONE无校验UART.PARITY_ODD奇校验UART.PARITY_EVEN偶校验。默认无校验。stop: 停止位位数。可选UART.STOPBITS_ONE1位UART.STOPBITS_TWO2位。默认1位。初始化完成后uart对象就可以用来收发数据了。4. 发送数据三种常见场景4.1 发送字符串最常用发送文本信息是最常见的操作比如打印调试信息。from machine import UART from machine import FPIOA # 1. 配置引脚 fpioa FPIOA() fpioa.set_function(11, FPIOA.UART2_TXD) fpioa.set_function(12, FPIOA.UART2_RXD) # 2. 初始化UART2 uart UART(UART.UART2, baudrate115200, bitsUART.EIGHTBITS, parityUART.PARITY_NONE, stopUART.STOPBITS_ONE) # 3. 要发送的字符串\n是换行符 message Hello, LuShan-Pi!\n # 4. 通过UART发送数据 uart.write(message) # 5. 释放UART资源如果后续不再使用 uart.deinit()如何测试将开发板的UART2TXD:GPIO11, RXD:GPIO12通过USB转TTL模块连接到电脑。打开电脑上的串口助手软件如Putty、MobaXterm、SecureCRT等选择对应的COM口设置波特率为115200数据位8停止位1无校验。运行上面的程序你就能在串口助手里看到Hello, LuShan-Pi!这行字了。4.2 发送字节数组用于原始数据/协议和单片机通信时经常需要发送十六进制的原始数据比如传感器指令0x01, 0x02。from machine import UART from machine import FPIOA fpioa FPIOA() fpioa.set_function(11, FPIOA.UART2_TXD) fpioa.set_function(12, FPIOA.UART2_RXD) uart UART(UART.UART2, baudrate115200) # 要发送的字节数组 data bytes([0x01, 0x02, 0x03, 0x04]) uart.write(data) uart.deinit()提示测试时记得把串口助手的显示格式从“字符串”切换到“十六进制”这样才能正确显示01 02 03 04。4.3 循环发送数据模拟传感器实际项目中我们经常需要定时发送数据比如模拟一个温度传感器每隔一段时间上报一次数据。import time from machine import UART from machine import FPIOA fpioa FPIOA() fpioa.set_function(11, FPIOA.UART2_TXD) fpioa.set_function(12, FPIOA.UART2_RXD) uart UART(UART.UART2, baudrate115200) # 模拟的传感器数值从0开始累加 sensor_value 0 while True: # 构造要发送的消息 message Sensor Value: {}\n.format(sensor_value) uart.write(message) # 模拟数值变化 sensor_value sensor_value 1 # 延时100毫秒避免发送太快 time.sleep(0.1)运行这个程序串口助手就会持续收到Sensor Value: 0 Sensor Value: 1 Sensor Value: 2 ...5. 接收数据四种读取方式光会发不行还得会收。MicroPython提供了几种读取串口数据的方法。5.1 基本读取read()read()方法是最直接的可以指定读取的最大字节数不指定则读取尽可能多的数据。from machine import UART from machine import FPIOA fpioa FPIOA() fpioa.set_function(11, FPIOA.UART2_TXD) fpioa.set_function(12, FPIOA.UART2_RXD) uart UART(UART.UART2, baudrate115200) data None # 如果接收不到数据就一直尝试读取 while data None: # 尝试读取数据如果没有数据read()会返回None data uart.read() # 通过CanMV IDE的串行终端打印出来 print(Received:, data) # 再把接收到的数据通过UART2发回去 uart.write(UART2 Received:{}\n.format(data)) uart.deinit()测试方法用串口助手向开发板发送任意字符串比如3465345612yzh。你会在CanMV IDE的终端看到Received: b3465345612yzh同时串口助手也会收到回显UART2 Received:b3465345612yzh。5.2 读取一行readline()如果对方发送的数据是以换行符\n结尾的文本行用readline()会更方便它会一直读到换行符为止。from machine import UART from machine import FPIOA fpioa FPIOA() fpioa.set_function(11, FPIOA.UART2_TXD) fpioa.set_function(12, FPIOA.UART2_RXD) uart UART(UART.UART2, baudrate115200) line b while line b: # 尝试读取一行 line uart.readline() # 注意当前固件此方法可能有问题建议用read()配合判断 print(Received Line:, line) uart.deinit()注意根据原始资料提示readline()方法在当前固件中可能无法正常工作。如果遇到问题可以先用read()读取所有数据然后自己在代码里根据\n来分割行。5.3 高效读取到缓冲区readinto()当需要高效处理大量数据时可以预分配一个固定大小的缓冲区bytearray然后用readinto()方法将数据直接读入这个缓冲区避免频繁创建新的字节对象。from machine import UART from machine import FPIOA fpioa FPIOA() fpioa.set_function(11, FPIOA.UART2_TXD) fpioa.set_function(12, FPIOA.UART2_RXD) uart UART(UART.UART2, baudrate115200) # 创建一个10字节的缓冲区 buffer bytearray(10) bytes_received 0 while bytes_received 0: # 将数据读取到buffer中返回实际读取的字节数 bytes_received uart.readinto(buffer) # 只打印实际接收到的部分 print(Received Data:, buffer[:bytes_received]) uart.deinit()5.4 持续监听接收常用模式实际项目中我们往往需要程序持续运行随时准备接收数据。这可以通过一个主循环来实现。import time from machine import UART from machine import FPIOA fpioa FPIOA() fpioa.set_function(11, FPIOA.UART2_TXD) fpioa.set_function(12, FPIOA.UART2_RXD) uart UART(UART.UART2, baudrate115200) while True: data uart.read() # 非阻塞读取有数据就返回没有就返回None或空字节 if data: # 只有当确实收到数据时才处理 print(Received:, data) # 可以在这里添加数据处理逻辑比如控制LED、解析指令等 time.sleep(0.1) # 短暂延时避免CPU占用率100% # 通常这种监听程序不会执行到deinit这个程序会一直运行只要串口助手发来数据它就会在终端打印出来。time.sleep(0.1)这个小延时很重要可以避免循环空转消耗过多CPU资源。6. 终极验证硬件环路测试代码写完了怎么知道硬件连接和软件配置到底对不对最好的办法就是做一次环路测试。原理很简单把开发板串口的发送端TXD和接收端RXD用一根杜邦线短接起来让它“自己发自己收”。如果收发的数据一致就证明整个通路包括引脚配置、UART初始化都是好的。6.1 硬件连接对于我们在用的UART2GH1.25接口1找到这个接口的T(TXD, GPIO11) 和R(RXD, GPIO12) 引脚。用一根杜邦线将T和R这两个引脚直接连接起来。警告做环路测试时务必确保没有其他设备连接到这个串口否则信号会冲突可能损坏设备。6.2 环路测试代码import time from machine import UART from machine import FPIOA # 1. 配置引脚 fpioa FPIOA() fpioa.set_function(11, FPIOA.UART2_TXD) fpioa.set_function(12, FPIOA.UART2_RXD) # 2. 初始化UART2 uart UART(UART.UART2, baudrate115200) # 3. 定义要发送的测试数据 test_message bUART Loopback Test! # 4. 发送数据 uart.write(test_message) # 5. 等待数据发送并回环回来根据波特率和数据长度估算加个小延时 time.sleep(0.1) # 6. 尝试读取回环的数据 received_data uart.read() # 7. 判断测试结果 if received_data: if received_data test_message: print(*** Loopback Test PASSED! ***) print(Sent: , test_message) print(Received: , received_data) else: print(*** Loopback Test FAILED! ***) print(Data mismatch!) print(Sent: , test_message) print(Received: , received_data) else: print(*** Loopback Test FAILED! ***) print(No data received.) # 8. 释放资源 uart.deinit()6.3 结果分析运行上面的代码如果测试通过你会在CanMV IDE的终端看到*** Loopback Test PASSED! ***并且发送和接收的数据完全一致。恭喜你硬件连接和软件配置全部正确如果测试失败提示No data received很可能是硬件连接有问题检查杜邦线是否插稳是否连接的是正确的T和R引脚。提示Data mismatch收到的数据和发送的不一样。这可能是波特率等参数配置错误或者引脚复用配置错了比如把UART2的引脚配成了UART1的功能。请回头仔细检查代码。这个环路测试是我调试串口时必做的第一步它能最直接地帮你排除硬件连接和基础配置的错误。希望这篇教程能帮你顺利打通庐山派K230的串口通信。如果遇到问题多看几遍引脚定义表检查一下线有没有接反参数有没有设对大部分问题都能解决。