写在前面的话欢迎大家在评论区指正错误,该博文是我在这几天使用hal库的时候碰到的问题的记录,对于暂时没有写的像dma、阻塞接收等函数,在后期如果我用道的话,我也会在该博文里面更新。当让也欢迎大家在评论区指正。
函数在这里不介绍关于DMA的操作,只是用有关串口的阻塞和非阻塞函数。
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);
以上4个分别是串口的阻塞接受,发送和非阻塞的接受和发送。(关于阻塞和非阻塞,阻塞的过程cpu是需要等待的,而非阻塞的过程相当于中断)
关于在使用的时候遇到的问题发送HAL_UART_Transmit在发送方面,使用HAL_UART_Transmit阻塞数据发送的时候,一定要计算好发送数据的时间。如果发送时间到了,但是数据还没有发送完成的话,会导致没有发送的数据丢失。
HAL_UART_Transmit_IT该函数是以中断的方式发送的数据,是非阻塞的。在使用的时候,可以写成类似printf的函数。在这里我参照的是正点原子库函数版本改过来的。
void u2_printf(char *str,...)
{
uint16_t j;
va_list ap;
va_start(ap,str);
vsprintf((char*)USART2_T_M,str,ap);
va_end(ap);
HAL_UART_Transmit_IT(&huart2,(uint8_t *)USART2_T_M,strlen((const char*)USART2_T_M));
}
但是该函数还存在问题,在字符串中默认0x00是一个字符串的接受。所以自己写的这种类printf的函数并不能在字符串中间加入0x00进行数据发送。(0x00一般在某些模块的数据通信中会使用到)但是使用半主机模式下的printf函数可以解决该问题。
使用printf函数这一部分代码我参照的是正点原子的给出的代码,直接改过来使用的。使用的是半主机模式下的printf函数。
#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 = (uint8_t) ch;
return ch;
}
#endif
在这里面,通过更改USART1修改映射串口。
接收阻塞模式下的接收函数没有测试过,就不在这里写了。以后有机会用到了,会进行添加。
HAL_UART_Receive_IT使用中断的方式进行接受数据,在这里需要注意的一个点是,使用中断的方式接收到数据之后,需要在中断里面在调用一次HAL_UART_Receive_IT函数,重新开启下一次数据接收,否则会导致,接收完一次数据之后,不会接收下一次数据。
HAL_UART_Receive_IT(&huart2,&usart2_rdata,1);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART2) //串口屏,接收中断
{
HAL_UART_Receive_IT(&huart2,&usart2_rdata,1);
}
}
在这里我是用的是,接收一个字符后就会触发一次中断。当然也可以一次接收多个字符数据。