全部博文(36)
分类: 嵌入式
2012-08-27 19:20:05
昨天晚上写了一遍文章就是按键控制led灯的,不知道为啥这个坑爹的把我的博文给弄没了,显示有四篇,可是只能看见3篇。
按键控制led灯,这是第二个实验。按键我使用是外部中断,在中断处理函数里面点亮led灯。
要完成这个实验的话,主要是熟悉中断控制系统。首先贴个图。
这个就是2440中断控制部分的处理框图,如果你把这个框图看明白了,基本中断就没有问题了。而中断控制部分,我觉得也是arm裸机控制中最核心最麻烦的一部分,那么我就必须要征服它。
从图中可以看出来,请求源分为两个,第一个是带sub寄存器的,另一个是不带sub寄存器的。这个的区别就是说有没有分支,带sub的就是有分支的,不带的就是没有分支的。比如串口,肯定是有分支的,有接受和发送;再比如,外部中断,肯定没有分支。
首先看带sub的,首先经过一个subsrcpnd,这个是带sub的挂起寄存器,不好懂,其实它就是告诉你中断来了没有,如果外面来了一个中断,那么这个寄存器就会自动把相应的置位。注意这里是自动置位,不需要你人为地控制。然后经过一个submask,这个是带sub的屏蔽寄存器,好懂,屏蔽你的中断,你就算到了这里,我也不让你过(留下买路财都没用),然后就是到了带sub和不带sub都经过的地方srcpnd,这个与前面subsrcpnd是一样的,然后到了mask,这个与sunmask是一样意思,总屏蔽,这个关你也要过,不然你中断还是得倒在这里。这里还有一个mode,这个就是设置为什么模式,快速中断firq还是普通的irq,默认是irq。最后终于到了intpnd这里了,这个也是一个挂起寄存器,表示你是否产生了中断,看似好像跟以前的一样,但是其实不是一样的。刚开始的subsrcpnd、srcpnd置位的话,可能有多个中断来了,因为这个不一定的,但是最后一个是表明正在处理的,那么肯定只有一个,这就是区别。
熟悉了中断控制部分了,那么我们接下来就是操作寄存器。与上面对应的寄存器有srcpnd,intmod,intmsk,intpnd、intoffset,sunsrcpnd,intsubmsk。这几个寄存器是分别与上面的部分对应的。由于我们这里是使用外部中断,所以还要设置外部中断相关的部分,这里有这么几个寄存器extintn,eintmask,eintpend,从名字可以看出,分别是外部中断的控制,屏蔽,挂起寄存器,看一下2440的用户手册就会明白它的用法。那么知道寄存器了,我们就可以写代码了,可以按照刚才上面讲的一步一步写下去。
我这里说一下我写的时候,遇到的一些问题。第一点,当你设置相应的位,那么你只要管好你要设置的位,不要去碰其他的位,不然后果有点严重,效果出不来;第二点,对于某些寄存器的设置要按照特定的方式,rINTMSK &=~(1<<5);和rINTMSK &= (0<<5);你可以自己试试看,这两个的效果是不一样的,因为这个寄存器的初始值的关系,所以你得按照第一种规范的方式,不然效果肯定出不来;第三点,就是关于中断函数的,首先你的中断向量表与你启动代码中的要一致,不然出问题,还有中断函数加一个__irq,无参数,无返回值,而且记得在里面把挂起寄存器的内容清掉,因为你从图中看的出来,如果你不清掉的话,它就会一直响应中断,那么你的程序就会一直死在那里。你的中断响应就是因为挂起的置位导致的,所以清零之后让它可以重新接受你(忘掉以前那个混球)。
下面把主要代码贴出来,mini2440玩家可以参考参考。
void __irq interupt()
{
if(rEINTPEND & (1<<8)) //检测到K1 按下
{
rGPBDAT = ~(0x1<<5); //第一个LED灯亮
rEINTPEND &= ~(1<<8);
}
if(rEINTPEND & (1<<11)) //检测到K2 按下
{
rGPBDAT = ~(0x1<<6); //第二个LED灯亮
}
if(rEINTPEND & (1<<13)) //检测到K3 按下
{
rGPBDAT = ~(0x1<<7); //第三个LED灯亮
}
if(rEINTPEND & (1<<14)) //检测到K4 按下
{
rGPBDAT = ~(0x1<<8); //第四个LED灯亮
}
if(rEINTPEND & (1<<15)) //检测到K5 按下
{
rGPBDAT = ~(0xf<<5); //全亮
}
if(rEINTPEND & (1<<19)) //K6按下
{
rGPBDAT = ~(0x0<<5); //全灭
}
}
void Main(void)
{
Set_Clk();
MMU_Init();
rGPBCON = 0X55 << 10;
//设置中断
rGPGCON &= ~(3 | (3<<6) | (3<<10) | (3<<12) | (3<<14) | (3<<22));
rGPGCON |= ~(2 | (2<<6) | (2<<12) | (3<<12) | (3<<14) | (3<<22));
//打开中断
rEINTMASK &=~(1<<8 | 1<<11 | 1<<13 | 1<<14 | 1<<15 | 1<<19 );
//外部中断触发方式 低电平
rEXTINT1 &=~(7 | (7<<12) | (7<<20) | (7<<24) | (7<<28));
rEXTINT2 &=~(7<<12);
rINTMSK &=~(1<<5);
pISR_EINT8_23 = (U32)interupt;
while(1)
{
rGPGCON |=(0xf<<5);
}
}
整个代码其实不难,但是一定要规范的写,不然效果是出不来的。
又花了点时间把它写完,为了防止类似事件的发生,我觉得保存每次的文章。