龙空技术网

STM32F4 HAL库学习笔记之串口通讯 2

第六个葫芦娃呀 53

前言:

今天同学们对“串口初始化的函数是哪个核心参数是哪个”大约比较重视,咱们都想要分析一些“串口初始化的函数是哪个核心参数是哪个”的相关内容。那么小编在网上收集了一些有关“串口初始化的函数是哪个核心参数是哪个””的相关资讯,希望咱们能喜欢,兄弟们一起来了解一下吧!

#头号有新人#

STM32F4HAL库学习笔记之串口通讯 2步骤函数使用串口初始化串口中断串口接收串口发送串口使用流程总结步骤GPIO和串口时钟使能;初始化GPIO,复用;设置串口参数及中断;使能串口;编写中断服务函数。

函数使用

串口初始化

HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);

串口初始化函数,这个函数有一个入口参数huart(句柄), UART_HandleTypeDef 结构体指针类型,UART_HandleTypeDef 中包含了另外的结构体和参数,用到了句柄用来专门登记各应用对象在内存中的地址变化。

typedef struct{USART_TypeDef *Instance;UART_InitTypeDef Init;uint8_t *pTxBuffPtr;uint16_t TxXferSize;uint16_t TxXferCount;uint8_t *pRxBuffPtr;uint16_t RxXferSize;uint16_t RxXferCount;DMA_HandleTypeDef *hdmatx;DMA_HandleTypeDef *hdmarx;HAL_LockTypeDef Lock;__IO HAL_UART_StateTypeDef State;__IO uint32_t ErrorCode;}UART_HandleTypeDef;

UART_HandleTypeDef 中配置串口相关设置,在HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)调用时会使能响应串口,不需要另外单独使能。

执行HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)时会先调用MSP初始化回调函数进行MCU初始化,打开这个函数,在356行有

HAL_UART_MspInit(huart);

这句前面是看用户有没有自定义回调函数,判断是否执行这个。自定义下面会写。在这里面可以执行GPIO和中断相关配置。打开这个函数里面是

__weak void HAL_UART_MspInit(UART_HandleTypeDef *huart){UNUSED(huart);/* NOTE: This function should not be modified, when the callback is needed,the HAL_UART_MspInit could be implemented in the user file}

__weak是定义的一个弱函数,如果用户重新定义了这个函数,那么会优先执行用户定义的函数,可以重新定义这个函数配置与MCU级别相关的硬件初始化,这也是HAL库的优点。

所以HAL库中的初始化流程为:先初始化与MCU无关的串口协议,再初始化与MCU相关的硬件配置,这样在移植过程中只需要修改回调函数中的参数,即可完成适配。

回调函数:

函数A调用函数B的时候,通过参数将函数C的指针传递给了函数B(也就是函数B的入口参数写为函数C的指针)。在函数B执行过程中调用了函数C,这个动过叫做回调。在这个过程中先是被当作指针传入又被回调的函数C就是回调函数。

很多资料中说HAL_UART_MspInit(huart)是回调函数,其实这里只是写成了回调函数的样式,如果用户没有自定义回调函数,这个就可以看做是普通调用。

用户自定义回调函数:

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)UART_InitCallbacksToDefault(huart);if (huart->MspInitCallback == NULL){huart->MspInitCallback = HAL_UART_MspInit;}huart->MspInitCallback(huart);#elseHAL_UART_MspInit(huart);#endif

如果定义了USE_HAL_UART_REGISTER_CALLBACKS=1,那么用户可以自定义串口的初始化函数

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)void UART_InitCallbacksToDefault(UART_HandleTypeDef *huart){/* Init the UART Callback settings */huart->TxHalfCpltCallback = HAL_UART_TxHalfCpltCallback; /* Legacy weak TxHalfCpltCallback */huart->TxCpltCallback = HAL_UART_TxCpltCallback; /* Legacy weak TxCpltCallback */huart->RxHalfCpltCallback = HAL_UART_RxHalfCpltCallback; /* Legacy weak RxHalfCpltCallback */huart->RxCpltCallback = HAL_UART_RxCpltCallback; /* Legacy weak RxCpltCallback */huart->ErrorCallback = HAL_UART_ErrorCallback; /* Legacy weak ErrorCallback */huart->AbortCpltCallback = HAL_UART_AbortCpltCallback; /* Legacy weak AbortCpltCallback */huart->AbortTransmitCpltCallback = HAL_UART_AbortTransmitCpltCallback; /* Legacy weak AbortTransmitCpltCallback */huart->AbortReceiveCpltCallback = HAL_UART_AbortReceiveCpltCallback; /* Legacy weak AbortReceiveCpltCallback */}

这种状态就是回调函数了。

最后调用HAL_UART_Receive_IT函数开启接收中断,并设置接收缓冲以及最大接收数量。

串口中断

要使用中断,首先需要配置中断,由于NVIC属于MCU级别,所以放在HAL_UART_Msplnit中初始化,与库函数不同,HAL库中使用了两个函数配置中断:

void HAL_NVIC_EnableIRQ(IRQn_Type IRQn)//使能中断void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)//配置抢占优先级、子优先级。
串口接收编写中断服务函数
USARTX_IRQHandler

HAL库中定义了一个串口中断处理通用函数:

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart);

打开这个函数,找到如下部分:

if (errorflags == RESET){/* UART in mode Receiver -------------------------------------------------*/if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET)){UART_Receive_IT(huart);return;}}

isrflags 宏定义串口状态寄存器,cr1its控制状态寄存器,调用上面的通用函数后,会判断串口状态,是否进入UART_Receive_IT(huart),在这个函数中开始启动接收工作并调用串口数据处理函数:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

这个函数和上面一样是一个回调函数(用户可自定义)库中该函数的定义为弱函数,在这里进行串口数据处理,HAL库中所有的串口数据处理在这里面进行,所以这里面会判断是哪一个串口的数据再进行判断,剩下的流程就和用库函数处理是一样的了。

串口发送

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

这是HAL库中的串口发送函数,在标准库中串口发送只需要指定串口和数据,但是需要发送多个字节时是需要自己写函数的,如果要求比较高还要另外再做超时程序。在HAl库中使用这个函数可以定义发送长度,增加了超时处理,还是挺方便的,减少了开发的工作量。

调用后要等待发送完成

while(__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_TC)!=SET);

不然会有各种奇奇怪怪的错误。

串口使用流程

上面只是记录了各个函数的使用和原理,毕竟连函数的运行机制都没搞明白也写不出来好的程序,出了错误也找不到。

如果只是想用串口而已,知道下面写这些就可以了。

首先对串口与硬件级无关的参数进行初始化,对串口初始化

时会调用串口硬件级初始化的回调函数,所以要做好回调函数,在回调函数中做好与硬件相关的串口参数配置,这样便于移植。

编写串口中断服务程序,中断触发后会调用串口数据处理回调函数。注意:串口处理函数是公用的,串口中断服务函数不是。

串口发送只需要调用库中定义好的函数,指定串口、数据、长度、超时即可。但要注意等待发送完成。

总结

C功底不够扎实,库中有很多东西看不明白,各种指针也是绕来绕去,我当初为什么要选择这个专业QAQ,想想当条咸鱼也没什么不好的。

标签: #串口初始化的函数是哪个核心参数是哪个