【CS32L015C8T6】UART串口通信详解及驱动配置方法(内附完整代码及注释)
目录
六、如果这篇文章能帮助到你,请点个赞鼓励一下吧ξ( ✿>◡❛)~
前言:
长颈鹿最近在使用芯海的CS32L015C8T6单片机进行工程开发,发现网上有关这款单片机的资料非常少,而且官方提供的驱动代码有些不适用,因此决定记录一下造轮子的过程,前车之鉴,后车之师,希望能够帮助后来的开发者减少一些重复性造轮子的工作,少走一些弯路。
一、串/并行通信简介
我们今天要介绍的串口通信,在嵌入式系统中指的就是UART串口协议,属于串行通信中的一种具体的方法,需要知道 串行通信 和 串口通信 的区别:串行通信(Serial Port)是一个广泛的类,不仅包括UART串口协议,还包括SPI、IIC、CAN等我们所熟知的协议;区别于多数据线同时收发数据的并行通讯(同时传输多个比特位),在串行通信中,数据以位的形式,按顺序通过单一通信线路发送接收。
串行通信:
非常常见,我们在开发过程中经常遇到的IIC、SPI、UART、CAN、RS232、RS485、USB等,全部都是以串行通信为基础的通信协议,并且串行通信的抗干扰能力强,因为只用一根数据线进行发送/接收,不用担心IO口高速工作状态下的高频信号干扰问题和时钟同步问题,再结合上保障通信安全的校验位,通信速度已经可以做到非常快了,现在的USB3.0,SATA等串行通信技术,通信速率已经可以达到5Gbps以上,这个速度远超过常规并行通信能达到的200Mbps。
并行通信:
如今,并行通信在实际项目中已经不常见了,少部分LCD显示屏还会使用并口通信。主要是因为并行通信的对硬件资源要求高,要占用许多IO口,但是速度却受限。并行通信就相当于许多个高速工作的IO口排列在一起,当电信号快速翻转时,可以想象一下,插上一根铁丝那不就成天线发射接收器了吗,所以说相互之间非常容易受到干扰;还有一点,就是高速工作状态下的时钟信号协同比较困难,容易出错,这两点因素限制了并行通信的发展,强调一点,不是通信引线越多,通信速度就越快,至少2025年来看是这样的。
但是有个例外,CPU中的总线采用的仍是并行通信,例如STM32MCU中的32位数据总线和地址总线,采用并口通信进行数据通信,每次能处理32位数据,能以非常高速稳定运行,这是为什么呢?
因为CPU内部,数据通信不需要引线连接,而是通过光刻或者腐蚀制造的金属互连层来进行通信,通信距离非常短,只有微米级,IO口之间的干扰可以降到很低,并且芯片内部时钟非常精确,可以改善并行通信高速状态下时钟信号难以同步的问题,所以可以使用并行通信达到很高的传输速率(Gbps),这是一个特殊情况。
二、UART串口通信简介
UART串口通信是嵌入式开发中非常常见的一种 串行 异步 数据通信协议,一共有4个引脚,VCC(供电引脚)、GND(共地引脚)、Tx(数据发送引脚)、Rx(数据接收引脚),主机和从机在通信开始前,需要先约定好双方通信的频率(也叫波特率)、数据有效位个数、校验位、停止位等参数,在硬件连接上,主机的Tx端口需要连接到从机的Rx上,Rx端口需要连接到从机的Tx端口上,GND互相连接,作为基准低电平,连接方式如上图所示。
UART时序基于波特率而非外部时钟信号,使用起始位、数据位、奇偶校验位和停止位的格式来传输数据,按帧发送接收数据。最常用UART数据帧格式是:8/N/1,8指的是8位数据位,N指的是无校验位,1指的是1位停止位。如图所示,就是一帧UART数据的格式,一帧共10位,包括1位起始位,8位数据位,1位停止位,非常简单明了,当然,UART也有其他的格式,例如9位数据位、2位停止位等,但都大差不差,可自行脑部。
三、CS32L015C8T6串口硬件资源介绍
CS32L015C8T6单片机有4个通用串口外设(UART),1个支持低功耗模式的串口外设(LPUART),两者的区别如下图所示:

由图可知,低功耗串口LPUART相较于通用串口,缺少了IrDA模式,这里简单介绍一下IrDA协议:串口的IrDA模式是指将串口配置为使用IrDA协议(红外数据通信协议)进行数据通信的一种特殊工作模式,那什么是IrDA呢?IrDA是一种通过红外线进行数据传输的协议,由1993年红外数据协会制定。在IrDA模式下,串口的Tx和Rx不再传输电信号,而是驱动红外LED光发射红外光信号,同时使用Rx管脚接收外设发射的红外光信号。普通串口通过电信号来进行数据通信,需要硬件物理链接,IrDA模式通过红外光信号进行数据通信,不需要物理连接。
GPIO口配置为串口输入输出时,对应的复用功能可以通过查找芯片数据手册得到,如下图所示:

四、串口配置流程
不管什么类型的MCU,配置UART都有相关的一套流程,相差无几,但需要注意的是,CS32L015串口配置中有一个参数叫 “BaudDouble”,字面意思似乎是双倍波特率,但实际上该参数开启后,在相同的系统时钟下,可以支持更高的波特率,但串口本身配置的波特率不会变化。串口配置流程如下所示:
1、GPIO复用功能初始化
2、UART串口配置初始化
3、设置串口中断
4、配置中断回调函数
五、完整代码及注释
1、GPIO初始化
/******************************************************************************
[函数名称]MX_UART_MspInit
[函数功能]串口GPIO初始化函数
[参 数]
[返 回 值]
[备 注]
******************************************************************************/
void MX_UART_MspInit()
{
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA的RCC时钟
GPIO_InitTypeDef GPIOx = {0};
GPIOx.Mode = GPIO_MODE_AF; //GPIO复用模式
GPIOx.Debounce.Enable = GPIO_DEBOUNCE_DISABLE; //关闭去抖动
GPIOx.SlewRate = GPIO_SLEW_RATE_HIGH; //高速
GPIOx.DrvStrength = GPIO_DRV_STRENGTH_HIGH; //强驱动
GPIOx.Alternate = GPIO_AF_MODE_1; //配置串口复用功能
GPIOx.OpenDrain = GPIO_PUSHPULL; //GPIO推挽输出
GPIOx.Pin = UART_TX_Pin;
GPIOx.Pull = GPIO_PULLUP; //上拉
HAL_GPIO_Init(UART_TX_GPIO_Port, &GPIOx);
GPIOx.Pin = UART_RX_Pin;
GPIOx.Pull = GPIO_NOPULL;
HAL_GPIO_Init(UART_RX_GPIO_Port, &GPIOx);
}
2、串口UART初始化
UART_HandleTypeDef huart1 = {0};
/******************************************************************************
[函数名称]MX_UART_Init
[函数功能]串口初始化函数
[参 数]
[返 回 值]
[备 注]
******************************************************************************/
void MX_UART_Init()
{
MX_UART_MspInit();
__HAL_RCC_UART0_CLK_ENABLE(); //使能UART0串口时钟
huart1.Instance = UART0;
huart1.Init.BaudRate = 115200; //设置波特率
huart1.Init.BaudDouble = UART_BAUDDOUBLE_ENABLE; //支持更高波特率
huart1.Init.WordLength = UART_WORDLENGTH_8B; //8位数据长度
huart1.Init.Parity = UART_PARITY_NONE; //无奇偶校验
huart1.Init.Mode = UART_MODE_TX_RX; //全双工
HAL_UART_Init( &huart1 );
//HAL_NVIC_SetPriority( UART0_IRQn, 2 );
NVIC_EnableIRQ( UART0_IRQn ); //开启串口中断使能
HAL_UART_Receive_IT(&huart1, &receData, 1); //开启接收中断
}
3、中断回调函数配置
/*****************************************************************************
[函数名称]HAL_UART_RxCpltCallback
[函数功能]接收中断回调函数
[参 数]
[备 注]1、在中断函数中处理,接收完成1个字节后,进入接收中断回调函数
2、将接收到的数据放入接收队列中
3、重新使能串口接收中断
*****************************************************************************/
extern “C”{
extern UART_HandleTypeDef huart1;
void UART0_IRQHandler(void) //串口中断回调
{
HAL_UART_IRQHandler( &huart1 );
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == UART1)
{
m_bRcvTime = TRUE; //接收忙标志置1
m_psQueueRcv->bAddItem(rec_buf); //将接收到的1字节数据添加到队列中
HAL_UART_Receive_IT(huart, &rec_buf, 1);//重新使能串口接收中断
}
}
}
4、UART发送接收函数
芯海提供的HAL库已经封装好了UART的发送接收函数,本例程中使用常规方法——UART中断接收,发送直接调用HAL_UART_Transmit();函数进行阻塞发送。
HAL_UART_Transmit(&huart1, &u8Item, 1, 0xFFFF); // 发送1字节数据
HAL_UART_Receive_IT(&huart1, &rec_buf, 1); // 启动接收中断
六、如果这篇文章能帮助到你,请点个赞鼓励一下吧ξ( ✿>◡❛)~
更多推荐



所有评论(0)