最近在做一个便携式储能的 BMS 项目,使用的主控芯片是晶丰明源的 LKS32MC45x 系列 MCU。应串口通信和低功耗唤醒的需求,在 LKS32MC45x 的 UART 上做了一些测试,以下是关于 UART 模块的驱动说明。
先说明 LKS32MC45x 的 UART 模块主要特征如下:
- 支持全双工、半双工;
- 支持 8/9 bit 数据位
- 支持 1/2 bit 停止位
- 支持奇/偶/无校验模式
- 带 1 Byte 发送/接收缓存
- 支持 LIN 模式 break character 收发
- 支持一主多从的 Multi-drop Slave/Master 模式
一、UART 功能配置
UART 的配置主要有:GPIO 的初始化配置、UART 模块的初始化配置、中断的初始化配置、DMA 的初始化配置。
1、GPIO 的初始化配置
以 UART1 的 P2_5(RXD)和 P2_6(TXD)为例,LKS32MC45x 系列 MCU 要求将 TXD 的 IO 配置为输出(OUTPUT),将 RXD 的 IO 配置为输入(INPUT)。
|
GPIO_StructInit(&uart1_gpio_config); uart1_gpio_config.GPIO_Pin = GPIO_Pin_6; // 要配置的PIN uart1_gpio_config.GPIO_Mode = GPIO_Mode_OUT; // GPIO模式:输入、输出、模拟 uart1_gpio_config.GPIO_PuPd = GPIO_PuPd_NOPULL; // 上拉/下拉 uart1_gpio_config.GPIO_PODEna = DISABLE; // 开漏使能 uart1_gpio_config.GPIO_PFLT = DISABLE; // 滤波使能 GPIO_Init(GPIO2, &uart1_gpio_config);
GPIO_StructInit(&uart1_gpio_config); uart1_gpio_config.GPIO_Pin = GPIO_Pin_5; // 要配置的PIN uart1_gpio_config.GPIO_Mode = GPIO_Mode_IN; // GPIO模式:输入、输出、模拟 uart1_gpio_config.GPIO_PuPd = GPIO_PuPd_NOPULL; // 上拉/下拉 uart1_gpio_config.GPIO_PODEna = DISABLE; // 开漏使能 uart1_gpio_config.GPIO_PFLT = DISABLE; // 滤波使能 GPIO_Init(GPIO2, &uart1_gpio_config); |
接着要把 P2_5(RXD)和 P2_6(TXD)两个管脚配置成复用 UART 模式。
|
GPIO_PinAFConfig(GPIO2, GPIO_PinSource_5, GPIO_AF_UART); GPIO_PinAFConfig(GPIO2, GPIO_PinSource_6, GPIO_AF_UART); |
2、UART 模块的初始化配置
UART 模块的初始化配置如下,这些参数中首先要注意将波特率(BAUDRATE)配置成正确的值。其它参数配置可根据自己的需求来修改。
|
uart1_config.DUPLEX = DISABLE; // 半双工模式使能,tx_data uart1_config.MD_EN = DISABLE; // Multi-drop 使能 uart1_config.CK_EN = DISABLE; // 数据校验使能 uart1_config.CK_TYPE = 0; // 奇偶校验配置 0: 偶校验(EVEN); 1: 奇校验(ODD) uart1_config.BIT_ORDER = 0; // 数据发送顺序配置 0: LSB; 1: MSB uart1_config.STOP_LEN = 0; // 停止位长度配置 0: 1-Bit; 1: 2-Bit uart1_config.BYTE_LEN = 0; // 数据长度配置 0: 8-Bit; 1: 9-Bit uart1_config.BAUDRATE = 9600; // 波特率 uart1_config.ADR = 0; // 多机通讯时的从机地址 uart1_config.TX_BUF_EMPTY = DISABLE; // 发送缓冲区空 DMA 请求使能 uart1_config.RX_DONE = DISABLE; // 接收完成 DMA 请求使能 uart1_config.TX_DONE = DISABLE; // 发送完成 DMA 请求使能 uart1_config.TXD_INV = DISABLE; // TXD 输出极性取反 uart1_config.RXD_INV = DISABLE; // RXD 输入极性取反 uart1_config.IE = DISABLE; // 中断配置
UART_Init(UART1, &uart1_config); |
3、中断的初始化配置
如果需要用到中断功能,首先要在前面描述的 UART 初始化中,使能 IE 的相应位,比如:发送完成中断(UART_IRQEna_SendOver)、接收完成中断(UART_IRQEna_RcvOver)、发送缓冲区空中断(UART_IRQEna_SendBuffEmpty),等等。
|
uart1_config.IE = UART_IRQEna_SendOver | UART_IRQEna_RcvOver; // 使能发送&接收完成中断 |
另外,还需要开启 UART 中断,并设置其中断优先级,比如:
|
NVIC_SetPriority(UART1_IRQn, 1); // 设置 UART1 中断优先级 NVIC_EnableIRQ(UART1_IRQn); // 使能 UART1 中断 |
4、DMA 的初始化配置
如果需要用到 DMA 功能,首先要在前面描述的 UART 初始化中,使能相应的 DMA 功能,比如:TX_BUF_EMPTY、RX_DONE、TX_DONE。
|
uart1_config.TX_DONE = ENABLE; // 发送完成 DMA 请求使能 |
二、UART 数据发送和接收
1、数据发送
在发送数据之前,需要等待上一个数据已发送完成,即发送缓冲区空才能发送下一个数据。
在没有开启“发送完成”中断时,需要调用函数 UART_DelaySendOver(UART1) 等待发送缓冲区空。
|
UART_DelaySendOver(UART1); // 发送数据前需要等待之前的数据发送完成 UART_SendData(UART1, num); // 发送数据 |
如果开启“发送完成”中断,可以在中断处理函数 UART1_IRQHandler 中处理。
|
void UART1_IRQHandler(void) { if (UART_GetIRQFlag(UART1, UART_IF_SendOver)) { UART_SendData(UART1, num); // 发送数据 UART_ClearIRQFlag(UART1, UART_IF_SendOver); } } |
如果使用 DMA 发送,则只需要指定发送数据的长度和数据的源地址,然后使能 DMA。
|
void uart1_dma_senddata(u8 *t, u16 len) { DMA_InitTypeDef uart1_dma_config; uart1_dma_config.DMA_Channel_EN = ENABLE; /* DMA 通道使能*/ uart1_dma_config.DMA_IRQ_EN = DISABLE; /* DMA 中断使能 */ uart1_dma_config.DMA_RMODE = ENABLE; /* 多轮传输使能 */ uart1_dma_config.DMA_CIRC = DISABLE; /* 循环模式使能 */ uart1_dma_config.DMA_SINC = ENABLE; /* 源地址递增使能 */ uart1_dma_config.DMA_DINC = DISABLE; /* 目的地址递增使能 */ uart1_dma_config.DMA_SBTW = 0; /* 源地址访问位宽, 0:byte, 1:half-word, 2:word */ uart1_dma_config.DMA_DBTW = 0; /* 目的地址访问位宽, 0:byte, 1:half-word, 2:word */ uart1_dma_config.DMA_REQ_EN = DMA_REQ_UART1_TX; /* 通道 x 硬件 DMA 请求使能,高有效 */ uart1_dma_config.DMA_TIMES = len; /* DMA 通道 x 数据搬运次数 */ uart1_dma_config.DMA_SADR = (u32)t; /* DMA 通道 x 源地址 */ uart1_dma_config.DMA_DADR = 0; /* DMA 通道 x 目的地址 */
DMA_Init(DMA_CH0, &uart1_dma_config); DMA_CH0->REN |= DMA_REQ_SW; } |
2、数据接收
在接收数据之前,需要等待接收完成,才能读取数据。如果开启“接收完成”中断,可以在中断处理函数 UART1_IRQHandler 中处理。
|
void UART1_IRQHandler(void) { if (UART_GetIRQFlag(UART1, UART_IF_RcvOver)) { uart_buffer[uart_buffer_p] = UART_ReadData(UART1); uart_buffer_p++; UART_ClearIRQFlag(UART1, UART_IF_RcvOver); } } |
如果使用 DMA 接收,则只需要指定接收数据的长度和目标地址,然后使能 DMA。
这里要注意的是:每一个 DMA 通道一般在同一时间通常只使能一个硬件 DMA 请求,所以如果发送和接收同时使用 DMA 的时候,就需要设置 2 个 DMA 通道。
|
DMA_InitTypeDef uart1_dma_config; uart1_dma_config.DMA_Channel_EN = ENABLE; /* DMA 通道使能*/ uart1_dma_config.DMA_IRQ_EN = DISABLE; /* DMA 中断使能 */ uart1_dma_config.DMA_RMODE = ENABLE; /* 多轮传输使能 */ uart1_dma_config.DMA_CIRC = DISABLE; /* 循环模式使能 */ uart1_dma_config.DMA_SINC = ENABLE; /* 源地址递增使能 */ uart1_dma_config.DMA_DINC = DISABLE; /* 目的地址递增使能 */ uart1_dma_config.DMA_SBTW = 0; /* 源地址访问位宽, 0:byte, 1:half-word, 2:word */ uart1_dma_config.DMA_DBTW = 0; /* 目的地址访问位宽, 0:byte, 1:half-word, 2:word */ uart1_dma_config.DMA_REQ_EN = DMA_REQ_UART1_RX; /* 通道 x 硬件 DMA 请求使能,高有效 */ uart1_dma_config.DMA_TIMES = len; /* DMA 通道 x 数据搬运次数 */ uart1_dma_config.DMA_SADR = 0; /* DMA 通道 x 源地址 */ uart1_dma_config.DMA_DADR = (u32)&UART1_BUFF; /* DMA 通道 x 目的地址 */
DMA_Init(DMA_CH1, &uart1_dma_config); |
三、总结
以上是关于晶丰明源的 LKS32MC45x 的 UART 模块软件驱动的说明。如果想了解更多,可以在下方评论区留言,或者发邮件给我们:atu.sh@wpi-group.com。
四、参考资料
LKS32M45x 外设示例工程:lks32mc45x_demo_prj_v2.9。
如有更多需求,欢迎联系大联大世平集团 ATU 部门:atu.sh@wpi-group.com 作者:五月小姐姐
更多资讯,请扫码关注我们!

