[ARM应用]按键中断驱动实例

发布者:TranquilSoul最新更新时间:2016-11-22 来源: eefocus关键字:ARM  按键  中断驱动 手机看文章 扫描二维码
随时随地手机看文章

1  实验目的

(1)了解按键原理及其与S3C2410的接口电路设计

(2)了解S3C2410芯片的外部中断处理机制

(3)掌握按键中断驱动的编写及测试过程


2  实验原理

(1)按键的硬件原理

在嵌入式系统中,按键的硬件原理比较简单,通过一个上拉电阻将处理器的外部中断(或GPIO)引脚拉高,电阻的另一端连接按键并接地即可实现。如图2-1所示:

[ARM应用]按键中断驱动实例 - Fantity Wei - Footprint

 图

2-1按键接口电路

仔细看图2-1,不难知道,当按键被按下时,EINT0上将产生低电平,这个低电平将中断CPU,CPU可以依据中断判断按键被按下。

(2)按键“消抖”

所有按键、触摸屏等机械设备都存在一个固有的问题,那就是"抖动",按键从最初接通到稳定接通要经过数毫秒乃至数十毫秒,其间可能发生多次"接通―断开"的过程。因此仅仅依据中断被产生就认定有一次按键行为是很不准确的。如果不消除"抖动"的影响,一次按键可能被理解为多次按键。

消除按键抖动影响的方法是:在判断有键按下后,进行软件延时(如20ms,在延时过程中要屏蔽对应中断),再判断键盘状态,如果仍处于按键按下状态,则可以判定该按键被按下。图2-2是典型的包含消抖功能的按键中断处理流程。


[ARM应用]按键中断驱动实例 - Fantity Wei - Footprint

图2-2 按键中断处理流程

3  实验任务

(1)编写按键中断设备驱动程序,驱动程序中手动定义设备名称及主设备号为213,实现与BUTTON设备相应的端口配置,中断的申请,以及读写设备的接口函数等。

(2)将驱动编译成模块,并实现模块的加载及卸载。

(3)编写驱动的测试程序,在程序中实现打开BUTTON设备和LED设备,主循环中不断读取按键的状态,当按键按下时,控制LED亮一段时间(1S左右)后灭掉。

4. 实验步骤

以下操作都在nfs文件系统目录(/home/kernel/rootfs/rootfs)下进行,因此先执行如下命令。获取

cd /home/kernel/rootfs/rootfs

(1)编写led.c文件

建立led目录:

mkdir usr/button

进入button目录,在该目录下建立两个子目录driver 和test ,前者用来存放驱动程序,后者用来存放驱动测试程序:

cd usr/ button

mkdir driver test

进入驱动程序目录,建立设备驱动文件button.c:

cd driver 

vi button.c

按键驱动程序如下button.c所示:

/*************************** 头文件 ***************************/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

//*********************** 定义设备结构体及相关宏 ***************************

#define DEVICE_NAME          "button"         //定义设备名

#define DEVICE_MAJOR        213      //手动定义BUTTON设备的主设备号为213

static int button_major = DEVICE_MAJOR ;

 

#define BUTTON_IRQ IRQ_EINT0  //定义BUTTON对应S3C2410的外部中断0

#define BUTTON S3C2410_GPF0   //定义BUTTON对应S3C2410的GPF0端口

#define     BUTTON_EINT0 S3C2410_GPF0_EINT0

#define     BUTTON_INP S3C2410_GPF0_INP

 

#define BUTTON_UP     0  //按键抬起状态

#define BUTTON_DOWN       1  //按键按下状态

#define BUTTON_X        2  //不确定状态,本实例中可理解为抖动状态

 

//定义BUTTON设备结构体

struct button_dev

{

         struct cdev cdev;  //BUTTON设备对应一个字符设备结构体

         int status;  //按键状态标识:抬起、按下、抖动

};

static struct button_dev dev;

 

//***************************** 函数声明 *********************************

void s3c2410_button_s3c2410_button_InitIO(void);  //初始化IO端口的函数

 

/*

 ******************************s3c2410_button_InitIO**********************

 *描述     :初始化IO端口

 *参数     :无

 *返回值:无

 *************************************************************************

 */

void s3c2410_button_InitIO(void)

{

         s3c2410_gpio_cfgpin(BUTTON,BUTTON_EINT0); //配置按键中断的端口为中断功能

}

 

 

/*

 ******************************isr_button()*******************************

 *描述     :EINT0的中断处理函数,设置按键状态为BUTTON_X

 *参数     :irq :中断号; dev_id;regs;

 *返回值:成功返回0

 *在linux/interrupt.h中定义了typedef irqreturn_t (*irq_handler_t)(int, void *);

 *************************************************************************

 */

static irqreturn_t isr_button(int irq,void *dev_id,struct pt_regs *regs)

{

         disable_irq(0);  //禁止中断

         dev.status = BUTTON_X;//将按键置为抖动状态,说明有按键中断,但不一定有键按下

         enable_irq(0);  //使能中断

         return 0;

}

 

 

/*

 **************************s3c2410_button_open()**************************

 *描述     :打开设备函数,向系统申请中断

 *参数     :struct inode *inode,struct file *filp

 *返回值:失败返回错误代码ret,成功返回0

 *************************************************************************

 */

static int s3c2410_button_open(struct inode *inode,struct file *filp)

{      

         int ret;

        ret=request_irq(BUTTON_IRQ,isr_button,IRQF_SAMPLE_RANDOM,DEVICE_NAME,NULL); //申请中断

         if(ret) {//申请失败

                   printk("BUTTON_IRQ: could not register interrupt\n");

                   return ret;

                   }

         return 0;

}

 

/*

 ************************s3c2410_button_release()*************************

 *描述     :注销设备函数,实现中断释放

 *参数     :struct inode *inode,struct file *filp

 *返回值:0

 *************************************************************************

 */

static int s3c2410_button_release(struct inode *inode,struct file *filp)

{

         free_irq(BUTTON_IRQ,NULL); //释放中断

         return 0;

}

 

/*

 **************************3c2410_button_ioctl()**************************

 *描述     :IO控制函数,本实例中不做任何事

 *参数     :cmd: 用户定义的IO控制命令; arg: 传递用户参数

 *返回值:0

 *************************************************************************

 */

static int s3c2410_button_ioctl(struct inode *inode,struct file *filp,

                                  unsigned int cmd,unsigned long arg)

{

         return 0;

}

 

/*

 **************************s3c2410_button_read()**************************

 *描述     :读函数,读取按键的状态

 *参数     :buffer: 用来存储按键状态;

         count: 用来记录用户读取了多少个字符

 *返回值:count:用户读取的字符数

 *************************************************************************

 */

static ssize_t s3c2410_button_read(struct file *filp,char *buffer,size_t count,loff_t *ppos)

{

         int ret = count  ;

         if(dev.status = BUTTON_X){//如果按键状态是BUTTON_X,说明有按键中断产生。

         msleep(20);                 //延时20毫秒去除按键抖动

         disable_irq(0);  //禁止中断

         s3c2410_gpio_cfgpin(BUTTON,BUTTON_INP); //配置按键中断的端口为输入功能

         if(!s3c2410_gpio_getpin(BUTTON)){//读取端口的值,如果是0说明按键按下

                                               dev.status = BUTTON_DOWN;

                                               }

         else dev.status = BUTTON_UP;  //如果为1,说明只是按键抖动

                                          //重新配置按键中断的端口为中断功能

         s3c2410_gpio_cfgpin(BUTTON,S3C2410_GPF0_EINT0);   

         enable_irq(0);  //使能中断

         }

        

         put_user(dev.status,(int *)buffer);    //将按键状态提交给用户

         return ret;

}

 

/*

 **************************3c2410_button_write()**************************

 *描述     :写操作函数,本实例中不做任何事

 *参数     :

 *返回值:count

 *************************************************************************

 */

static ssize_t s3c2410_button_write(struct file *filp,char *buffer,size_t count,loff_t *ppos)

{

         int ret = count;

         return ret;

}

 

/*

 **************************s3c2410_button_fops****************************

 *描述     :文件操作结构体,实现 s3c2410_button_open()等函数与open()等系统调用的连接

 *参数     :

 *返回值:

 *************************************************************************

 */

static struct file_operations s3c2410_button_fops = {

                   .owner   = THIS_MODULE,

                   .open        = s3c2410_button_open,

                   .release = s3c2410_button_release,

                   .ioctl   = s3c2410_button_ioctl,

                   .read    = s3c2410_button_read,

                   .write   = s3c2410_button_write,

};

 

/*

 **************************button_setup_cdev()****************************

 *描述     :安装模块的函数,在设备加载模块里面调用

 *参数     :无

 *返回值:无

 *************************************************************************

 */

static void button_setup_cdev(void)

{

                   int err,devno = MKDEV(button_major,0);

                   cdev_init(&dev.cdev,&s3c2410_button_fops);

                   dev.cdev.owner = THIS_MODULE;

                   dev.cdev.ops = &s3c2410_button_fops;

                   err = cdev_add(&dev.cdev,devno,1);

                   if(err)

                            printk("Error %d adding BUTTON%d",err);

}

 

/*

 ****************************s3c2410_button_init()************************

 *描述     :模块加载,IO及相关变量初始化

 *参数     :无

 *返回值:无

 *************************************************************************

 */

static int  s3c2410_button_init(void)

{

         int result;

         set_irq_type(BUTTON_IRQ,IRQT_FALLING); //设置外部中断0为下降沿中断

         dev_t devno = MKDEV(button_major,0);

         if(button_major)

                   result = register_chrdev_region(devno,1,DEVICE_NAME);

         else{

                   result = alloc_chrdev_region(&devno ,0 ,1,DEVICE_NAME);

                   button_major = MAJOR(devno);

         }

         if(result < 0)return result;

         button_setup_cdev();

         s3c2410_button_InitIO(); //初始化IO端口

         dev.status = BUTTON_UP; //初始化按键状态为抬起状态

         printk(DEVICE_NAME " initialized\n");

         return 0;

}

 

/*

 ****************************s3c2410_button_exit()************************

 *描述     :模块卸载

 *参数     :无

 *返回值:无

 *************************************************************************

 */

static void  s3c2410_button_exit(void)

{

         cdev_del(&dev.cdev); //注销设备

         unregister_chrdev_region(MKDEV(button_major,0),1); //释放设备号

}

module_init(s3c2410_button_init);

module_exit(s3c2410_button_exit);

MODULE_LICENSE("GPL");

(2)编写Makefile文件(主机的/home/kernel/rootfs/rootfs/usr/button/driver目录下)

vi Makefile

在该文件中加入以下内容:

#如果已定义KERNELRELEASE,则说明是从内核构造系统调用的,

#因此可利用其内建语句。

ifneq ($(KERNELRELEASE),)

         obj-m := button.o

#要构建的模块名称为button.ko,

#并由两个源文件生成(比如file1.c和file2.c)

         #module-objs := file1.o file2.o

#否则,是直接从命令行调用的,

#这时要调用内核构造系统。

else

KERNELDIR := /home/kernel/linux-2.6.24.4

PWD := $(shell pwd)

default:

         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

endif

clean:

         rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions *.order *symvers

(3)编译

make

执行make命令进行编译,编译完成后,该目录下有一些文件,其中button.ko就是编译成功的模块文件。

(4)加载模块

首先设置内核以NFS方式加载根文件系统,在宿主机上运行minicom,加载完U-Boot,内核和nfs文件系统之后按回车键进入目标机shell控制台,在目标机控制台中输入模块加载命令:

insmod usr/led/driver/led.ko

insmod usr/button/driver/button.ko

如果输出“button initialized”,表示button设备驱动加载成功

(5)编写测试文件button_led.c(该测试程序还依赖LED的驱动)

进入宿主机的/home/kernel/rootfs/rootfs/usr/button/test目录。

cd /home/kernel/rootfs/rootfs/usr/button/test

vi button_led.c

驱动测试文件button_led.c如下所示:

#include

#include

#include

#include

#include

#include

 

#define UP      0

#define DOWN        1

#define X         2

 

#define LED_ON     0

#define LED_OFF 1

int main()

{

         int fd0,fd1,i,j;

         int ret= 0;

         int button_status;

        

         fd0 = open("/dev/button",O_RDWR);//打开button设备fd0

         if (fd0 == -1) {//打开fd0设备失败

                   printf("open device button errr!\n");

                   return 0;

         }

        

         fd1 = open("/dev/led",O_RDWR);//打开led设备fd1

        if (fd1 == -1) {//打开fd1设备失败

                 printf("open device led errr!\n");

                 return 0;

         }

        

         ioctl(fd1,LED_OFF); //先熄灭D1

         printf("button test show. press ctrl+c to exit \n");

         while(1) {//主循环

                   read(fd0,&button_status,1);//读取按键的状态,看是否被按下

                   if(button_status == DOWN){//如果按键按下了

                            ioctl(fd1,LED_ON);  //点亮D1

                            for(i=0;i<300;i++)

                                     for(j=0;j<5000;j++);//延时一段时间

                                               ioctl(fd1,LED_OFF); //熄灭D1

                   }

                  

                   for(i=0;i<300;i++)

                            for(j=0;j<5000;j++);

         }

        

         close(fd0);//关闭fd0设备

         close(fd1);//关闭fd1设备

         return 0;

}

(6)编译测试程序

arm-linux-gcc -o led_button led_button.c

该命令的意思是使用的交叉编译器arm-linux-gcc对测试程序led_button.c进行编译,编译成功后在test目录下会生成目标机的可执行文件led_button。

(7)运行测试程序

创建设备

在目标机中,通过查看/proc/devices中注册进内核的设备条目及相关的设备号。进入/dev目录,创建设备,设备名为led,属于字符型设备,主设备号是212,次设备号是0;创建设备,设备名为button,属于字符型设备,主设备号是213,次设备号是0。(要与led.c和button.c文件中的定义相符):

cat /proc/devices

cd /dev

mknod led c 212 0

mknod button c 213 0

  

./usr/button/test/led_button或/usr/led/test/led_button

(10)卸载模块

rmmod /dev/button

rmmod /dev/led


From:嵌入式Linux初级实验


关键字:ARM  按键  中断驱动 引用地址:[ARM应用]按键中断驱动实例

上一篇:[ARM笔记]GPIO硬件介绍
下一篇:[ARM笔记]驱动对设备的识别过程及实例——NAND Flash

推荐阅读最新更新时间:2024-03-16 15:21

ARM存储器结构,映射,重新映射
ARM存储器结构 ARM存储器:片内Flash、片内静态RAM、片外存储器 存储器映射(Memory Map) 映射就是一一对应的意思。重映射就是重新分配这种一一对应的关系。 我们可以把存储器看成一个具有输出和输入口的黑盒子。输入量是地址,输出的是对应地址上存储的数据。当然这个黑盒子是由很复杂的半导体电路实现的,具体的实现的方式我们现在不管。存储单位一般是字节。这样,每个字节的存储单元对应一个地址,当一个合法地址从存储器的地址总线输入后,该地址对应的存储单元上存储的数据就会出现在数据总线上面。 普通的单片机把可执行代码和数据存放到存储器中。单片机中的CPU从储器中取指令代码和数据。其中存储器中每
[单片机]
<font color='red'>ARM</font>存储器结构,映射,重新映射
ARM嵌入式系统的中断服务例程跳转
在32位ARM系统中,一般都是在中断向量表中放置一条分支指令或PC寄存器加载指令,实现程序跳转到中断服务例程的功能。 例如: IRQEntry B HandleIRQ ;跳转范围较小 B HandleFIQ 或IRQEntry LDR PC,=HandleIRQ ;跳转的范围是任意32位地址空间 LDR PC,=HandleFIQ LDR伪指令等效生成1条存储读取指令和1条32位常数定义指令。32位常数存储在LDR指令附近的存储单元中,相对偏移小于4KB。该32位数据就是要跳转到的中断服务程序入口地址。 之所以使用LDR伪指令,是因为ARM的RISC指令为单字指令,不能装载32位的立即数(常数),无法直接把一个32位常数数据或
[单片机]
DynamIQ,ARM的千亿出货量大生意
eeworld网DSP小编午间播报:2016年初,随着AlphaGo大败围棋世界冠军李世石,人工智能概念大热,各类人工智能产品也迎来了爆发。众多的科技巨头也纷纷在人工智能领域投下了重注。根据国外调查机构Trac TI ca的统计预测数字显示,到2024年人工智能的市场规模将达到406亿美元(约合人民币2700亿)。相比之下2015年人工智能市场规模仅为490亿元,而这也意味着整个人工智能市场将呈现出爆炸式增长。 面对这样一个巨大的市场需求,ARM也开始了行动。 来看这么一组数字:第一个500亿片出货用了22年,第二个500亿片只用了4年,下一个1000亿出货需要多长时间? ARM给出的答案是用5年时间,即到2022年。ARM新推出
[嵌入式]
基于ARM+FPGA的真空冻干控制系统设计
0 引言     冷冻干燥技术自1980年代在我国兴起以来已取得长足发展,并已广泛应用于食品、低温和真空等科学领域,基于一些食品和药品加工行业的工艺需要,真空冷冻干燥技术需要迅速应用与推广。控制系统对物料的加工过程和质量影响比较大,还决定了真空冷冻干燥装置运行的自动化程度。近年来国内外一些有实力的厂家对冻干机控制系统的研究有了较大的进展,采用了PLC、触摸屏等装置,能够绘制冻干过程的工艺曲线,较大地改善了冻干机的性能。     随着科技的发展,由于触摸屏和PLC控制系统不易实现功能扩展、升级困难、操作界面不够丰富等原因,已经不能完全满足企业的需要,市场需要开发出更加先进的冻干设备控制系统。2007年1月上海远东制药机械总厂
[单片机]
ARM 关键几个寄存器
图中缩写如下: R:Register;寄存器 PC:Program Counter;程序计数器 CPSR:Current Program Status Register;当前程序状态寄存器 SPSR:Saved Program Status Register;保存的程序状态寄存器 SP:Stack Pointer;数据栈指针 LR:Link Register;连接寄存器 SB:静态基址寄存器 SL:数据栈限制指针 FP:帧指针 IP:Intra-Procedure-call Scratch Register;内部程序调用暂存寄存器 ARM共有37个寄存器,可以工作在7种不同的模式。以下根据上图进行分类的说明: 未分组寄
[单片机]
<font color='red'>ARM</font> 关键几个寄存器
Ubuntu9.10制作ARM交叉编译器
本环境内核版本:Linux ubuntu910 2.6.31-21-generic #59-Ubuntu SMP i686 GNU/Linux 准备软件包如下: bison_13a2.3.dfsg-4build1_i386.deb build-essential_11.4_i386.deb flex_2.5.33-10build1_i386.deb libncurses5-dev_5.6+20071124-1ubuntu2_i386.deb m4_1.4.8-1build1_i386.deb patch_2.5.9-5_i386.deb gcc-3.4.5.tar.gz glibc-2.3.6.tar.gz l
[单片机]
LCD控制暨驱动IC 整合按键输入【盛群半导体】
03/03/2011——盛群的LCD控制暨驱动IC系列,继HT16C22之后,再推出第二颗采用I2C串行式接口的新产品--HT16K23。此系列IC具有低功耗、高抗噪声及高系统ESD防护能力;HT16K23的区段驱动输出端口(Segment output)整合按键输入端口(Key input),高整合度的设计使IC封装脚位最少、IC功能强化、可减少主版MCU I/O数目、可降低产品整体成本。 HT16K23采用28SOP包装,有2种显示点数:20 Segment x 4 Common + 20根按键或 16 Segment x 8 Common + 16根按键;内建显示内存及RC振荡电路;工作电压宽广:2.4V
[单片机]
LCD控制暨<font color='red'>驱动</font>IC 整合<font color='red'>按键</font>输入【盛群半导体】
基于ARM核的ADμC7O26硬件系统开发及其在医疗仪器中的应用
0 引言 随着人们生活水平的不断提高,人们对于自身健康的关注也提升到一个前所未有的高度。在今天,越来越多的高科技手段开始运用到医疗仪器的设计当中。心电图、脑电图等生理参数检测设备,各类型的监护仪器,超声波、X射线成影设备,核磁共振仪器,以及各式各样的物理治疗仪都开始在各地医院广泛使用,并且医学仪器正在向着组合式、多功能、智能化和微型化方向发展。现代的医学仪器一般都广泛采用了嵌入式微处理器来增强仪器的智能化程度,提高其稳定性和数据处理的精确性,使医学信号的采集、处理、通信一体化,并具有自诊断、自校验等一系列优点。其中ARM(Advanced RISC Machines)嵌入式微型主板作为中央处理模块,凭借自身体积小巧、功能强大、
[单片机]
基于<font color='red'>ARM</font>核的ADμC7O26硬件系统开发及其在医疗仪器中的应用
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved