从原子F103 HAL库基础串口例程来看HAL程序结构;
从main函数开始,首先是HAL库两个函数的初始化:
- HAL_Init();
- Stm32_Clock_Init(RCC_PLL_MUL9);
解析HAL_Init()
分为四个部分:
A:启用FLASH预取缓存区;
B:设置中断组优先级(由于F0是M0系列的,因此没有组优先级一说);
C:配置SYSTICK时钟;
D:初始化低等级的硬件;
HAL_StatusTypeDef HAL_Init(void) { /* Configure Flash prefetch */ #if (PREFETCH_ENABLE != 0) #if defined(STM32F101x6) || defined(STM32F101xB) || defined(STM32F101xE) || defined(STM32F101xG) || \ defined(STM32F102x6) || defined(STM32F102xB) || \ defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) || \ defined(STM32F105xC) || defined(STM32F107xC) /* Prefetch buffer is not available on value line devices */ __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); #endif #endif /* PREFETCH_ENABLE */ /* Set Interrupt Group Priority */ HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); /* Use systick as time base source and configure 1ms tick (default clock after Reset is MSI) */ HAL_InitTick(TICK_INT_PRIORITY); /* Init the low level hardware */ HAL_MspInit(); /* Return function status */ return HAL_OK; }
A:启用预取缓存区
预取缓存区通常用于通过ICode总线进行指令提取,且在复位后启用;
/** * @brief Enable the FLASH prefetch buffer. * @retval None */ #define __HAL_FLASH_PREFETCH_BUFFER_ENABLE() (FLASH->ACR |= FLASH_ACR_PRFTBE)
B:设置中断优先级组
通常PRIORITY GROUP存在于M3和M4以上的内核中,采用M0的话不存在该项设置;
/** * @brief Sets the priority grouping field (pre-emption priority and subpriority) * using the required unlock sequence. * @param PriorityGroup: The priority grouping bits length. * This parameter can be one of the following values: * @arg NVIC_PRIORITYGROUP_0: 0 bits for pre-emption priority * 4 bits for subpriority * @arg NVIC_PRIORITYGROUP_1: 1 bits for pre-emption priority * 3 bits for subpriority * @arg NVIC_PRIORITYGROUP_2: 2 bits for pre-emption priority * 2 bits for subpriority * @arg NVIC_PRIORITYGROUP_3: 3 bits for pre-emption priority * 1 bits for subpriority * @arg NVIC_PRIORITYGROUP_4: 4 bits for pre-emption priority * 0 bits for subpriority * @note When the NVIC_PriorityGroup_0 is selected, IRQ pre-emption is no more possible. * The pending IRQ priority will be managed only by the subpriority. * @retval None */ void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup) { /* Check the parameters */ assert_param(IS_NVIC_PRIORITY_GROUP(PriorityGroup)); /* Set the PRIGROUP[10:8] bits according to the PriorityGroup parameter value */ NVIC_SetPriorityGrouping(PriorityGroup); }
C:配置SYSTICK时钟
/** * @brief This function configures the source of the time base. * The time source is configured to have 1ms time base with a dedicated * Tick interrupt priority. * @note This function is called automatically at the beginning of program after * reset by HAL_Init() or at any time when clock is reconfigured by HAL_RCC_ClockConfig(). * @note In the default implementation, SysTick timer is the source of time base. * It is used to generate interrupts at regular time intervals. * Care must be taken if HAL_Delay() is called from a peripheral ISR process, * The the SysTick interrupt must have higher priority (numerically lower) * than the peripheral interrupt. Otherwise the caller ISR process will be blocked. * The function is declared as __Weak to be overwritten in case of other * implementation in user file. * @param TickPriority: Tick interrupt priority. * @retval HAL status */ __weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) { /*Configure the SysTick to have interrupt in 1ms time basis*/ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); /*Configure the SysTick IRQ priority */ HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority ,0); /* Return function status */ return HAL_OK; }
解析:HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
通过层层拆解,可以看到SYSTICK的配置是通过设置寄存器LOAD、VAL、CTRL和NVIC的SCB_SHP、NVIC_IP来实现的;
/** * @brief Initializes the System Timer and its interrupt, and starts the System Tick Timer. * Counter is in free running mode to generate periodic interrupts. * @param TicksNumb: Specifies the ticks Number of ticks between two interrupts. * @retval status: - 0 Function succeeded. * - 1 Function failed. */ uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb) { return SysTick_Config(TicksNumb); } /** \brief System Tick Configuration \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. Counter is in free running mode to generate periodic interrupts. \param [in] ticks Number of ticks between two interrupts. \return 0 Function succeeded. \return 1 Function failed. \note When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b> must contain a vendor-specific implementation of this function. */ __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) { if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) { return (1UL); /* Reload value impossible */ } SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ return (0UL); /* Function successful */ } /** \brief Set Interrupt Priority \details Sets the priority of an interrupt. \note The priority cannot be set for every core interrupt. \param [in] IRQn Interrupt number. \param [in] priority Priority to set. */ __STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) { if ((int32_t)(IRQn) < 0) { SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } else { NVIC->IP[((uint32_t)(int32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } }
关于SysTick寄存器的介绍在M3权威指南中有详细的介绍;
关于NVIC这两个寄存器的配置
SCB->SHP系统处理程序优先级寄存器用来控制异常处理程序的优先级;
NVIC->IP中断优先级控制寄存器组设置响应优先级和抢占优先级;
解析:HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority ,0);
其中NVIC_SetPriority()的函数同上SysTick_Config()中设置的NVIC函数,都是配置中断的配置优先级组、抢占优先级和响应优先级;
/** * @brief Sets the priority of an interrupt. * @param IRQn: External interrupt number * This parameter can be an enumerator of IRQn_Type enumeration * (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f10xxx.h)) * @param PreemptPriority: The pre-emption priority for the IRQn channel. * This parameter can be a value between 0 and 15 * A lower priority value indicates a higher priority * @param SubPriority: the subpriority level for the IRQ channel. * This parameter can be a value between 0 and 15 * A lower priority value indicates a higher priority. * @retval None */ void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority) { uint32_t prioritygroup = 0x00; /* Check the parameters */ assert_param(IS_NVIC_SUB_PRIORITY(SubPriority)); assert_param(IS_NVIC_PREEMPTION_PRIORITY(PreemptPriority)); prioritygroup = NVIC_GetPriorityGrouping(); NVIC_SetPriority(IRQn, NVIC_EncodePriority(prioritygroup, PreemptPriority, SubPriority)); }
D:配置初始化的硬件,保持为空;
/** * @brief Initializes the Global MSP. * @param None * @retval None */ void HAL_MspInit(void) { }
解析Stm32_Clock_Init(RCC_PLL_MUL9);
主要是实现了两个配置:
- 时钟源配置
- 系统时钟SYSCLK配置
void Stm32_Clock_Init(u32 PLL) { HAL_StatusTypeDef ret = HAL_OK; RCC_OscInitTypeDef RCC_OscInitStructure; RCC_ClkInitTypeDef RCC_ClkInitStructure; RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE; RCC_OscInitStructure.HSEState=RCC_HSE_ON; RCC_OscInitStructure.HSEPredivValue=RCC_HSE_PREDIV_DIV1; RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON; RCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSE; RCC_OscInitStructure.PLL.PLLMUL=PLL; ret=HAL_RCC_OscConfig(&RCC_OscInitStructure); if(ret!=HAL_OK) while(1); RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2); RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1; RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV2; RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV1; ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_2); if(ret!=HAL_OK) while(1); }
RCC_OscInitStructure用来设置时钟源、使能相应的时钟源、时钟源分频和PLL时钟配置;
RCC_ClkInitStructure用来配置SYSCLK的HCLK、PCLK1和PCLK2;
这个与系统自带常规的时钟配置不同,采用的是手动的时钟配置;
解析delay_init(u8 SYSCLK);
主要是选择SysTick时钟是HCLK还是HCLK/8;通常选取SysTick=HCLK;
void delay_init(u8 SYSCLK) { HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); fac_us=SYSCLK; } /** * @brief Configures the SysTick clock source. * @param CLKSource: specifies the SysTick clock source. * This parameter can be one of the following values: * @arg SYSTICK_CLKSOURCE_HCLK_DIV8: AHB clock divided by 8 selected as SysTick clock source. * @arg SYSTICK_CLKSOURCE_HCLK: AHB clock selected as SysTick clock source. * @retval None */ void HAL_SYSTICK_CLKSourceConfig(uint32_t CLKSource) { /* Check the parameters */ assert_param(IS_SYSTICK_CLK_SOURCE(CLKSource)); if (CLKSource == SYSTICK_CLKSOURCE_HCLK) { SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK; } else { SysTick->CTRL &= ~SYSTICK_CLKSOURCE_HCLK; } }
解析uart_init(115200);
其配置串口和传统的库函数配置相似,从波特率、数据格式、极性、流处理和模式;
重点在最后一句话对IT的配置;
void uart_init(u32 bound) { UART1_Handler.Instance=USART1; UART1_Handler.Init.BaudRate=bound; UART1_Handler.Init.WordLength=UART_WORDLENGTH_8B; UART1_Handler.Init.StopBits=UART_STOPBITS_1; UART1_Handler.Init.Parity=UART_PARITY_NONE; UART1_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE; UART1_Handler.Init.Mode=UART_MODE_TX_RX; HAL_UART_Init(&UART1_Handler); HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE); }
根据注释给出的,该函数会开启接收中断,设置标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量;
- 获取此时对应的串口状态;
- 若此时串口空闲或串口正在处理发送,进入下一步判断;
- 将数据放入接收缓冲中,并将接收的数据长度放入相应的接收判断中;
- 置位无错误标志位;
- 如果此时在发送则为发送和接收同时进行标志,若总线空闲则为接收进行标志;
- 使能串口中断:UART_IT_PE、UART_IT_ERR和UART_IT_RXNE;
/** * @brief Receives an amount of data in non blocking mode * @param huart: Pointer to a UART_HandleTypeDef structure that contains * the configuration information for the specified UART module. * @param pData: Pointer to data buffer * @param Size: Amount of data to be received * @retval HAL status */ HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) { uint32_t tmp_state = 0; tmp_state = huart->State; if((tmp_state == HAL_UART_STATE_READY) || (tmp_state == HAL_UART_STATE_BUSY_TX)) { if((pData == NULL ) || (Size == 0)) { return HAL_ERROR; } /* Process Locked */ __HAL_LOCK(huart); huart->pRxBuffPtr = pData; huart->RxXferSize = Size; huart->RxXferCount = Size; huart->ErrorCode = HAL_UART_ERROR_NONE; /* Check if a transmit process is ongoing or not */ if(huart->State == HAL_UART_STATE_BUSY_TX) { huart->State = HAL_UART_STATE_BUSY_TX_RX; } else { huart->State = HAL_UART_STATE_BUSY_RX; } /* Process Unlocked */ __HAL_UNLOCK(huart); /* Enable the UART Parity Error Interrupt */ __HAL_UART_ENABLE_IT(huart, UART_IT_PE); /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */ __HAL_UART_ENABLE_IT(huart, UART_IT_ERR); /* Enable the UART Data Register not empty Interrupt */__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE); return HAL_OK; } else { return HAL_BUSY; } }
串口初始化有包含对应的硬件初始化:HAL_UART_MspInit(huart);
- 配置的核心在UART_SetConfig(huart);这句话中;
- HAL_UART_MspInit(huart);会在判断串口复位状态后进行重新初始化;
/** * @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 */ 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->State == HAL_UART_STATE_RESET) { /* Allocate lock resource and initialize it */ huart->Lock = HAL_UNLOCKED; /* Init the low level hardware */HAL_UART_MspInit(huart); } huart->State = 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->State= HAL_UART_STATE_READY; return HAL_OK; }
具体的硬件配置:GPIO
- 若USART1配置存在,则开启对应引脚GPIOA时钟、外设时钟、复位时钟;
- 配置对应的GPIOA;
- 同时若开启了USART1的接收打开了,则开启串口1的中断,并设置该中断优先级;
void HAL_UART_MspInit(UART_HandleTypeDef *huart) { GPIO_InitTypeDef GPIO_Initure; if(huart->Instance==USART1) { __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_AFIO_CLK_ENABLE(); GPIO_Initure.Pin=GPIO_PIN_9; GPIO_Initure.Mode=GPIO_MODE_AF_PP; GPIO_Initure.Pull=GPIO_PULLUP; GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA,&GPIO_Initure); GPIO_Initure.Pin=GPIO_PIN_10; GPIO_Initure.Mode=GPIO_MODE_AF_INPUT; HAL_GPIO_Init(GPIOA,&GPIO_Initure); #if EN_USART1_RX HAL_NVIC_EnableIRQ(USART1_IRQn); HAL_NVIC_SetPriority(USART1_IRQn,3,3); #endif } }
解析USART1_IRQHandler(void):
这段函数主要是两个部分:
- 对中断标志位判断后处理;
- 超时检测:
void USART1_IRQHandler(void) { u32 timeout=0; HAL_UART_IRQHandler(&UART1_Handler); timeout=0; while (HAL_UART_GetState(&UART1_Handler) != HAL_UART_STATE_READY) { timeout++; if(timeout>HAL_MAX_DELAY) break; } timeout=0; while(HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE) != HAL_OK) { timeout++; if(timeout>HAL_MAX_DELAY) break; } }
不同于传统的采用HAL库或库函数对中断标志的判断后进行处理,HAL库自带的中断处理会帮我们做这件事,并在判断完中断标志位后引用回调处理函数;
核心判断的方式是通过__HAL_UART_GET_FLAG()和__HAL_UART_GET_IT_SOURCE()这两个函数来获取此时的串口状态和中断标志位;
前面有很大一部分是对中断极性错误PE、格式错误FE、噪声错误NE、溢出错误ORE极性判断并置位串口句柄中错误标志位;
串口数据缓冲接收到数据、空闲线路检测以及传输完成三个判断是处理核心,分别对应UART_Receive_IT(huart);和UART_Transmit_IT(huart);以及UART_EndTransmit_IT(huart);
/** * @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 tmp_flag = 0, tmp_it_source = 0; tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_PE); tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE); /* UART parity error interrupt occurred ------------------------------------*/ if((tmp_flag != RESET) && (tmp_it_source != RESET)) { huart->ErrorCode |= HAL_UART_ERROR_PE; } tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_FE); tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR); /* UART frame error interrupt occurred -------------------------------------*/ if((tmp_flag != RESET) && (tmp_it_source != RESET)) { huart->ErrorCode |= HAL_UART_ERROR_FE; } tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_NE); /* UART noise error interrupt occurred -------------------------------------*/ if((tmp_flag != RESET) && (tmp_it_source != RESET)) { huart->ErrorCode |= HAL_UART_ERROR_NE; } tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_ORE); /* UART Over-Run interrupt occurred ----------------------------------------*/ if((tmp_flag != RESET) && (tmp_it_source != RESET)) { huart->ErrorCode |= HAL_UART_ERROR_ORE; } tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE); tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE); /* UART in mode Receiver ---------------------------------------------------*/ if((tmp_flag != RESET) && (tmp_it_source != RESET)) { UART_Receive_IT(huart); } tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_TXE); tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE); /* UART in mode Transmitter ------------------------------------------------*/ if((tmp_flag != RESET) && (tmp_it_source != RESET)) { UART_Transmit_IT(huart); } tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_TC); tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC); /* UART in mode Transmitter end --------------------------------------------*/ if((tmp_flag != RESET) && (tmp_it_source != RESET)) { UART_EndTransmit_IT(huart); } if(huart->ErrorCode != HAL_UART_ERROR_NONE) { /* Clear all the error flag at once */ __HAL_UART_CLEAR_PEFLAG(huart); /* Set the UART state ready to be able to start again the process */ huart->State = HAL_UART_STATE_READY; HAL_UART_ErrorCallback(huart); } }
这里在串口数据缓存寄存器接收到数据时使用了UART_Receive_IT(huart);来调用接收数据的回调处理函数;
- 这个函数的核心在于HAL_UART_RxCpltCallback(huart);这句调用回调处理函数的函数;
- 除此之外都在对接收缓存区中的数据进行处理;
- 判断传输计数后关闭中断,接受完成中断状态更新,并关闭PE和ERR中断,最后执行回调函数;
/** * @brief Receives an amount of data in non blocking mode * @param huart: Pointer to a UART_HandleTypeDef structure that contains * the configuration information for the specified UART module. * @retval HAL status */ static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart) { uint16_t* tmp; uint32_t tmp_state = 0; tmp_state = huart->State; if((tmp_state == HAL_UART_STATE_BUSY_RX) || (tmp_state == HAL_UART_STATE_BUSY_TX_RX)) { if(huart->Init.WordLength == UART_WORDLENGTH_9B) { tmp = (uint16_t*) huart->pRxBuffPtr; if(huart->Init.Parity == UART_PARITY_NONE) { *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF); huart->pRxBuffPtr += 2; } else { *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF); huart->pRxBuffPtr += 1; } } else { if(huart->Init.Parity == UART_PARITY_NONE) { *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF); } else { *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F); } } if(--huart->RxXferCount == 0) { __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE); /* Check if a transmit process is ongoing or not */ if(huart->State == HAL_UART_STATE_BUSY_TX_RX) { huart->State = HAL_UART_STATE_BUSY_TX; } else { /* 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); huart->State = HAL_UART_STATE_READY; } HAL_UART_RxCpltCallback(huart); return HAL_OK; } return HAL_OK; } else { return HAL_BUSY; } }
关于状态检测:
HAL_UART_STATE_READY是外设已初始化并可以使用标志位,通过检测这个标志位来确定向外设接收数据完成;
timeout = 0; while(HAL_UART_GetState(&UART1_Handler) != HAL_UART_STATE_READY) { timeout++; if(timeout>HAL_MAX_DELAY) break; }
完成一次接收处理后,再次调用一次HAL_UART_Receive_IT来重新启动串口接收中断,并设置RxXferCount为1作为初始值;
timeout=0; while(HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE) != HAL_OK) { timeout++; if(timeout>HAL_MAX_DELAY) break; }
解析HAL_UART_RxCpltCallback()
其功能实现很简单,就是判断结束标志是否是回车符(0x0d 0x0a),同时将数据缓存接收到缓存数组中;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance==USART1) { if((USART_RX_STA&0x8000)==0) { if(USART_RX_STA&0x4000) { if(aRxBuffer[0]!=0x0a)USART_RX_STA=0; else USART_RX_STA|=0x8000; } else { if(aRxBuffer[0]==0x0d)USART_RX_STA|=0x4000; else { USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ; USART_RX_STA++; if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0; } } } } }
解析主函数main():
主要是通过判断串口标志位USART_RX_STA来实现
判断串口接收完成标志位;
获取数据长度;
将缓存数组中的数据传输出去;
等待传输完成;
清空串口接收完成标志位;
while(1) { if(USART_RX_STA&0x8000) { len=USART_RX_STA&0x3fff; HAL_UART_Transmit(&UART1_Handler,(uint8_t*)USART_RX_BUF,len,1000); while(__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_TC)!=SET); USART_RX_STA=0; } }
来源:https://www.cnblogs.com/lpfdezh/p/11039956.html