1.外设中断寄存器说明
F2833x系列可支持7个外部中断,分别是XINT1-XINT7,每个外部中断可以选择上升沿或下降沿触发,且可以被使能或禁止。
GPIO外部中断寄存器主要有选择寄存器(GPIOXINTnSEL)控制寄存器(XINTnCR)(n=1~7)
1.1 选择寄存器
选择寄存器GPIOXINTnSEL的含义如下图所示:
- GPIOXINTnSEL16位寄存器的0-4位数值表示所选择的的外部中断GPIO口
- GPIO0-31引脚可选择的外部中断XINT1或者XINT2,GPIO32-63号引脚可选择外部中断XINT3~7
- 选择寄存器和配置寄存器相互对应,如GPIOXINT1SEL对应XINT1CR
1.2 配置寄存器
选择寄存器XINTnCR的含义如下图所示:
- XINTnCR16位寄存器的0位数值表示外部中断的使能信号,0表示不使能,1表示使能
- XINTnCR16位寄存器的2~3位表示中断信号的极性选择,0表示下降沿触发,1表示上升沿触发
- 配置寄存器所配置的对象为选择寄存器选择的中断,二者相互对应,如GPIOXINT1SEL对应XINT1CR
2.代码实例
下面通过外部GPIO中断触发LED灯的实例来进行说明。硬件电路如下如所示:
其中:
- TZ1连接GPIO12
- TZ2连接GPIO13
- EQEP1A连接GPIO50
- LED灯组D8-D14分别对应的GPIO引脚为GPIO60/GPIO61/GPIO64~68
当按下或松开按键SW3时,EQEP1A的高低电平信号会触发TZ1有一个高低电平变化的信号,从而可以触发外部GPIO中断,操作LED灯以某种变化点亮或熄灭,同理,当按下或松开按键SW6时,EQEP1A的高低电平信号会触发TZ2有一个高低电平变化的信号。代码实现如下:
// 中断服务子程序声明
interrupt void xint1_isr(void);
interrupt void xint2_isr(void);
// 全局变量定义;
volatile Uint32 Xint1Count; //发生外部中断1的次数;
volatile Uint32 Xint2Count; //发生外部中断2的次数;
volatile Uint32 Xint2Loop; //给外部中断2的for循环变量
#define keyon1 GpioDataRegs.GPADAT.bit.GPIO12
#define keyon2 GpioDataRegs.GPADAT.bit.GPIO13
#define DELAY 35.700L
void main(void)
{
// 步骤 1. 初始化系统控制:
// 设置PLL, WatchDog, 使能外设时钟
InitSysCtrl();
EALLOW;
//初始化GPIO50
GpioCtrlRegs.GPBPUD.bit.GPIO50 = 0; // 使能 GPIO50 引脚上拉
GpioDataRegs.GPBCLEAR.bit.GPIO50 = 1; // GPIO50引脚复位
GpioCtrlRegs.GPBMUX2.bit.GPIO50 = 0; // GPIO50定义为输入输出
GpioCtrlRegs.GPBDIR.bit.GPIO50 = 1; // GPIO50 用于输出
EDIS;
DINT; // 禁止CPU全局中断
// 初始化PIE控制寄存器到他们的默认状态,禁止PIE中断及清除所有PIE中断标志
InitPieCtrl();
// 禁止CPU中断和清除所有CPU中断标志
IER = 0x0000;
IFR = 0x0000;
// 初始化PIE中断向量表,并使其指向中断服务子程序(ISR)
InitPieVectTable();
// 用到的中断重新映射到定义的中断服务子程序;
EALLOW; // 修改被保护的寄存器,修改前应添加EALLOW语句
PieVectTable.XINT1 = &xint1_isr;
PieVectTable.XINT2 = &xint2_isr;
EDIS; // EDIS的意思是不允许修改被保护的寄存器
// 清除计数器
Xint1Count = 0; // 计数外部中断1(XINT1)
Xint2Count = 0; // 计数外部中断2(XINT2)
// 在外设中断扩展模块中断使能寄存器中允许XINT1和XINT2: (PIE组1中断4 & 5)
// 使能CPU中断1(INT1):
PieCtrlRegs.PIECTRL.bit.ENPIE = 1; // 使能外设中断扩展PIE模块
PieCtrlRegs.PIEIER1.bit.INTx4 = 1; // 使能PIE组1的INT4
PieCtrlRegs.PIEIER1.bit.INTx5 = 1; // 使能PIE组1的INT5
IER |= M_INT1; // 使能CPU中断1(INT1)
EINT; // 开全局中断
// GPIO60-61,GPIO64-68 功能选择为通用I/O口,并输出高电;
EALLOW;
GpioDataRegs.GPBSET.bit.GPIO60 = 1; // 输出高电平
GpioCtrlRegs.GPBMUX2.bit.GPIO60 = 0; // 选择为通用I/O口
GpioCtrlRegs.GPBDIR.bit.GPIO60 = 1; // 方向定义为输出
GpioDataRegs.GPBSET.bit.GPIO61 = 1; // 输出高电平
GpioCtrlRegs.GPBMUX2.bit.GPIO61 = 0; // 选择为通用I/O口
GpioCtrlRegs.GPBDIR.bit.GPIO61 = 1; // 方向定义为输出
GpioDataRegs.GPCSET.all = 0x001F; // GPIO64-66输出高电平
GpioCtrlRegs.GPCMUX1.all = 0x0000; // GPIO64-68选择为通用I/O口
GpioCtrlRegs.GPCDIR.all = 0x0001F; // GPIO64-68方向定义为输出
EDIS;
// GPIO12和GPIO13配置为输入引脚通用I/O口
EALLOW;
GpioCtrlRegs.GPAMUX1.bit.GPIO12 = 0; // 选择为通用I/O口
GpioCtrlRegs.GPADIR.bit.GPIO12 = 0; // 方向定义为输入
GpioCtrlRegs.GPAQSEL1.bit.GPIO12 = 0; // 外部中断1(XINT1)与系统时钟SYSCLKOUT同步
GpioCtrlRegs.GPAMUX1.bit.GPIO13 = 0; // 选择为通用I/O口
GpioCtrlRegs.GPADIR.bit.GPIO13 = 0; // 方向定义为输入
GpioCtrlRegs.GPAQSEL1.bit.GPIO13 = 2; // 外部中断2(XINT2)输入限定6个采样窗口
GpioCtrlRegs.GPACTRL.bit.QUALPRD1 = 0xFF; // 每个采样窗口的周期为510*SYSCLKOUT
EDIS;
// 通过GPIO外部中断选择寄存器,选择GPIO10为外部中断1,选择GPIO11为外部中断2
EALLOW;
GpioIntRegs.GPIOXINT1SEL.bit.GPIOSEL = 0x0C; // XINT1是GPIO12
GpioIntRegs.GPIOXINT2SEL.bit.GPIOSEL = 0x0D; // XINT2是GPIO13
EDIS;
// 配置外部中断1和2的中断控制寄存器
XIntruptRegs.XINT1CR.bit.POLARITY = 0; // 下降沿触发中断
XIntruptRegs.XINT2CR.bit.POLARITY = 0; // 下降沿触发中断
// 使能外部中断1和外部中断2
XIntruptRegs.XINT1CR.bit.ENABLE = 1; // 使能XINT1
XIntruptRegs.XINT2CR.bit.ENABLE = 1; // 使能XINT2
// 步骤6. 无限循环:
for(;;);
}
//步骤7.在这里插入中断服务子程序,如果需要使用中断服务子程序,必须在步骤5中重新定义中断
//向量表中对应地地址
interrupt void xint1_isr(void)
{
Uint32 i;
for(i=0;i<1000000;i++); //键盘消抖动
while(keyon1==0);
GpioDataRegs.GPBTOGGLE.all = 0x30000000; // GPIO60-GPIO61输出电平取反
GpioDataRegs.GPCTOGGLE.all = 0x001F; // GPIO64-GPIO68输出电平取反
Xint1Count++;
// 应答寄存器的位1清0,以响应同组内其他中断;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}
interrupt void xint2_isr(void)
{
Uint32 i;
for(Xint2Loop=1;Xint2Loop<=8;Xint2Loop++)
{
GpioDataRegs.GPBTOGGLE.all = 0x30000000; // GPIO60-GPIO61输出电平取反
GpioDataRegs.GPCTOGGLE.all = 0x001F; // GPIO64-GPIO68输出电平取反
DELAY_US(100000); //延时0.1s
}
Xint2Count++;
for(i=0;i<1000000;i++); //键盘消抖动
while(keyon2==0);
// 应答寄存器的位1清0,以响应同组内其他中断;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}
- 从子程序实例可以看出,当按下按键SW3时,LED灯不变化,灯松开时,灯由亮变灭,或由灭变亮,当按下按键SW4时,LED灯立即以较快的频率反复亮灭几次。
最后,附上一张2812中的外部中断在PIE中的分组表,其他相关知识,可参考DSP2812之中断系统