相关寄存器
状态寄存器 (USART_SR)
主要关注RXNE位和TC位
RXNE(读数据寄存器非空):当该位被置1的时候,就是提示已经有数据被接收到了,并且可以读出来了。读取USART_DR,从而将该位清零,也可以向该位写0,直接清除。
TC(发送完成):当该位被置1的时候,表示USART_DR内的数据已经被发送完成了。如果设置了这个位的中断,则会产生中断。该位也有两种清零方式:读USART_SR,写USART_DR;直接向该位写0。
数据寄存器 (USART_DR)
进行发送数据操作时,往USART_DR写入数据会自动存储在TDR内;当进行读取数据操作时,向USART_DR读取数据会自动提取RDR数据。
发送数据时把TDR内容转移到发送移位寄存器上,接收数据时则是把接收到的每一位顺序保存在接收移位寄存器内进而转移到RDR。
波特率寄存器 (USART_BRR)
波特率寄存器包括定义了两个部分:DIV_Mantissa(整数部分)和DIV_Fraction(小数部分)。
控制寄存器 x (USART_CRx)
控制寄存器 1 (USART_CR1)
控制寄存器 2 (USART_CR2)
控制寄存器 3 (USART_CR3)
控制寄存器主要用于各类使能,如USART使能、检验控制使能、校验选择(奇校验偶校验)、发送缓冲区空中断使能、发送完成中断使能、接收缓冲区非空使能、发送使能、接受使能等等,具体位请查找中文参考手册。
串口配置
使用CubeMX配置.
串口初始化
UART_HandleTypeDef huart1;
void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200; //波特率
huart1.Init.WordLength = UART_WORDLENGTH_8B; //字长为8位数据格式
huart1.Init.StopBits = UART_STOPBITS_1; //一个停止位
huart1.Init.Parity = UART_PARITY_NONE; //无奇偶校验位
huart1.Init.Mode = UART_MODE_TX_RX; //收发模式
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK) //初始化
{
Error_Handler();
}
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量,下文中断部分有介绍。
}
结构体类型UART_HandleTypeDef 变量huart1作为UART的句柄。如下图:其中UART_InitTypeDef用于初始化波特率,奇偶校验位等。
typedef struct __UART_HandleTypeDef
{
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 */
__IO uint16_t TxXferCount; /*!< UART Tx Transfer Counter */
uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */
uint16_t RxXferSize; /*!< UART Rx Transfer size */
__IO 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 gState; /*!< UART state information related to global Handle management and also related to Tx operations. This parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations. This parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO uint32_t ErrorCode; /*!< UART Error code */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
void (* TxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Tx Half Complete Callback */
void (* TxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Tx Complete Callback */
void (* RxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Half Complete Callback */
void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Complete Callback */
void (* ErrorCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Error Callback */
void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Complete Callback */
void (* AbortTransmitCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Transmit Complete Callback */
void (* AbortReceiveCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Receive Complete Callback */
void (* WakeupCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Wakeup Callback */
void (* MspInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp Init callback */
void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp DeInit callback */
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
} UART_HandleTypeDef;
GPIO配置,开启中断
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(uartHandle->Instance==USART1)
{
/* USART1 clock enable */
__HAL_RCC_USART1_CLK_ENABLE(); //使能串口1时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟
/*
USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
//GPIO配置
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1 interrupt Init */
//开启串口1中断
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
}
中断函数
引用原子哥一张串口接收中断的流程图更好理解。
由流程图可以看到,当RxXferCount为0时,才调用中断回调函数
首先在.h文件中声明几个变量
#define USART_REC_LEN 200 //定义最大接收字节数 200
#define RXBUFFERSIZE 1 //缓存大小
extern uint8_t aRxBuffer[RXBUFFERSIZE]; //HAL库USART接收Buffer
extern uint8_t USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern uint16_t USART_RX_STA; //接收状态标记
我们在前文串口初始化时提到了HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE);如下:
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(huart);
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->RxXferCount = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
/* Process Unlocked */
__HAL_UNLOCK(huart);
/* Enable the UART Parity Error Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_PE);
/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
/* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
由函数定义可以看到,RxXferCount为我们传入的参数RXBUFFERSIZE为1,另外 这个函数使能了接收完成中断__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);,也就是说每接收一个字节就会进入一次中断USART1_IRQHandler。
串口1中断服务函数
串口产生中断,就会自动调用USART1_IRQHandler这个中断服务函数
void USART1_IRQHandler(void)
{
uint32_t timeout=0;
uint32_t maxDelay=0x1FFFF;
#if SYSTEM_SUPPORT_OS //使用OS
OSIntEnter();
#endif
HAL_UART_IRQHandler(&huart1); //调用HAL库中断处理函数
timeout=0;
while (HAL_UART_GetState(&huart1)!=HAL_UART_STATE_READY)//等待就绪
{
timeout++;超时处理
if(timeout>maxDelay)
break;
}
timeout=0;
while(HAL_UART_Receive_IT(&huart1,(uint8_t *)aRxBuffer, RXBUFFERSIZE)!=HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1
{
timeout++; //超时处理
if(timeout>maxDelay)
break;
}
#if SYSTEM_SUPPORT_OS //使用OS
OSIntExit();
#endif
}
在这个函数里,首先调用HAL_UART_IRQHandler(&huart1);这个HAL库中断处理函数,主要用于判断中断类型。通过这个中断处理函数会调用UART_Receive_IT(huart);如下:(由于函数太长,只选取了一小部分)
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
}
}
该函数是将接收到的数据保存到指定的串口缓冲区aRxBuffer。接着再判断。RxXferCount自减后是否等于0.
如果等于0 ,则关闭接收完成中断,进行中断回调函数。如果需要再一次开启时。需要再一次开启中断,也就是调用 HAL_UART_Receive_IT()函数。
串口1中断回调函数
首先,在win系统下enter表示回车(r)加换行(n),在16进制的表示下,r的ascii码为0x0d,n的ascii码为0x0a.由此下面逻辑就比较好理解了。16位置1表示接收完成,即0x8000;15位置1表示接收到了0x0d.将收到的数据储存在数组USART_RX_BUF[]里
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1)//如果是串口1
{
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d r
{
if(aRxBuffer[0]!=0x0a)
USART_RX_STA=0;//接收错误,重新开始 0x0a n
else
USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到0X0D
{
if(aRxBuffer[0]==0x0d)
USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))
USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
相关寄存器
状态寄存器 (USART_SR)
主要关注RXNE位和TC位
RXNE(读数据寄存器非空):当该位被置1的时候,就是提示已经有数据被接收到了,并且可以读出来了。读取USART_DR,从而将该位清零,也可以向该位写0,直接清除。
TC(发送完成):当该位被置1的时候,表示USART_DR内的数据已经被发送完成了。如果设置了这个位的中断,则会产生中断。该位也有两种清零方式:读USART_SR,写USART_DR;直接向该位写0。
数据寄存器 (USART_DR)
进行发送数据操作时,往USART_DR写入数据会自动存储在TDR内;当进行读取数据操作时,向USART_DR读取数据会自动提取RDR数据。
发送数据时把TDR内容转移到发送移位寄存器上,接收数据时则是把接收到的每一位顺序保存在接收移位寄存器内进而转移到RDR。
波特率寄存器 (USART_BRR)
波特率寄存器包括定义了两个部分:DIV_Mantissa(整数部分)和DIV_Fraction(小数部分)。
控制寄存器 x (USART_CRx)
控制寄存器 1 (USART_CR1)
控制寄存器 2 (USART_CR2)
控制寄存器 3 (USART_CR3)
控制寄存器主要用于各类使能,如USART使能、检验控制使能、校验选择(奇校验偶校验)、发送缓冲区空中断使能、发送完成中断使能、接收缓冲区非空使能、发送使能、接受使能等等,具体位请查找中文参考手册。
串口配置
使用CubeMX配置.
串口初始化
UART_HandleTypeDef huart1;
void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200; //波特率
huart1.Init.WordLength = UART_WORDLENGTH_8B; //字长为8位数据格式
huart1.Init.StopBits = UART_STOPBITS_1; //一个停止位
huart1.Init.Parity = UART_PARITY_NONE; //无奇偶校验位
huart1.Init.Mode = UART_MODE_TX_RX; //收发模式
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK) //初始化
{
Error_Handler();
}
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量,下文中断部分有介绍。
}
结构体类型UART_HandleTypeDef 变量huart1作为UART的句柄。如下图:其中UART_InitTypeDef用于初始化波特率,奇偶校验位等。
typedef struct __UART_HandleTypeDef
{
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 */
__IO uint16_t TxXferCount; /*!< UART Tx Transfer Counter */
uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */
uint16_t RxXferSize; /*!< UART Rx Transfer size */
__IO 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 gState; /*!< UART state information related to global Handle management and also related to Tx operations. This parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations. This parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO uint32_t ErrorCode; /*!< UART Error code */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
void (* TxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Tx Half Complete Callback */
void (* TxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Tx Complete Callback */
void (* RxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Half Complete Callback */
void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Complete Callback */
void (* ErrorCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Error Callback */
void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Complete Callback */
void (* AbortTransmitCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Transmit Complete Callback */
void (* AbortReceiveCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Receive Complete Callback */
void (* WakeupCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Wakeup Callback */
void (* MspInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp Init callback */
void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp DeInit callback */
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
} UART_HandleTypeDef;
GPIO配置,开启中断
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(uartHandle->Instance==USART1)
{
/* USART1 clock enable */
__HAL_RCC_USART1_CLK_ENABLE(); //使能串口1时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟
/*
USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
//GPIO配置
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1 interrupt Init */
//开启串口1中断
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
}
中断函数
引用原子哥一张串口接收中断的流程图更好理解。
由流程图可以看到,当RxXferCount为0时,才调用中断回调函数
首先在.h文件中声明几个变量
#define USART_REC_LEN 200 //定义最大接收字节数 200
#define RXBUFFERSIZE 1 //缓存大小
extern uint8_t aRxBuffer[RXBUFFERSIZE]; //HAL库USART接收Buffer
extern uint8_t USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern uint16_t USART_RX_STA; //接收状态标记
我们在前文串口初始化时提到了HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE);如下:
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(huart);
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->RxXferCount = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
/* Process Unlocked */
__HAL_UNLOCK(huart);
/* Enable the UART Parity Error Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_PE);
/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
/* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
由函数定义可以看到,RxXferCount为我们传入的参数RXBUFFERSIZE为1,另外 这个函数使能了接收完成中断__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);,也就是说每接收一个字节就会进入一次中断USART1_IRQHandler。
串口1中断服务函数
串口产生中断,就会自动调用USART1_IRQHandler这个中断服务函数
void USART1_IRQHandler(void)
{
uint32_t timeout=0;
uint32_t maxDelay=0x1FFFF;
#if SYSTEM_SUPPORT_OS //使用OS
OSIntEnter();
#endif
HAL_UART_IRQHandler(&huart1); //调用HAL库中断处理函数
timeout=0;
while (HAL_UART_GetState(&huart1)!=HAL_UART_STATE_READY)//等待就绪
{
timeout++;超时处理
if(timeout>maxDelay)
break;
}
timeout=0;
while(HAL_UART_Receive_IT(&huart1,(uint8_t *)aRxBuffer, RXBUFFERSIZE)!=HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1
{
timeout++; //超时处理
if(timeout>maxDelay)
break;
}
#if SYSTEM_SUPPORT_OS //使用OS
OSIntExit();
#endif
}
在这个函数里,首先调用HAL_UART_IRQHandler(&huart1);这个HAL库中断处理函数,主要用于判断中断类型。通过这个中断处理函数会调用UART_Receive_IT(huart);如下:(由于函数太长,只选取了一小部分)
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
}
}
该函数是将接收到的数据保存到指定的串口缓冲区aRxBuffer。接着再判断。RxXferCount自减后是否等于0.
如果等于0 ,则关闭接收完成中断,进行中断回调函数。如果需要再一次开启时。需要再一次开启中断,也就是调用 HAL_UART_Receive_IT()函数。
串口1中断回调函数
首先,在win系统下enter表示回车(r)加换行(n),在16进制的表示下,r的ascii码为0x0d,n的ascii码为0x0a.由此下面逻辑就比较好理解了。16位置1表示接收完成,即0x8000;15位置1表示接收到了0x0d.将收到的数据储存在数组USART_RX_BUF[]里
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1)//如果是串口1
{
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d r
{
if(aRxBuffer[0]!=0x0a)
USART_RX_STA=0;//接收错误,重新开始 0x0a n
else
USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到0X0D
{
if(aRxBuffer[0]==0x0d)
USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))
USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
举报