3.5 独立按键中断实验
一、实验目的
本节课主要学习K210的独立按键以及中断的功能。
二、实验准备
1.实验元件
独立按键BOOT、RGB灯
2.元件特性
独立按键BOOT按下时IO口为低电平,松开为高电平。
3.硬件连接
K210开发板出厂默认已经焊接好BOOT按键和RGB灯。按键连接的引脚为IO16。RGB灯R连接的是IO6,G连接的是IO7, B连接的是IO8。
4.SDK中对应API功能
对应的头文件 plic.h
PLIC可以将任一外部中断源单独分配到每个 CPU 的外部中断上。这提供了强大的灵活性,能适应不同的应用需求。
PLIC模块可以设置中断回调函数,当触发中断时,会自动运行中断回调函数,并且可以配置中断优先级。
为用户提供以下接口:
• plic_init:PLIC初始化外部中断。
• plic_irq_enable:使能外部中断。
• plic_irq_disable:禁用外部中断。
• plic_set_priority:设置中断优先级。
• plic_get_priority:获取中断优先级。
• plic_irq_register:注册外部中断函数。
• plic_irq_deregister:注销外部中断函数。
三、实验原理
BOOT按键按下的时候会把电平拉低,松开的时候会把电平拉高,只需要检测BOOT按键的IO口的电平,如果是按下则会产生下降沿,松开会产生上升沿,以此的方式来检测并触发系统的中断,然后控制RGB灯亮或者灭。
四、实验过程
1.首先根据上面的硬件连接引脚图,K210的硬件引脚和软件功能使用的是FPIOA映射关系。
这里要注意的是程序里操作的都是软件引脚,所以需要先把硬件引脚映射成软件GPIO功能,操作的时候直接操作软件GPIO即可。
2.第二部需要初始化外部中断服务,并且使能全局中断。如果没有这一步操作,系统的中断就不会运行,所以也不会调用中断回调函数。
3.在使用RGB灯前需要初始化,也就是把RGB灯的软件GPIO设置为输出模式。
4.然后关闭RGB灯,同样是设置RGB灯的GPIO为高电平则可以让RGB灯熄灭。
5.使用BOOT按键同样需要初始化,设置BOOT键为上拉输入模式,设置按键的GPIO电平触发模式为上升沿和下降沿,也可以设置单上升沿或单下降沿等,设置BOOT按键的中断回调函数为key_irq_cb,参数为g_count, g_count是一个全局uint32_t变量,功能是记录电平触发的次数。
6.每次BOOT按下或者松开都会触发中断函数key_irq_cb,在中断里先读取当前按键的状态,保存到key_state中,并且通过串口打印出当前按键的状态,这里只是为了调试才在中断中打印信息的,在后续的开发中不建议这样操作。由于ctx为void型指针,void型指针表示不指定指针类型,所以我们需要新建一个uint32_t类型的指针tmp指向它,然后每次进中断tmp所指向的值自动加1,也就是g_count的值加1。最后是判断按键的状态,当按键为按下时,点亮红灯,当按键为松开时,关闭红灯。
7.最后是一个while(1)循环,这个是必须的,否则系统就会退出,不再运行。
8.编译调试,烧录运行
把本课程资料中的button复制到SDK中的src目录下,
然后进入build目录,运行以下命令编译。
cmake .. -DPROJ=button -G "MinGW Makefiles"
make
编译完成后,在build文件夹下会生成button.bin文件。
使用type-C数据线连接电脑与K210开发板,打开kflash,选择对应的设备,再将程序固件烧录到K210开发板上。
五、实验现象
烧录完成固件后,系统会弹出一个终端界面,如果没有弹出终端界面的可以打开串口助手显示调试内容。
打开电脑的串口助手,选择对应的K210开发板对应的串口号,波特率设置为115200,然后点击打开串口助手。注意还需要设置一下串口助手的DTR和RTS。在串口助手底部此时的4.DTR和7.RTS默认是红色的,点击4.DTR和7.RTS,都设置为绿色,然后按一下K210开发板的复位键。
按下BOOT按键不松开,可以看到RGB亮红灯,并且串口助手上显示IRQ The PIN is 0 count is 0,松开的时候会显示IRQ The PIN is 1 count is 1,每次按下或松开count的值都自动加1。
六、实验总结
1.BOOT按键与RGB同样适用GPIOHS的函数,只是按键使用输入模式,RGB使用输出模式。
2.使用外部中断前需要先初始化PLIC以及使能全局中断服务。
3.在中断回调函数中可以传入一个参数,参数类型可以传入自己需要的类型。
附:API
对应的头文件 plic.h
PLIC初始化外部中断。
void plic_init(void)
无。
无。
使能外部中断。
int plic_irq_enable(plic_irq_t irq_number)
参数名称 | 描述 | 输入输出 |
irq_number | 中断号 | 输入 |
返回值 | 描述 |
0 | 成功 |
非0 | 失败 |
禁用外部中断。
int plic_irq_disable(plic_irq_t irq_number)
参数名称 | 描述 | 输入输出 |
irq_number | 中断号 | 输入 |
返回值 | 描述 |
0 | 成功 |
非0 | 失败 |
设置中断优先级。
int plic_set_priority(plic_irq_t irq_number, uint32_t priority)
参数名称 | 描述 | 输入输出 |
irq_number | 中断号 | 输入 |
priority | 中断优先级 | 输入 |
返回值 | 描述 |
0 | 成功 |
非0 | 失败 |
获取中断优先级。
uint32_t plic_get_priority(plic_irq_t irq_number)
参数名称 | 描述 | 输入输出 |
irq_number | 中断号 | 输入 |
irq_number中断的优先级。
注册外部中断函数。
int plic_irq_register(plic_irq_t irq, plic_irq_callback_t callback, void* ctx)
参数名称 | 描述 | 输入输出 |
irq | 中断号 | 输入 |
callback | 中断回调函数 | 输入 |
ctx | 回调函数的参数 | 输入 |
返回值 | 描述 |
0 | 成功 |
非0 | 失败 |
注销外部中断函数。
int plic_irq_deregister(plic_irq_t irq)
参数名称 | 描述 | 输入输出 |
irq | 中断号 | 输入 |
返回值 | 描述 |
0 | 成功 |
非0 | 失败 |
/* 设置GPIOHS0的触发中断 */
int count = 0;
int gpiohs_pin_onchange_isr(void *ctx)
{
int *userdata = (int *)ctx;
*userdata++;
}
plic_init();
plic_set_priority(IRQN_GPIOHS0_INTERRUPT, 1);
plic_irq_register(IRQN_GPIOHS0_INTERRUPT, gpiohs_pin_onchange_isr, &count);
plic_irq_enable(IRQN_GPIOHS0_INTERRUPT);
sysctl_enable_irq();
相关数据类型、数据结构定义如下:
· plic_irq_t:外部中断号。
· plic_irq_callback_t:外部中断回调函数。
外部中断号。
typedef enum _plic_irq
{
IRQN_NO_INTERRUPT = 0, /*!< The non-existent interrupt */
IRQN_SPI0_INTERRUPT = 1, /*!< SPI0 interrupt */
IRQN_SPI1_INTERRUPT = 2, /*!< SPI1 interrupt */
IRQN_SPI_SLAVE_INTERRUPT = 3, /*!< SPI_SLAVE interrupt */
IRQN_SPI3_INTERRUPT = 4, /*!< SPI3 interrupt */
IRQN_I2S0_INTERRUPT = 5, /*!< I2S0 interrupt */
IRQN_I2S1_INTERRUPT = 6, /*!< I2S1 interrupt */
IRQN_I2S2_INTERRUPT = 7, /*!< I2S2 interrupt */
IRQN_I2C0_INTERRUPT = 8, /*!< I2C0 interrupt */
IRQN_I2C1_INTERRUPT = 9, /*!< I2C1 interrupt */
IRQN_I2C2_INTERRUPT = 10, /*!< I2C2 interrupt */
IRQN_UART1_INTERRUPT = 11, /*!< UART1 interrupt */
IRQN_UART2_INTERRUPT = 12, /*!< UART2 interrupt */
IRQN_UART3_INTERRUPT = 13, /*!< UART3 interrupt */
IRQN_TIMER0A_INTERRUPT = 14, /*!< TIMER0 channel 0 or 1 interrupt */
IRQN_TIMER0B_INTERRUPT = 15, /*!< TIMER0 channel 2 or 3 interrupt */
IRQN_TIMER1A_INTERRUPT = 16, /*!< TIMER1 channel 0 or 1 interrupt */
IRQN_TIMER1B_INTERRUPT = 17, /*!< TIMER1 channel 2 or 3 interrupt */
IRQN_TIMER2A_INTERRUPT = 18, /*!< TIMER2 channel 0 or 1 interrupt */
IRQN_TIMER2B_INTERRUPT = 19, /*!< TIMER2 channel 2 or 3 interrupt */
IRQN_RTC_INTERRUPT = 20, /*!< RTC tick and alarm interrupt */
IRQN_WDT0_INTERRUPT = 21, /*!< Watching dog timer0 interrupt */
IRQN_WDT1_INTERRUPT = 22, /*!< Watching dog timer1 interrupt */
IRQN_APB_GPIO_INTERRUPT = 23, /*!< APB GPIO interrupt */
IRQN_DVP_INTERRUPT = 24, /*!< Digital video port interrupt */
IRQN_AI_INTERRUPT = 25, /*!< AI accelerator interrupt */
IRQN_FFT_INTERRUPT = 26, /*!< FFT accelerator interrupt */
IRQN_DMA0_INTERRUPT = 27, /*!< DMA channel0 interrupt */
IRQN_DMA1_INTERRUPT = 28, /*!< DMA channel1 interrupt */
IRQN_DMA2_INTERRUPT = 29, /*!< DMA channel2 interrupt */
IRQN_DMA3_INTERRUPT = 30, /*!< DMA channel3 interrupt */
IRQN_DMA4_INTERRUPT = 31, /*!< DMA channel4 interrupt */
IRQN_DMA5_INTERRUPT = 32, /*!< DMA channel5 interrupt */
IRQN_UARTHS_INTERRUPT = 33, /*!< Hi-speed UART0 interrupt */
IRQN_GPIOHS0_INTERRUPT = 34, /*!< Hi-speed GPIO0 interrupt */
IRQN_GPIOHS1_INTERRUPT = 35, /*!< Hi-speed GPIO1 interrupt */
IRQN_GPIOHS2_INTERRUPT = 36, /*!< Hi-speed GPIO2 interrupt */
IRQN_GPIOHS3_INTERRUPT = 37, /*!< Hi-speed GPIO3 interrupt */
IRQN_GPIOHS4_INTERRUPT = 38, /*!< Hi-speed GPIO4 interrupt */
IRQN_GPIOHS5_INTERRUPT = 39, /*!< Hi-speed GPIO5 interrupt */
IRQN_GPIOHS6_INTERRUPT = 40, /*!< Hi-speed GPIO6 interrupt */
IRQN_GPIOHS7_INTERRUPT = 41, /*!< Hi-speed GPIO7 interrupt */
IRQN_GPIOHS8_INTERRUPT = 42, /*!< Hi-speed GPIO8 interrupt */
IRQN_GPIOHS9_INTERRUPT = 43, /*!< Hi-speed GPIO9 interrupt */
IRQN_GPIOHS10_INTERRUPT = 44, /*!< Hi-speed GPIO10 interrupt */
IRQN_GPIOHS11_INTERRUPT = 45, /*!< Hi-speed GPIO11 interrupt */
IRQN_GPIOHS12_INTERRUPT = 46, /*!< Hi-speed GPIO12 interrupt */
IRQN_GPIOHS13_INTERRUPT = 47, /*!< Hi-speed GPIO13 interrupt */
IRQN_GPIOHS14_INTERRUPT = 48, /*!< Hi-speed GPIO14 interrupt */
IRQN_GPIOHS15_INTERRUPT = 49, /*!< Hi-speed GPIO15 interrupt */
IRQN_GPIOHS16_INTERRUPT = 50, /*!< Hi-speed GPIO16 interrupt */
IRQN_GPIOHS17_INTERRUPT = 51, /*!< Hi-speed GPIO17 interrupt */
IRQN_GPIOHS18_INTERRUPT = 52, /*!< Hi-speed GPIO18 interrupt */
IRQN_GPIOHS19_INTERRUPT = 53, /*!< Hi-speed GPIO19 interrupt */
IRQN_GPIOHS20_INTERRUPT = 54, /*!< Hi-speed GPIO20 interrupt */
IRQN_GPIOHS21_INTERRUPT = 55, /*!< Hi-speed GPIO21 interrupt */
IRQN_GPIOHS22_INTERRUPT = 56, /*!< Hi-speed GPIO22 interrupt */
IRQN_GPIOHS23_INTERRUPT = 57, /*!< Hi-speed GPIO23 interrupt */
IRQN_GPIOHS24_INTERRUPT = 58, /*!< Hi-speed GPIO24 interrupt */
IRQN_GPIOHS25_INTERRUPT = 59, /*!< Hi-speed GPIO25 interrupt */
IRQN_GPIOHS26_INTERRUPT = 60, /*!< Hi-speed GPIO26 interrupt */
IRQN_GPIOHS27_INTERRUPT = 61, /*!< Hi-speed GPIO27 interrupt */
IRQN_GPIOHS28_INTERRUPT = 62, /*!< Hi-speed GPIO28 interrupt */
IRQN_GPIOHS29_INTERRUPT = 63, /*!< Hi-speed GPIO29 interrupt */
IRQN_GPIOHS30_INTERRUPT = 64, /*!< Hi-speed GPIO30 interrupt */
IRQN_GPIOHS31_INTERRUPT = 65, /*!< Hi-speed GPIO31 interrupt */
IRQN_MAX
} plic_irq_t;
成员名称 | 描述 |
IRQN_NO_INTERRUPT | 不存在 |
IRQN_SPI0_INTERRUPT | SPI0中断 |
IRQN_SPI1_INTERRUPT | SPI1中断 |
IRQN_SPI_SLAVE_INTERRUPT | 从SPI中断 |
IRQN_SPI3_INTERRUPT | SPI3中断 |
IRQN_I2S0_INTERRUPT | I2S0 中断 |
IRQN_I2S1_INTERRUPT | I2S1 中断 |
IRQN_I2S2_INTERRUPT | I2S2 中断 |
IRQN_I2C0_INTERRUPT | I2C0 中断 |
IRQN_I2C1_INTERRUPT | I2C1 中断 |
IRQN_I2C2_INTERRUPT | I2C2 中断 |
IRQN_UART1_INTERRUPT | UART1中断 |
IRQN_UART2_INTERRUPT | UART2中断 |
IRQN_UART3_INTERRUPT | UART3中断 |
IRQN_TIMER0A_INTERRUPT | TIMER0通道0和1中断 |
IRQN_TIMER0B_INTERRUPT | TIMER0通道2和3中断 |
IRQN_TIMER1A_INTERRUPT | TIMER1通道0和1中断 |
IRQN_TIMER1B_INTERRUPT | TIMER1通道2和3中断 |
IRQN_TIMER2A_INTERRUPT | TIMER2通道0和1中断 |
IRQN_TIMER2B_INTERRUPT | TIMER2通道2和3中断 |
IRQN_RTC_INTERRUPT | RTC 滴答中断和报警中断 |
IRQN_WDT0_INTERRUPT | 看门狗0中断 |
IRQN_WDT1_INTERRUPT | 看门狗1中断 |
IRQN_APB_GPIO_INTERRUPT | 普通GPIO中断 |
IRQN_DVP_INTERRUPT | 数字摄像头(DVP)中断 |
IRQN_AI_INTERRUPT | AI 加速器中断 |
IRQN_FFT_INTERRUPTFFT | 傅里叶加速器中断 |
IRQN_DMA0_INTERRUPT | DMA 通道0中断 |
IRQN_DMA1_INTERRUPT | DMA 通道1中断 |
IRQN_DMA2_INTERRUPT | DMA 通道2中断 |
IRQN_DMA3_INTERRUPT | DMA 通道3中断 |
IRQN_DMA4_INTERRUPT | DMA 通道4中断 |
IRQN_DMA5_INTERRUPT | DMA 通道5中断 |
IRQN_UARTHS_INTERRUPT | 高速UART中断 |
IRQN_GPIOHS0_INTERRUPT | 高速GPIO0中断 |
IRQN_GPIOHS1_INTERRUPT | 高速GPIO1中断 |
IRQN_GPIOHS2_INTERRUPT | 高速GPIO2中断 |
IRQN_GPIOHS3_INTERRUPT | 高速GPIO3中断 |
IRQN_GPIOHS4_INTERRUPT | 高速GPIO4中断 |
IRQN_GPIOHS5_INTERRUPT | 高速GPIO5中断 |
IRQN_GPIOHS6_INTERRUPT | 高速GPIO6中断 |
IRQN_GPIOHS7_INTERRUPT | 高速GPIO7中断 |
IRQN_GPIOHS8_INTERRUPT | 高速GPIO8中断 |
IRQN_GPIOHS9_INTERRUPT | 高速GPIO9中断 |
IRQN_GPIOHS10_INTERRUPT | 高速GPIO10中断 |
IRQN_GPIOHS11_INTERRUPT | 高速GPIO11中断 |
IRQN_GPIOHS12_INTERRUPT | 高速GPIO12中断 |
IRQN_GPIOHS13_INTERRUPT | 高速GPIO13中断 |
IRQN_GPIOHS14_INTERRUPT | 高速GPIO14中断 |
IRQN_GPIOHS15_INTERRUPT | 高速GPIO15中断 |
IRQN_GPIOHS16_INTERRUPT | 高速GPIO16中断 |
IRQN_GPIOHS17_INTERRUPT | 高速GPIO17中断 |
IRQN_GPIOHS18_INTERRUPT | 高速GPIO18中断 |
IRQN_GPIOHS19_INTERRUPT | 高速GPIO19中断 |
IRQN_GPIOHS20_INTERRUPT | 高速GPIO20中断 |
IRQN_GPIOHS21_INTERRUPT | 高速GPIO21中断 |
IRQN_GPIOHS22_INTERRUPT | 高速GPIO22中断 |
IRQN_GPIOHS23_INTERRUPT | 高速GPIO23中断 |
IRQN_GPIOHS24_INTERRUPT | 高速GPIO24中断 |
IRQN_GPIOHS25_INTERRUPT | 高速GPIO25中断 |
IRQN_GPIOHS26_INTERRUPT | 高速GPIO26中断 |
IRQN_GPIOHS27_INTERRUPT | 高速GPIO27中断 |
IRQN_GPIOHS28_INTERRUPT | 高速GPIO28中断 |
IRQN_GPIOHS29_INTERRUPT | 高速GPIO29中断 |
IRQN_GPIOHS30_INTERRUPT | 高速GPIO30中断 |
IRQN_GPIOHS31_INTERRUPT | 高速GPIO31中断 |
外部中断回调函数。
typedef int (*plic_irq_callback_t)(void *ctx);