将 LED,独立按键五项摇杆按键的跳线(KEY JMP)接好。
按下 CTR(五项摇杆中间)按键,LED1灯状态变化一次。
GPIO工作模式详细介绍
GPIO_MODE_INPUT //浮空输入
GPIO_MODE_OUTPUT_PP //推挽输出
GPIO_MODE_OUTPUT_OD //开漏输出
GPIO_MODE_AF_PP //复用推完输出
GPIO_MODE_AF_OD //复用开漏输出
GPIO_MODE_AF_INPUT //与GPIO_MODE_INPUT相同
GPIO_MODE_ANALOG //模拟输入
GPIO_MODE_IT_RISING //具有上升边缘触发检测的外部中断模式
GPIO_MODE_IT_FALLING //具有下降边缘触发检测的外部中断模式
GPIO_MODE_IT_RISING_FALLING //具有上升/下降边缘触发检测的外部中断模式
GPIO_MODE_EVT_RISING //具有上升边缘触发检测的外部事件模式
GPIO_MODE_EVT_FALLING //具有下降边缘触发检测的外部事件模式
GPIO_MODE_EVT_RISING_FALLING //具有上升/下降边缘触发检测的外部事件模式
如何理解 “外部中断” 与 “外部事件” ?
NVIC中断
NVIC 的全称是 Nested vectored interrupt controller,即嵌套向量中断控制器。
对于 M3/M4/M7 内核的 MCU,每个中断的优先级都是用寄存器中的 8 位来设置的。8 位的话就可以设置 2^8 = 256 级中断,实际中用不了这么多,所以芯片厂商根据自己生产的芯片做出了调整。比如
ST 的 STM32F1xx,F4xx 和 H7 只使用了这个 8 位中的高四位[7:4],低四位取零,这样 2^4=16,只能
表示 16 级中断嵌套。
对于这个 NVIC,有个重要的知识点就是优先级分组、抢占优先级和子优先级。STM32F1xx,F4xx 和 H7 都是只使用了这个 8 位寄存器的高四位[7:4]。
#define NVIC_PRIORITYGROUP_0 ((uint32_t)0x00000007) /*!< 0 bits for pre-emption priority
4 bits for subpriority */
#define NVIC_PRIORITYGROUP_1 ((uint32_t)0x00000006) /*!< 1 bits for pre-emption priority
3 bits for subpriority */
#define NVIC_PRIORITYGROUP_2 ((uint32_t)0x00000005) /*!< 2 bits for pre-emption priority
2 bits for subpriority */
#define NVIC_PRIORITYGROUP_3 ((uint32_t)0x00000004) /*!< 3 bits for pre-emption priority
1 bits for subpriority */
#define NVIC_PRIORITYGROUP_4 ((uint32_t)0x00000003) /*!< 4 bits for pre-emption priority
0 bits for subpriority */
STM32 支持 5 种优先级分组。系统上电复位后,默认使用的是优先级分组 0,也就是没有抢占式优先级,只有子优先级。
① 初始化HAL
HAL_Init();
设置优先级分组4并开启SYSCFG时钟
HAL_StatusTypeDef HAL_Init(void)
{
/* 设置中断优先级分组 */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); //设置优先级分组4
/* 使用systick作为时基源,并配置1ms刻度(重置后的默认时钟为HSI) */
if(HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK)
{
return HAL_ERROR;
}
/* 初始化底层硬件 */
HAL_MspInit();
/* 返回函数状态 */
return HAL_OK;
}
void HAL_MspInit(void)
{
__HAL_RCC_SYSCFG_CLK_ENABLE(); //开启SYSCFG时钟
}
② 系统时钟配置
SystemClock_Config();
③ GPIO初始化
MX_GPIO_Init();
其函数实现与GPIO输入输出实验类似,不同的是在GPIO输入输出中,PI11引脚即CTR配置为输入模式,PB6引脚即LED1配置为上拉电阻,在GPIO中断中,PI11引脚即CTR配置为具有下降沿触发检测的外部中断模式,PB6引脚即LED1不配置上拉/下拉电阻。
配置中断优先级,并使能中断。
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* 使能GPIO端口时钟 */
__HAL_RCC_GPIOI_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/* 配置GPIO引脚输出电平 */
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
/* 配置引脚PI11即CTR */
GPIO_InitStruct.Pin = KEY_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; //具有下降边缘触发检测的外部中断模式
GPIO_InitStruct.Pull = GPIO_PULLUP; //上拉电阻
HAL_GPIO_Init(KEY_GPIO_Port, &GPIO_InitStruct);
/* 配置引脚PB6即LED1 */
GPIO_InitStruct.Pin = LED_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出模式
GPIO_InitStruct.Pull = GPIO_NOPULL; //不设置上拉/下拉电阻
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; //高速
HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0); //设置抢占优先级为0,子优先级为0
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); //使能中断
}
④ 中断服务函数
EXTI15_10_IRQHandler();
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);
}
⑤ 编写中断处理回调函数
HAL_GPIO_EXTI_Callback();
/* 编写中断处理回调函数 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
i = ~i;
if(i){
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
}else{
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
}
}