一、本节内容
外接实验开发板K1-K4按钮和交通灯模块,其中两个按键接PA口,两个按键接PB口,所有LED灯接PB口,要求通过中断获得按键按下信息,并且实现如下功能:
- K1:交通灯所有红灯亮
- K2:交通灯所有绿灯亮
- K3:南北通行、东西截止
- K4:所有灯灭
二、原理讲解
本节涉及了PINCM寄存器,GPIO寄存器输入功能,IOMUX寄存器。
在GPIO输出功能中,对每个GPIO口进行配置,设置引脚对应的IOMUX寄存器、操作GPIO寄存器、然后操作使能寄存器进行GPIO的使能控制。
在GPIO输入功能中,直接设置GPIO口使能开启,在检测数据输出对应位是否被置为1。
在串口设置中,设置GPIO口的输入功能,然后关闭中断屏蔽,再开启下降沿中断,最后配置NVIC。
三、寄存器
IOMUX等部分寄存器介绍:学习MSP432M0手册——第一节GPIO输出功能
PINCM等部分寄存器介绍:学习MSP432M0手册——第二节GPIO输入和输出
GPIO的寄存器,用于关闭中断屏蔽,也就是开启中断。
下面使用CUPSS的IIDX寄存器,是因为IIDX只能识别IMASK配置的中断。
GPIO的寄存器,用于配置触发条件。
CPUSS的寄存器,GROUP[]记录第几个中断,默认1为GPIOA,2为GPIOB,以此类推,并且此寄存器先读取索引最小的 ,索引越小优先级越高。
除了使用IIDX,还有别的办法设置中断优先级。
注意:每读取一次这个寄存器就会自动全部清0。在从CPU读取后,就必须使用第二高优先级中断清0该寄存器。
此寄存器只通过使用IMASK选择的中断。
GPIO的寄存器,用于记录对应总线的引脚号此寄存器先读取索引最小的 ,索引越小优先级越高。
除了使用IIDX,还有别的办法设置中断优先级。
注意:每读取一次这个寄存器就会自动全部清0。在从CPU读取后,就必须使用第二高优先级中断清0该寄存器。
此寄存器只通过使用IMASK选择的中断。
四、软件代码
int main(void)
{
SYSCFG_DL_init();//初始化
//PA18,按键输入、下降沿中断
IOMUX->SECCFG.PINCM[39] |= 0x01<<0 | 0x01<<7 | 0x01<<18;//输入功能
GPIOA->CPU_INT.IMASK |= 0X01<<18;//关闭中断屏蔽
GPIOA->POLARITY31_16 |= 0X02<<4; //下降沿中断
//PA17,按键输入、下降沿中断
IOMUX->SECCFG.PINCM[38] |= 0x01<<0 | 0x01<<7 | 0x01<<18; //输入功能
GPIOA->CPU_INT.IMASK |= 0X01<<17;//关闭中断屏蔽
GPIOA->POLARITY31_16 |= 0X02<<2; //下降沿中断
//PB6,按键输入、下降沿中断
IOMUX->SECCFG.PINCM[22] |= 0x01<<0 | 0x01<<7 | 0x01<<18;
GPIOB->CPU_INT.IMASK |= 0X01<<6;
GPIOB-> POLARITY15_0 |= 0X03<<12;
//PB7,按键输入、下降沿中断
IOMUX->SECCFG.PINCM[23] |= 0x01<<0 | 0x01<<7 | 0x01<<18;
GPIOB->CPU_INT.IMASK |= 0X01<<7;
GPIOB-> POLARITY15_0 |= 0X03<<14;
NVIC->ISER[0] |= 0X01<<1;//配置NVIC
//PB1,led1
IOMUX->SECCFG.PINCM[12] |= 0X01<<0 | 0X01<<7;//设置GPIO口为输出功能
GPIOB->DOESET31_0 = 0X01<<1;//输出启用设置
GPIOB->DOUTSET31_0 = 0X01<<1;//数据输出设置
//PB12,led3
IOMUX->SECCFG.PINCM[28] |= 0X01<<0 | 0X01<<7; //设置GPIO口为输出功能
GPIOB->DOESET31_0 = 0X01<<12; //输出启用设置
GPIOB->DOUTSET31_0 = 0X01<<12; //数据输出设置
//PB17,led4
IOMUX->SECCFG.PINCM[42] |= 0X01<<0 | 0X01<<7;
GPIOB->DOESET31_0 = 0X01<<17;
GPIOB->DOUTSET31_0 = 0X01<<17;
//PB15,led6
IOMUX->SECCFG.PINCM[31] |= 0X01<<0 | 0X01<<7;
GPIOB->DOESET31_0 = 0X01<<15;
GPIOB->DOUTSET31_0 = 0X01<<15;
//PB0,led7
IOMUX->SECCFG.PINCM[11] |= 0X01<<0 | 0X01<<7;
GPIOB->DOESET31_0 = 0X01<<0;
GPIOB->DOUTSET31_0 = 0X01<<0;
//PB16,led9
IOMUX->SECCFG.PINCM[32] |= 0X01<<0 | 0X01<<7;
GPIOB->DOESET31_0 = 0X01<<16;
GPIOB->DOUTSET31_0 = 0X01<<16;
//PB20,led10
IOMUX->SECCFG.PINCM[47] |= 0X01<<0 | 0X01<<7;
GPIOB->DOESET31_0 = 0X01<<20;
GPIOB->DOUTSET31_0 = 0X01<<20;
//PB13,led12
IOMUX->SECCFG.PINCM[29] |= 0X01<<0 | 0X01<<7;
GPIOB->DOESET31_0 = 0X01<<13;
GPIOB->DOUTSET31_0 = 0X01<<13;
}
void GROUP1_IRQHandler(void)
{
int nowiidx;//记录中断引脚参数
switch (CPUSS->INT_GROUP[1].IIDX)//记录中断总线
{
case 1: //GPIOA 中断IIDX
nowiidx = GPIOA->CPU_INT.IIDX; //记录中断引脚
if (nowiidx == 19) //引脚编号加1,具体中断A,B
{
GPIOB->DOUTCLR31_0 = 0X01<<1;//输出启用清除
GPIOB->DOUTCLR31_0 = 0X01<<12; //输出启用清除
GPIOB->DOUTCLR31_0 = 0X01<<17; //输出启用清除
GPIOB->DOUTCLR31_0 = 0X01<<15; //输出启用清除
GPIOB->DOUTCLR31_0 = 0X01<<0;
GPIOB->DOUTCLR31_0 = 0X01<<16;
GPIOB->DOUTCLR31_0 = 0X01<<20;
GPIOB->DOUTCLR31_0 = 0X01<<13;
GPIOB->DOUTSET31_0 = 0X01<<12; //数据输出启用设置
GPIOB->DOUTSET31_0 = 0X01<<15; //数据输出启用设置
GPIOB->DOUTSET31_0 = 0X01<<16;
GPIOB->DOUTSET31_0 = 0X01<<13;
}
if (nowiidx == 18) //引脚编号加1,具体中断A,B
{
GPIOB->DOUTCLR31_0 = 0X01<<1;
GPIOB->DOUTCLR31_0 = 0X01<<12;
GPIOB->DOUTCLR31_0 = 0X01<<17;
GPIOB->DOUTCLR31_0 = 0X01<<15;
GPIOB->DOUTCLR31_0 = 0X01<<0;
GPIOB->DOUTCLR31_0 = 0X01<<16;
GPIOB->DOUTCLR31_0 = 0X01<<20;
GPIOB->DOUTCLR31_0 = 0X01<<13;
GPIOB->DOUTSET31_0 = 0X01<<1;
GPIOB->DOUTSET31_0 = 0X01<<17;
GPIOB->DOUTSET31_0 = 0X01<<0;
GPIOB->DOUTSET31_0 = 0X01<<20;
}
break;
case 2: //GPIOB 中断IIDX
nowiidx = GPIOB->CPU_INT.IIDX; //记录中断引脚
if (nowiidx ==7)
{
GPIOB->DOUTCLR31_0 = 0X01<<1;
GPIOB->DOUTCLR31_0 = 0X01<<12;
GPIOB->DOUTCLR31_0 = 0X01<<17;
GPIOB->DOUTCLR31_0 = 0X01<<15;
GPIOB->DOUTCLR31_0 = 0X01<<0;
GPIOB->DOUTCLR31_0 = 0X01<<16;
GPIOB->DOUTCLR31_0 = 0X01<<20;
GPIOB->DOUTCLR31_0 = 0X01<<13;
GPIOB->DOUTSET31_0 = 0X01<<1;
GPIOB->DOUTSET31_0 = 0X01<<15;
GPIOB->DOUTSET31_0 = 0X01<<0;
GPIOB->DOUTSET31_0 = 0X01<<13;
}
if (nowiidx ==8)
{
GPIOB->DOUTCLR31_0 = 0X01<<1;
GPIOB->DOUTCLR31_0 = 0X01<<12;
GPIOB->DOUTCLR31_0 = 0X01<<17;
GPIOB->DOUTCLR31_0 = 0X01<<15;
GPIOB->DOUTCLR31_0 = 0X01<<0;
GPIOB->DOUTCLR31_0 = 0X01<<16;
GPIOB->DOUTCLR31_0 = 0X01<<20;
GPIOB->DOUTCLR31_0 = 0X01<<13;
GPIOB-> DOUTSET31_0 = 0X01<<1;
GPIOB-> DOUTSET31_0 = 0X01<<12;
GPIOB-> DOUTSET31_0 = 0X01<<17;
GPIOB-> DOUTSET31_0 = 0X01<<15;
GPIOB-> DOUTSET31_0 = 0X01<<0;
GPIOB-> DOUTSET31_0 = 0X01<<16;
GPIOB-> DOUTSET31_0 = 0X01<<20;
GPIOB-> DOUTSET31_0 = 0X01<<13;
}
break;
}
本节介绍了对GPIO口进行中断配置,设置引脚对应的IOMUX寄存器、操作GPIO中断寄存器、然后关闭中断屏蔽,再开启下降沿触发。
注意
DOE与DOUT寄存器存在区别,中断控制需要记录具体GPIO口。
IIDX中断每读取一次这个寄存器就会自动全部清0。在从CPU读取后,就必须使用第二高优先级中断清0该寄存器。
IIDX中断寄存器只通过使用IMASK选择的中断。
关于其他中断配置,笔者会放在其他章节介绍。