完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter)是一个全双工的串行通信设备;UART(Universal Asynchronous Receiver and Transmitter)是在USART基础上裁掉了同步通信功能,只有异步通信。 USART满足外部设备对工业标准NRZ异步串行数据格式的要求,并且使用了小数波特率发生器,可以提供多种波特率。USART支持同步单向通信和半双工单线通信;还支持局域互连网络、智能卡协议与LrDA SIR ENDEC规范;还支持DMA,可实现高速数据通信。 如下图是USART功能框图,我们将对此框图进行分析。 1.功能引脚 TX:发送数据输出引脚 RX:接收数据输入引脚 SW_RX:数据接收引脚,内部引脚,只用于单线和智能卡模式 nRTS:发送请求输出端,n表示低电平有效。如果是能RTS流控制,当USART接收器准备好接收新的数据时会将nRTS编程低电平;当接收寄存器已满时,nRTS将会被设置为高电平,该引脚至适用于硬件流控制。 nCTS:请求发送输入端,n表示低电平有效。如果使能CTS流控制,发送器在发送下一帧数据之前会检测nCTS引脚,如果为低电平则发送数据,如果为高电平则在发送完当前数据之后停止发送,该引脚只适用于硬件流控制。 SCLK:发送器时钟输出引脚,仅适用于同步模式。 注意:UART只有异步传输功能,故没有SCLK、nRTS和nCTS引脚。 2.数据寄存器 USART数据寄存器(USART_DR)包含TDR和RDR,两者是介于系统总线和移位寄存器之间,只有低9位或低8有效,两者选择取决于USART控制寄存器1(USART_CR1)的M位,M=0为8位数据字长,M=1为9位数据字长。 3.控制器 USART有专门的控制发送的发送器、控制接收的接收器,还有唤醒单元、中断控制等。使用USART之前,需要将USART_CR1的UE置1,使能串口时钟供给。 发送器: USART_CR1的TE置1,启动数据发送,发送移位寄存器的数据会以低位在前、高位在后的形式从TX引脚输出,如果是同步模式SCLK也将输出时钟信号。 如下,字符发送时序图所示,一个字符帧发送需要三个部分:起始位+数据帧+停止位。起始位是一个位周期的低电平;数据帧是我们发送的8位或9位数据;停止位是一定时间周期的高电平,可以设置为0.5、1、1.5、2个停止位,默认使用1个停止位,2个停止位适用于USART模式、单线模式和调制解调器模式,0.5和1.5适用于智能卡模式。 发送数据重要的标志位
如果USART_CR1的RE置位,使能USART接受,使得接收器在RX线开始搜索起始位。接收数据时,几个比较重要的标志位如下
4.小波特率生成 波特率指数据信号对载波的调制速率,它用单位时间内载波调制状态改变次数来表示,单位为波特。比特率指单位时间内传播的比特数。对于USART波特率与比特率相等。 USART的发送器和接收器使用相同的波特率,计算公式如下 其中,f为USART时钟,USARTDIV是一个放在波特率寄存器(USART_BRR)的一个无符号定点数。其中 DIV_Mantissa[11:0]位定义USARTDIV的整数部分,DIV_Fraction[3:0]位定义USARTDIV 的小数部分。 5.校验控制 USART支持奇偶校验。使用校验位时,串口传输的数据长度将是在8位的数据帧基础上加上1位,此时需要将USART_CR1的M为置1,然后将USART_CR1的PCE置1启动奇偶校验。 奇偶校验在发送和接收都是由硬件自动完成,如果在接收出现奇偶校验失败,会将USART_SR的PE置1,并可以产生奇偶校验中断。 6.中断控制 USART有多个中断请求事件,如下
7.USART初始化结构体详解 HAL库函数对每个外设都建立了一个初始化结构体和初始化配置函数,如USART_InitTypeDef和USART_Init(),USART_InitTypeDef用于配置外设工作参数,USART_Init()则将参数配置到相应的寄存器。 typedef struct { uint32_t BaudRate; //波特率 uint32_t WordLength; //字长 uint32_t StopBits; //停止位 uint32_t Parity; //校验位 uint32_t Mode; //UART 模式 uint32_t HwFlowCtl; //硬件流控制 uint32_t OverSampling; // 过采样模式 uint32_t CLKLastBit; // 最尾位时钟脉冲 } USART_InitTypeDef;
8.编程要点 1) 使能 RX 和 TX 引脚 GPIO 时钟和 USART 时钟; 2) 初始化 GPIO,并将 GPIO 复用到 USART 上; 3) 配置 USART 参数; 4) 配置中断控制器并使能 USART 接收中断; 5) 使能 USART; 6) 在 USART 接收中断服务函数实现数据接收和发送 9.代码分析 GPIO和USART宏定义 //串口波特率 #define DEBUG_USART_BAUDRATE 115200 //引脚定义 /*******************************************************/ #define DEBUG_USART USART1 #define DEBUG_USART_CLK_ENABLE() __HAL_RCC_USART1_CLK_ENABLE(); #define DEBUG_USART_RX_GPIO_PORT GPIOA #define DEBUG_USART_RX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() #define DEBUG_USART_RX_PIN GPIO_PIN_10 #define DEBUG_USART_TX_GPIO_PORT GPIOA #define DEBUG_USART_TX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() #define DEBUG_USART_TX_PIN GPIO_PIN_9 #define DEBUG_USART_IRQHandler USART1_IRQHandler #define DEBUG_USART_IRQ USART1_IRQn /************************************************************/ void Usart_SendString(uint8_t *str); void DEBUG_USART_Config(void); int fputc(int ch, FILE *f); int fgetc(FILE *f); extern UART_HandleTypeDef UartHandle; USART初始化配置。函数体中UartHandle 是定义为 UART_HandleTypeDef 结构体类型的全局变量,它管理着串口的所有配置,该函数与硬件无关。 具体的MCU底层硬件相关的配置如引脚、时钟、DMA、中断等等是在HAL_UART_MspInit(UART_HandleTypeDef *huart)中完成,该函数被HAL_UART_Init 函数所调用,所以我们只需要重新定义HAL_UART_MspInit函数即可完成底层硬件的配置。 /** * @brief DEBUG_USART GPIO 配置,工作模式配置。115200 8-N-1 * @param 无 * @retval 无 */ void DEBUG_USART_Config(void) { UartHandle.Instance = DEBUG_USART; UartHandle.Init.BaudRate = DEBUG_USART_BAUDRATE; UartHandle.Init.WordLength = UART_WORDLENGTH_8B; UartHandle.Init.StopBits = UART_STOPBITS_1; UartHandle.Init.Parity = UART_PARITY_NONE; UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE; UartHandle.Init.Mode = UART_MODE_TX_RX; HAL_UART_Init(&UartHandle); /*使能串口接收断 */ __HAL_UART_ENABLE_IT(&UartHandle,UART_IT_RXNE); } /** * @brief UART MSP 初始化 * @param huart: UART handle * @retval 无 */ void HAL_UART_MspInit(UART_HandleTypeDef *huart) { GPIO_InitTypeDef GPIO_InitStruct; DEBUG_USART_CLK_ENABLE(); DEBUG_USART_RX_GPIO_CLK_ENABLE(); DEBUG_USART_TX_GPIO_CLK_ENABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ /* 配置Tx引脚为复用功能 */ GPIO_InitStruct.Pin = DEBUG_USART_TX_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStruct); /* 配置Rx引脚为复用功能 */ GPIO_InitStruct.Pin = DEBUG_USART_RX_PIN; GPIO_InitStruct.Mode=GPIO_MODE_AF_INPUT; //模式要设置为复用输入模式! HAL_GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStruct); HAL_NVIC_SetPriority(DEBUG_USART_IRQ ,0,1); //抢占优先级0,子优先级1 HAL_NVIC_EnableIRQ(DEBUG_USART_IRQ ); //使能USART1中断通道 } 字符发送函数 /***************** 发送字符串 **********************/ void Usart_SendString(uint8_t *str) { unsigned int k=0; do { HAL_UART_Transmit(&UartHandle,(uint8_t *)(str + k) ,1,1000); k++; } while(*(str + k)!=' |