由于原来的F407的板子烧坏了,现在换成F103的板子进行学习
1、外部中断简介
STM32F1的每个IO口都可以作为外部中断的中断输入,STM32F103的中断控制器支持19个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。STM32F103的19个外部中断为:
- EXTI线0~15:对应外部IO口的输入中断
- EXTI线16:连接到PVD输出
- EXTI线17:连接到RTC闹钟事件
- EXTI线18:连接到USB唤醒事件
- EXTI线19:连接到以太网唤醒事件(互联网型产品)
STM32F103供IO口使用的中断线只有16个,但是IO口却远不止16个。下图为GPIO跟中断线的映射关系图
2、硬件介绍
板子的几个按键的原理图如下
在第2章我们学习到了按键的检测,本章将在按键检测的基础上学习外部中断,将用上升沿触发和下降沿触发两种触发方式来实现中断,并在中断中通过串口输出对应的字符串。
其中S4是高电平有效,因此应设置为下拉、上升沿触发中断 。而S1,S2,S3都是低电平有效,因此设置2为上拉,下降沿触发中断。
3、STM32CubeMX设置
选择芯片STM32F103ZET6,建立工程,设置好工程名称及目录。
RCC设置外接HSE,时钟设置为72M。
设置串口1,并打开串口中断。
(1)、将PA0设置成外部中断模式,触发模式选择上升沿触发,GPIO Pull-up/Pull-down中选择Pull-down上拉,并命名为S4。
(2)将PE4,PE3,PE3,设置成外部中断模式,触发模式选择下降沿触发,GPIO Pull-up/Pull-down中选择Pull-up上拉,命名分别命名为S1,S2,S3
(3)、使能外部中断,并将优先级都设置为2.
配置好时钟树和基础设置即可生成代码了。
4、代码编写
在在gpio.c文件中可以看到PA0/PE2/PE3/PE4管脚的初始化函数。
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_SET);
/*Configure GPIO pins : PEPin PEPin PEPin */
GPIO_InitStruct.Pin = S3_Pin|S2_Pin|S1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = LED3_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(LED3_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = S4_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(S4_GPIO_Port, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
HAL_NVIC_SetPriority(EXTI2_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
HAL_NVIC_SetPriority(EXTI3_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI3_IRQn);
HAL_NVIC_SetPriority(EXTI4_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI4_IRQn);
}
随后我们可以在stm32f1xx_it.c中看到我们所配置的中断服务函数
重定义串口函数,
unsigned char tx_buf[256];
#define printf1(...) HAL_UART_Transmit(&huart1,tx_buf,sprintf((char*)tx_buf,__VA_ARGS__),10);
在main文件中编写中断回调函数
void delay(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=0;j<110;j++);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
delay(10); //延时消抖,不建议
switch(GPIO_Pin){
case GPIO_PIN_0:
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==1)
printf1("STM32F103 EXTI test this key is S4\r\n"); //A0
break;
case GPIO_PIN_2::
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_2)==0)
printf1("STM32F103 EXTI test this key is S3\r\n"); //E2
break;
case GPIO_PIN_3:
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==0)
printf1("STM32F103 EXTI test this key is S2\r\n"); //E3
break;
case GPIO_PIN_4:
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==0)
printf1("STM32F103 EXTI test this key is S1\r\n"); //E4
break;
}
}
在这里我自己写了一个延时函数,用作按键的消抖,至于为什么不适用hal库的延时函数(HAL_Delay();),是因为在使用的时候触发中断时程序会卡死,经过调试后发现程序卡死在delay函数中的while循环中,可能是因为在中断过程中导致时钟不再更新了导致的(个人观点),有知道的大佬可以在评论区留言。
中断函数应该是快进快出的,这里加了延时消抖是会影响效率的,所以不建议加。
5、程序验证
将程序编译无误后下载到板子上,按下相应按键就会输出对应的信息。
参考文献:
【STM32】HAL库 STM32CubeMX教程三----外部中断(HAL库GPIO讲解)_hal_gpio_exti_callback-CSDN博客