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

本文开发环境:

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

本文内容:

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

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

初始化Uart(异步串口)

串口是MCU最常用的外设之一,通常用来和传感器等通讯或作为调试打印输出口,在学习笔记(2)中通过IO口的初始化,也介绍了新建一个工程的流程,这里我们演示在一个已经存在的工程上,进一步配置串口。首先我们打开工程所在目录:
STM32F0x HAL库学习笔记(4)串口的数据的收发(轮询模式)_第1张图片
DemoPro是建立工程时候的名字,它的文件类型为STM32CubeMx,双击打开后就可以开始配置串口了(通常都是使用异步模式,这里也以异步串口为例)。在弹出的串口中,默认应该就是打开Pinout&Configuration选项,我们选择USART1,然后配置Mode,最后设置好基本参数,基本参数的配置要根据具体情况,当通讯的双方需要配置一致才可以正常的通讯。具体操作如下图所示:
STM32F0x HAL库学习笔记(4)串口的数据的收发(轮询模式)_第2张图片
这里还建议串口的发送IO口配置为上拉模式(如果你的电路没有外部上拉),否则可能电平不稳定情况。比如如果使用默认的No pull-up no pull Down模式,那么开启中断后,可能会出现误触发情况:
STM32F0x HAL库学习笔记(4)串口的数据的收发(轮询模式)_第3张图片
最后配置完毕,直接点击右上角 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)中添加了以上2行代码,它用来把收到的数据返回出去。

函数 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模块中插入电脑,在设备管理器中看到有串口驱动,如下图所示:
    (该窗口可由 我的电脑 右键 管理 调出)
    STM32F0x HAL库学习笔记(4)串口的数据的收发(轮询模式)_第4张图片
    如果出现感叹号,或插入USB转串口模块后显示无法设别,那就应该安装驱动,假如你不知道如何查找驱动,可以尝试使用驱动精灵或询问卖家索要一份驱动。

  2. 接着我们短接USB转串口模块的RX和TX,这样使用串口助手发送的数据,它会原封不动的返回给串口助手,如果你可以正常的收到发出的数据,那么证明串口模块和串口助手都是正常工作的。

  3. 如果在排除硬件和上位机软件的原因后,可以尝试复位MCU,有时候下载选项没有勾选**“Reset and Run”**导致每次下载程序后都需要复位,当然似乎有时候勾选了,还是需要复位才可以正常运行。
    STM32F0x HAL库学习笔记(4)串口的数据的收发(轮询模式)_第5张图片

  4. 如果以上方式都已经排除,那么则很可能是代码的原因,我们需要重新检查一下代码,如果你有一个参考的demo,则会方便很多。

串口性能的测试

建议通讯之前,可以先了解串口的性能,比如在测试过程中,可以通过不断发送接收到的数据来测试串口。我测试时的函数如下:

  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很快就出现数据溢出,这时候就会观察到统计数据中,发送数据一直在增加,但是接收数据已经不再增加了。
STM32F0x HAL库学习笔记(4)串口的数据的收发(轮询模式)_第6张图片
了解外设的性能是重要的,这是为了在设计程序的时候提供一些有助于稳定性的指导。

你可能感兴趣的:(STM32F0x,HAL库,#,使用,STM32CubeMx,配置,STM32,外设)