从原子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()/); /*Configure the SysTick IRQ priority */
HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority ,); /* 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) < )
{
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();
  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();
}

  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,并且设置接收缓冲以及接收缓冲接收最大数据量;

  1. 获取此时对应的串口状态;
  2. 若此时串口空闲或串口正在处理发送,进入下一步判断;
  3. 将数据放入接收缓冲中,并将接收的数据长度放入相应的接收判断中;
  4. 置位无错误标志位;
  5. 如果此时在发送则为发送和接收同时进行标志,若总线空闲则为接收进行标志;
  6.   使能串口中断: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 = ; tmp_state = huart->State;
if((tmp_state == HAL_UART_STATE_READY) || (tmp_state == HAL_UART_STATE_BUSY_TX))
{
if((pData == NULL ) || (Size == ))
{
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,,);
#endif
}
}

解析USART1_IRQHandler(void):

这段函数主要是两个部分:

  • 对中断标志位判断后处理;
  • 超时检测:
void USART1_IRQHandler(void)
{
u32 timeout=;
HAL_UART_IRQHandler(&UART1_Handler); timeout=;
while (HAL_UART_GetState(&UART1_Handler) != HAL_UART_STATE_READY)
{
timeout++;
if(timeout>HAL_MAX_DELAY) break; } timeout=;
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 = , tmp_it_source = ; 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 = ; 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 += ;
}
else
{
*tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
huart->pRxBuffPtr += ;
}
}
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 == )
{
__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 = ;
while(HAL_UART_GetState(&UART1_Handler) != HAL_UART_STATE_READY)
{
  timeout++;
  if(timeout>HAL_MAX_DELAY) break;
}

完成一次接收处理后,再次调用一次HAL_UART_Receive_IT来重新启动串口接收中断,并设置RxXferCount为1作为初始值;

timeout=;
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)==)
{
if(USART_RX_STA&0x4000)
{
if(aRxBuffer[]!=0x0a)USART_RX_STA=;
else USART_RX_STA|=0x8000;
}
else
{
if(aRxBuffer[]==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[] ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-))USART_RX_STA=;
}
}
}
}
}

解析主函数main():

主要是通过判断串口标志位USART_RX_STA来实现

  判断串口接收完成标志位;

  获取数据长度;

  将缓存数组中的数据传输出去;

  等待传输完成;

  清空串口接收完成标志位;

while()
{
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;
HAL_UART_Transmit(&UART1_Handler,(uint8_t*)USART_RX_BUF,len,);
while(__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_TC)!=SET);
USART_RX_STA=;
}
}

STM32F0_HAL库驱动描述——基于F1的USART串口IT中断实现解析的更多相关文章

  1. STM32F0_HAL库驱动描述——LL驱动程序概述

    LL驱动概述 低层(LL)驱动器旨在提供快速轻量级的专家导向层,它比硬件更接近硬件: 与HAL相反,LLAPI不适用于优化访问不是关键功能的外设设备,或者需要大量软件配置和/或复杂的高级堆栈(如USB ...

  2. STM32F0_HAL库驱动描述——HAL驱动程序概述

    HAL库文件结构: HAL驱动文件: 外设驱动API文件和头文件:包含了常见主要的通用API,其中ppp表示外设名称,如adc.usart.gpio.irda等: stm32f0xx_hal_ppp. ...

  3. 基于zynq 7020的串口UART中断实验

    1.参考 UG585,P1790[JokerのZYNQ7020]UART学会Zynq(27)UART中断驱动模式示例 2.理论知识 在ZYNQ的中断中有一个IOP的中断集,它包几个外设的中断,其中包含 ...

  4. thinkphp 标签库驱动

    任何一个模板引擎的功能都不可能是为你量身定制的,具有一个良好的可扩展机制也是模板引擎的另外一个考量,Smarty采用的是插件方法来实现扩展,Think\Template由于采用了标签库技术,比Smar ...

  5. 【STM32H7教程】第29章 STM32H7的USART串口基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第29章       STM32H7的USART串口基础知识和 ...

  6. UART学习之路(三)基于STM32F103的USART实验

    关于STM32串口的资料可以在RM0008 Reference Manual中找到,有中文版的资料.STM32F103支持5个串口,选取USART1用来实验,其对应的IO口为PA9和PA10.这次的实 ...

  7. uboot的GPIO驱动分析--基于全志的A10芯片【转】

    本文转载自:http://blog.csdn.net/lw2011cg/article/details/68954707 uboot的GPIO驱动分析--基于全志的A10芯片 转载至:http://b ...

  8. 判断OpenCV是否为共享库,Windows基于CMake编译Caffe需要opencv共享库

    判断OpenCV是否为共享库,Windows基于CMake编译Caffe需要opencv共享库 TLDR 只考虑windows下opencv预编译包的情况. 对于opencv2.4.x系列,cmake ...

  9. STM32F072从零配置工程-基于HAL库的串口UART中断配置

    先上一个采用串口直接传输的Demo: 此处的思路是完全采用HAL库来实现的,核心是运用HAL_UART_Transmit_IT和HAL_UART_Receive_IT两个函数来实现的,可以作为一个De ...

随机推荐

  1. Qt程序打包发布方法(使用官方提供的windeployqt工具)

    Qt程序打包发布方法(使用官方提供的windeployqt工具) 转自:http://tieba.baidu.com/p/3730103947?qq-pf-to=pcqq.group Qt 官方开发环 ...

  2. python selenium chrome 测试

    #coding=utf-8 from selenium import webdriver from selenium.webdriver.common.keys import Keys from se ...

  3. 活锁(livelock) 专题

    活锁(livelock) 活锁指的是任务或者执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试,失败,尝试,失败. 活锁和死锁的区别在于,处于活锁的实体是在不断的改变状态,所谓的“活”, 而处于 ...

  4. Win10《芒果TV》商店版更新v3.2.7:修复下载任务和会员下载权限异常

    在第89届奥斯卡颁奖典礼,<爱乐之城>摘获最佳导演.女主.摄影等六项大奖,<月光男孩>爆冷获最佳影片之际,Win10版<芒果TV>迅速更新至v3.2.7,主要是修复 ...

  5. oracle 使用db_link 导入导出小结

    客户有一个需求,是将一个库中的某个用户迁移到一台新的oracle服务器上,因数据量较小,并且不涉及版本的升级,所以可以采用创建一个dblink,然后通过这个dblink直接从源库将用户数据导出并导入到 ...

  6. Android签名打包

    生成正式的签名APK文件 1.使用AndroidStudio生成: 点击导航栏上的Build-->Generate Signed APK,弹出创建签名APK对话框(首次点击可能会提示输入操作系统 ...

  7. 如何让你的Sublime和Codeblocks支持C++11

    闲来没事看了一下C++11,比起C++0x多了很多新功能,像auto变量,智能指针等,g++4.7以上版本也提供了对C++11的支持,但是,如何在你的编辑器上执行C++11代码呢? 刚开始以为用法和以 ...

  8. win2003浏览器提示是否需要将当前访问的网站添加到自己信任的站点中去

    Win2003的操作系统,的确比其它操作系统在安全上增加了不少,这是为用户所考虑的.当然,既然提供了安全性,尤其是在上网的时候,可以禁止某些活动脚本的显示,这样,就可以多方面的避免在使用Win2003 ...

  9. java集合框架collection(6)继承结构图

    根据<java编程思想>里面的说法,java集合又叫容器,按照单槽和双槽分为两类,Collection和Map,这两个都是接口. 一.Collection Collection下面又分了三 ...

  10. python的实用函数

    >>> file=open('txt.txt','a') >>> print >> file,'hello,world' >>> fi ...