首页 » 互联网 » 「ARM应用」按键中断驱动实例_按键_装备

「ARM应用」按键中断驱动实例_按键_装备

萌界大人物 2025-01-15 11:05:17 0

扫一扫用手机浏览

文章目录 [+]

本文引用地址:http://www.eepw.com.cn/article/201612/341050.htm

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

「ARM应用」按键中断驱动实例_按键_装备 「ARM应用」按键中断驱动实例_按键_装备 互联网

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

「ARM应用」按键中断驱动实例_按键_装备 「ARM应用」按键中断驱动实例_按键_装备 互联网
(图片来自网络侵删)

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

2 实验事理

(1)按键的硬件事理

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

2-1按键接口电路

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

(2)按键“消抖”

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

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

图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(BUT

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()

本文引用地址:http://www.eepw.com.cn/article/201612/341050.htm

描述 :模块加载,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低级实验

12月9日,北京北辰洲际酒店,给你一个让你物联网化的物联网开拓者大会!

http://www.eepw.com.cn/event/action/2016IOT/index.htm

标签:

相关文章

若何检测电子膨胀阀的短长_膨胀阀_阻值

冷库冷冻机、风幕柜系统的膨胀阀都在蒸发器入口处,以是细管都是散热的,不用加保温。●电子膨胀阀检测方法: ①拔掉膨胀阀线圈排线插座,...

互联网 2025-01-15 阅读0 评论0