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

时间:2022-02-06 16:00:43

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

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

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

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

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

GPGCON 地址: 0x56000060

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

图画错了,应该是 输入模式 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 文件

 #include"led.h"
#include"button.h"
#include"isrservice.h"
#include"interrupt.h" int main()
{
Led_Init(); //初始化LED
KeyInt_Init(); //初始化按键
Irq_Init(); //初始化外部中断
while() //循环,等待中断发生
{
;
}
}

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

led.h 文件

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

led.c 文件

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

________________________________________________________________________________________________________________________________________________________________________________________________________

button.h 文件

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

button.c 文件

 /************************************************
* mini2440板子上六个按键对应的GPIO和中断
按键 GPIO 中 断
* K1 GPG0 EINT8
* K2 GPG3 EINT11
* K3 GPG5 EINT13
* K4 GPG6 EINT14
* K5 GPG7 EINT15
* K6 GPG11 EINT19
************************************************/
/*
#include<s3c2440.h>
#include"button.h" // 不能理解,为什么要添加 这一个文件 ????????????????????? #define KEY1_C (3<<0) // LED1
#define KEY2_C (3<<6) // LED2
#define KEY3_C (3<<10) // LED3
#define KEY4_C (3<<12) // LED4 #define KEY1 (2<<0)
#define KEY2 (2<<6)
#define KEY3 (2<<10)
#define KEY4 (2<<12) ****************************************************
* 函数名称:void KeyInt_Init()
* 全局变量:无
* 参数说明:无
* 返 回 值;无
* 功 能:设置GPG0、3、5、6、7、11为外部中断输入功能
*****************************************************/
/*
void KeyInt_Init(void)
{
GPGCON&=~(KEY1_C|KEY2_C|KEY3_C|KEY4_C);
GPGCON|=KEY1|KEY2|KEY3|KEY4; //将GPG0、3、5、6、7、11设为输入功能
GPGUP&=~((1<<0)|(1<<3)|(1<<5)|(1<<6));
GPGDAT|=(1<<0)|(1<<3)|(1<<5)|(1<<6); //因为按下按键后,相应的GPIO口为0,所以初始化为高电平 }
*/ // 我们来自己编写一个 中断
#include<s3c2440.h>
#include"button.h" #define KEY1_C (3<<0) // LED1 也就是把 10 位设为 11
#define KEY2_C (3<<6) // LED2 76 11
#define KEY3_C (3<<10) // LED3 11 10 11
#define KEY4_C (3<<12) // LED4 13 12 11 #define skey ( ~(KEY1_C|KEY2_C|KEY3_C|KEY4_C) ) // 也就是取反 ,也就是13 12 11 10 7 6 10 全为 00 00 00 00
#define Dkey ( (1<<0)|(1<<3)|(1<<5)|(1<<6) ) // 为了后面的 GPG0 3 5 6 位 为 1 1 1 1 void KeyInt_Init(void)
{
GPGCON&=skey; // 那么13 12 11 10 7 6 10 全为 00 00 00 00 ,其他位不变,那么GPG0、3、5、6 初始化为 输入模式
GPGUP&=~((<<)|(<<)|(<<)|(<<)); // 1 3 5 6 位 设为 0 ,上拉电阻
GPGDAT|=(<<)|(<<)|(<<)|(<<); // 开关本来是断开的,按下后接通,说明GPG0 3 5 6 被拉低成低电平,说明GPG0 3 5 6 本身就是 高电平, }

________________________________________________________________________________________________________________________________________________________________________________________________________

interrupt.h 文件

 #ifndef    __INTERRUPT_H__
#define __INTERRUPT_H__ /****************************************************
* 函数名称:void Irq_Init(void)
* 全局变量:无
* 参数说明:无
* 返 回 值;无
* 功 能:将Led1-4按键对应的中断屏蔽位置设为无效
*****************************************************/
void Irq_Init(void); #endif

interrupt.c 文件

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

_____________________________________________________________________________________________________________________________________________________________________________________________________

irservice.h 文件

 #ifndef    __ISRSERVICE_H__
#define __ISRSERVICE_H__ /****************************************************
* 函数名称:void __irq IRQ_Handler(void)
* 全局变量:无
* 参数说明:无
* 返 回 值;无
* 功 能:中断服务函数,必须加__irq
*****************************************************/
void __irq IRQ_Handler(void); #endif

isrservice.c 文件

 #include<s3c2440.h>
#include"isrservice.h"
#include"led.h" void delay(void);
/****************************************************
* 函数名称:void __irq IRQ_Handler(void)
* 全局变量:无
* 参数说明:无
* 返 回 值;无
* 功 能:中断服务函数,必须加__irq
*****************************************************/
void __irq IRQ_Handler(void)
{
unsigned long oft=INTOFFSET; 外部按键 控制 LED  中断 (参考 http://www.oschina.net/question/565065_115196?sort=time  )外部按键 控制 LED  中断 (参考 http://www.oschina.net/question/565065_115196?sort=time  ) unsigned long val; val=EINTPEND; //EINT寄存器,它的位x为1时,表示EINT已经发生(x为4——23)。
外部按键 控制 LED  中断 (参考 http://www.oschina.net/question/565065_115196?sort=time  )
外部按键 控制 LED  中断 (参考 http://www.oschina.net/question/565065_115196?sort=time  ) // 比如 EINTPEND 的 第八位 指向 EINT
if(val&(<<)) //K1被按下,LED1被点亮
{
Led1_On();delay();Led1_Off();
} if(val&(<<)) //K2被按下,LED2被点亮
{
Led2_On();delay();Led2_Off();
} if(val&(<<)) //K3被按下,LED3被点亮
{
Led3_On();delay();Led3_Off();
}
if(val&(<<)) //K4被按下,LED4被点亮
{
Led4_On();delay();Led4_Off();
} // 清除中断

if(oft==) // 也就是 INTPND寄存器中哪一位被置1了,即INTPEND寄存器中位[X]为1时,INTOFFSET寄存器的值为 X(0-31),显然这里便是 第5位,EINT8_23 为 5
EINTPEND=(<<)|(<<)|(<<)|(<<); //清除EINTPEND寄存器,往某位写入1即可清除此位 。。 不清楚为什么是 写1 , 不是应该写0 吗???(手册实说 It is cleared by writing "1")
SRCPND=<<oft; //清除SRCPND寄存器,往某位写入1即可清楚此位 ,// 是不是 也就是 中断被拒绝???
INTPND=<<oft; //清除INTPND寄存器,往某位写入1即可清楚此位
//注意:清除顺序很重要:先是EINTPEND,然后是SRCPND,最后是INTPND
}
/****************************************************
* 函数名称:static void delay(void)
* 全局变量:无
* 参数说明:无
* 返 回 值;无
* 功 能:延时函数,前边加static是为了限制该函数只在
* 本文件中使用
*****************************************************/
static void delay(void)
{
int i,j;
for(i=;i<;i++)
for(j=;j<;j++);
}

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

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

当然 我们调试的时候 ,把 .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中,开始还好好的,编译是没有问题的,也生成了,就是 调试不了。。

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