这个文章的主要总结的是程序在HAL库里面初始化和执行过程,同时对于一些中断的响应执行过程
GPIO
对于普通的GPIO的初始化没有任何回调函数
对于使用了中断的GPIO,中断的开启和优先级设置时在初始化时完成,但是其中断的响应是调用首先调用HAL库提供的中断处理函数HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_8);在这个函数里面通过回调HAL_GPIO_EXTI_Callback(GPIO_Pin);函数完成中断的响应和处理,因此这个函数需要我们自己编写代码实现
串口
对于串口的初始化调用的函数为HAL_UART_Init,但是这个函数会回调一个函数HAL_UART_MspInit 这个函数需要我们自己编写完成,主要完成的功能是对对应外设引脚的初始化和中断设置操作
串口的中断发送和接收,使用这两个函数
中断发送和接收完成的处理过程为:
通过中断服务程序调用 HAL_UART_IRQHandler(&huart1),并回调如下两个函数(接收和中断完成调用的回调函数不一样),这两个函数如果使用中断都需要我们自己编写完成
ADC
初始化使用函数HAL_ADC_Init(&hadc),但是会回调函数HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)完成初始化。
注意上面的仅是初始化了ADC的功能,但是ADC并不知道去采集那个通道的数据
需通过如下设置,完成通道的采样设置
如果ADC使用了中断
中断调用这个函数HAL_ADC_IRQHandler(&hadc);并回调HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)ADC转换完成回调函数
DMA
初始化
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(adcHandle->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspInit 0 */
/* USER CODE END ADC1_MspInit 0 */
/* ADC1 clock enable */
__HAL_RCC_ADC1_CLK_ENABLE();
/**ADC GPIO Configuration
PA1 ------> ADC_IN1
PA4 ------> ADC_IN4
*/
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* ADC1 DMA Init */
/* ADC Init */
hdma_adc.Instance = DMA1_Channel1;
hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc.Init.Mode = DMA_CIRCULAR;
hdma_adc.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_adc) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc);
/* USER CODE BEGIN ADC1_MspInit 1 */
/* USER CODE END ADC1_MspInit 1 */
}
}
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{
if(adcHandle->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspDeInit 0 */
/* USER CODE END ADC1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_ADC1_CLK_DISABLE();
/**ADC GPIO Configuration
PA1 ------> ADC_IN1
PA4 ------> ADC_IN4
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1|GPIO_PIN_4);
/* ADC1 DMA DeInit */
HAL_DMA_DeInit(adcHandle->DMA_Handle);
/* USER CODE BEGIN ADC1_MspDeInit 1 */
/* USER CODE END ADC1_MspDeInit 1 */
}
}
如果DMA需要打开中断,在任意地方调用这两个函数即可
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
DMA中断的执行过程
中断响应函数调用
HAL_DMA_IRQHandler(&hdma_adc);,并回调HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)这个函数
这里有个需要注意的点,如果直接跟踪函数HAL_DMA_IRQHandler,是无法看到对应回调的实现的,而是通过函数指针调用的这个函数(具体的函数指针是:hdma->XferCpltCallback(hdma);),这指针的初始化是在打开DMA功能时赋值进去的即这个函数HAL_ADC_Start_DMA(这里有这么一段:
这函数函数就是后期我们需要实现,分别转换完成,半转换,错误时的调用完成的)