关于串口数据接收处理有多种方法,下面主要总结两种:
1.引入接收状态标记USART_RX_STA
int main(void)
{
u8 len;
u16 times = 0;
HAL_Init();
SystemClock_Config();
delay_init(80);
uart_init(115200);
LED_Init();
KEY_Init();
while(1)
{
if(USART_RX_STA & 0x8000)
{
len = USART_RX_STA & 0x3fff;
HAL_UART_Transmit(&UART1_Handler, (uint8_t*)USART_RX_BUF, len, 1000);
while(__HAL_UART_GET_FLAG(&UART1_Handler, UART_FLAG_TC) != SET);
printf("\r\n\r\n");
USART_RX_STA = 0;
}
else
{
times++;
if(times % 5000 == 0)
{
printf("%ld",times);
}
if(times % 30 == 0)LED_B_TogglePin;
delay_ms(10);
}
}
}
void USART1_IRQHandler(void)
{
u8 Res;
if((__HAL_UART_GET_FLAG(&UART1_Handler, UART_FLAG_RXNE) != RESET))
{
HAL_UART_Receive(&UART1_Handler, &Res, 1, 1000);
if((USART_RX_STA & 0x8000) == 0)
{
if(USART_RX_STA & 0x4000)
{
if(Res != 0x0a)USART_RX_STA = 0;
else USART_RX_STA |= 0x8000;
}
else
{
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);
}
函数:HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint16_t *pData, uint16_t Size, uint32_t Timeout) 大致流程:判断是否忙–>锁住–>标记接收忙–>获取tick计数–>赋值RxXferCount有多少数据要接收–>每次从DR内获取一个Byte存在pData指向的空间 这个接收函数是阻塞式的。参数Timeout是超时时间,代表某次执行函数最多占用串口的时间,单位是毫秒。简单来说,在本次数据接收完之前,不能处理其他数据。所以,调用函数的时候要指明参数,本次接收占用多长时间,在此期间,串口资源被独占。如果在规定的时间内,数据接收完毕,那就释放占用的串口资源;如果到了时间,即便数据还没有接收完毕,(比如数据量很大),仍需要归还串口资源的控制权,供其他外设使用。
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
uint16_t *tmp;
uint16_t uhMask;
uint32_t tickstart = 0;
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
__HAL_LOCK(huart);
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
tickstart = HAL_GetTick();
huart->RxXferSize = Size;
huart->RxXferCount = Size;
UART_MASK_COMPUTATION(huart);
uhMask = huart->Mask;
while (huart->RxXferCount > 0U)
{
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
{
tmp = (uint16_t *) pData ;
*tmp = (uint16_t)(huart->Instance->RDR & uhMask);
pData += 2U;
}
else
{
*pData++ = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask);
}
huart->RxXferCount--;
}
huart->RxState = HAL_UART_STATE_READY;
__HAL_UNLOCK(huart);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
2.使用回调函数
串口中断的执行过程:
USART2_IRQHandler(void)
HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
UART_Receive_IT(UART_HandleTypeDef *huart)
HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
首先在启动文件中找到中断向量,然后依次go to definition 就可以顺藤摸瓜捋清串口中断的执行步骤。 接下来是回调函数的处理:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
HAL_UART_Transmit(&husartx,&aRxBuffer,3,0xffff);
HAL_UART_Receive_IT(&husartx,&aRxBuffer,3);
}
显然使用回调函数程序逻辑清晰、代码简洁易懂,执行效率较高。 引用正点原子的流程图:
3.串口发送中断
串口发送中断使用较少,这里简单补充说明。 串口发送中断的过程大致如下:
USART2_IRQHandler(void)
HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
UART_EndTransmit_IT(UART_HandleTypeDef *huart)
HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
使能中断发送:发送指定长度的数据并使能发送中断
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
|