承接上一篇文章,这次是用按键触发外部中断,通过LED灯显示
这次的实验也是通过对寄存器进行操作来实现相关功能。在进行代码编写之前,先来了解一下关于GPIO寄存器的中断定义解释以及不同赋值下的功能解释。
1.GPIO -> IS(Interrupt Sense) :触发状态选择寄存器
0x00:边缘触发
0x01:电平触发
2.GPIO -> IBE(Interrupt Both Edges):双边触发寄存器
0x00:正常触发中断
0x01:下降沿上升沿都触发中断
3.GPIO -> IEV(Interrupt Event):触发方式选择寄存器
0x00:下降沿触发或者低电平触发
0x01:高电平或上升沿触发
4.GPIO->IM(Interrupt Mask):中断屏蔽寄存器
0x00:中断屏蔽状态
0x01:相应引脚中断发送到中断控制器(说简单点就是不屏蔽那个引脚了)
5.GPIO->RIS(Raw Interrupt Status):原始中断状态寄存器,对于边沿触发,通过向ICR写1来清除RIS标志;对于电平触发,在电平无效的时候会自动清零
0x00:相应引脚上没有发生中断
0x01:相应引脚上发生了中断
6.GPIO->MIS(Masked Interrupt Status):已屏蔽中断状态寄存器,触发以及清除方式同RIS
0x00:相应引脚上中断被屏蔽或者没发生
0x01:相应引脚上中断条件出发了中断控制器中断
7.GPIO->ICR(Interruput Clear):中断标志清除寄存器,对于边沿触发,ICR置1会清除相应引脚上的RIS以及MIS的相应位。对于电平检测,这个就没什么用了,因为电平无效的时候RIS和MIS会自动清除。此外,将0写入ICR是无效的,没有任何作用
0x00:无效
0x01:相应中断被清除
8.GPIO->SI,这个寄存器只在P、Q端口上可用,这里不做介绍
关于如何配置相应GPIO口中断,TI手册里也有介绍
1. 通过清除 GPIOIM 寄存器中的 IME 字段来屏蔽相应的端口。
2. 配置GPIOIS寄存器中的IS字段和GPIOIBE寄存器中的IBE字段。
3. 清除 GPIORIS 寄存器。
4. 通过设置 GPIOIM 寄存器中的 IME 字段来取消屏蔽端口。
到这里,对于中断的基础配置应该已经是信手拈来了。不过因为已经做过MSP430以及STM32,我知道还有一步非常关键的操作手册里没说,那就是打开总中断!但是我翻了一下午的手册以及其他人的代码我都没找到怎么开总中断,无奈之下只能采取官方封装好的driverlib库里面的函数——MAP_IntEnable(INT_GPIOJ);官方库对于打开每个引脚或者是功能口中断的封装还是很完善的,这里也不继续去挖苦自己了(实在是找不到了)。对于系统功能寄存器里面的IM并不是用来打开总中断的。如果有会写的可以留言或者私信(万分感谢)。
按键中断无非就是GPIO设置为输入模式,输出拉高,输入电阻拉高,下降沿触发中断,不过这里并不做消抖工作(偷懒)。不过不消抖的按键是真的不灵敏,也不知道是我配置出问题了还是芯片问题,还是因为没消除抖动。
下面附上相关代码
/* DriverLib Includes */
#include <ti/devices/msp432e4/driverlib/driverlib.h>
/* Standard Includes */
#include <stdint.h>
#include <stdbool.h>
void key_init(){
GPIOJ->DIR&=~(BIT0+BIT1); //set as input
GPIOJ->PUR|=BIT0+BIT1; //Input set to pull-up resistor
GPIOJ->DEN|=BIT0+BIT1; //Digital enable
GPIOJ->DATA|=BIT0+BIT1;//Output set as high
}
void key_interrupt_init(){
GPIOJ->IS &=~BIT1;
GPIOJ->IBE &=~BIT1;
GPIOJ->IEV &=~BIT1;//== MAP_GPIOIntTypeSet(GPIO_PORTJ_BASE, GPIO_PIN_1, GPIO_FALLING_EDGE);
GPIOJ->IM |=BIT1;// == MAP_GPIOIntEnable(GPIO_PORTJ_BASE, GPIO_INT_PIN_1);
MAP_IntEnable(INT_GPIOJ);//打开GPIOJ中断,关于总中断的寄存器写法我没有找到,直接用driverlib库里的即可,也挺便捷的。
}
void led_init(){
GPION->DIR|=BIT1+BIT0;//D1,D2 light on
GPION->DEN|=BIT1+BIT0;
}
/*
中断函数,J口触发了中断就会进去,固定函数名,其他中断函数可以参考这个命名
*/
void GPIOJ_IRQHandler(void)
{
if (GPIOJ->RIS & BIT1){//获取中断状态,看看是不是真的触发了
GPION->DATA ^=BIT1;
}
GPION->DATA ^=BIT0;
GPIOJ->ICR |=BIT1;//清除中断标志位,不清除下次就进不来这个中断了
}
int main(void)
{
SYSCTL->RCGCGPIO |= SYSCTL_RCGCGPIO_R12+SYSCTL_RCGCGPIO_R8; // activate clock for Port N,J
while((SYSCTL->RCGCGPIO & (SYSCTL_PRGPIO_R12+SYSCTL_RCGCGPIO_R8)) == 0){}; // wait for preparation of Port N,J
key_init();
key_interrupt_init();
led_init();
while(1){ // if switch is pressed, led light on
//switch1 -> PJ0 -> control D2->PN0
if ((GPIOJ->DATA) & BIT0)
GPION->DATA&=~BIT0;
else
GPION->DATA|=BIT0;
}
}