外部按键 控制 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中,开始还好好的,编译是没有问题的,也生成了,就是 调试不了。。
开发板环境配置可能哪里出现了问题