这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » NUCLEO-U083RC学习历程3-串口接收中断数据

共5条 1/1 1 跳转至

NUCLEO-U083RC学习历程3-串口接收中断数据

菜鸟
2024-10-18 18:55:52     打赏

简要:

最近一直在研究hal库的驱动函数,之前工作,学习都是使用的标准库,来学习、使用STM32的代码,所以借助电子产品世界的平台,记录一下学习STM32的hal库的学习旅程,同时也希望自己的学习经历可以帮助正在学习的32的人们。

几种不同的通讯基础知识:

单工:两种不同的通讯方,只能是单相通讯,即通讯只能从A到B,而不能从B到A,

半双工:两种不同的通讯方,通讯A和通讯B可以相互通讯,但是在同一时刻,只能存在单方向的通讯。例如:RS485的通讯方式。

全双工:两种不同的通讯方,通讯A和通讯B可以相互通讯,但是在同一时刻,可以存在双方方向的通讯。例如:RS232的通讯方式。

一:STM32U083RC-串口中断的介绍:

STM32的串口中断是指当串口收到数据时,cpu会产生串口中断信号信息,通知单片机内部的中断服务函数去处理数据。此时,在串口中断服务程序中,我们可以将数据先放到串口的接收串口缓冲区内,当把所有的数据接收完整时,再去调用串口处理函数。

通俗的说:串口中断服务函数需要使用中断接收功能实现。当有新的数据到达串口时,单片机触发中断请求,从而程序运行到中断服务程序里面。中断服务程序在处理完接收到的数据后,可以根据当时的要求进行处理。采用中断的方式优点是:提高单片机的运行效率,减少了资源浪费。

二:STM32cube软件配置过程:

之前提到的基本配置这里不再重复介绍,只是介绍有关串口的配置过程和注意事项;


image.png

在上图中主要配置选中的哪种串口,串口的工作模式、波特率、数据位、停止位 和使用的引脚信息。

配置串口接收中断

image.png


配置一下引脚的工作模式是否正常。

image.png


image.png

最后点击生成代码即可。

三:代码编写。

编写串口发送、接收中断函数:

串口1初始化部分,注意在初始化完成后,需要手动开启串口1的接收中断功能,否则程序进入不了串口的接收中断。

/**
  * @brief LPUART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_LPUART1_UART_Init(void)
{

  /* USER CODE BEGIN LPUART1_Init 0 */

  /* USER CODE END LPUART1_Init 0 */

  /* USER CODE BEGIN LPUART1_Init 1 */

  /* USER CODE END LPUART1_Init 1 */
  hlpuart1.Instance = LPUART1;
  hlpuart1.Init.BaudRate = 115200;
  hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
  hlpuart1.Init.StopBits = UART_STOPBITS_1;
  hlpuart1.Init.Parity = UART_PARITY_NONE;
  hlpuart1.Init.Mode = UART_MODE_TX_RX;
  hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  hlpuart1.FifoMode = UART_FIFOMODE_DISABLE;
  if (HAL_UART_Init(&hlpuart1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetTxFifoThreshold(&hlpuart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetRxFifoThreshold(&hlpuart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_DisableFifoMode(&hlpuart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN LPUART1_Init 2 */
   HAL_UART_Receive_IT(&hlpuart1,&Rxbuffer[0],1);
  /* USER CODE END LPUART1_Init 2 */

}

3.1 STM32复用 printf输出函数

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "string.h"
#include "stdint.h"
const uint8_t OUTPUT_str[] = "Hello STM32U083RC! Hello NUCLEO! autor by congconggege \r\n";
UART_HandleTypeDef hlpuart1;
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/*串口1重定义*/
int fputc(int ch, FILE *f)
{
	HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xFFFF);
	return ch;
}

注意一下:复用printf时候,可以切换不同的串口号,根据硬件具体的要求,进行串口的复用。

然后我将代码下载到程序里面,发现串口输出功能不正常,然后进入仿真看一下,发现程序运行延时函数里面,而串口输出、指示灯功能并不正常,如下图所示:

image.png

后来想到可能是没有打开,micolib库,导致程序运行不正常,然后打开下图的按键,重新编译下载。

image.png

串口输出结果如下:

image.png

利用printf输出调试信息功能基本上是调试好了。

3.2串口接收中断调试

需要在软件代码中,找到串口接收回调函数

/**
  * @brief  Rx Transfer completed callback.
  * @param  huart UART handle.
  * @retval None
  */
__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(huart);

  /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_UART_RxCpltCallback can be implemented in the user file.
   */
}

由于是软件生成底层驱动代码,弱定义模式,我们使用的时候只需要将其复制到主函数中进行处理

void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)//串口中断回调函数
{

	    uint8_t temp =0;     
    if (huart ->Instance ==LPUART1)    
    {
        temp = LPUART1->RDR; 
				Rxbuffer[RecPoint] = temp ;
				RecPoint ++ ;
				if(  RecPoint  == 7)
				{
					RecPoint = 0 ;
//					bPack = 1 ;
				}
/*串口发送正常函数*/
				HAL_UART_Transmit(&hlpuart1, (uint8_t *)&temp, 1, 2);
			
///*利用串口发送中断,导致少发送字节,图片中进行测试*/			
//				HAL_UART_Transmit_IT(&hlpuart1,&temp,1);		
        HAL_UART_Receive_IT(&hlpuart1, &Rxbuffer[0], 1);  //开启接收中断

    }
}

void Sendbuffer(unsigned char * buffer,int length)
{
	int	i=0 ;
  for(i=0 ; i<length ; i++ )
	{
		HAL_UART_Transmit(&hlpuart1, (uint8_t *)&buffer[i], 1, 2);
	}
}
HAL_UART_Transmit函数:是指HAL库中(hardware abstraction layer)中的一个串口发送函数,用来串口的数据发送功能
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)
四个参数的含义:
UART_HandleTypeDef *huart:指针指向的是UART_HandleTypeDef 的结构体指针,包括串口结构体中的配置信息
const uint8_t *pData :指针指向的是数据发送缓冲区内的数据。
uint16_t Size :本次数据传输的多少个字节数
uint32_t Timeout :超时判断,单位为毫秒,如果在传输操作过程中,发送函数超过此时间值时,该函数会返回错误值。
下面我使用该函数对串口接收过来的数据进行返回。

给大家分享两个不同发送数据的图片

image.png

image.png

然后我发现使用不同的发送函数会导致接收数据不正常的情况,看了下两种不同的发送函数还是有区别的:

HAL_UART_Transmit为阻塞式发送函数,意思就是说发送数据时候会一直等待数据发送完成后才会返回。

而HAL_UART_Transmit_IT 是非阻塞式的发送函数,即发送数据时候,不会等待数据发送完成,而是立即返回,数据发送完成后会触发中断函数。

因此,如果使用HAL_UART_Transmit发送数据时候,程序会一直阻塞在该函数处,直到数据发送完成后才会继续执行下一条指令,而如果使用HAL_UART_Transmit_IT发送数据,则程序会立即返回,可以指继续执行下一条质量,数据发送完成后会触发中断函数,在中断函数中进行数据发送完成后的处理。

所以在我们使用的串口发送数据,需要根据当前函数操作进行判断使用哪种发送函数,如果数据量不大的情况下,可以使用HAL_UART_Transmit,如果数据量较大的情况下,可以使用串口接收的空闲中断方式,待接收完成所有的数据包后,在进行数据的发送,或者是使用CPU资源,使用DMA的方式进行发送数据。

调试代码:TEST03_USART_rec.zip




关键词: NUCLEO-U083RC     串口     输出    

专家
2024-10-18 19:35:17     打赏
2楼

感谢分享


专家
2024-10-18 19:36:11     打赏
3楼

感谢分享


专家
2024-10-18 19:37:59     打赏
4楼

感谢分享


专家
2024-10-19 00:24:05     打赏
5楼

感谢分享


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]