7.【NXP 号令者RT1052】开发——实战-串口通信
7.【NXP 号令者RT1052】开发——实战-串口通信
本章将实现如下功能:RT1052 通过串口和上位机的对话,RT1052 在收到上位机发过来的字符串后,原原本本的返回给上位机。
做一个简单的回显。
7.1 RT1052 串口简介
关于串口的基础知识这里不做介绍了。下面仅仅分析一下fsl库关于串口的API函数。
初始化函数详解:LPUART_Init
c
status_t LPUART_Init(LPUART_Type *base, const lpuart_config_t *config, uint32_t srcClock_Hz);
- base:选择具体串口控制器(LPUART1~LPUART8)。每个串口都有独立的寄存器组与时钟根路径;在 RT1052 上通常以 UART_CLK_ROOT(80 MHz)为源。
- config:串口配置参数结构体指针,类型为 lpuart_config_t(见下文详解)。此结构体决定了波特率、校验、数据位、停止位、收发开关等。
- srcClock_Hz:串口根时钟频率(单位 Hz)。你的项目中使用 PLL3_SW_CLK/6 = 80 MHz,因此传入 80000000。
你的使用示例(保持原样):
c
lpuart_config_t lpuart1_config;
lpuart1_config.baudRate_Bps=bound; // 波特率
lpuart1_config.dataBitsCount=kLPUART_EightDataBits; // 8 位数据位
lpuart1_config.stopBitCount=kLPUART_OneStopBit; // 1 位停止位
lpuart1_config.parityMode=kLPUART_ParityDisabled;// 无奇偶校验
lpuart1_config.enableRx=true; // 使能接收
lpuart1_config.enableTx=true; // 使能发送
LPUART_Init(LPUART1,&lpuart1_config,80000000); // 初始化 LPUART1
关键点与注意事项:
- 不需要单独调用时钟使能:FSL 驱动在 LPUART_Init 内部会调用 CLOCK_EnableClock 打开 LPUART 模块时钟。
- 配置一致性:波特率的正确性取决于 srcClock_Hz 与 UART CLK 根的真实值一致;若你更改了时钟树或分频,需要同步更新 srcClock_Hz。
- 复用与根时钟:确保已通过 CLOCK_SetMux/Div 将 UART MUX 指向 PLL3/6 且分频为 1(你之前的代码已设置),否则实际波特率会偏差。
配置结构体逐项解释:lpuart_config_t
c
typedef struct _lpuart_config
{uint32_t baudRate_Bps; // 波特率lpuart_parity_mode_t parityMode; // 奇偶校验lpuart_data_bits_t dataBitsCount; // 数据位bool isMsb; // 是否高位先传输#if defined(FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORTlpuart_stop_bit_count_t stopBitCount; // 停止位配置
#endif#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFOuint8_t txFifoWatermark; // 发送 FIFO 水位线uint8_t rxFifoWatermark; // 接收 FIFO 水位线
#endif#if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORTbool enableRxRTS; // 使能接收 RTSbool enableTxCTS; // 使能发送 CTSlpuart_transmit_cts_source_t txCtsSource; lpuart_transmit_cts_config_t txCtsConfig;
#endiflpuart_idle_type_select_t rxIdleType; // 接收空闲类型lpuart_idle_config_t rxIdleConfig; // 接收空闲字符数量bool enableTx; // 使能发送bool enableRx; // 使能接收
} lpuart_config_t;
- baudRate_Bps:串口波特率;常用 115200、57600、9600 等。取决于 srcClock_Hz 与内部分频器;FSL 驱动会计算并写入合适的分频值。
- parityMode(lpuart_parity_mode_t):
- kLPUART_ParityDisabled:无校验
- kLPUART_ParityEven:偶校验
- kLPUART_ParityOdd:奇校验
- dataBitsCount(lpuart_data_bits_t):
- kLPUART_EightDataBits:8 数据位
- kLPUART_SevenDataBits:7 数据位(部分 SoC 支持)
- isMsb:是否使用高位在前(MSB-first),通常保持 false(LSB-first)。
- stopBitCount(lpuart_stop_bit_count_t):
- kLPUART_OneStopBit:1 位停止位(常用)
- kLPUART_TwoStopBit:2 位停止位(提高容错)
- FIFO 相关项(若支持):影响中断/ DMA 触发水位;默认 0 意味着尽快触发。
- Modem(RTS/CTS)相关项(若支持):用于硬件流控;如不接线,保持关闭。
- rxIdleType/rxIdleConfig:接收空闲检测配置,典型用于多机通信或帧边界判定;默认即可。
- enableTx/enableRx:打开收发通道;通常两者都为 true。
建议实践:
- 面向通用串口通信:8N1(8 数据位,无校验,1 停止位),对应你的配置。
- 若与外设/模块匹配失败:优先检查校验位与停止位是否一致,确保 srcClock_Hz 正确。
默认配置函数:LPUART_GetDefaultConfig
函数原型与作用:
c
void LPUART_GetDefaultConfig(lpuart_config_t *config);
- 将 config 初始化为默认值:115200 波特率、8N1、关闭收发、关闭 RTS/CTS、默认空闲配置。
- 常用流程:先调用默认配置,再在此基础上填入实际需求(如开启 Tx/Rx、修改波特率)。
你的原文说明保持不变;这里补充一个典型用法(不修改你的配置写法,仅补充思路):
- 先默认:LPUART_GetDefaultConfig(&cfg);
- 再改动:cfg.enableTx = true; cfg.enableRx = true; cfg.baudRate_Bps = bound; 等。
串口中断:使能与关闭
函数与参数保持你的原文:
c
LPUART_EnableInterrupts(LPUART1, kLPUART_RxDataRegFullInterruptEnable);
LPUART_DisableInterrupts(LPUART1, kLPUART_RxDataRegFullInterruptEnable);
补充说明:
- kLPUART_RxDataRegFullInterruptEnable:当接收数据寄存器(RDR)非空时触发中断,用于接收。
- 若使用中断收发:需要在 NVIC 中设置优先级并 EnableIRQ(LPUARTx_IRQn),且在 ISR 内读取 DATA 寄存器清除状态。
- 与 FIFO/水位线配合:可降低中断频率,建议在大量数据场景中根据硬件支持进行优化。
数据收发:单字节与多字节阻塞
单字节 API:
c
void LPUART_WriteByte(LPUART_Type *base, uint8_t data);
uint8_t LPUART_ReadByte(LPUART_Type *base);
- 写一个字节到 DATA 寄存器,或从 DATA 读出一个字节。适合简单测试或中断处理中的字节流。
阻塞式多字节 API:
c
void LPUART_WriteBlocking(LPUART_Type *base, const uint8_t *data, size_t length);
status_t LPUART_ReadBlocking (LPUART_Type *base, uint8_t *data, size_t length);
- WriteBlocking:逐字节发送并等待发送完成,直到 length 发送完毕。
- ReadBlocking:逐字节等待接收,直到填满 length;若无数据,会阻塞。可在任务型框架或初始化阶段使用,不适合高实时性主循环。
注意事项:
- 阻塞读在空闲时会卡住线程;若不希望阻塞,改用中断或设置超时策略(自行封装)。
- 阻塞写会占用 CPU;大量数据发送建议使用中断或 DMA(若驱动支持)。
状态查询:LPUART_GetStatusFlags
c
uint32_t LPUART_GetStatusFlags(LPUART_Type *base);
- 返回 STAT 寄存器的当前状态位集合。
- 常见状态位用途(示例):发送完成、发送缓冲空、接收缓冲满、帧错误、噪声错误、溢出等。实际位定义请查看 fsl_lpuart.h 的枚举。
- 调试策略:在异常时读 STAT,结合错误位(如 Overrun、Framing)定位问题。
7.2 硬件设计
本实验需要用到的硬件资源有:
1) 指示灯 DS0
2) 串口 1
串口 1 之前还没有介绍过,本实验用到的串口 1 与 USB 串口并没有在 PCB 上连接在一起,需要通过跳线帽来连接一下。这里我们把 P4 的 RXD 和 TXD 用跳线帽与 P112(GPIO1_IO12)和 P113(GPIO1_IO13)连接起来。




7.3 软件设计
本章的代码设计,比前两章简单很多,因为我们的串口初始化代码和接收代码就是用我们之前介绍的 SYSTEM 文件夹下的串口部分的内容。
打开上一章的工程,因为本章我们用不到按键的功能,所以先注释掉。
然后在 SYSTEM 组下双击 lpuart.c,我们就可以看到该文件里面的代码,先介绍LPUART1_Init 函数,该函数代码如下:
//初始化IO 串口1
//bound:波特率
void LPUART1_Init(u32 bound)
{ u32 freq=0; //串口的时钟源频率CLOCK_EnableClock(kCLOCK_Lpuart1); //使能LPUART1时钟CLOCK_SetMux(kCLOCK_UartMux,0); //设置UART时钟源为PLL3 80Mhz,PLL3/6=480/6=80MHzCLOCK_SetDiv(kCLOCK_UartDiv,0); //设置UART时钟1分频,即UART时钟为80Mhz//LPUART1所使用的IO功能配置,即:从ALT0~ALT7选择合适的功能。IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_12_LPUART1_TX,0U); //GPIO_AD_B0_12设置为LPUART1_TXIOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_13_LPUART1_RX,0U); //GPIO_AD_B0_13设置为LPUART1_RX//配置IO引脚GPIO_AD_B0_12和GPIO_AD_B0_13的功能//低转换速度,驱动能力为R0/6,速度为100Mhz,关闭开路功能,使能pull/keepr//选择keeper功能,下拉100K Ohm,关闭HystIOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_12_LPUART1_TX,0x10B0u); IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_13_LPUART1_RX,0x10B0u); freq=LPUART_SrcFreqGet(); LPUART_GetDefaultConfig(&lpuart1_config); //先设置为默认配置,后面在根据实际情况配置//初始化NXP官方提供的debug console,此函数会重新初始化LPUART1,但是我们后面会//重新显示的初始化一次LPUART1,DbgConsole_Init()主要是给那些想要使用NXP官方//调试功能的开发者使用的,不需要使用的话就可以将下面代码注释掉DbgConsole_Init(BOARD_DEBUG_UART_BASEADDR,bound,BOARD_DEBUG_UART_TYPE,freq);lpuart1_config.baudRate_Bps=bound; //波特率lpuart1_config.dataBitsCount=kLPUART_EightDataBits; //8位lpuart1_config.stopBitCount=kLPUART_OneStopBit; //1位停止位lpuart1_config.parityMode=kLPUART_ParityDisabled; //无奇偶校验lpuart1_config.enableRx=true; //使能接收lpuart1_config.enableTx=true; //使能发送LPUART_Init(LPUART1,&lpuart1_config,freq); //初始化LPUART1 #if EN_LPUART1_RX //是否需要开启中断? //LPUART中断设置LPUART_EnableInterrupts(LPUART1,kLPUART_RxDataRegFullInterruptEnable); //使能接收中断RT1052_NVIC_SetPriority(LPUART1_IRQn,5,0); //抢占优先级5,子优先级0EnableIRQ(LPUART1_IRQn); //使能LPUART1中断
#endif
}
在代码中,原本调用的 CLOCK_EnableClock 用于开启 LPUART1 时钟,但实际上可以省略,因为 LPUART_Init 内部已经会自动完成时钟使能。接着,将串口时钟源配置为 80 MHz,并通过 IOMUXC 将 GPIO_AD_B0_12 和 GPIO_AD_B0_13 分别复用为 LPUART1 的 TX 和 RX 引脚。完成 IO 配置后,调用 LPUART_Init 初始化串口 1。
由于需要使用串口中断接收功能,需要在 lpuart.h 中确保宏 EN_LPUART1_RX 置为 1(默认即为 1)。这样初始化函数会自动配置接收中断并开启 LPUART1 的 NVIC 中断。最后,将串口 1 的中断优先级设置为抢占优先级 5、子优先级 0,并在 LPUART1_IRQHandler 中编写具体的中断服务逻辑。
然后写main.c的代码
#include "sys.h"
#include "lpuart.h"
#include "delay.h"
#include "led.h"
#include "key.h"int main(void)
{u8 key=0;u8 led0sta=1,led1sta=1; //LED0,LED1的当前状态u8 len; //接收数据长度u16 times=0; //延时计数器MPU_Memory_Protection(); //初始化MPURT1052_Clock_Init(); //配置系统时钟DELAY_Init(600); //延时函数初始化LPUART1_Init(115200); //初始化串口1RT1052_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);//优先级分组4LED_Init(); //初始化LEDKEY_Init(); //初始化KEYLED0(0); //先点亮红灯 while(1){
#ifdef KEY_DEBUGkey=KEY_Scan(0); //得到键值if(key){ switch(key){ case WKUP_PRES: //控制LED0,LED1互斥点亮led1sta=!led1sta;led0sta=!led1sta;break;case KEY2_PRES: //控制LED0翻转led0sta=!led0sta;break;case KEY1_PRES: //控制LED1翻转 led1sta=!led1sta;break;case KEY0_PRES: //同时控制LED0,LED1翻转 led0sta=!led0sta;led1sta=!led1sta;break;}LED0(led0sta); //控制LED0状态LED1(led1sta); //控制LED1状态}else delay_ms(10);
#endif // KEY_DEBUGif(LPUART_RX_STA&0x8000){ len=LPUART_RX_STA&0x3fff;//得到此次接收到的数据长度printf("\r\n发送的消息为:\r\n");LPUART_WriteBlocking(LPUART1,LPUART_RX_BUF,len);//发送接收到的数据printf("\r\n\r\n");//插入换行LPUART_RX_STA=0;}else{times++;if(times%5000==0){printf("\r\nALIENTEK RT1052开发板 串口实验\r\n");}if(times%200==0)printf("请输入数据,以回车键结束\r\n"); if(times%30==0)LED0_Toggle;//闪烁LED,提示系统正在运行.delay_ms(10); }}
}
一定注意使用GB2312格式编码!!!!
然后编译,下载。
打开串口调试工具。

数据回显,同时红色小灯闪烁。
总结
这一节比较简单,主要难点是串口接收中断这部分。串口发送相反简单一点,因为我们在新建工程的时候已经有所了解。
