介绍 此文会记录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); } }