外部按键 控制 LED 中断 (参考 http://www.oschina.net/question/565065_115196?sort=time )

转帖: http://www.oschina.net/question/565065_115196?sort=time

实验目的: mini2440开发板上有6个按键,将其中的前4个按键设为外部中断方式,当按下K1时,LED1亮;当按下K2时,LED2亮;当按下K3时,LED3亮;当按下K4时,LED4亮。

首先我们先了解一下 mini2440 按键和LED接口:

   

GPBCON 地址: 0x56000010 (LED 灯可以参考流水灯的随笔)

GPGCON 地址: 0x56000060

图画错了,应该是 输入模式 input ,而不是 EINT 

要将 GPG 0 3 5 6 7 11 设为 输入功能的话, 那么 但是由于主要考虑的是 K1 k2 K3 K4 所以只要这几个 为输入模式 就行了

19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
            0 0 0 0     0 0         0 0
            input   input       input           input  
            K4   K3       K2           K1  
            GPG6   GPG5       GPG3           GPG0  

 

 

 

 

                                                                        

 

按键接口电路如图2所示,当按键没有按下时,GPGx引脚为高电平;当按键按下时,引脚电平变为低电平。

外部中断文件布局:

该工程有三个模块组成。

按键模块主要包含 button.c 和  button.h

LED模块包含led.c和led.h。

中断处理模块主要包含     interrupt.c、interrupt.h、isrservice.c和isrservice.h文件。其中,interrupt.h和interrupt.c文件主要包含中断初始化函数,isrservice.c和isrservice.h文件主要包含中断处理函数。

_______________________________________________________________________________________________________________________________________________________________________

main.c 文件

 1 #include"led.h"
 2 #include"button.h"
 3 #include"isrservice.h"
 4 #include"interrupt.h"
 5 
 6 
 7 int main()
 8 {    
 9     Led_Init();            //初始化LED
10     KeyInt_Init();        //初始化按键
11     Irq_Init();            //初始化外部中断
12     while(1)            //循环,等待中断发生
13     {   
14         ;                            
15     }
16 }

 

 

————————————————————————————————————————————————————————————————————————————————————————————————————————————————

led.h 文件

 1 #ifndef __LED_H__
 2 #define __LED_H__           
 3 
 4 //   #include<s3c2440.h>   我们也把它注释掉看看
 5 //  添加以下代码
 6 
 7 #define GPBDAT               (*(volatile unsigned long *) 0x56000014)
 8 //  添加上面一行就可以运行,而不需要 GPBDAT GPBUP 说明,这里的 void Led_Init()与它无关
 9 
10 
11 #define Led1_On()        {GPBDAT&=(~(1<<5));}    // 第5位 为 0,按位与,所以 GPBDAT 第五位始终为 0,LED1 也就是 GPB5 灯亮
12 #define    Led1_Off()        {GPBDAT|=(1<<5);}        //  第5位为 1 ,按位或 ,始终为 1 ,灯灭
13 #define Led2_On()        {GPBDAT&=(~(1<<6));}
14 #define    Led2_Off()        {GPBDAT|=(1<<6);}
15 #define Led3_On()        {GPBDAT&=(~(1<<7));}
16 #define    Led3_Off()        {GPBDAT|=(1<<7);}
17 #define Led4_On()        {GPBDAT&=(~(1<<8));}
18 #define    Led4_Off()        {GPBDAT|=(1<<8);}
19 /****************************************************
20 * 函数名称:void Led_Init(void)
21 * 全局变量:无 
22 * 参数说明:无
23 * 返 回 值;无
24 * 功    能:设置GPN5-8为输出功能,初始化4个LED灯灭
25 *****************************************************/
26 void Led_Init(void);
27 
28 #endif

 

 

led.c 文件

 1 /****************************************************
 2 * 我的mini2440开发板上4个LED灯对应的GPIO口
 3 * LED1---GPB5    LED2---GPB6
 4 * LED3---GPB7    LED4---GPB8
 5 
 6 注意 LED 口 是低电平,亮
 7 *****************************************************/
 8 
 9 
10 
11 //   #include<s3c2440.h>    // 我们也把它注释掉,主要为了练习,添加下面代码,来熟悉C语言
12 #define GPBCON               (*(volatile unsigned long *) 0x56000010)
13 #define GPBDAT               (*(volatile unsigned long *) 0x56000014)
14 #define GPBUP                (*(volatile unsigned long *) 0x56000018)
15              
16 
17 /****************************************************
18 * 函数名称:void Led_Init(void)
19 * 全局变量:无 
20 * 参数说明:无
21 * 返 回 值;无
22 * 功    能:设置GPB5-8为输出功能,初始化4个LED灯灭
23 *****************************************************/
24 
25 // 自己添加一下 代码
26 
27 void Led_Init(void)
28 {
29            
30     //    GPBCON&=~((3<<10)|(3<<12)|(3<<14)|(3<<16));
31     //    GPBCON|=((1<<10)|(1<<12)|(1<<14)|(1<<16));//设置GPB5-8口为输出功能
32     //    GPBUP&=~((1<<5)|(1<<6)|(1<<7)|(1<<8));//上拉电阻使能
33     //    GPBDAT|=(1<<5)|(1<<6)|(1<<7)|(1<<8);//令GPBDAT5-8均为高电平,即令4个led灯全灭
34 
35        GPBCON=0x0015400;          //  设置 GPB5-8 口为输出功能 ,也就是   GPB8--GPB5 为 17-10位为(01 01 01 01)(http://www.cnblogs.com/shengruxiahua/p/4888028.html)
36        GPBUP&=~((1<<5)|(1<<6)|(1<<7)|(1<<8));//上拉电阻使能       使得 5-8位 全为0 ,上拉使能
37        GPBDAT|=( (1<<5)|(1<<6)|(1<<7)|(1<<8) ); //  5678位,为 1,使用 按位或 运算符,显然可以令GPBDAT5-8均为高电平,即令4个led灯全灭
38       
39 
40 }

 

 

________________________________________________________________________________________________________________________________________________________________________________________________________

 

button.h 文件

#ifndef __BUTTON_H__
#define __BUTTON_H__

/****************************************************
* 函数名称:void KeyInt_Init()
* 全局变量:无 
* 参数说明:无
* 返 回 值;无
* 功    能:设置GPG0、3、5、6、7、11为外部中断输入功能
*****************************************************/
void KeyInt_Init(void);

#endif

 

 

button.c 文件

 1 /************************************************
 2 * mini2440板子上六个按键对应的GPIO和中断
 3       按键    GPIO  中    断
 4 *       K1   GPG0   EINT8
 5 *       K2   GPG3   EINT11
 6 *       K3   GPG5   EINT13
 7 *       K4   GPG6   EINT14
 8 *       K5   GPG7   EINT15
 9 *       K6   GPG11  EINT19
10 ************************************************/
11 /*
12 #include<s3c2440.h>
13 #include"button.h"   //  不能理解,为什么要添加 这一个文件     ?????????????????????
14 
15 #define    KEY1_C    (3<<0)       // LED1 
16 #define    KEY2_C    (3<<6)       // LED2
17 #define    KEY3_C    (3<<10)       // LED3
18 #define    KEY4_C    (3<<12)       // LED4
19 
20 #define    KEY1    (2<<0)
21 #define    KEY2    (2<<6)
22 #define    KEY3    (2<<10)
23 #define    KEY4    (2<<12)
24 
25 ****************************************************
26 * 函数名称:void KeyInt_Init()
27 * 全局变量:无 
28 * 参数说明:无
29 * 返 回 值;无
30 * 功    能:设置GPG0、3、5、6、7、11为外部中断输入功能
31 *****************************************************/
32 /*
33  void KeyInt_Init(void)
34 {
35     GPGCON&=~(KEY1_C|KEY2_C|KEY3_C|KEY4_C);        
36     GPGCON|=KEY1|KEY2|KEY3|KEY4;    //将GPG0、3、5、6、7、11设为输入功能
37     GPGUP&=~((1<<0)|(1<<3)|(1<<5)|(1<<6));
38     GPGDAT|=(1<<0)|(1<<3)|(1<<5)|(1<<6);        //因为按下按键后,相应的GPIO口为0,所以初始化为高电平    
39 
40     
41 
42 }
43  */
44 
45 // 我们来自己编写一个 中断
46 #include<s3c2440.h>
47 #include"button.h" 
48 
49 #define    KEY1_C    (3<<0)       // LED1      也就是把 10 位设为 11
50 #define    KEY2_C    (3<<6)       // LED2              76         11
51 #define    KEY3_C    (3<<10)       // LED3              11 10        11
52 #define    KEY4_C    (3<<12)       // LED4              13  12    11
53 
54 #define skey       ( ~(KEY1_C|KEY2_C|KEY3_C|KEY4_C) )   //  也就是取反 ,也就是13 12 11 10 7 6 10 全为 00 00 00 00 
55 #define Dkey    (   (1<<0)|(1<<3)|(1<<5)|(1<<6)  )     //   为了后面的 GPG0 3 5 6 位 为 1 1 1 1 
56   
57 void KeyInt_Init(void)
58 {
59     GPGCON&=skey;      //  那么13 12 11 10 7 6 10 全为 00 00 00 00 ,其他位不变,那么GPG0、3、5、6 初始化为 输入模式
60     GPGUP&=~((1<<0)|(1<<3)|(1<<5)|(1<<6));          //  1 3 5 6 位 设为 0 ,上拉电阻
61     GPGDAT|=(1<<0)|(1<<3)|(1<<5)|(1<<6);        // 开关本来是断开的,按下后接通,说明GPG0 3 5 6 被拉低成低电平,说明GPG0 3 5 6 本身就是 高电平,    
62 
63 }

 

 

________________________________________________________________________________________________________________________________________________________________________________________________________

interrupt.h 文件

 1 #ifndef    __INTERRUPT_H__
 2 #define    __INTERRUPT_H__
 3 
 4 
 5 /****************************************************
 6 * 函数名称:void Irq_Init(void)
 7 * 全局变量:无 
 8 * 参数说明:无
 9 * 返 回 值;无
10 * 功    能:将Led1-4按键对应的中断屏蔽位置设为无效
11 *****************************************************/
12 void Irq_Init(void);
13 
14 #endif

 

 

 

interrupt.c 文件

 1 /************************************************
 2 * mini2440板子上六个按键对应的GPIO和中断
 3 *      按键    GPIO  中    断
 4 *       K1   GPG0   EINT8
 5 *       K2   GPG3   EINT11
 6 *       K3   GPG5   EINT13
 7 *       K4   GPG6   EINT14
 8 *       K5   GPG7   EINT15
 9 *       K6   GPG11  EINT19
10 ************************************************/
11 
12 #include<s3c2440.h>
13 #include"interrupt.h"        // 为什么要添加 这一项呢,感觉没用啊,C语言学的很烂
14 
15 
16 /****************************************************
17 * 函数名称:void Irq_Init(void)
18 * 全局变量:无 
19 * 参数说明:无
20 * 返 回 值;无
21 * 功    能:将Led1-4按键对应的中断屏蔽位置设为无效
22 *****************************************************/
23 void Irq_Init(void)
24 {    
25     //对于EINT8,EINT11,EINT13,EINT14,需要在EINTMASK寄存器使能它们   0 为允许中断, 1为禁止,所以呢
26     EINTMASK&=(~(1<<8))&(~(1<<11))&(~(1<<13))&(~(1<<14)); // 见 P305页, 外部中断允许寄存器
27     //这4个外部中断的优先级是相同的,EINT8_23都接仲裁器的REQ1引脚
28     //所以不用像韦东山程序里那样再设置优先级了
29     
30     //EINT8,EINT11,EINT13,EINT14使能
31     INTMSK&=(~(1<<5));               //   P388 页 
32 }

 

 

 

_____________________________________________________________________________________________________________________________________________________________________________________________________

 

irservice.h 文件

 1 #ifndef    __ISRSERVICE_H__
 2 #define __ISRSERVICE_H__
 3 
 4 /****************************************************
 5 * 函数名称:void __irq IRQ_Handler(void)  
 6 * 全局变量:无 
 7 * 参数说明:无
 8 * 返 回 值;无
 9 * 功    能:中断服务函数,必须加__irq
10 *****************************************************/
11 void __irq IRQ_Handler(void);
12 
13 #endif

 

 

isrservice.c 文件

 1 #include<s3c2440.h>
 2 #include"isrservice.h"
 3 #include"led.h"
 4 
 5  void delay(void);
 6 /****************************************************
 7 * 函数名称:void __irq IRQ_Handler(void)  
 8 * 全局变量:无 
 9 * 参数说明:无
10 * 返 回 值;无
11 * 功    能:中断服务函数,必须加__irq
12 *****************************************************/
13 void __irq IRQ_Handler(void)      
14 {
15     unsigned long oft=INTOFFSET;    





16 unsigned long val; 17 18 19 val=EINTPEND; //EINT寄存器,它的位x为1时,表示EINT已经发生(x为4——23)。

// 比如 EINTPEND 的 第八位 指向 EINT
20 if(val&(1<<8)) //K1被按下,LED1被点亮 21 { 22 Led1_On();delay();Led1_Off(); 23 } 24 25 if(val&(1<<11)) //K2被按下,LED2被点亮 26 { 27 Led2_On();delay();Led2_Off(); 28 } 29 30 if(val&(1<<13)) //K3被按下,LED3被点亮 31 { 32 Led3_On();delay();Led3_Off(); 33 } 34 if(val&(1<<14)) //K4被按下,LED4被点亮 35 { 36 Led4_On();delay();Led4_Off(); 37 } 38 39
// 清除中断
40 if(oft==5) // 也就是 INTPND寄存器中哪一位被置1了,即INTPEND寄存器中位[X]为1时,INTOFFSET寄存器的值为 X(0-31),显然这里便是 第5位,EINT8_23 为 5 41 EINTPEND=(1<<8)|(1<<11)|(1<<13)|(1<<14); //清除EINTPEND寄存器,往某位写入1即可清除此位 。。 不清楚为什么是 写1 , 不是应该写0 吗???(手册实说 It is cleared by writing "1") 42 SRCPND=1<<oft; //清除SRCPND寄存器,往某位写入1即可清楚此位 ,// 是不是 也就是 中断被拒绝??? 43 INTPND=1<<oft; //清除INTPND寄存器,往某位写入1即可清楚此位 44 //注意:清除顺序很重要:先是EINTPEND,然后是SRCPND,最后是INTPND 45 } 46 /**************************************************** 47 * 函数名称:static void delay(void) 48 * 全局变量:无 49 * 参数说明:无 50 * 返 回 值;无 51 * 功 能:延时函数,前边加static是为了限制该函数只在 52 * 本文件中使用 53 *****************************************************/ 54 static void delay(void) 55 { 56 int i,j; 57 for(i=0;i<100;i++) 58 for(j=0;j<10;j++); 59 }

 

 

 

总共 10个文件(包括初始化的 s3c2440.s 文件)

 

 

当然 我们调试的时候 ,把 .sct 文件改了一下,才能在 norflash 里面运行

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_ROM1 0x00000000 0x0200000  {    ; load region size_region
  ER_ROM1 0x00000000 0x0200000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_RAM1 0x30000000 0x04000000  {  ; RW data
   .ANY (+RW +ZI)
  }
  RW_IRAM1 0x40000000 0x00001000  {
   .ANY (+RW +ZI)
  }
}

可以测试了,但是 只有 三个按键可以控制灯 亮灭,所以自己需要思考修改,现在看自己的了。

17:13:56

 

 

很不幸,下午在debug 的时候,老是调试在运行模式,进入不了debug中,开始还好好的,编译是没有问题的,也生成了,就是 调试不了。。

开发板环境配置可能哪里出现了问题

 

posted on 2015-10-19 10:37  无悔这一生。  阅读(716)  评论(0编辑  收藏  举报

导航