zoukankan      html  css  js  c++  java
  • ok6410按键中断编程,linux按键裸机

                      6410按键中断编程

    一、流程分析

    外部中断控制寄存器(s3c6410x  359页)

      

      

    1、EINTxCONy: 外部中断组x的第y个控制器。这个就是设置中断的触发方式。有5种触发方式。

      

    2、EINTxFLTCONy:外部中断组x的第y个滤波功能控制器。S3C6410对于外部中断有滤波功能,这个就是用来设置滤波功能。有延迟滤波,有数字滤波。滤波,可以用来滤掉毛刺信号。在以前51做按键外部中断,按键是有抖动的,就需要一个去抖动的一个东西。但是有了这个滤波的话,直接设定滤波的时间,就可以滤掉这一段时间的毛刺了。就不用再加去抖动的程序了。

      

    3、EINTxMASK:外部中断组x的屏蔽寄存器。用来使能中断的。当要使用某个中断的时候,就需要让这个中断使能,就需要在这个寄存器中的对应位写入0,来打开中断。默认为中断都是屏蔽的。

      

    4、EINTxPEND:外部中断组x的中断挂起寄存器。这个寄存器就是用来保存中断的状态的。当对应的中断产生时,对应的位为1。当中断处理完毕后,需要往对应对写入1进行清除。

    1.1设置引脚为中断模式

      初始化中断源,也就是设置中断源是什么,以及中断的触发方式(高电平,低电平,上边沿,下降沿,双边沿)

      

      #define GPNCON (volatile unsigned long*)0x7f008830 

      void button_init()

      {

          *(GPNCON) = 0xaaa;  

      }

    1.2中断控制器

      初始化中断控制器,也就是使能对应的中断,让中断信号能够传递到CPU。在这里还需要设置中断优先级,中断滤波等与中断的相关设置

      这两个是中断控制器,分别管理各自的32个中断(6410数据手册410页)

      

      为了节约中断,不可能为每个外部管脚都分配一个中断号,所以就会把某几个外部中断给合并成一个中断号。例如,对于外部中断0-3,就合并成了一个中断号,INT_EINT0。当这4个中断有任意一个产生中断时,INT_EINT0会挂起,CPU就会知道产生了外部中断0-3中断,然后去执行中断处理,在中断服务程序中,为了知道具体是哪一个中断,还需要去查询寄存器以知道是哪一个中断产生。

      

      S3C6410中断处理有向量模式和非向量方式。因为要与之前的ARM系列兼容,所以保存了非向量方式。

    1.3中断触发方式

      //配置按键中断下降沿出发

      *(EINT0CON0) = 0x222;

    1.4取消中断屏蔽

      //打开外部中断(取消中断屏蔽)

      *(EINT0MASK) = 0;   

    1.5使能中断号

      //使能外部中断号          

      *(VIC0INTENABLE) = 0x00000003;

    1.6编写中断处理入口

      //将函数地址赋给中断处理程序

      *(VIC0VECTADDR0) = (int)key1_lsr;

      *(VIC0VECTADDR1) = (int)key2_lsr;

    1.7开启向量中断

      

    1.8打开总中断

      

    1.9编写中断服务函数

      在中断函数前和中断函数末尾都有使用嵌入汇编。这段代码是固定的。目的是为了保存环境,将r0-r12,lr寄存器的值给压入栈中,然后执行完后,在将这些值返回给r0-r12,pc寄存器。这样r0-r12寄存器的内容就恢复了,同时pc得到返回地址,就返回到中断前的程序地址去了。

      这里有sub lr,lr,#4。将lr的值减去4。这个原因就要从ARM的流水线说起了。ARM采用流水线,取址,译码,执行。所以pc的值永远是当前执行指令的地址+8.

      中断跳转的时候,会将pc的值给lr,pc的值为当前执行程序地址+8,lr的值就是pc的值。而返回的地址应该是执行阶段的下一条地址,也就是当前执行程序地址+4,所以直接返回lr的值就不对了,应该返回lr-4的值。

      

      中断处理完后,需要将中断挂起位给清零。这里,很简单的将所有中断位都给清零。然后再将中断执行地址给清0。

      这个寄存器,当执行中断函数的时候,值是中断函数的入口地址。往这个寄存器写入任意的值,就清除这个中断了。所以最后需要将这个寄存器给清0。

      

      if((0x01 & GPNDAT) == 0)

          led_on(1); 

      

      因为外部中断源INT_EINT0里面包含外部0~3四个外部中断,所以要通过相应I/O口寄存器数据判断是哪个中断被触发。

    二、源代码如下:

     1 /*interrupt registes*/
     2 #define EXT_INT_0_CON       *((volatile unsigned int *)0x7f008900)   
     3 #define EXT_INT_0_MASK      *((volatile unsigned int *)0x7f008920) 
     4 #define EXT_INT_0_PEND      *((volatile unsigned int *)0x7f008924)     
     5 
     6 #define VIC0INTENABLE       *((volatile unsigned int *)0x71200010)   
     7 
     8 #define EINT0_VECTADDR      *((volatile unsigned int *)0x71200100)  
     9 #define EINT5_VECTADDR      *((volatile unsigned int *)0x71200104) 
    10    
    11 #define VIC0ADDRESS         *((volatile unsigned int *)0x71200f00)   
    12 #define VIC1ADDRESS         *((volatile unsigned int *)0x71300f00)
    13 
    14 #define GPNDAT              *((volatile unsigned int *)0x7F008834)
    15 void key1_handle()
    16 {
    17     __asm__( 
    18     
    19     "sub lr, lr, #4
    "  
    20     "stmfd sp!, {r0-r12, lr}
    "       
    21     : 
    22     : 
    23    );
    24     if((0x01 & GPNDAT) == 0)
    25     led_on(1); 
    26     if((0x02 & GPNDAT) == 0)
    27     led_on(2);
    28     if((0x04 & GPNDAT) == 0)
    29     led_on(3);   
    30     if((0x08 & GPNDAT) == 0)
    31     led_on(4);
    32     /* 清除中断 */
    33     EXT_INT_0_PEND = ~0x0;  
    34     VIC0ADDRESS = 0; 
    35     VIC1ADDRESS = 0; 
    36    
    37     __asm__( 
    38     "ldmfd sp!, {r0-r12, pc}^ 
    "       
    39     : 
    40     : 
    41   );
    42    
    43 }
    44 
    45 void key6_handle()
    46 {
    47     __asm__( 
    48     
    49     "sub lr, lr, #4
    "  
    50     "stmfd sp!, {r0-r12, lr}
    "       
    51     : 
    52     : 
    53   );
    54     if((0x10 & GPNDAT) == 0)
    55     led_on(4); 
    56     if((0x20 & GPNDAT) == 0)
    57     led_off(); 
    58     /* 清除中断 */
    59     EXT_INT_0_PEND = ~0x0; 
    60     VIC0ADDRESS = 0;  
    61     __asm__( 
    62     "ldmfd sp!, {r0-r12, pc}^ 
    "       
    63     : 
    64     : 
    65   ); 
    66 }
    67 
    68 void init_irq()
    69 { 
    70     EXT_INT_0_CON = 0x222;            /* 配置为下降沿触发 */  
    71     
    72     EXT_INT_0_MASK = 0;                   /* 取消屏蔽外部中断 */  
    73  
    74     VIC0INTENABLE = 0x00000003;                     /* 使能外部中断*/  
    75     
    76     EINT0_VECTADDR = (int)key1_handle;           /* 用户按下key时,CPU就会自动的将VIC0VECTADDR0的值赋给VIC0ADDRESS并跳转到这个地址去执 */  
    77     EINT5_VECTADDR = (int)key6_handle;
    78     
    79     __asm__( 
    80     
    81     "mrc p15,0,r0,c1,c0,0
    "
    82     "orr r0,r0,#(1<<24)
    "
    83     "mcr p15,0,r0,c1,c0,0
    "
    84 
    85     "mrs r0,cpsr
    "
    86     "bic r0, r0, #0x80
    "
    87     "msr cpsr_c, r0
    "            
    88     : 
    89     : 
    90   );
    91 }

    当然还有还有IO初始化设置

    1 #define GPNCON (volatile unsigned long*)0x7f008830
    2 
    3 void button_init()
    4 {
    5     *(GPNCON) = 0x00000aaa;        //设置按键1到按键6
    6 }
  • 相关阅读:
    codeforce1028A Find Square
    2018ccpc网络赛 Buy and Resell
    差分约束
    Lost Cows
    动态查询区间第k大
    疫情控制
    天天爱跑步
    次小生成树
    树上差分闇の連锁
    Stars in Your Window
  • 原文地址:https://www.cnblogs.com/wmx-learn/p/5320579.html
Copyright © 2011-2022 走看看