介绍 此文会记录stm32中外部中断和定时器中断的使用方法及注意事项。中断可以一定程度上模拟计算机中的多线程进程,但需要特别注意优先级问题(特别是HAL_DELAY函数优先级冲突导致的卡死问题)。
 
外部中断 可通过外部按钮,IO口等外部控制中断。
EXTI.c 选择IO口后选择”GPIO_EXTIx”,根据端点情况GPIP mode选rising edge或falling edge。进入NVIC enable对应通道,设置优先级后生成代码。
完成后加入”void EXTIx_IRQHandler(void)”函数(注意EXTI0会在system文件中重复定义,注销掉即可),”void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)”函数,这两个函数名是确定的,不能改变。注意不要使用HAL_DELAY函数,解决方法之后有机会去研究下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 /** Configure pins as         * Analog         * Input         * Output         * EVENT_OUT         * EXTI */ void EXTI_Init(void) {   GPIO_InitTypeDef GPIO_InitStruct = {0};   /* GPIO Ports Clock Enable */   __HAL_RCC_GPIOD_CLK_ENABLE();   __HAL_RCC_GPIOA_CLK_ENABLE();   /*Configure GPIO pin : PA0 */   GPIO_InitStruct.Pin = GPIO_PIN_0;   GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;   GPIO_InitStruct.Pull = GPIO_PULLDOWN;   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);   /* EXTI interrupt init*/   HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);   HAL_NVIC_EnableIRQ(EXTI0_IRQn); } void EXTI0_IRQHandler(void) { 	HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {     //HAL_Delay(100); //!!! dont use it !!!     switch(GPIO_Pin)     {         case  GPIO_PIN_0: 	if (WK_UP==1){ 		LED_switch(LED0); 	} 	break ;     } } 
 
EXTI.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 extern "C"  { /* Includes ------------------------------------------------------------------*/ void EXTI_Init(void); } 
 
实例 按下WK_UP按钮会变换LED0状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 void SystemClock_Config(void); int main(void) {    HAL_Init();   SystemClock_Config();   EXTI_Init();   LED_Init();   KEY_Init();   while  (1)   { 	HAL_Delay(500); 	LED_switch(LED1);   } } 
 
定时器中断 通过内部计时定时中断。
在Cube MX选择定时器(TIM2为例), Clock Source: Internal Clock Prescaler: 7200-1 Counter Period: 5000-1 auto-reload preload: Enable (important) (Tout=((arr+1)(psc+1))Tclk)=(5000 7200) (1/72Mhz)=0.5s,会每隔500ms中断下循环。但现实却有细微误差,和HAL_DELAY(500)同时运行会发现频率有细微差别,初步估计是内部语句运行误差。
别忘记在NVIC中enable interrupt并设定优先级。
tim.c 需自行加上(void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim))回调函数,同时在initialization函数末尾加上(HAL_TIM_Base_Start_IT(&htim2);)开启计时器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 TIM_HandleTypeDef htim2; /* TIM2 init function  */ void MX_TIM2_Init(void) {   TIM_ClockConfigTypeDef sClockSourceConfig = {0};   TIM_MasterConfigTypeDef sMasterConfig = {0};   htim2.Instance = TIM2;   htim2.Init.Prescaler = 7200-1;   htim2.Init.CounterMode = TIM_COUNTERMODE_UP;   htim2.Init.Period = 5000-1;   htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;   htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;   if  (HAL_TIM_Base_Init(&htim2) != HAL_OK)   {     Error_Handler();   }   sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;   if  (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)   {     Error_Handler();   }   sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;   sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;   if  (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)   {     Error_Handler();   } 	HAL_TIM_Base_Start_IT(&htim2); } void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) {   if (tim_baseHandle->Instance==TIM2)   {     /* TIM2 clock enable  */     __HAL_RCC_TIM2_CLK_ENABLE();     /* TIM2 interrupt Init */     HAL_NVIC_SetPriority(TIM2_IRQn, 2, 0);     HAL_NVIC_EnableIRQ(TIM2_IRQn);   } } void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle) {   if (tim_baseHandle->Instance==TIM2)   {     /* Peripheral clock disable  */     __HAL_RCC_TIM2_CLK_DISABLE();     /* TIM2 interrupt Deinit */     HAL_NVIC_DisableIRQ(TIM2_IRQn);   } } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {     if (htim==(&htim2))     {         LED_switch(LED0);     } } 
 
tim.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 extern "C"  { /* Includes ------------------------------------------------------------------*/ extern TIM_HandleTypeDef htim2; void MX_TIM2_Init(void); } 
 
实例 LED0和LED1会同时闪烁,LED0为定时器中断控制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 /* Private includes ----------------------------------------------------------*/ /* Private typedef -----------------------------------------------------------*/ void SystemClock_Config(void); int main(void) {   /* MCU Configuration--------------------------------------------------------*/   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */   HAL_Init();   /* Configure the system clock */   SystemClock_Config();   /* Initialize all configured peripherals */   MX_GPIO_Init();   MX_TIM2_Init(); 	LED_Init();   /* Infinite loop */   while  (1)   { 		HAL_Delay(500); 		LED_switch(LED1); 	} }