您的位置:首页 > 科技 > 能源 > 徐州自助建站模板_站长查询站长工具_网站制作工具_如何建网站详细步骤

徐州自助建站模板_站长查询站长工具_网站制作工具_如何建网站详细步骤

2025/4/16 4:44:49 来源:https://blog.csdn.net/AFK3060/article/details/145532237  浏览:    关键词:徐州自助建站模板_站长查询站长工具_网站制作工具_如何建网站详细步骤
徐州自助建站模板_站长查询站长工具_网站制作工具_如何建网站详细步骤

此实验使用单片机串口收发(中断接收),具体功能:

  1. 在没收到数据时,会隔一段时间就发送“请输入数据,以回车键结束”
  2. 在接受到数据时,将收到的字符发送回去(回显)
  3. LED0不断闪烁以证明系统运行

实验程序运行顺序和嵌套

未接收到数据

mainHAL_Initsys_stm32_clock_initdelay_initusart_initled_initwhile(1) //进入循环printf("请输入数据,以回车键结束\r\n");delay_ms(10);

接收到数据(触发串口中断)

mainHAL_Initsys_stm32_clock_initdelay_initusart_initled_initwhile(1) //进入循环printf("请输入数据,以回车键结束\r\n");delay_ms(10);USART_UX_IRQHandler // 即USART1_IRQHandler,此时串口IO接收到数据HAL_UART_IRQHandler // HAL库公共处理函数UART_Receive_ITHAL_UART_RxCpltCallback //用户自己实现的数据处理HAL_UART_Receive_IT //每次数据处理完都要调用一次中断接收USART_UX_IRQHandler //上个字节接收处理完毕,现在接收到第二个字节,第二次触发串口中断HAL_UART_IRQHandler	UART_Receive_ITHAL_UART_RxCpltCallbackHAL_UART_Receive_IT...... //直到数据全部接收完毕printf("\r\n您发送的消息为:\r\n"); // 接收完毕后就开始回显HAL_UART_Transmit // 发送接收到的数据 while(__HAL_UART_GET_FLAG!=SET); // 等待发送结束 printf("请输入数据,以回车键结束\r\n"); // 回显完毕,继续回到没接收到数据的状态delay_ms(10);

发送

HAL库的发送很简单,硬件初始化完成后,使用对应的函数即可发送,仅需两行完成发送

HAL_UART_Transmit(&g_uart1_handle,(uint8_t*)g_usart_rx_buf,len,1000);    /* 发送接收到的数据 */while(__HAL_UART_GET_FLAG(&g_uart1_handle,UART_FLAG_TC)!=SET);           /* 等待发送结束 */

其中g_uart1_handle是串口号,g_usart_rx_buf是要发送的字符串,len是发送的长度(单位字节),1000是超时时间,如果到这个时间还没有发送出去则超时;然后__HAL_UART_GET_FLAG等待发送结束

如何使用printf发送?需要重写fputc函数,将下面这段代码加入usart.h内即可

/******************************************************************************************/
/* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */#if 1
#if (__ARMCC_VERSION >= 6010050)                    /* 使用AC6编译器时 */
__asm(".global __use_no_semihosting\n\t");          /* 声明不使用半主机模式 */
__asm(".global __ARM_use_no_argv \n\t");            /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */#else
/* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
#pragma import(__use_no_semihosting)struct __FILE
{int handle;/* Whatever you require here. If the only file you are using is *//* standard output using printf() for debugging, no file handling *//* is required. */
};#endif/* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
int _ttywrch(int ch)
{ch = ch;return ch;
}/* 定义_sys_exit()以避免使用半主机模式 */
void _sys_exit(int x)
{x = x;
}char *_sys_command_string(char *cmd, int len)
{return NULL;
}/* FILE 在 stdio.h里面定义. */
FILE __stdout;/* 重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
int fputc(int ch, FILE *f)
{while ((USART1->SR & 0X40) == 0);               /* 等待上一个字符发送完成 */USART1->DR = (uint8_t)ch;                       /* 将要发送的字符 ch 写入到DR寄存器 */return ch;
}
#endif
/***********************************************END*******************************************/

实际可以看到,fputc是往USART1的DR寄存器中直接写入数据

串口初始化

usart.h

#ifndef _USART_H
#define _USART_H#include "stdio.h"
#include "./SYSTEM/sys/sys.h"/*******************************************************************************************************/
/* 引脚 和 串口 定义 * 默认是针对USART1的.* 注意: 通过修改这12个宏定义,可以支持USART1~UART7任意一个串口.*/#define USART_TX_GPIO_PORT              GPIOA
#define USART_TX_GPIO_PIN               GPIO_PIN_9
#define USART_TX_GPIO_AF                GPIO_AF7_USART1
#define USART_TX_GPIO_CLK_ENABLE()      do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)   /* 发送引脚时钟使能 */#define USART_RX_GPIO_PORT              GPIOA
#define USART_RX_GPIO_PIN               GPIO_PIN_10
#define USART_RX_GPIO_AF                GPIO_AF7_USART1
#define USART_RX_GPIO_CLK_ENABLE()      do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)   /* 接收引脚时钟使能 */#define USART_UX                        USART1
#define USART_UX_IRQn                   USART1_IRQn
#define USART_UX_IRQHandler             USART1_IRQHandler
#define USART_UX_CLK_ENABLE()           do{ __HAL_RCC_USART1_CLK_ENABLE(); }while(0)  /* USART1 时钟使能 *//*******************************************************************************************************/#define USART_REC_LEN   200                     /* 定义最大接收字节数 200 */
#define USART_EN_RX     1                       /* 使能(1)/禁止(0)串口1接收 */
#define RXBUFFERSIZE    1                       /* 缓存大小 */extern UART_HandleTypeDef g_uart1_handle;       /* UART句柄 */extern uint8_t  g_usart_rx_buf[USART_REC_LEN];  /* 接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 */
extern uint16_t g_usart_rx_sta;                 /* 接收状态标记 */
extern uint8_t g_rx_buffer[RXBUFFERSIZE];       /* HAL库USART接收Buffer */void usart_init(uint32_t baudrate);             /* 串口初始化函数 */#endif

进行一些宏定义

串口初始化函数

/*** @brief       串口X初始化函数* @param       baudrate: 波特率, 根据自己需要设置波特率值* @note        注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.*              这里的USART的时钟源在sys_stm32_clock_init()函数中已经设置过了.* @retval      无*/
void usart_init(uint32_t baudrate)
{g_uart1_handle.Instance = USART_UX;                         /* USART1 */g_uart1_handle.Init.BaudRate = baudrate;                    /* 波特率 */g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B;        /* 字长为8位数据格式 */g_uart1_handle.Init.StopBits = UART_STOPBITS_1;             /* 一个停止位 */g_uart1_handle.Init.Parity = UART_PARITY_NONE;              /* 无奇偶校验位 */g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;        /* 无硬件流控 */g_uart1_handle.Init.Mode = UART_MODE_TX_RX;                 /* 收发模式 */HAL_UART_Init(&g_uart1_handle);                             /* HAL_UART_Init()会使能UART1 *//* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);
}/*** @brief       UART底层初始化函数* @param       huart: UART句柄类型指针* @note        此函数会被HAL_UART_Init()调用*              完成时钟使能,引脚配置,中断配置* @retval      无*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{GPIO_InitTypeDef gpio_init_struct;if(huart->Instance == USART_UX)                             /* 如果是串口1,进行串口1 MSP初始化 */{USART_UX_CLK_ENABLE();                                  /* USART1 时钟使能 */USART_TX_GPIO_CLK_ENABLE();                             /* 发送引脚时钟使能 */USART_RX_GPIO_CLK_ENABLE();                             /* 接收引脚时钟使能 */gpio_init_struct.Pin = USART_TX_GPIO_PIN;               /* TX引脚 */gpio_init_struct.Mode = GPIO_MODE_AF_PP;                /* 复用推挽 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */gpio_init_struct.Alternate = USART_TX_GPIO_AF;          /* 复用为USART1 */HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct);   /* 初始化发送引脚 */gpio_init_struct.Pin = USART_RX_GPIO_PIN;               /* RX引脚 */gpio_init_struct.Alternate = USART_RX_GPIO_AF;          /* 复用为USART1 */HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct);   /* 初始化接收引脚 */#if USART_EN_RXHAL_NVIC_EnableIRQ(USART_UX_IRQn);                      /* 使能USART1中断通道 */HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3);              /* 抢占优先级3,子优先级3 */
#endif}
}

在usart_init中实例化一个串口初始化结构体,对其赋值后调用HAL库自带的HAL_UART_Init,若想要开启串口中断,还需调用一次HAL_UART_Receive_IT,这也是HAL库自带的函数
串口初始化结构体这个参数最终会传入UART_SetConfig这个HAL库自带的函数,其内部才会真正的读写串口外设寄存器

/*** @brief  Initializes the UART mode according to the specified parameters in*         the UART_InitTypeDef and create the associated handle.* @param  huart  Pointer to a UART_HandleTypeDef structure that contains*                the configuration information for the specified UART module.* @retval HAL status*/
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)
{/* Check the UART handle allocation */if (huart == NULL){return HAL_ERROR;}/* Check the parameters */if (huart->Init.HwFlowCtl != UART_HWCONTROL_NONE){/* The hardware flow control is available only for USART1, USART2, USART3 and USART6.Except for STM32F446xx devices, that is available for USART1, USART2, USART3, USART6, UART4 and UART5.*/assert_param(IS_UART_HWFLOW_INSTANCE(huart->Instance));assert_param(IS_UART_HARDWARE_FLOW_CONTROL(huart->Init.HwFlowCtl));}else{assert_param(IS_UART_INSTANCE(huart->Instance));}assert_param(IS_UART_WORD_LENGTH(huart->Init.WordLength));assert_param(IS_UART_OVERSAMPLING(huart->Init.OverSampling));if (huart->gState == HAL_UART_STATE_RESET){/* Allocate lock resource and initialize it */huart->Lock = HAL_UNLOCKED;#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)UART_InitCallbacksToDefault(huart);if (huart->MspInitCallback == NULL){huart->MspInitCallback = HAL_UART_MspInit;}/* Init the low level hardware */huart->MspInitCallback(huart);
#else/* Init the low level hardware : GPIO, CLOCK */HAL_UART_MspInit(huart);
#endif /* (USE_HAL_UART_REGISTER_CALLBACKS) */}huart->gState = HAL_UART_STATE_BUSY;/* Disable the peripheral */__HAL_UART_DISABLE(huart);/* Set the UART Communication parameters */UART_SetConfig(huart);/* In asynchronous mode, the following bits must be kept cleared:- LINEN and CLKEN bits in the USART_CR2 register,- SCEN, HDSEL and IREN  bits in the USART_CR3 register.*/CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN));CLEAR_BIT(huart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN));/* Enable the peripheral */__HAL_UART_ENABLE(huart);/* Initialize the UART state */huart->ErrorCode = HAL_UART_ERROR_NONE;huart->gState = HAL_UART_STATE_READY;huart->RxState = HAL_UART_STATE_READY;return HAL_OK;
}

HAL库自带的串口初始化函数很长,里面进行了很多对参数的判断处理,这些不是主要的,其主要执行了HAL_UART_MspInit和UART_SetConfig。HAL_UART_MspInit是HAL库声明的虚函数,需要用户自己编写,在这个函数内用户要自己实现串口IO的初始化和中断NVIC使能配置;UART_SetConfig是HAL库自己实现的函数,里面主要是对串口寄存器进行配置

/*** @brief       UART底层初始化函数* @param       huart: UART句柄类型指针* @note        此函数会被HAL_UART_Init()调用*              完成时钟使能,引脚配置,中断配置* @retval      无*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{GPIO_InitTypeDef gpio_init_struct;if(huart->Instance == USART_UX)                             /* 如果是串口1,进行串口1 MSP初始化 */{USART_UX_CLK_ENABLE();                                  /* USART1 时钟使能 */USART_TX_GPIO_CLK_ENABLE();                             /* 发送引脚时钟使能 */USART_RX_GPIO_CLK_ENABLE();                             /* 接收引脚时钟使能 */gpio_init_struct.Pin = USART_TX_GPIO_PIN;               /* TX引脚 */gpio_init_struct.Mode = GPIO_MODE_AF_PP;                /* 复用推挽 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */gpio_init_struct.Alternate = USART_TX_GPIO_AF;          /* 复用为USART1 */HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct);   /* 初始化发送引脚 */gpio_init_struct.Pin = USART_RX_GPIO_PIN;               /* RX引脚 */gpio_init_struct.Alternate = USART_RX_GPIO_AF;          /* 复用为USART1 */HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct);   /* 初始化接收引脚 */#if USART_EN_RXHAL_NVIC_EnableIRQ(USART_UX_IRQn);                      /* 使能USART1中断通道 */HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3);              /* 抢占优先级3,子优先级3 */
#endif}
}

HAL_UART_MspInit内实现了串口GPIO的初始化,如果需要串口接收中断,则在这也进行配置,可以发现,HAL库声明这个虚函数就是为了用户能自由配置串口的IO

HAL库接收(中断接收)

函数调用与嵌套

USART_UX_IRQHandler // 第一个字节HAL_UART_IRQHandlerUART_Receive_ITHAL_UART_RxCpltCallbackHAL_UART_Receive_IT
USART_UX_IRQHandler // 第二个字节HAL_UART_IRQHandlerUART_Receive_ITHAL_UART_RxCpltCallbackHAL_UART_Receive_IT......

可以看到,当串口接收到数据后,会立即触发串口中断,进入USART_UX_IRQHandler,在里面HAL库插入了一个公共串口处理函数HAL_UART_IRQHandler,里面有很多判断和错误处理,主要是调用了一次UART_Receive_IT,在其内部又调用串口回调函数HAL_UART_RxCpltCallback,每次仅接受和处理一字节数据,处理完又调用HAL_UART_Receive_IT以开启串口中断,等到下个字节来临触发串口中断又进入USART_UX_IRQHandler,直到把所有数据接收完毕

/*** @brief       串口1中断服务函数* @param       无* @retval      无*/
void USART_UX_IRQHandler(void)
{ 
#if SYS_SUPPORT_OS                              /* 使用OS */OSIntEnter();    
#endifHAL_UART_IRQHandler(&g_uart1_handle);       /* 调用HAL库中断处理公用函数 */#if SYS_SUPPORT_OS                              /* 使用OS */OSIntExit();
#endif
}
~~~~```
uart.h中将USART1_IRQHandler宏定义为USART_UX_IRQHandler,USART1_IRQHandler就是写在启动汇编文件中的中断地址,其被映射为串口中断的处理函数,当硬件发现串口中断标志位被置高时,会立即跳转到该函数的地址并执行,无论标准库还是寄存器或HAL库,到目前为止都是一样的,串口接收到数据就跳到串口中断处理函数中。
其他的开发方式一般就在这里开始处理串口数据了,HAL库在这里插入了自己的公共处理函数,并加入了很多模式判断和错误处理,以保证复杂情况的处理```c
/*** @brief  This function handles UART interrupt request.* @param  huart  Pointer to a UART_HandleTypeDef structure that contains*                the configuration information for the specified UART module.* @retval None*/
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{uint32_t isrflags   = READ_REG(huart->Instance->SR);uint32_t cr1its     = READ_REG(huart->Instance->CR1);uint32_t cr3its     = READ_REG(huart->Instance->CR3);uint32_t errorflags = 0x00U;uint32_t dmarequest = 0x00U;/* If no error occurs */errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));if (errorflags == RESET){/* UART in mode Receiver -------------------------------------------------*/if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET)){UART_Receive_IT(huart);return;}}/* If some errors occur */if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET))){/* UART parity error interrupt occurred ----------------------------------*/if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET)){huart->ErrorCode |= HAL_UART_ERROR_PE;}/* UART noise error interrupt occurred -----------------------------------*/if (((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET)){huart->ErrorCode |= HAL_UART_ERROR_NE;}/* UART frame error interrupt occurred -----------------------------------*/if (((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET)){huart->ErrorCode |= HAL_UART_ERROR_FE;}/* UART Over-Run interrupt occurred --------------------------------------*/if (((isrflags & USART_SR_ORE) != RESET) && (((cr1its & USART_CR1_RXNEIE) != RESET) || ((cr3its & USART_CR3_EIE) != RESET))){huart->ErrorCode |= HAL_UART_ERROR_ORE;}/* Call UART Error Call back function if need be --------------------------*/if (huart->ErrorCode != HAL_UART_ERROR_NONE){/* UART in mode Receiver -----------------------------------------------*/if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET)){UART_Receive_IT(huart);}/* If Overrun error occurs, or if any error occurs in DMA mode reception,consider error as blocking */dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest){/* Blocking error : transfer is abortedSet the UART state ready to be able to start again the process,Disable Rx Interrupts, and disable Rx DMA request, if ongoing */UART_EndRxTransfer(huart);/* Disable the UART DMA Rx request if enabled */if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)){CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);/* Abort the UART DMA Rx stream */if (huart->hdmarx != NULL){/* Set the UART DMA Abort callback :will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;if (HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK){/* Call Directly XferAbortCallback function in case of error */huart->hdmarx->XferAbortCallback(huart->hdmarx);}}else{/* Call user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)/*Call registered error callback*/huart->ErrorCallback(huart);
#else/*Call legacy weak error callback*/HAL_UART_ErrorCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */}}else{/* Call user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)/*Call registered error callback*/huart->ErrorCallback(huart);
#else/*Call legacy weak error callback*/HAL_UART_ErrorCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */}}else{/* Non Blocking error : transfer could go on.Error is notified to user through user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)/*Call registered error callback*/huart->ErrorCallback(huart);
#else/*Call legacy weak error callback*/HAL_UART_ErrorCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */huart->ErrorCode = HAL_UART_ERROR_NONE;}}return;} /* End if some error occurs *//* Check current reception Mode :If Reception till IDLE event has been selected : */if (  (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)&&((isrflags & USART_SR_IDLE) != 0U)&&((cr1its & USART_SR_IDLE) != 0U)){__HAL_UART_CLEAR_IDLEFLAG(huart);/* Check if DMA mode is enabled in UART */if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)){/* DMA mode enabled *//* Check received length : If all expected data are received, do nothing,(DMA cplt callback will be called).Otherwise, if at least one data has already been received, IDLE event is to be notified to user */uint16_t nb_remaining_rx_data = (uint16_t) __HAL_DMA_GET_COUNTER(huart->hdmarx);if (  (nb_remaining_rx_data > 0U)&&(nb_remaining_rx_data < huart->RxXferSize)){/* Reception is not complete */huart->RxXferCount = nb_remaining_rx_data;/* In Normal mode, end DMA xfer and HAL UART Rx process*/if (huart->hdmarx->Init.Mode != DMA_CIRCULAR){/* Disable PE and ERR (Frame error, noise error, overrun error) interrupts */CLEAR_BIT(huart->Instance->CR1, USART_CR1_PEIE);CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);/* Disable the DMA transfer for the receiver request by resetting the DMAR bitin the UART CR3 register */CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);/* At end of Rx process, restore huart->RxState to Ready */huart->RxState = HAL_UART_STATE_READY;huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);/* Last bytes received, so no need as the abort is immediate */(void)HAL_DMA_Abort(huart->hdmarx);}
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)/*Call registered Rx Event callback*/huart->RxEventCallback(huart, (huart->RxXferSize - huart->RxXferCount));
#else/*Call legacy weak Rx Event callback*/HAL_UARTEx_RxEventCallback(huart, (huart->RxXferSize - huart->RxXferCount));
#endif}return;}else{/* DMA mode not enabled *//* Check received length : If all expected data are received, do nothing.Otherwise, if at least one data has already been received, IDLE event is to be notified to user */uint16_t nb_rx_data = huart->RxXferSize - huart->RxXferCount;if (  (huart->RxXferCount > 0U)&&(nb_rx_data > 0U) ){/* Disable the UART Parity Error Interrupt and RXNE interrupts */CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));/* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);/* Rx process is completed, restore huart->RxState to Ready */huart->RxState = HAL_UART_STATE_READY;huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)/*Call registered Rx complete callback*/huart->RxEventCallback(huart, nb_rx_data);
#else/*Call legacy weak Rx Event callback*/HAL_UARTEx_RxEventCallback(huart, nb_rx_data);
#endif}return;}}/* UART in mode Transmitter ------------------------------------------------*/if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET)){UART_Transmit_IT(huart);return;}/* UART in mode Transmitter end --------------------------------------------*/if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET)){UART_EndTransmit_IT(huart);return;}
}

HAL的公共串口处理函数,内容很多,大多是在判断模式或错误处理,对于正常流程,主要是调用了UART_Receive_IT

/*** @brief  Receives an amount of data in non blocking mode* @param  huart  Pointer to a UACRT_HandleTypeDef structure that contains*                the configuration information for the specified UART module.* @retval HAL status*/
static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{uint8_t  *pdata8bits;uint16_t *pdata16bits;/* Check that a Rx process is ongoing */if (huart->RxState == HAL_UART_STATE_BUSY_RX){if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE)){pdata8bits  = NULL;pdata16bits = (uint16_t *) huart->pRxBuffPtr;*pdata16bits = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);huart->pRxBuffPtr += 2U;}else{pdata8bits = (uint8_t *) huart->pRxBuffPtr;pdata16bits  = NULL;if ((huart->Init.WordLength == UART_WORDLENGTH_9B) || ((huart->Init.WordLength == UART_WORDLENGTH_8B) && (huart->Init.Parity == UART_PARITY_NONE))){*pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);}else{*pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);}huart->pRxBuffPtr += 1U;}if (--huart->RxXferCount == 0U){/* Disable the UART Data Register not empty Interrupt */__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);/* Disable the UART Parity Error Interrupt */__HAL_UART_DISABLE_IT(huart, UART_IT_PE);/* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */__HAL_UART_DISABLE_IT(huart, UART_IT_ERR);/* Rx process is completed, restore huart->RxState to Ready */huart->RxState = HAL_UART_STATE_READY;/* Check current reception Mode :If Reception till IDLE event has been selected : */if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE){/* Disable IDLE interrupt */CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)/*Call registered Rx Event callback*/huart->RxEventCallback(huart, huart->RxXferSize);
#else/*Call legacy weak Rx Event callback*/HAL_UARTEx_RxEventCallback(huart, huart->RxXferSize);
#endif}else{/* Standard reception API called */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)		  /*Call registered Rx complete callback*/huart->RxCpltCallback(huart);
#else/*Call legacy weak Rx complete callback*/HAL_UART_RxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */}huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;return HAL_OK;}return HAL_OK;}else{return HAL_BUSY;}
}

HAL库自己的中断接收函数,主要是调用了HAL_UART_RxCpltCallback,即用户自己编写的回调函数

/*** @brief       Rx传输回调函数* @param       huart: UART句柄类型指针* @retval      无*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART_UX)             /* 如果是串口1 */{if((g_usart_rx_sta & 0x8000) == 0)      /* 接收未完成 */{if(g_usart_rx_sta & 0x4000)         /* 接收到了0x0d */{if(g_rx_buffer[0] != 0x0a) {g_usart_rx_sta = 0;         /* 接收错误,重新开始 */}else {g_usart_rx_sta |= 0x8000;   /* 接收完成了 */}}else                                /* 还没收到0X0D */{if(g_rx_buffer[0] == 0x0d){g_usart_rx_sta |= 0x4000;}else{g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = g_rx_buffer[0] ;g_usart_rx_sta++;if(g_usart_rx_sta > (USART_REC_LEN - 1)){g_usart_rx_sta = 0;     /* 接收数据错误,重新开始接收 */}}}}HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);}
}

每次接收到一字节的数据时就会进一次回调函数,在其中对这一字节的数据进行处理,处理完后要调用HAL_UART_Receive_IT以开启串口接收中断来接收下一个字节

/*** @brief  Receives an amount of data in non blocking mode.* @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),*         the received data is handled as a set of u16. In this case, Size must indicate the number*         of u16 available through pData.* @param  huart Pointer to a UART_HandleTypeDef structure that contains*               the configuration information for the specified UART module.* @param  pData Pointer to data buffer (u8 or u16 data elements).* @param  Size  Amount of data elements (u8 or u16) to be received.* @retval HAL status*/
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{/* Check that a Rx process is not already ongoing */if (huart->RxState == HAL_UART_STATE_READY){if ((pData == NULL) || (Size == 0U)){return HAL_ERROR;}/* Process Locked */__HAL_LOCK(huart);/* Set Reception type to Standard reception */huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;return(UART_Start_Receive_IT(huart, pData, Size));}else{return HAL_BUSY;}
}

开启串口接收中断,每次回调函数处理完数据后,其实串口接收中断是被失能的,需要调用这个函数来重新使能串口接收中断

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com