按键中断是一种外部中断,即他属于一种异常状态,可以产生中断。那么我们怎么样来分析和编写一个基于S3C2440的按键中断代码呢。
一、第一部我们要初始化号响应的参数,分为三步
1.我们肯定要设置一个中断源,让他能够发出中断信号。必须保证2440能够感受到这个外部中断, 这个时候就要通过设置中断源来实现。
2.我们还需要设置一个中断控制器,让他可以向CPU发出中断信号
3.我们还要再设置CPU,里面有个CPSR,他是中断的总开关
二、处理过程
要分辨中断源你,对不同中断执行不同的中断函数
三、处理完清除中断
大概理清中断的思路之后我们开始写代码。
我们先看数据手册
从数据手册可以看出,Bit7位为中断总开关,我们要把Bit7位清零,当Bit7置1的时候,CPU无法中断。
接着我们开始写代码,我们的大致设置目的是,在按键中断里点亮或熄灭LED灯,我们先定义两个函数,一个是初始化中断控制器的函数,另外一个是初始化按键并且把他设置为中断源的函数。具体函数名字如图:
第一个初始化中断控制器的函数分为三个部分:
- 中断源的初始化:把按键设置为中断引脚,使得他按下或者松开都能触发中断。
- 中断控制器的初始化,
- 设置CPU的CPSR寄存器,使能中断
由数据手册与原理图可以得知:
按键的引脚分别为:按键1:GPF0 按键2:GPG15 按键3:GPG3 按键4:GPG11
接着开始编写这部分的代码:
1.我们先确定按键的引脚并且把他设置为中断引脚
具体代码如下
/*配置GPIO为中断引脚*/
GPFCON &= ~((3<<0) | (3<<4));
GPFCON |= ((2<<0) | (2<<4)); /*s2,s3被配置为中断引脚*/
GPGCON &= ~((3<<6) | (3<<11));
GPGCON |= ((2<<0) | (2<<11)); /*s4,s5被配置为中断引脚*/
/*设置中断触发方式,按下松开都触发中断,双边沿触发*/
EXTINT0 |= (7<<0) | (7<<8); /*s2,s3*/
EXTINT1 |= (7<<12); /* s4 */
EXTINT2 |= (7<<12); /* s5 */
接着我们来看中断开关控制寄存器,查找数据手册得到:我们要把个个中断线控制器的位置0以使能中断控制线。
接着我们来看EINTMASK寄存器
INTMAKS用来屏蔽中断产生
再来看INTPBND寄存器INTPND用来显示当前优先级最高的,正在发生的中断的中断线,我们可以取他的值以得知现在是什么中断在进行
我们先来查阅一下中断向量表
又中断向量表的地址可以得到各个中断方式对应的地址为:
/0x0c :Abort (prefetch)/
/0x10 :Abort (data)/
/0x14 :Reserved/
/0x18 :IRQ/
/0x1c :FIQ/
知道中断的地址之后,我们知道判断是否中断是通过CPSR寄存器的值来判断的,我们来查阅一下数据手册:
查阅数据手册可以得到,当发生外部中断的时候,外部中断CPSR的值为10010,返回地址为CPSR的地址减4。
SRCPND 用来显示哪个中断产生了, 需要清除对应位
由数据手册可得:
- bit0-eint0
- bit2-eint2
- bit5-eint8_23
我们这下可以开始写代码了:
先要使能中断控制器:(通过操控INTMSK来使能开启中断)
使能中断以后,就可以接收来自按键得中断了,中断源有多个,那我们应该怎么样来分辨各个中断呢,由上文可知INTOFFSET寄存器可以确定当前是哪个中断线发生得中断,我们可以通过分析INTOFFSET寄存器的值来确定是哪个中断进而处理中断,代码如下:
if (bit == 0 || bit == 2 || bit == 5) /* eint0,2,eint8_23 */
{
key_eint_irq(bit); /* 处理中断, 清中断源EINTPEND */
}
进入中断并且完成中断中需要完成的任务之后我们要清除掉中断标志位以便于下一次再进入中断,清除中断时我们只需把SRCPND与INTPND寄存器相应的位置1即可清除相应的中断。、
代码如下:
/* 清中断 : 从源头开始清 */
SRCPND = (1<<bit);
INTPND = (1<<bit);
清除中断以后接下来我们编写中断处理函数:
LED与按键的初始化代码我们就省略了:
代码如下:
void key_eint_irq(int irq)
{
unsigned int val = EINTPEND;
unsigned int val1 = GPFDAT;
unsigned int val2 = GPGDAT;
if (irq == 0) /* eint0 : s2 控制 D12 */
{
if (val1 & (1<<0)) /* s2 --> gpf6 */
{
/* 松开 */
GPFDAT |= (1<<6);
}
else
{
/* 按下 */
GPFDAT &= ~(1<<6);
}
}
else if (irq == 2) /* eint2 : s3 控制 D11 */
{
if (val1 & (1<<2)) /* s3 --> gpf5 */
{
/* 松开 */
GPFDAT |= (1<<5);
}
else
{
/* 按下 */
GPFDAT &= ~(1<<5);
}
}
else if (irq == 5) /* eint8_23, eint11--s4 控制 D10, eint19---s5 控制所有LED */
{
if (val & (1<<11)) /* eint11 */
{
if (val2 & (1<<3)) /* s4 --> gpf4 */
{
/* 松开 */
GPFDAT |= (1<<4);
}
else
{
/* 按下 */
GPFDAT &= ~(1<<4);
}
}
else if (val & (1<<19)) /* eint19 */
{
if (val2 & (1<<11))
{
/* 松开 */
/* 熄灭所有LED */
GPFDAT |= ((1<<4) | (1<<5) | (1<<6));
}
else
{
/* 按下: 点亮所有LED */
GPFDAT &= ~((1<<4) | (1<<5) | (1<<6));
}
}
}
EINTPEND = val;
}