STM32F0x HAL库学习笔记(4)串口的数据的收发(轮询模式)

本文开发环境:

  • MCU型号:STM32F051R8T6
  • IDE环境: MDK 5.25
  • 代码生成工具:STM32CubeMx 5.0.1
  • HAL库版本:v1.9.0(STM32Cube MCU PackageforSTM32F0 Series)

本文内容:

  1. STM32CubeMx 配置异步串口初始化代码
  2. 串口数据的收发
  3. 重定义printf
  4. 调试建议
  5. 串口性能测试

所需工具:
硬件:USB转串口模块
软件:串口助手

初始化Uart(异步串口)

串口是MCU最常用的外设之一,通常用来和传感器等通讯或作为调试打印输出口,在学习笔记(2)中通过IO口的初始化,也介绍了新建一个工程的流程,这里我们演示在一个已经存在的工程上,进一步配置串口。首先我们打开工程所在目录:
在这里插入图片描述
DemoPro是建立工程时候的名字,它的文件类型为STM32CubeMx,双击打开后就可以开始配置串口了(通常都是使用异步模式,这里也以异步串口为例)。在弹出的串口中,默认应该就是打开Pinout&Configuration选项,我们以此在选择USART1,然后配置Mode,最后设置好基本参数,基本参数的配置要根据具体情况,不通讯双方需要配置一致才可以可以通讯。具体操作如下图所示:
在这里插入图片描述
最后配置完毕,直接点击右上角 GENERATE CODE 即可生成代码。

发送/接收 函数的使用

我们打开工程文件中stm32f0xx_hal_uart.h文件,在1291行开始,可以发现HAL库给我们提供了不少的API函数,堵塞收发,中断收发,DMA,回调函数等等:

/* 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);
... ...
/* Transfer Abort functions */
HAL_StatusTypeDef HAL_UART_Abort(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_AbortTransmit(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);
... ...

HAL库的注释似乎标准库详细准确很多,每一个函数在定义处都会给出使用方法,这里就不一一介绍,仅以常用的接收发送函数举例:

  while (1)
  {
	  uint8_t recv_data[1];           //接收数据
	  uint8_t send_data[1];           //发送数据
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	 
		if(!HAL_UART_Receive(&huart1,recv_data,1,500))                 //如果接收到一个数据
		{
			HAL_UART_Transmit(&huart1,recv_data,1,500);                //返回接收到的数据
		}
		
  }

其它的工程保持不变,我在while(1)中添加了以上4行代码,它用来把收到的数据返回出去。

函数 HAL_UART_Receive()

HAL_UART_Receive()函数拥有四个参数:

  • *huart:这个参数是一个指针,表示使用哪一个串口
  • *pDate:指向存放数据的地址,当我们收到数据后,就会以此存放在一这个地址开始的内存中
  • Size:大小,表示要接收的数据
  • Timeout:超时时间,单位为毫秒,指的是如果这个时间内收不到指定大小的数据包,函数将返回

所以 HAL_UART_Receive(&huart1,recv_data,1,500) 表示每次使用接收异步串口1,接收1个字节,存放在data为首的地址中,超时时间为500ms。

HAL_UART_Transmit()

HAL_UART_Transmit()函数通用拥有四个参数,其原理和HAL_UART_Receive()一样,只不过是发送。

发送大数据

在STM32F051中,我测试接受比较大的数据时,参数Size为1并不是一个好的选择,由于HAL函数封装程序高,效率也有所影响,频繁的调用函数容易造成数据溢出,在上文代码中,如果每次发送的数据较多,就要多次调用HAL_UART_Receive()函数,所以如果你要每次要接收256个字节,建议使用Size为256的函数:

HAL_UART_Receive(&huart1,recv_data,256,5000)

这样,当你收到256个字节整后,函数才会被调用一次,同时建议:每次发送数据的间隔最好控制在超时时间内,也就是说尽量不要让该函数超时,在测试过程中,这很容易引起丢包现象。

重定义printf

我们重定义了fputc()函数,这样就可以方便的使用printf来打印调试数据了,毕竟M0/M0+ 系列没有ITM,具体代码如下所示,我代码放在了main.c中:

int fputc(int ch, FILE *f)
{
	HAL_UART_Transmit(&huart1,(unsigned char *)&ch,1,0x200);
	return ch;
}

这样当你使用printf的时候,就可以在串口助手出看到打印信息。

调试建议

理论上来讲,串口的配置是简单的,函数也很简单,一般认为一次性可以通过,但是实际操作中,我们仍然可能发现初始化完成后,使用发送函数发送数据,但是串口助手观察不到数据,这是有几种情况造成的,我们首先要保证我们调试的工具是正常使用的:

  1. 将串口转USB模块中插入电脑,在设备管理器中看到有串口驱动,如下图所示:
    (该窗口可由 我的电脑 右键 管理 调出)
    在这里插入图片描述
    如果出现感叹号,或插入USB转串口模块后显示无法设别,那就应该安装驱动,加入你不知道如何查找驱动,可以尝试使用驱动精灵或询问卖家索要一份驱动。
    2.接着我们短接USB转串口模块的RX和TX,这样使用串口助手发送的数据,它会原封不动的返回给串口助手,如果你可以正常的收到发出的数据,那么证明串口模块和串口助手都是正常工作的
    3.如果在排除硬件和上位机软件的原因后,可以尝试复位MCU,有时候下载选项没有勾选**“Reset and Run”**导致每次下载程序后都需要复位,当然似乎有时候勾选了,还是需要复位才可以正常运行。
    在这里插入图片描述

串口性能的测试

建议通讯之前,可以先了解串口的性能,比如在测试过程中,可以通过不断发送接收到的数据来测试串口。我测试时的函数如下:
while (1)
{
uint8_t recv_data[512];
uint8_t send_data[512];
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
 
	if(!HAL_UART_Receive(&huart1,recv_data,512,5000))
	{
		HAL_UART_Transmit(&huart1,recv_data,512,5000);
	}

}
由于每次都是512个字节,所以在串口助手发送处,我也输入了512个字节的数据,然后使用定时发送,每200ms或150ms发送一次,最后观察发送和接受数据统计是否一致。在我的测试中,200ms没有测出问题,但是120ms或100ms很快就出现数据溢出,这时候就会观察到统计数据中,发送数据一直在增加,但是接收数据已经不再增加了。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_17351161/article/details/89411248