技术文章: 操作系统中的中断详解

一口Linux
关注

五、代码实现

要处理中断异常,必须安装异常向量表,异常的处理流程可以参考前面的文章《6. 从0开始学ARM-异常、异常向量表、swi》

1. 异常向量表基址

异常向量表地址是可以修改的,比如uboot在启动的时候,会从flash中搬运代码到RAM中,而flash的异常向量表地址和ram的地址肯定不一样,所以搬运完代码后,就必须要修改对应的异常向量表地址。

修改异常向量表的地址的需要借助协处理器指令mcr:

ldr r0,=0x40008000
mcr p15,0,r0,c12,c0,0  @ Vector Base Address Register

上述命令是将地址0x40008000设置为异常向量表的地址,关于mcr指令,我们没有必要深究,知道即可。

RAM中异常向量表地址我们选用的是0x40008000,以下是exynos4412 地址空间分布。

exynos4412 地址分布2. 异常向量表安装.text
.global _start
_start:
 b  reset
 ldr  pc,_undefined_instruction
 ldr  pc,_software_interrupt
 ldr  pc,_prefetch_abort
 ldr  pc,_data_abort
 ldr  pc,_not_used
 ldr  pc,=irq_handler
 ldr  pc,_fiq
reset:
ldr r0,=0x40008000
mcr p15,0,r0,c12,c0,0  @ Vector Base Address Register
init_stack:
//初始化栈
……
b main //跳转至c的main函数
irq_handler: //中断入口函数
sub  lr,lr,#4
stmfd sp!,{r0-r12,lr}
.weak do_irq
bl do_irq
ldmfd sp!,{r0-r12,pc}^
stacktop:    .word   stack+4*512//栈顶
.data
stack:  .space  4*512 //栈空间

中断入口函数do_irq()

void do_irq(void)

static int a = 1;
int irq_num;
irq_num = CPU0.ICCIAR&0x3ff;  //获取中断号
switch(irq_num)

 case 57:
  printf("in the irq_handler");
  //清GPIO中断标志位
  EXT_INT41_PEND = EXT_INT41_PEND |((0x1 << 1));
  //清GIC中断标志位
  ICDICPR.ICDICPR1 = ICDICPR.ICDICPR1 | (0x1 << 25);
 break;

 //清cpu中断标志
CPU0.ICCEOIR = CPU0.ICCEOIR&(~(0x3ff))|irq_num;位

实现按键中断的初始化函数key_init():

void key_init(void)  
{  
   GPX1.CON =GPX1.CON & (~(0xf << 4)) |(0xf << 4); //配置引脚功能为外部中断  
   GPX1.PUD = GPX1.PUD & (~(0x3 << 2));  //关闭上下拉电阻  
   EXT_INT41_CON = EXT_INT41_CON &(~(0xf << 4))|(0x2 << 4); //外部中断触发方式  
   EXT_INT41_MASK = EXT_INT41_MASK & (~(0x1 << 1));  //使能中断  
   ICDDCR = 1;  //使能分配器  
   ICDISER.ICDISER1 = ICDISER.ICDISER1 | (0x1 << 25); //使能相应中断到分配器  
   ICDIPTR.ICDIPTR14 = ICDIPTR.ICDIPTR14 & (~(0xff << 8))|(0x1 << 8); //选择CPU接口  
   CPU0.ICCPMR = 255; //中断屏蔽优先级  
   CPU0.ICCICR = 1;   //使能中断到CPU  
  return ;  
} 

六、轮询方式

除了中断方式之外我们还可以通过轮询方式读取按键的信息,原理如下:

循环检测GPX1_1引脚输入的电平,为低电压时,按键按下,为高电平时,按键抬起。
配置GPX1_1引脚功能为输入,设置内部上拉下拉禁止。 GPX1.CON = GPX1.CON &(~(0xf<<4)) ;
GPX1.PUD = GPX1.PUD & ~(0x3 << 2);

按键消抖:按键按下后由于机械特性,会在极短的时间内出现电平忽0忽1,所以我们检测到按键按下后,需要给一个延时,然后再判断按键是不是仍然按下。

代码实现

int main (void)

led_init();
pwm_init();
GPX1.CON = GPX1.CON &(~(0xf<<4))|0x0<<4;
while(1)

    if(!(GPX1.DAT & (0x1<<1)))  // 返回为真,按键按下
    {
     delay_ms(10);
        if(!(GPX1.DAT & (0x1<<1))) //二次检测,去抖
        {
            GPX2.DAT |= 0x1 << 7;  //Turn on LED2
            delay_ms(500);
            beep_on();
            GPX2.DAT &= ~(0x1<<7);  //Turn off LED2
            delay_ms(500);
            while(!(GPX1.DAT & (0x1<<1)));
            beep_off();
        }
    }

  return 0;


声明: 本文由入驻OFweek维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。
侵权投诉

下载OFweek,一手掌握高科技全行业资讯

还不是OFweek会员,马上注册
打开app,查看更多精彩资讯 >
  • 长按识别二维码
  • 进入OFweek阅读全文
长按图片进行保存