zoukankan      html  css  js  c++  java
  • s5pv210的外部中断

      中断,在学单片机的时候就没有学好,这次接触到210的中断体系,直接蒙圈了。。前天下午老师简单的讲了一下,他的每句话拆开都可以听得懂,联系起来就傻了,,而且懂了与会写差距还远着呢。当天下午所有人都是萎靡的状态(不懂,不会写极其郁闷),以为参照裸机开发指南可以边写会慢慢理解,结果越写越是打击。晚上没有回去,一直想体验下在教室通宵的感觉,除了蚊子比较多、床不好睡、网速依旧渣、睡得太累,好吧,好像并没有什么优点。

      虽然说是通宵了,但是几乎什么都没有学到,反而把自己搞得劳累。得不偿失!早上去领了免费包子,吃完回教室,大家在吐槽寝室那边“习俗”的事和程序的事,得到老师的承诺说下午会带着写程序,整个早上也没有怎么瞎折腾了,随便看看。

      前几天写好的makefile今天打开居然无法使用,编译到最后连接的时候有段错误!!(致命一击),重新把程序审视了一遍,什么都没有发现。请教老师也没有找出来,可能是ld程序出错了,后来重启了几次依旧如此,不想再纠结了,直接做中断了。

      6410和210的中断体系增加了向量中断的概念,相比2440,复杂程度乘法增加的。部分理解如下:

      四个向量中断:每个分别存放32个中断源,注意是中断”源“,不是单个中断,理解这点很重要,因为每个中断“源”里面包含了若干中断

              其中外部中断全部在第一个中断向量中,中断“源”是16,,,16中断“源”包含了EXT_INT[16] ~ [31]号中断,这里主要讨论16--19和24--28号的外部按键中断

              由于存在中断“源”和具体中断的区别,所以分别有两套寄存器控制着,这一点也是非常重要的,操作“源”就可以操作里面的中断,里面具体的哪一号中断还要          另外控制。呵呵,现在只能理解部分,以后要好好加深。

      中断处理函数和中断服务程序:(起这样两个名字的人有没有考虑过初学者的感受。。。)处理一个中断需要两级跳转,首先是跳转到中断处理函数(irq_handle和irq_handler          这两个函数真心不晓得是哪个),中断处理函数负责入栈、出栈等操作外,还负责跳转到中断服务程序(isr_key),在中断服务函数判断产生了具体哪个中断          (不是哪个中断“源”),然后执行相应的操作。

      关于注册地址:中断处理函数需要注册到异常向量表的中断异常地址上,实现中断异常的跳转。

             中断服务程序需要注册到相应的中断“源”地址上,

             因为两者都是通过注册地址来调用的,所以都不需要直接动手调用函数

     /******************************************************************************************************************************************************************************************************************/      具体程序如下: 

    #include "stdio.h"

    // 1.设置按键
    #define GPH2CON     *((volatile unsigned int *)0xE0200C40)
    #define GPH3CON      *((volatile unsigned int *)0xE0200C60)


    //中断状态寄存器,可以通过该寄存器知道中断是否发生
    #define VIC0IRQSTATUS     *((volatile unsigned int *)0xF2000000)
    //中断选择
    #define VIC0INTSELECT     *((volatile unsigned int *)0xF200000C)
    //中断使能寄存器
    #define VIC0INTENABLE      *((volatile unsigned int *)0xF2000010)
    //禁止所有中断
    #define VIC0INTENCLEAR    *((volatile unsigned int *)0xF2000014)


    //存放中断处理函数的地址
    //VICAddress:向量地址寄存器.当IRQ中断产生时,
    //此寄存器保存当前激活的中断向量的地址.
    #define VIC0ADDR       *((volatile unsigned int *)0xF2000F00)
    //存放中断服务程序的地址
    #define VIC0VECTADDR16   *((volatile unsigned int *)0xF2000140)
    //#define VIC0_BASE (0xF2000000)
    //#define VIC0EINT16ADDR    ( *((volatile unsigned long *)(VIC0_BASE + 0x100 + 64)) )

    //设置中断为下降沿触发
    #define EXT_INT_2_CON *((volatile unsigned int *)0xE0200E08)
    #define EXT_INT_3_CON *((volatile unsigned int *)0xE0200E0C)
    //不屏蔽中断
    #define EXT_INT_2_MASK   *((volatile unsigned int *)0xE0200F08)
    #define EXT_INT_3_MASK   *((volatile unsigned int *)0xE0200F0C)
    //记录中断,有中断发生相应位就会置1,初始化时相应位清零
    //可以用来检测具体哪一个中断是否发生
    //VIC0IRQSTATUS是检测是否有中断产生(总体与个体的关系)
    #define EXT_INT_2_PEND   *((volatile unsigned int *)0xE0200F48)
    #define EXT_INT_3_PEND    *((volatile unsigned int *)0xE0200F4C)

    //中断向量表
    #define _Exception_Vector 0xD0037400
    #define pExceptionRESET      ( *((volatile unsigned long *)(_Exception_Vector + 0x0)) )
    #define pExceptionUNDEF     ( *((volatile unsigned long *)(_Exception_Vector + 0x4)) )
    #define pExceptionSWI          ( *((volatile unsigned long *)(_Exception_Vector + 0x8)) )
    #define pExceptionPABORT       ( *((volatile unsigned long *)(_Exception_Vector + 0xc)) )
    #define pExceptionDABORT       ( *((volatile unsigned long *)(_Exception_Vector + 0x10)) )
    #define pExceptionRESERVED       ( *((volatile unsigned long *)(_Exception_Vector + 0x14)) )
    #define pExceptionIRQ          ( *((volatile unsigned long *)(_Exception_Vector + 0x18)) )
    #define pExceptionFIQ       ( *((volatile unsigned long *)(_Exception_Vector + 0x1c)) )


    void IRQ_handle(void); //用来现场保护和恢复,并且跳转到中断处理函数,不用调用

    void enable_irq(void); //使能cpsr的总中断
    void disable_irq(void); //关闭cpsr的总中断

    void key_isq(void);
    void delay(void);
    /************************************************************************************************/
    int init_interrupt_reg()
    {

        //printf("here1 ");
      //禁止所有中断
      VIC0INTENCLEAR = 0xffffffff;

       //设置成普通中断模式
      VIC0INTSELECT = 0x0;

      //清除中断地址
      VIC0ADDR = 0x0;
      return 0;
    }

    int init_gpio(void)
    {
    //printf("here3 ");
    //设置GPH2 0~3为中断方式
    //GPH2CON &= 0xffff0000;
    GPH2CON |= 0x0000ffff;
    GPH3CON |= 0x0000ffff;

    //设置外部中断为下降沿触发
    EXT_INT_2_CON &= 0xffff8888; //保留位不清零
    EXT_INT_2_CON |= 0x00002222;

    EXT_INT_3_CON &= 0xffff8888; //保留位不清零
    EXT_INT_3_CON |= 0x00002222;

    //打开外部中断16--19
    EXT_INT_2_MASK &= 0xfffffff0;
    //打开外部中断24--27
    EXT_INT_3_MASK &= 0xfffffff0;

    //通过清除中断记录,清除外部中断,写1清零
    EXT_INT_2_PEND = 0xff;
    EXT_INT_3_PEND = 0xff;

    //使能16号外部中断源

    VIC0INTENABLE |= (0x1<<16);
    return 0;
    }

    int set_isr_addr(void)
    {
    //printf("here2 ");

    //注册中断服务子函数到相应的中断响应地址
    //每个源都有一个特有的地址,16号中断源
    VIC0VECTADDR16 = (unsigned long)key_isq;

    //注册中断处理函数到中断异常
    pExceptionIRQ = (unsigned long)IRQ_handle;

    return 0;
    }

    //编写中断服务子函数
    void key_isq(void)
    {
    //printf("here6 ");
    delay();//消抖

    unsigned int reg = 0;
    unsigned int reg1 = 0;
    reg = EXT_INT_2_PEND;//有中断产生时相应位就会有记录为1
    reg1 = EXT_INT_3_PEND; // 25--28的中断记录

    //判断16--19号外部中断产生 了哪一个
    if((reg & 0x01)==0x01)
    {
    //记录位为1,有中断,为EINT16
    printf("key1(EINT16) down ");
    }
    else if(reg & (0x01<<1))
    {
    //记录位为1,有中断,为EINT17
    printf("key2(EINT17) down ");
    }
    else if(reg & (0x01<<2))
    {
    //记录位为1,有中断,为EINT18
    printf("key3(EINT18) down ");
    }
    else if(reg & (0x01<<3))

    {
    //记录位为1,有中断,为EINT19
    printf("key4(EINT19) down ");
    }

    //判断25--28号外部中断产生 了哪一个
    if((reg1 & 0x01)==0x01)
    {
    //记录位为1,有中断,为EINT19
    printf("key5(EINT24) down ");
    }
    else if(reg1 & (0x01<<1))
    {
    //记录位为1,有中断,为EINT19
    printf("key6(EINT25) down ");
    }
    else if(reg1 & (0x01<<2))
    {
    //记录位为1,有中断,为EINT19
    printf("key7(EINT26) down ");
    }
    else if(reg1 & (0x01<<3))
    {
    //记录位为1,有中断,为EINT19
    printf("key8(EINT27) down ");
    }

    VIC0ADDR =0x0; //随便写入一个值表示中断服务子函数结束

    EXT_INT_2_PEND = 0xf; //通过写1去清零16--19相应的记录位
    EXT_INT_3_PEND = 0xf; //通过写1去清零25--28相应的记录位

    }


    typedef void funp(void);//定义了funp的函数类型,记得加;号
    //中断处理函数
    void irq_handler(void)
    {
    //printf("here5 ");

    unsigned int reg = 0;

    void (*isr)(void);

    reg = VIC0IRQSTATUS;

    if(reg !=0)
    {
    //有中断产生
    isr = (funp*)VIC0ADDR;//类型强转,读取中断向量的地址执行中断服务子程序
    }
    (*isr)();
    }
    /**************************************************************************************/
    void init_exint(void)
    {
    disable_irq();
    init_interrupt_reg();

    set_isr_addr();

    //irq_handler(void);由IRQ_handle()函数调用到

    //中断处理函数和中断服务程序不用注册,
    //key_isq(void);由于已经安装了地址,有中断产生时自然会调用

    init_gpio();

    enable_irq();
    }

    、*********************************************************************************************************************************************************************/

      吐槽下博客园的程序文本格式。。。

      虽然说程序写完了,准确的说是抄完了,现在让我一个写还是没有把握写出来,毕竟那么多寄存器不是那么好找的,更别说用了。在老师程序的基础上,完成了全部八个外部按键中断,

      还有一点是要注意的是,由于裸机是没有标准库的,所以要想很好的调试程序,在裸机上面移植了网上的printf函数,只要把自己写的程序最后组装成一个函数,然后直接把组装好的函数扔进printf的主函数即可。

      记得要把源代码赋值到printf的目录,直接加到项目工程是不能编译的,,,加进去之后还有把目录里面的加载到工程里面,否则修改不到。。。(这种错误,智商捉急啊。。)

  • 相关阅读:
    BZOJ3573: [Hnoi2014]米特运输
    BZOJ3531: [Sdoi2014]旅行
    BZOJ3505: [Cqoi2014]数三角形
    BZOJ3309: DZY Loves Math
    BZOJ3260: 跳
    BZOJ3252: 攻略
    BZOJ3226: [Sdoi2008]校门外的区间
    BZOJ3155: Preprefix sum
    BZOJ2843: 极地旅行社
    BZOJ2671: Calc
  • 原文地址:https://www.cnblogs.com/ygy1784717631/p/4778229.html
Copyright © 2011-2022 走看看