文章目录
前言
这篇文章详细记录外部中断方式控制LED的亮灭以及蜂鸣器的开关;本文从原理图开始到最后实现功能,内容详细。
本栏目的所有都是基于STM32F407ZET6芯片,博主采用的是普中的天马F407开发板。
实现功能:LED0与LED1默认熄灭,蜂鸣器默认关闭。按下按键KEY0,控LED0亮灭;按下按键KEY1,控制LED1亮灭;
按下按键KEY2控制蜂鸣器开关。
1. 电路原理图理解
1.1 LED与KEY原理图理解
LED部分:
3.3V电压经过一个电阻R12连到DS0发光二极管,如果VCC和LED0对应的引脚之间存在压降,则DS0导通,发光。
3.3V电压经过一个电阻R14连到DS1发光二极管,如果VCC和LED1对应的引脚之间存在压降,则DS1导通,发光。
因此我们要先让LED发光的话,要让LED0和LED1标号对应的引脚输出低电平,才能确保LED0和LED1发光,但由于我们默认状态是LED暗的,所以这里都先要制为高电平。
KEY部分:
KEY0-2三个按键一端都接地,所以KEY0-2都需要先拉高。因为要通过电平的上升或下降沿触发中断,所以必须要有电平的变化。
那如果我们想用KEY_UP也可以,只不过要默认拉低。
1.2 BEEP蜂鸣器
要想蜂鸣器一开始不响,这里BEEP的引脚初始状态应该为0,理由如下:
- Q2是NPN型三极管,只有集电极到发射机这一段导通到地,蜂鸣器PG之间才有压降,蜂鸣器才会响。
- 要想蜂鸣器一开始不响,那就是NPN三极管不导通,基极应该没有电流,没有压降。
- 因为R38接地,所以R38上面这个点的电压为0,即三极管基极电压已经为0,如果BEEP这一端的电压为3.3V,通过电阻R37就会产生电流,就会导致三极管导通,蜂鸣器会响。
2. 外部中断配置阐述
用STM32CubeMX来配置外部中断的话就非常方便,只需要选择需要配置的引脚,将其设置为外部中断的模式,接着对它进行使能,后面一个CodeGenerate就自动配置好了,这比标准库自己配置要快很多。
这个外部中断和串口传输中断稍有些不一样,前者是一直都可以触发,后者我在使用的时候是使能一次触发一次。提及这个是因为和后面写回调函数这种稍有区别。
3. STM32CubeMX配置
这三个KEY引脚分别设置为外部中断,这里KEY2对应GPIO_EXIT2,KEY1对应GPIO_EXIT3,KEY0对应GPIO_EXIT4。
LED0,LED1,BEEP对应的引脚分别设置为GPIO_Output,
GPIO引脚配置
对于KEY配置
LED和BEEP配置
中断使能
配置外部晶振
Debug
调试的接口,看你自己的调试接口设备,一般都是SerialWire。
时钟树配置
这里把最终的时钟设为最大的,软件会自动选择时钟源以及分频器系数。
代码生成
这里因为是以keil为代码平台,所以这里选择MDK-ARM
下面的两个选项看个人喜好勾选,这里只是做一个介绍。
配置完成后点击右上角的即可生成目标项目的代码。
下图是生成的目标代码,我们对中断的配置主要在紫色框的源文件内,代码的框架如红色框所示。
4. 代码编写
4.1 代码编写思路
按键触发外部中断都是通过对应的中断服务程序进行的。
比如下图中的EXTI4_IRQHandle(void)函数,这个函数是在KEY0按下的时候调用的中断服务程序。
其他的EXTI2和3都是同理。
我们看到所有的中断服务程序最终都会去调用`HAL_GPIO_EXTI_IRQHandler(xxx)这个函数,那么找到这个函数的定义
我们会发现所有的对应的外部中断其实最终都是调用这个函数,只不过传的引脚参数不一样。引脚参数的不同,就对不同的引脚的外部中断使用不同的中断服务程序。
每一个中断服务程序不论是什么参数,都会调用HAL_GPIO_EXTI_Callback(GPIO_Pin)
这个函数,也就是中断触发完了之后的回调函数。这个是什么意思呢?就是我按键按下以后,触发了外部中断,告知系统外部中断触发完了之后要做什么?
再查找这个函数定义。
我们发现这是个弱函数,也就是可以拿来重写的接口。
所以我们对中断触发完之后的所有对应操作其实都可以写在这个回调函数里。表示我每触发一次中断,就要干嘛干嘛。
4.2 重写回调函数
既然已经知道代码修改哪里了,那么无非就是重写回调函数。
我们需要实现的功能这里再列举一下:
LED0与LED1默认点亮,蜂鸣器默认关闭。按下按键KEY0,控LED0亮灭;按下按键KEY1,控制LED1亮灭;
按下按键KEY2控制蜂鸣器开关。
那我这里无非就是判断是哪个中断触发了,然后对应的状态调整一下即可。
我们KEY0按下,那就是把LED0从亮变成暗,即翻转一下电平。
其他同理。
回调函数源码:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin){
case KEY0_Pin:
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
break;
}
case KEY1_Pin:
{
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
break;
}
case KEY2_Pin:
{
HAL_GPIO_TogglePin(BEEP_GPIO_Port,BEEP_Pin);
break;
}
}
}
剩下的就是编译烧录运行了,这里就不再阐述。
如果编译出现错误,可以参考我的博客:STM32 keil烧录出现program algorithm出错问题
因为买的是普中天马F407ZET6,送的调试烧录器是DAP的,所以这个烧写器可能得按照自己对应的烧写器来改一下。
如果你的是STlink的,那就根据自己的调试器进行修改吧
TIPS
keil5的自动补全确实不怎么滴,我同样的配置方法,在不同电脑上竟然会出现补全没作用的情况。
但我的台式机自动补全又没事,有点搞人。
如果你想Keil自动补全,像下面这样。
那就
如果左边的没有,那就重装一个keil,主要不要汉化版。汉化版的确实没有这个自动补全。
如果这样设置还是不行,那就再生成一个STM32CubeIDE的工程,代码什么的弄成一样,用STM32IDE编写,毕竟那个自动补全做的好,只不过调试器就被限定了,必须得是ST公司的全家桶。如果你想像我的一样使用DAP这种店家送的调试器,还是得用keil。
总结
这篇博客很久以前就开了个头一直没有完善,虽然比较简单,但对中断的整个调用过程以及STM32CubeMX+Keil的配合使用流程做了详细阐述。总的来说写下来收获还是可以的。