使用中断的方式来进行检测按键
- 实验目的
本节实验目的为通过中断的方式来获取按键状态。这一节计划采取中断的方式来检测按键状态,按键每按下一次,触发一次中断,在中断回调函数中翻转一下LED的状态,以此来表示检测到按键按下的动作并成功产生中断,调用了中断回调函数,所使用的LED为前面提到的红色LED。
- 实验准备
1)、带按键和发光二极管(LED)的K210开发板一块,用于实践并查看实验现象;
2)、官方裸机编程指导手册:kendryte_standalone_programming_guide,用于查阅SDK中接口说明。
- 实验原理
如下图硬件设计,当微动开关(按键)按下时,会将IO电平拉低,松开时,IO电平拉高,所以,如果采用中断方式来判断按键状态的话,只需设置中断触发模式,当操作按键满足触发条件时,触发中断,执行中断回调函数。
- 硬件设计
硬件电路图如下:
- 软件设计
软件流程图如下:
- 软件实现
根据硬件设计和软件设计可知,本节应用实现步骤如下:
1)、设置引脚复用功能:由硬件原理图可知:我们需要将IO12和IO16设置为GPIOHS功能,如下图:
2)、LED初始化,如下图:
3)、按键初始化,如下图:
4)、实现按键中断回调函数,在按键回调函数中对LED进行控制,如下图:
根据上述实现步骤,最终代码如下:
#include <fpioa.h>
#include <gpiohs.h>
#include <plic.h>
#include <sysctl.h>
#define LED_R_PIN (12)
#define LED_R_GPIOHSNUM (0)
#define LED_R_FUNC (FUNC_GPIOHS0+LED_R_GPIOHSNUM)
#define KEY_BT1_PIN (16)
#define KEY_BT1_GPIOHSNUM (1)
#define KEY_BT1_FUNC (FUNC_GPIOHS0+KEY_BT1_GPIOHSNUM)
/*********************************
* 管脚功能初始化
********************************/
void init_hardware(void)
{
// 将红色LED管脚设置复用为GPIOHS
fpioa_set_function(LED_R_PIN, LED_R_FUNC);
// 将按键管脚设置复用为GPIOHS
fpioa_set_function(KEY_BT1_PIN, KEY_BT1_FUNC);
}
/*********************************
* LED初始化
********************************/
void init_led(gpio_pin_value_t value)
{
// 设置输出
gpiohs_set_drive_mode(LED_R_GPIOHSNUM, GPIO_DM_OUTPUT);
// 设置初始电平状态
gpiohs_set_pin(LED_R_GPIOHSNUM, value);
}
/*********************************
* 控制LED亮灭
********************************/
void ctl_led(gpio_pin_value_t value)
{
gpiohs_set_pin(LED_R_GPIOHSNUM, value);
}
gpio_pin_value_t led_r_value = GPIO_PV_HIGH; // LED初始电平
/*********************************
* 按键中断回调函数
********************************/
int irq_key_bt1(void *ctx)
{
gpio_pin_value_t *value = (gpio_pin_value_t *)(ctx);
*value = !(*value);
ctl_led(*value);
return 0;
}
/*********************************
* 按键初始化
********************************/
void init_key(void)
{
// 初始化外部中断
plic_init();
// 设置输入
gpiohs_set_drive_mode(KEY_BT1_GPIOHSNUM, GPIO_DM_INPUT);
// 设置中断触发模式
gpiohs_set_pin_edge(KEY_BT1_GPIOHSNUM, GPIO_PE_FALLING);
// 设置中断回调函数
gpiohs_irq_register(KEY_BT1_GPIOHSNUM, 1, irq_key_bt1, &led_r_value);
// 使能系统中断,如果使用中断,一定要开启系统中断
sysctl_enable_irq();
}
int main()
{
init_hardware(); // 设置管脚复用功能
init_led(led_r_value); // LED初始化
init_key(); // 按键初始化
while(1);
return 0;
}
- 编译
1)、同上一节类似,在SDK中创建key_irq文件夹,在新建的文件夹中创建一个main.c文件,然后将本节代码输入到main.c文件中,如下图:
2)、同上一节的编译方式类似,打开vscode终端,在终端中进入上一节创建的build文件夹,然后输入:cmake ../ -DPROJ=key_irq -G "MinGW Makefiles" ,生成makefile文件,如下图:
3)、生成makefile文件后,输入:make ,开始编译,如下图:
4)、编译完成后,会在build目录下生成烧录文件:key_irq.bin,如下图:
- 烧录
同上一节的烧录方式类似,注意:Firmware那一项选择我们刚编译出的key_irq.bin文件。
- 实验现象
每按一次按键,LED状态反转一次,例如:初始LED灭,按下一次按键,LED亮,再按一下按键,LED灭,以此循环。
- 实验总结
1)、使用外部中断时,必须先初始化外部中断,如果要使中断生效,必须使能系统中断;
2)、GPIOHS中断触发模式有多种模式,除了我这里使用的下降沿触发,还有上升沿触发、双边沿触发、高电平触发和低电平触发,用户可根据实际需求选择触发模式。