简要:
最近一直在研究hal库的驱动函数,之前工作,学习都是使用的标准库,来学习、使用STM32的代码,所以借助电子产品世界的平台,记录一下学习STM32的hal库的学习旅程,同时也希望自己的学习经历可以帮助正在学习的32的人们。
几种不同的通讯基础知识:
单工:两种不同的通讯方,只能是单相通讯,即通讯只能从A到B,而不能从B到A,
半双工:两种不同的通讯方,通讯A和通讯B可以相互通讯,但是在同一时刻,只能存在单方向的通讯。例如:RS485的通讯方式。
全双工:两种不同的通讯方,通讯A和通讯B可以相互通讯,但是在同一时刻,可以存在双方方向的通讯。例如:RS232的通讯方式。
一:STM32U083RC-串口中断的介绍:
STM32的串口中断是指当串口收到数据时,cpu会产生串口中断信号信息,通知单片机内部的中断服务函数去处理数据。此时,在串口中断服务程序中,我们可以将数据先放到串口的接收串口缓冲区内,当把所有的数据接收完整时,再去调用串口处理函数。
通俗的说:串口中断服务函数需要使用中断接收功能实现。当有新的数据到达串口时,单片机触发中断请求,从而程序运行到中断服务程序里面。中断服务程序在处理完接收到的数据后,可以根据当时的要求进行处理。采用中断的方式优点是:提高单片机的运行效率,减少了资源浪费。
二:STM32cube软件配置过程:
之前提到的基本配置这里不再重复介绍,只是介绍有关串口的配置过程和注意事项;
在上图中主要配置选中的哪种串口,串口的工作模式、波特率、数据位、停止位 和使用的引脚信息。
配置串口接收中断
配置一下引脚的工作模式是否正常。
最后点击生成代码即可。
三:代码编写。
编写串口发送、接收中断函数:
串口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时候,可以切换不同的串口号,根据硬件具体的要求,进行串口的复用。
然后我将代码下载到程序里面,发现串口输出功能不正常,然后进入仿真看一下,发现程序运行延时函数里面,而串口输出、指示灯功能并不正常,如下图所示:
后来想到可能是没有打开,micolib库,导致程序运行不正常,然后打开下图的按键,重新编译下载。
串口输出结果如下:
利用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 :超时判断,单位为毫秒,如果在传输操作过程中,发送函数超过此时间值时,该函数会返回错误值。
下面我使用该函数对串口接收过来的数据进行返回。
给大家分享两个不同发送数据的图片
然后我发现使用不同的发送函数会导致接收数据不正常的情况,看了下两种不同的发送函数还是有区别的:
HAL_UART_Transmit为阻塞式发送函数,意思就是说发送数据时候会一直等待数据发送完成后才会返回。
而HAL_UART_Transmit_IT 是非阻塞式的发送函数,即发送数据时候,不会等待数据发送完成,而是立即返回,数据发送完成后会触发中断函数。
因此,如果使用HAL_UART_Transmit发送数据时候,程序会一直阻塞在该函数处,直到数据发送完成后才会继续执行下一条指令,而如果使用HAL_UART_Transmit_IT发送数据,则程序会立即返回,可以指继续执行下一条质量,数据发送完成后会触发中断函数,在中断函数中进行数据发送完成后的处理。
所以在我们使用的串口发送数据,需要根据当前函数操作进行判断使用哪种发送函数,如果数据量不大的情况下,可以使用HAL_UART_Transmit,如果数据量较大的情况下,可以使用串口接收的空闲中断方式,待接收完成所有的数据包后,在进行数据的发送,或者是使用CPU资源,使用DMA的方式进行发送数据。
测试代码在附件中,有需要的可以自行下载
全部评论