1、UASRT简介
串口通讯 (Serial Communication) 是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,电子工程师在调试设备时也经常使用该通讯方式输出调试信息。
按位发送和接收的接口。如RS-232/422/485。
通讯方式:同步、异步,全双工,半双工,单工
物理层
串口通讯的物理层有很多标准及变种,我们主要讲解 RS-232 标准, RS-232 标准主要规定了信号的用途、通讯接口以及信号的电平标准。
在上面的通讯方式中,两个通讯设备的“DB9 接口”之间通过串口信号线建立起连接,串口信号线中使用“RS-232 标准”传输数据信号。由于 RS-232 电平标准的信号不能直接被控制器直接识别,所以这些信号会经过一个“电平转换芯片”转换成控制器能识别的“TTL 标准”的电平信号,才能实现通讯。
电平标准(串口通讯可分为 TTL 标准及 RS-232 标准,下图为232电平)
我们知道常见的电子电路中常使用 TTL 的电平标准,理想状态下,使用 5V 表示二进制逻辑 1,使用 0V 表示逻辑 0;而为了增加串口通讯的远距离传输及抗干扰能力,它使用-15V 表示逻辑 1,+15V 表示逻辑 0。
RS232 与 TTL 电平校准表示同一个信号时的对比
USART 系统框架
协议层
串口通讯的数据包由发送设备通过自身的 TXD 接口传输到接收设备的 RXD 接口。在串口通讯的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据。
USART 同步发送示例
USART 数据时钟时序图 (M=0)
硬件流控制
使用 nCTS 输入和 nRTS 输出可以控制 2 个器件间的串行数据流,如图
RTS 流控制
如果使能 RTS 流控制 (RTSE=1),只要 USART 接收器准备好接收新数据,便会将 nRTS 变 为有效(连接到低电平)。当接收寄存器已满时,会将 nRTS 变为无效,表明发送过程会在 当前帧结束后停止。图 268 显示了在使能 RTS 流控制的情况下进行通信的示例。
CTS 流控制
如果使能 CTS 流控制 (CTSE=1),则发送器会在发送下一帧前检查 nCTS。如果 nCTS 有效 (连接到低电平),则会发送下一数据(假设数据已准备好发送,即 TXE=0);否则不会进 行发送。如果在发送过程中 nCTS 变为无效,则当前发送完成之后,发送器停止。当 CTSE=1 时,只要 nCTS 发生变化,CTSIF 状态位便会由硬件自动置 1。这指示接收器是 否已准备好进行通信。如果 USART_CR3 寄存器中的 CTSIE 位置 1,则会产生中断。下图 显示了在使能 CTS 流控制的情况下进行通信的示例。
USART中断
USART 状态寄存器
TXE:发送数据寄存器为空 (Transmit data register empty)当 TDR 寄存器的内容已传输到移位寄存器时,该位由硬件置 1。如果 USART_CR1 寄存器 中TXEIE 位 = 1,则会生成中断。通过对 USART_DR 寄存器执行写入操作将该位清零。
0:数据未传输到移位寄存器
1:数据传输到移位寄存器
注意:单缓冲区发送期间使用该位。
TC:发送完成 (Transmission complete)如果已完成对包含数据的帧的发送并且 TXE 置 1,则该位由硬件置 1。如果 USART_CR1 寄存 器中 TCIE = 1,则会生成中断。该位由软件序列清零(读取 USART_SR 寄存器,然后写入 USART_DR 寄存器)。TC 位也可以通过向该位写入‘0’来清零。建议仅在多缓冲区通信 时使用此清零序列。
0:传送未完成
1:传送已完成
RXNE:读取数据寄存器不为空 (Read data register not empty)当 RDR 移位寄存器的内容已传输到 USART_DR 寄存器时,该位由硬件置 1。如果USART_CR1 寄存器中 RXNEIE = 1,则会生成中断。通过对 USART_DR 寄存器执行读入 操作将该位清零。RXNE 标志也可以通过向该位写入零来清零。建议仅在多缓冲区通信时使 用此清零序列。
0:未接收到数据
1:已准备好读取接收到的数据
NF:检测到噪声标志 (Noise detected flag)当在接收的帧上检测到噪声时,该位由硬件置 1。该位由软件序列清零(读入 USART_SR 寄 存器,然后读入 USART_DR 寄存器)。
0:未检测到噪声
1:检测到噪声
注意:如果 EIE 位置 1,则在进行多缓冲区通信时,该位不会生成中断,因为该位出现的时间与 本身生成中断的 RXNE 位因 NF 标志而生成的时间相同。
FE:帧错误 (Framing error)当检测到去同步化、过度的噪声或中断字符时,该位由硬件置 1。该位由软件序列清零(读入 USART_SR 寄存器,然后读入 USART_DR 寄存器)。
0:未检测到帧错误
1:检测到帧错误或中断字符
注意:该位不会生成中断,因为该位出现的时间与本身生成中断的 RXNE 位出现的时间相同。 如果当前正在传输的字同时导致帧错误和上溢错误,则会传输该字,且仅有 ORE 位被 置 1。如果 EIE 位置 1,则在进行多缓冲区通信时会对 FE 标志生成一个中断。
PE:奇偶校验错误 (Parity error)当在接收器模式下发生奇偶校验错误时,该位由硬件置 1。该位由软件序列清零(读取状态 寄存器,然后对 USART_DR 数据寄存器执行读或写访问)。将 PE 位清零前软件必须等待 RXNE 标志被置 1。 如果 USART_CR1 寄存器中 PEIE = 1,则会生成中断。
0:无奇偶校验错误
1:奇偶校验错误
USART 使用
USART相关结构体
USART_HandleTypeDef结构体
/** * @brief USART handle Structure definition */
typedef struct
{USART_TypeDef *Instance; /* USART registers base address */USART_InitTypeDef Init; /* Usart communication parameters */uint8_t *pTxBuffPtr; /* Pointer to Usart Tx transfer Buffer */uint16_t TxXferSize; /* Usart Tx Transfer size */__IO uint16_t TxXferCount; /* Usart Tx Transfer Counter */uint8_t *pRxBuffPtr; /* Pointer to Usart Rx transfer Buffer */uint16_t RxXferSize; /* Usart Rx Transfer size */__IO uint16_t RxXferCount; /* Usart Rx Transfer Counter */ DMA_HandleTypeDef *hdmatx; /* Usart Tx DMA Handle parameters */DMA_HandleTypeDef *hdmarx; /* Usart Rx DMA Handle parameters */HAL_LockTypeDef Lock; /* Locking object */__IO HAL_USART_StateTypeDef State; /* Usart communication state */__IO uint32_t ErrorCode; /* USART Error code */}USART_HandleTypeDef;
USART_InitTypeDef 结构体
/** * @brief USART Init Structure definition */
typedef struct
{uint32_t BaudRate; /*!< This member configures the Usart communication baud rate.The baud rate is computed using the following formula:- IntegerDivider = ((PCLKx) / (8 * (husart->Init.BaudRate)))- FractionalDivider = ((IntegerDivider - ((uint32_t) IntegerDivider)) * 8) + 0.5 */uint32_t WordLength; /*!< Specifies the number of data bits transmitted or received in a frame.This parameter can be a value of @ref USART_Word_Length */uint32_t StopBits; /*!< Specifies the number of stop bits transmitted.This parameter can be a value of @ref USART_Stop_Bits */uint32_t Parity; /*!< Specifies the parity mode.This parameter can be a value of @ref USART_Parity@note When parity is enabled, the computed parity is insertedat the MSB position of the transmitted data (9th bit whenthe word length is set to 9 data bits; 8th bit when theword length is set to 8 data bits). */uint32_t Mode; /*!< Specifies whether the Receive or Transmit mode is enabled or disabled.This parameter can be a value of @ref USART_Mode */uint32_t CLKPolarity; /*!< Specifies the steady state of the serial clock.This parameter can be a value of @ref USART_Clock_Polarity */uint32_t CLKPhase; /*!< Specifies the clock transition on which the bit capture is made.This parameter can be a value of @ref USART_Clock_Phase */uint32_t CLKLastBit; /*!< Specifies whether the clock pulse corresponding to the last transmitteddata bit (MSB) has to be output on the SCLK pin in synchronous mode.This parameter can be a value of @ref USART_Last_Bit */
}USART_InitTypeDef;
HAL_USART_StateTypeDef 结构体
/** * @brief HAL State structures definition */
typedef enum
{HAL_USART_STATE_RESET = 0x00, /*!< Peripheral is not yet Initialized */HAL_USART_STATE_READY = 0x01, /*!< Peripheral Initialized and ready for use */HAL_USART_STATE_BUSY = 0x02, /*!< an internal process is ongoing */ HAL_USART_STATE_BUSY_TX = 0x12, /*!< Data Transmission process is ongoing */ HAL_USART_STATE_BUSY_RX = 0x22, /*!< Data Reception process is ongoing */HAL_USART_STATE_BUSY_TX_RX = 0x32, /*!< Data Transmission Reception process is ongoing */HAL_USART_STATE_TIMEOUT = 0x03, /*!< Timeout state */HAL_USART_STATE_ERROR = 0x04 /*!< Error */
}HAL_USART_StateTypeDef;
HAL 库函数
初始化相关
/* Initialization/de-initialization functions **********************************/
HAL_StatusTypeDef HAL_USART_Init(USART_HandleTypeDef *husart);
HAL_StatusTypeDef HAL_USART_DeInit(USART_HandleTypeDef *husart);
void HAL_USART_MspInit(USART_HandleTypeDef *husart);
void HAL_USART_MspDeInit(USART_HandleTypeDef *husart);
操作相关
/* IO operation functions *******************************************************/
HAL_StatusTypeDef HAL_USART_Transmit(USART_HandleTypeDef *husart, uint8_t *pTxData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_USART_Receive(USART_HandleTypeDef *husart, uint8_t *pRxData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_USART_TransmitReceive(USART_HandleTypeDef *husart, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_USART_Transmit_IT(USART_HandleTypeDef *husart, uint8_t *pTxData, uint16_t Size);
HAL_StatusTypeDef HAL_USART_Receive_IT(USART_HandleTypeDef *husart, uint8_t *pRxData, uint16_t Size);
HAL_StatusTypeDef HAL_USART_TransmitReceive_IT(USART_HandleTypeDef *husart, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size);
HAL_StatusTypeDef HAL_USART_Transmit_DMA(USART_HandleTypeDef *husart, uint8_t *pTxData, uint16_t Size);
HAL_StatusTypeDef HAL_USART_Receive_DMA(USART_HandleTypeDef *husart, uint8_t *pRxData, uint16_t Size);
HAL_StatusTypeDef HAL_USART_TransmitReceive_DMA(USART_HandleTypeDef *husart, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size);
HAL_StatusTypeDef HAL_USART_DMAPause(USART_HandleTypeDef *husart);
HAL_StatusTypeDef HAL_USART_DMAResume(USART_HandleTypeDef *husart);
HAL_StatusTypeDef HAL_USART_DMAStop(USART_HandleTypeDef *husart);
void HAL_USART_IRQHandler(USART_HandleTypeDef *husart);
void HAL_USART_TxCpltCallback(USART_HandleTypeDef *husart);
void HAL_USART_TxHalfCpltCallback(USART_HandleTypeDef *husart);
void HAL_USART_RxCpltCallback(USART_HandleTypeDef *husart);
void HAL_USART_RxHalfCpltCallback(USART_HandleTypeDef *husart);
void HAL_USART_TxRxCpltCallback(USART_HandleTypeDef *husart);
void HAL_USART_ErrorCallback(USART_HandleTypeDef *husart);
获取状态函数
/* Peripheral State functions ************************************************/
HAL_USART_StateTypeDef HAL_USART_GetState(USART_HandleTypeDef *husart);
uint32_t HAL_USART_GetError(USART_HandleTypeDef *husart);
UART 使用
UART相关结构体
UART_HandleTypeDef结构体
typedef struct
{USART_TypeDef *Instance; /*!< UART registers base address */UART_InitTypeDef Init; /*!< UART communication parameters */uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */uint16_t TxXferSize; /*!< UART Tx Transfer size */uint16_t TxXferCount; /*!< UART Tx Transfer Counter */uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */uint16_t RxXferSize; /*!< UART Rx Transfer size */uint16_t RxXferCount; /*!< UART Rx Transfer Counter */ DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */HAL_LockTypeDef Lock; /*!< Locking object */__IO HAL_UART_StateTypeDef State; /*!< UART communication state */__IO uint32_t ErrorCode; /*!< UART Error code */}UART_HandleTypeDef;
UART_InitTypeDef 结构体
typedef struct
{uint32_t BaudRate; /*!< This member configures the UART communication baud rate.The baud rate is computed using the following formula:- IntegerDivider = ((PCLKx) / (8 * (OVR8+1) * (huart->Init.BaudRate)))- FractionalDivider = ((IntegerDivider - ((uint32_t) IntegerDivider)) * 8 * (OVR8+1)) + 0.5 Where OVR8 is the "oversampling by 8 mode" configuration bit in the CR1 register. */uint32_t WordLength; /*!< Specifies the number of data bits transmitted or received in a frame.This parameter can be a value of @ref UART_Word_Length */uint32_t StopBits; /*!< Specifies the number of stop bits transmitted.This parameter can be a value of @ref UART_Stop_Bits */uint32_t Parity; /*!< Specifies the parity mode.This parameter can be a value of @ref UART_Parity@note When parity is enabled, the computed parity is insertedat the MSB position of the transmitted data (9th bit whenthe word length is set to 9 data bits; 8th bit when theword length is set to 8 data bits). */uint32_t Mode; /*!< Specifies whether the Receive or Transmit mode is enabled or disabled.This parameter can be a value of @ref UART_Mode */uint32_t HwFlowCtl; /*!< Specifies whether the hardware flow control mode is enabledor disabled.This parameter can be a value of @ref UART_Hardware_Flow_Control */uint32_t OverSampling; /*!< Specifies whether the Over sampling 8 is enabled or disabled, to achieve higher speed (up to fPCLK/8).This parameter can be a value of @ref UART_Over_Sampling */
}UART_InitTypeDef;
HAL_UART_StateTypeDef结构体
typedef enum
{HAL_UART_STATE_RESET = 0x00, /*!< Peripheral is not yet Initialized */HAL_UART_STATE_READY = 0x01, /*!< Peripheral Initialized and ready for use */HAL_UART_STATE_BUSY = 0x02, /*!< an internal process is ongoing */ HAL_UART_STATE_BUSY_TX = 0x12, /*!< Data Transmission process is ongoing */ HAL_UART_STATE_BUSY_RX = 0x22, /*!< Data Reception process is ongoing */HAL_UART_STATE_BUSY_TX_RX = 0x32, /*!< Data Transmission and Reception process is ongoing */ HAL_UART_STATE_TIMEOUT = 0x03, /*!< Timeout state */HAL_UART_STATE_ERROR = 0x04 /*!< Error */
}HAL_UART_StateTypeDef;
UART相关库函数
初始化相关
/* Initialization/de-initialization functions **********************************/
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_HalfDuplex_Init(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_LIN_Init(UART_HandleTypeDef *huart, uint32_t BreakDetectLength);
HAL_StatusTypeDef HAL_MultiProcessor_Init(UART_HandleTypeDef *huart, uint8_t Address, uint32_t WakeUpMethod);
HAL_StatusTypeDef HAL_UART_DeInit (UART_HandleTypeDef *huart);
void HAL_UART_MspInit(UART_HandleTypeDef *huart);
void HAL_UART_MspDeInit(UART_HandleTypeDef *huart);
操作相关
/* IO operation functions *******************************************************/
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_DMAPause(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_DMAResume(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart);
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart);
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);
获取状态函数
/* Peripheral State functions **************************************************/
HAL_UART_StateTypeDef HAL_UART_GetState(UART_HandleTypeDef *huart);
uint32_t HAL_UART_GetError(UART_HandleTypeDef *huart);
UART使用示例
#include "usart.h"
#include "delay.h"
//
//如果使用os,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h" //os 使用
#endif
//
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F429开发板
//串口1初始化
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2015/9/7
//版本:V1.5
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved
//********************************************************************************
//V1.0修改说明
//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
//#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{ int handle;
}; FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{ x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{ while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 USART1->DR = (u8) ch; return ch;
}
#endif #if EN_USART1_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0; //接收状态标记 u8 aRxBuffer[RXBUFFERSIZE];//HAL库使用的串口接收缓冲
UART_HandleTypeDef UART1_Handler; //UART句柄//初始化IO 串口1
//bound:波特率
void uart_init(u32 bound)
{ //UART 初始化设置UART1_Handler.Instance=USART1; //USART1UART1_Handler.Init.BaudRate=bound; //波特率UART1_Handler.Init.WordLength=UART_WORDLENGTH_8B; //字长为8位数据格式UART1_Handler.Init.StopBits=UART_STOPBITS_1; //一个停止位UART1_Handler.Init.Parity=UART_PARITY_NONE; //无奇偶校验位UART1_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE; //无硬件流控UART1_Handler.Init.Mode=UART_MODE_TX_RX; //收发模式HAL_UART_Init(&UART1_Handler); //HAL_UART_Init()会使能UART1//HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量(使用回调函数处理中断需要调用该函数)}//UART底层初始化,时钟使能,引脚配置,中断配置
//此函数会被HAL_UART_Init()调用
//huart:串口句柄void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{//GPIO端口设置GPIO_InitTypeDef GPIO_Initure;if(huart->Instance==USART1)//如果是串口1,进行串口1 MSP初始化{__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟__HAL_RCC_USART1_CLK_ENABLE(); //使能USART1时钟GPIO_Initure.Pin=GPIO_PIN_9; //PA9GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用推挽输出GPIO_Initure.Pull=GPIO_PULLUP; //上拉GPIO_Initure.Speed=GPIO_SPEED_FAST; //高速GPIO_Initure.Alternate=GPIO_AF7_USART1; //复用为USART1HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA9GPIO_Initure.Pin=GPIO_PIN_10; //PA10HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA10__HAL_UART_DISABLE_IT(huart,UART_IT_TC);
#if EN_USART1_RX__HAL_UART_ENABLE_IT(huart,UART_IT_RXNE); //开启接收中断HAL_NVIC_EnableIRQ(USART1_IRQn); //使能USART1中断通道HAL_NVIC_SetPriority(USART1_IRQn,3,3); //抢占优先级3,子优先级3
#endif }}//串口1中断服务程序
void USART1_IRQHandler(void)
{ u8 Res;
#if SYSTEM_SUPPORT_OS //使用OSOSIntEnter();
#endifif((__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_RXNE)!=RESET)) //接收中断(接收到的数据必须是0x0d 0x0a结尾){HAL_UART_Receive(&UART1_Handler,&Res,1,1000); if((USART_RX_STA&0x8000)==0)//接收未完成{if(USART_RX_STA&0x4000)//接收到了0x0d{if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始else USART_RX_STA|=0x8000; //接收完成了 }else //还没收到0X0D{ if(Res==0x0d)USART_RX_STA|=0x4000;else{USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;USART_RX_STA++;if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收 } }} }HAL_UART_IRQHandler(&UART1_Handler);
#if SYSTEM_SUPPORT_OS //使用OSOSIntExit();
#endif
}
#endif