大家好,今天给大家介绍单片机STM32:HAL库-串口USART,文章末尾附有本毕业设计的论文和源码的获取方式,可进群免费领取。
USART简介
通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。
USART利用分数波特率发生器提供宽范围的波特率选择。
一个波特率寄存器(USART_BRR),12位的整数和4位小数
任何USART双向通信至少需要两个脚:
接收数据输入(RX)和发送数据输出(TX)
当发送器被激活并且不发送数据时,TX引脚处于高电平
在起始位期间,TX脚处于低电平,在停止位期间处于高电平。
发送和接收由一共用的波特率发生器驱动,当发送器和接收器的使能位分别置位时,分别为其产生时钟。
当起始位为1位,数据位为8位,停止位为1位时:
- 空闲帧包括了停止位。
- 断开帧是10位低电平,后跟停止位。
发送(TX)器
- 可设置寄存器来确定数据位是8位还是9位。
- 通过置位TE位来使能发送,发送移位寄存器中的数据将会被输出到TX引脚上。相应的时钟脉冲在CK脚上输出。
- 在TX引脚上首先移出数据的最低有效位LSB,先发送LSB
- TE位被激活后将发送一个空闲帧(空闲符号)
配置步骤
- 发送数据寄存器空(TXE)
- 发送完成(TE)
串口数据发送过程:
将数据写入DR(一个字节的大小)中,DR会将数据复制到TDR中,TDR会将数据复制到发送移位寄存器中,从LSB(最低有效位)一位位发送到TX引脚上,实现数据的发送。
其中:
每发送完一个字节(发送数据寄存器TDR为空)TXE标志会被置位。
全部数据发送完毕后TC标志会被置位。
接收器
USART可以根据USART_CR1的M位接收8位或9位的数据字
在USART接收期间,数据的最低有效位首先从RX脚移进到接收数据寄存器中。
空闲符号
当一空闲帧被检测到时,其处理步骤和接收到普通数据帧一样,但如果IDLEIE位被设置将产生一个中断。
配置步骤
- 接收到的数据已准备好读取(RXNE)
串口数据接收过程:
接收移位寄存器从RX引脚接收数据,从数据最低有效位开始(因为数据是先发送最低有效位)接收数据,当接收到一个字节的数据时,将数据复制到RDR寄存器和DR寄存器中,此时RXNE标志被置位,通过读取DR寄存器来获取接收的一个字节数据。
分数波特率
波特率寄存器(USART_BRR),12位的整数和4位小数
用12位二进制数表示整数部分,4位表示小数部分。
波特率计算公式
设置波特率位115200,fck = 36MHz,则USARTDIV = 19.5
整数部分为19 << 4 = 304
小数部分为0.5*16 = 8
USART_BRR寄存器的值位304+8=312=0x138
中断
注意:USART的各种中断事件被连接到同一个中断向量
demo
串口异步通信-阻塞式发送-仿printf发送
采用STM32F103C8T6单片机,KeilMDK5.32版本
串口异步通信,,仅开启发方向,阻塞式发送数据(仿printf发送)。
PC13控制LED灯,LED灯的亮灭指示程序正常运行。
串口仿printf发送函数
#define USART1_SENDBUFF_MAX_BYTES 100U //串口1发送缓冲区大小 单位字节
/**
* @brief UART 仿printf发送
* @param format 输出的字符串
* @retval 返回写入的字符总数
*/
int USART1Printf(const char* format, ...)
{
static char sendBuff[USART1_SENDBUFF_MAX_BYTES] = { 0 };//发送缓冲区
int bytes = 0;
va_list list;
va_start(list, format);
bytes = vsprintf(sendBuff, format, list);//格式化输入
va_end(list);
/* 发送之前清除标志位 */
CLEAR_BIT(huart1.Instance->SR, USART_SR_TC_Msk);//往TC位写入0来清除TC位
HAL_UART_Transmit(&huart1, (void*)sendBuff, bytes, INFINITE);//阻塞式发送数据,发送等待时间为最大等待时间
return bytes;
}
HAL_UART_Transmit()是HAL库串口阻塞式发送函数,这个函数没有用到TXE与TC标志位,发送结束后也没有清除标志。
主程序中的代码
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(1000);//延时1000毫秒
USART1Printf("Hello World! %hhu\r\n", times);
times++;
PCout(13) = !PCin(13);
}
STM32CubeMX配置
串口异步通信-非阻塞式发送-仿printf发送
采用STM32F103C8T6单片机,KeilMDK5.32版本
串口异步通信,,仅开启发方向,非阻塞式发送数据(仿printf发送)。
PC13控制LED灯,LED灯的亮灭指示程序正常运行。
串口仿printf发送函数
#define USART_SENDBUFF_MAX_BYTES 100U //串口1发送缓冲区大小 单位字节
/**
* @brief UART 仿printf发送
* @param huart 指向串口结构体的指针
* @param format 输出的字符串
* @retval 返回写入的字符总数
*/
int USARTPrintf(UART_HandleTypeDef *huart, const char* format, ...)
{
static char sendBuff[USART_SENDBUFF_MAX_BYTES] = { 0 };
int bytes = 0;
va_list list;
va_start(list, format);
bytes = vsprintf(sendBuff, format, list);
va_end(list);
/* 发送之前清除标志位 */
CLEAR_BIT(huart->Instance->SR, USART_SR_TC_Msk);//往TC位写入0来清除TC位
HAL_UART_Transmit_IT(huart, (void*)sendBuff, bytes);//非阻塞式发送数据,开启TXE中断,再全部数据都写入DR寄存器并发送后将关闭TXE中断,开启TC中断
return bytes;
}
HAL_UART_Transmit_IT()函数开启了TXE中断,并在最后一个字节发送结束之后开启TC中断。如下图
HAL_UART_IRQHandler()函数
这里有2个函数需要注意
- UART_Transmit_IT()是每发送完一个字节,则进入该函数里面,往DR寄存器写入下一个字节,如果是最后一个字节则关闭TXE中断开启TC中断。
- UART_EndTransmit_IT()全部数据发送完毕,关闭TC中断,进入发送完毕回调函数
STM32CubeMX配置
发送完成回调函数HAL_UART_TxCpltCallback()
在进入该函数前,TXE与TC中断已关闭。
在发生串口回调函数(TXE/TC)时,并且全部数据发送完毕,HAL_UART_IRQHandler()调用UART_EndTransmit_IT(),UART_EndTransmit_IT()在关闭TC中断后进入HAL_UART_TxCpltCallback()。
/**
* @brief Tx Transfer completed callbacks.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval None
*/
__weak void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_UART_TxCpltCallback could be implemented in the user file
*/
}
工程文件下载链接
串口异步通信-非阻塞式接收数据
HAL库的阻塞式接收数据函数HAL_UART_Receive()
使用示例HAL_UART_Receive(&huart1, (void*)receiveBuff, sizeof(receiveBuff), INFINITE);
/**
* @brief Receives an amount of data in blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must indicate the number
* of u16 available through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @param Timeout Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
非阻塞式接收数据函数HAL_UART_Receive_IT()
该函数会开启以下中断
- 奇偶检验错(PE)
- 帧错误、噪声错误、溢出错误(NE或ORT或FE)
- UART数据寄存器非空中断(RXNE)
并且会将huart的接收类型设置为HAL_UART_RECEPTION_STANDARD
接收类型值有
- HAL_UART_RECEPTION_STANDARD标准接收
- HAL_UART_RECEPTION_TOIDLE接收至完成或闲置事件
/**
* @brief Receives an amount of data in non blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must indicate the number
* of u16 available through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
HAL_UART_IRQHandler()函数会调用UART_Receive_IT()进行串口接收中断处理。UART_Receive_IT()会将DR寄存器中的数据复制到串口接收缓存区中,如果接收数据的字节数目满足指定的数目,则会关闭中断(RXNE,NE或ORT或FE,PE),根据接收类型进入相应的接收完成回调函数中。
下面示例串口非阻塞式接收数据
采用STM32F103C8T6单片机,KeilMDK5.32版本
串口异步通信,开启收发方向,阻塞式发送(仿printf发送);非阻塞式接收数据。
PC13控制LED灯,LED灯的亮灭指示接收到数据。
程序初始化完成之后,开启接收中断。
在接收完成回调函数中,重新开启接收中断(因为在进入接收回调函数前,所有与接收相关的中断已经关闭)
STM32CubeMX配置
完整工程文件可进群免费领取!!!
嵌入式物联网的学习之路非常漫长,不少人因为学习路线不对或者学习内容不够专业而错失高薪offer。不过别担心,我为大家整理了一份150多G的学习资源,基本上涵盖了嵌入式物联网学习的所有内容。点击下方链接,0元领取学习资源,让你的学习之路更加顺畅!记得点赞、关注、收藏、转发哦!
点击这里找小助理0元领取:扫码进群领资料