【通用异步收发器(UART)】
CW32L083 内部集成 6 个通用异步收发器 (UART),支持异步全双工、同步半双工和单线半双工模式,支持硬件数据流控和多机通信;可编程数据帧结构,可以通过小数波特率发生器提供宽范围的波特率选择。
UART 控制器工作在双时钟域下,允许在深度休眠模式下进行数据的接收,接收完成中断可以唤醒 MCU 回到运行模式。
【主要特性】
● 支持双时钟域驱动:
‒ 配置时钟 PCLK
‒ 传输时钟 UCLK
● 可编程数据帧结构:
‒ 数据字长:8、9 位,LSB 在前
‒ 校验位:无校验、奇校验、偶校验
‒ 停止位长度:1、1.5、2 位
● 16 位整数、4 位小数波特率发生器
● 支持异步全双工、同步半双工、单线半双工
● 支持硬件流控 RTS、CTS
● 支持直接内存访问 (DMA)
● 支持多机通信,自动地址识别
● 6 个带中断标志的中断源
● 错误检测:奇偶校验错误、帧结构错误
● 低功耗模式下收发数据,中断唤醒 MCU
【功能框图】
UART 控制器挂载到 APB 总线上,配置时钟域 PCLK,固定为 APB 总线时钟 PCLK,用于寄存器配置逻辑工作;传输时钟域 UCLK,用于数据收发逻辑工作,其来源可选择 PCLK 时钟、外部低速时钟(LSE)以及内部低速时钟(LSI)。双时钟域的设计更便于波特率的设置,支持从深度休眠模式下唤醒控制器。
UART 控制器的功能框图如下图所示:

【GPIO配置】
本次串口配置使用UART1。CW32L083使用端口,必须开启复用功能。在数据手册上可以查看复用表如下:

可以通过命令开启:
PA08_AFx_UART1TXD();
PA09_AFx_UART1RXD();
【时钟管理】
本次使用默认的时钟频率为8MHz
【代码编写】
1、新建usart.c/h文件,并把他加入工程HW分组之中。
2、编写串口Init函数如下:
#define  UART1_UclkFreq           8000000
void UART1_Init(uint32_t BaudRate)
{
	  GPIO_InitTypeDef GPIO_InitStructure = {0};
    UART_InitTypeDef UART_InitStruct = {0};
		//配置RCC
		
		//开启GPIOA时钟
		//开启UART1时钟
		__RCC_GPIOA_CLK_ENABLE();
    __RCC_UART1_CLK_ENABLE();
	
		// 先设置UART TX RX 复用,后设置GPIO的属性,避免口线上出现毛刺
    PA08_AFx_UART1TXD();
    PA09_AFx_UART1RXD();
		
		//GPIO配置
		GPIO_InitStructure.Pins = GPIO_PIN_8;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
		
    GPIO_InitStructure.Pins = GPIO_PIN_9;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
		
    //配置UART
		UART_InitStruct.UART_BaudRate = BaudRate;
    UART_InitStruct.UART_Over = UART_Over_16;
    UART_InitStruct.UART_Source = UART_Source_PCLK;
		UART_InitStruct.UART_UclkFreq = UART1_UclkFreq;
    UART_InitStruct.UART_StartBit = UART_StartBit_FE;
    UART_InitStruct.UART_StopBits = UART_StopBits_1;
    UART_InitStruct.UART_Parity = UART_Parity_No ;
    UART_InitStruct.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;
    UART_InitStruct.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
		UART_Init(CW_UART1, &UART_InitStruct);
		
		
}3、为了使用printf打印,根据我的帖子【STM32H5系列】串口printf之三-电子产品世界论坛 (eepw.com.cn)
稍作修改,可以快速移植好,代码如下:
uint8_t CW_U1_printf(char *format,...){  
		uint16_t timeout = 0xffff;
		int i;
    uint8_t send_str[128] = {0};  
    va_list listdata;  
    va_start(listdata,format);  
    vsprintf((char *)send_str,format,listdata);  
    va_end(listdata);  
		
		for(i = 0; i<strlen((const char*)send_str); i++)
		{
			CW_UART1->TDR = send_str[i];
			while (((REGBITS_GET(CW_UART1->ISR, UART_FLAG_TXE)) == RESET) && timeout--)  //等待发送缓冲区为空
			{
				
			}
			if (timeout == 0)
			{
					return 1;
			}
		}
		timeout = 0xffff;
    while (((REGBITS_GET(CW_UART1->ISR, UART_FLAG_TXBUSY)) == SET) && timeout--);  //等待发送为空
    if (timeout == 0)
    {
        return 1;
    }
		return 0;
    
}【测试】
在main.c中添加代码,首先初始化串口1的波特率为115200,打印系统时钟频率,代码如下:
#include "main.h"
#include "usart.h"
LED_InitTypeDef led;
int32_t main(void)
{
	int i;
	led.LED_Port = CW_GPIOC;
	led.LED_Pin = GPIO_PIN_3;
	LED_Init(&led);
	UART1_Init(115200);
	CW_U1_printf("hello world\r\n");
	CW_U1_printf("%d,%c,%x\n",0x30,0x30,0x30);  
  CW_U1_printf("%s\n%s\n",__FILE__,__TIME__);  
	CW_U1_printf("HCLK(Hz):%d\r\n",RCC_Sysctrl_GetHClkFreq());
	CW_U1_printf("PCLK(Hz):%d\r\n",RCC_Sysctrl_GetPClkFreq());
	while(1)
	{
		led.LED_Toggle(&led);
		FirmwareDelay(100000);
	}
	
}【实验效果】

【总结】
串口为最常见的外设之一,官方的数据手册提供了详细的配置说明,在示例中也给出了非常多的例程。作为初始配置还是容易入门的。
但是,由于本次的频率为8MHz,如果需要提高主频频率,还需要对RCC进行详细的学习。在摸透系统时钟树后,再进行深入的DMA、中断等配置。
附工程源码:UART_DMA.zip

 
					
				
 
			
			
			
						
			 
					
				 
					
				 
					
				 
					
				 
					
				 
					
				 
					
				 我要赚赏金
 我要赚赏金 STM32
STM32 MCU
MCU 通讯及无线技术
通讯及无线技术 物联网技术
物联网技术 电子DIY
电子DIY 板卡试用
板卡试用 基础知识
基础知识 软件与操作系统
软件与操作系统 我爱生活
我爱生活 小e食堂
小e食堂

