字符设备程序实列二-查询按键值,按键按下相应的LED灯亮,按键松开相应的LED灯灭
2014-06-02 21:51
246 查看
按照实例一,实现了从应用程序空间向内核空间传递数据,这一例实现从内核读取按键值到应用空间,然后把刚刚保存在应用空间按键值写到内核空间,内核空间按键值来操作对应的LED
驱动源码:keys_leds.c
驱动源码Makefile
测试源码: keys_leds_test.c
keys_leds.c:
/***************************************************************
程序编写过程中,编译出现的错误:
1.keys_leds_op后面忘掉等号,2.将按键驱动分为几个设备节点,没编译之前发现,但static struct class_device *keys_leds_dev[3]没有改过来3.头文件不记得写了
4.keys_leds_read/keys_leds_write中val忘记初始化为0,keys_leds_write对val
= 0即没有按键按下或按键松开时进行灭灯处理
Makefile:
跟实例一差不多
这里obj-m表示以模块动态加载的方式启用,并没有编入内核,所以开发板断电重启后,断电前的模块已经卸载掉了,同理对应的在模块中创建的设备文件也不存在了
测试模块keys_leds_test.c:
测试模块容易忘记的是头文件忘了写,一般复制以前模块的,如果再出现相应编译错误,然后man比如我只写了
所以加上
这2头文件O_RDWR的编译错误就消失了
还有可能忘了的对key_value==1或2调用的write将按键值传给内核空间,但没按下时的按键值key_value==0没调用write即没把无按键按下的值传给内核空间,导致松开按键后,LED灯不熄灭,因为程序不断read ->第一个write写1或2->read->第一个write写1或2...
在第一个write写1或2都是点亮LED4 或LED5,这样按下S2 LED4,LED4亮,松开S2 LED4不灭,所以需要对驱动没有读到按键值时在测试程序中做判断,然后将无按键的值0传给驱动keys_leds_write中的临时变量val使得在switch(0)中关掉LED4
LED5
,
测试看按键按下,相应的LED灯是否亮,松开,相应的LED灯黑,同时按下的反应
本驱动代码因为是在测试代码中轮询按键,所以CPU占用率几乎达到了100%,所以实用中均是用的中断方式
驱动源码:keys_leds.c
驱动源码Makefile
测试源码: keys_leds_test.c
keys_leds.c:
/***************************************************************
* filename: keys_leds.c * description: 无按键按下,熄灭全部LED,按键按下,点亮相应LED,松开熄灭相应LED * author: xyc * create time: 2014/6/2 * version:1 * modify info: ******************************************************/ #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <asm/irq.h> #include <asm/arch/regs-gpio.h> #include <asm/hardware.h> #include <asm-arm/io.h> #include <asm-arm/uaccess.h> static int KEYS_LEDS_MAJOR; static struct class *keys_leds; static struct class_device *keys_leds_dev; static volatile unsigned long *gpfcon=NULL; static volatile unsigned long *gpfdat=NULL; static int keys_leds_open(struct inode *inode, struct file *file) { /*配置按键为输入,LED为输出*/ *gpfcon &= ~(0x3<<(4*2)) & (~(0x3<<(0*2))) & (~(0x3<<(5*2)) ) & (~(0x3<<(2*2))); *gpfcon |= 0x1<<(4*2) |(0x0<<(0*2)) | (0x1<<(5*2) )|(0x0<<(2*2)); *gpfdat |=1<<4|1<<5; return 0; } static ssize_t keys_leds_read(struct file *file, char __user *userbuf, size_t count, loff_t *off) { char val =0;//初始化为0不要忘 /*记录按下的键*/ if( !(*gpfdat & (1<<0)) ) { /*s2按下*/ val =1; } if (!(*gpfdat & (1<<2))) { /*s3按下*/ val =2; } copy_to_user(userbuf, &val, 1); return 1; } static ssize_t keys_leds_write(struct file * file, const char __user * userbuf, size_t count, loff_t * off) { char val=0; //初始化为0,不要忘 /* *按键没按下keys_leds_read传给应用read的按键值为0, *应用write将按键值0传给 keys_leds_write的val,LED均熄灭 */ /* *按键按下,keys_leds_read传给应用read的按键值为1或2, *应用write将按键值1或2传给 keys_leds_write的val相应的LED亮 */ copy_from_user(&val, userbuf, 1); switch(val) { case 1: { /*点亮LED4*/ *gpfdat &=~(1<<4); break; } case 2: { /*点亮LED5*/ *gpfdat &=~(1<<5); break; } default: { /*俩个按键均没按下,此时read()读到的值为0, *再将0写入到驱动keys_leds_write()函数的自动变量val */ *gpfdat |= (1<<4)|(1<<5); //不要忘记没按键或按键松开时灭灯 break; } } } static struct file_operations keys_leds_op = { .owner = THIS_MODULE, .open = keys_leds_open, .read = keys_leds_read, .write = keys_leds_write, }; static int __init keys_leds_init() { int minor; KEYS_LEDS_MAJOR = register_chrdev(0, "keys_leds", &keys_leds_op); if(KEYS_LEDS_MAJOR <0){ printk("register char device failed\n"); return KEYS_LEDS_MAJOR; } keys_leds = class_create(THIS_MODULE, "keys_leds"); keys_leds_dev =class_device_create(keys_leds, NULL, MKDEV(KEYS_LEDS_MAJOR, 0), NULL, "leds"); gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16); gpfdat = gpfcon +1; return 0; } static void __exit keys_leds_exit() { unregister_chrdev(KEYS_LEDS_MAJOR, keys_leds); class_device_destroy(keys_leds, MKDEV(KEYS_LEDS_MAJOR, 0)); class_destroy(keys_leds); iounmap(gpfcon); } module_init(keys_leds_init); module_exit(keys_leds_exit); MODULE_LICENSE("GPL");
程序编写过程中,编译出现的错误:
1.keys_leds_op后面忘掉等号,2.将按键驱动分为几个设备节点,没编译之前发现,但static struct class_device *keys_leds_dev[3]没有改过来3.头文件不记得写了
4.keys_leds_read/keys_leds_write中val忘记初始化为0,keys_leds_write对val
= 0即没有按键按下或按键松开时进行灭灯处理
Makefile:
跟实例一差不多
KERN_DIR = /work/system/linux-2.6.22.6 all: make -C $(KERN_DIR) M=`pwd` modules clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order obj-m += keys_leds.o
这里obj-m表示以模块动态加载的方式启用,并没有编入内核,所以开发板断电重启后,断电前的模块已经卸载掉了,同理对应的在模块中创建的设备文件也不存在了
测试模块keys_leds_test.c:
/*************************************************************** * filename: keys_leds_test.c * description: 测试keys_leds.c驱动 * author: xyc * create time: 2014/6/2 * version: 1 * modify info: ****************************************************************/ #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> int main(int argc, char *argv[]) { int fd1; char key_value=0; if(argc !=2 ){ printf("Usage:\n"); printf("%s <dev> <on|off>\n",argv[0]); printf("eg. \n"); printf("%s /dev/leds \n", argv[0]); return -1; } fd1 = open(argv[1], O_RDWR); if( fd1<0){ printf("%s open failed", argv[1]); return -1; } while(1){ read(fd1, &key_value, 1); if( (key_value==1) |(key_value==2) ) write(fd1, &key_value, 1); else write(fd1, &key_value, 1); } close(fd1); return 0; }
测试模块容易忘记的是头文件忘了写,一般复制以前模块的,如果再出现相应编译错误,然后man比如我只写了
#include <stdio.h> #include <fcntl.h> #include <unistd.h>这3个头文件,导致O_RDWR未定义,此时因为O_RDWR是open使用的,这时在ubuntu下man 2 open看其需要包含的头文件为
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h>
所以加上
#include <sys/types.h> #include <sys/stat.h>
这2头文件O_RDWR的编译错误就消失了
还有可能忘了的对key_value==1或2调用的write将按键值传给内核空间,但没按下时的按键值key_value==0没调用write即没把无按键按下的值传给内核空间,导致松开按键后,LED灯不熄灭,因为程序不断read ->第一个write写1或2->read->第一个write写1或2...
在第一个write写1或2都是点亮LED4 或LED5,这样按下S2 LED4,LED4亮,松开S2 LED4不灭,所以需要对驱动没有读到按键值时在测试程序中做判断,然后将无按键的值0传给驱动keys_leds_write中的临时变量val使得在switch(0)中关掉LED4
LED5
,
测试看按键按下,相应的LED灯是否亮,松开,相应的LED灯黑,同时按下的反应
本驱动代码因为是在测试代码中轮询按键,所以CPU占用率几乎达到了100%,所以实用中均是用的中断方式
Mem: 6696K used, 54488K free, 0K shrd, 0K buff, 2068K cached CPU: 8% usr 91% sys 0% nice 0% idle 0% io 0% irq 0% softirq Load average: 0.99 0.96 0.84 PID PPID USER STAT VSZ %MEM %CPU COMMAND 793 770 0 R 1308 2% 99% ./keys_leds_test /dev/leds 806 770 0 R 3096 5% 0% top 770 1 0 S 3096 5% 0% -sh 1 0 0 S 3092 5% 0% init 762 2 0 SW< 0 0% 0% [rpciod/0] 6 2 0 SW< 0 0% 0% [khelper] 745 2 0 SW< 0 0% 0% [kmmcd] 2 0 0 SW< 0 0% 0% [kthreadd] 3 2 0 SWN 0 0% 0% [ksoftirqd/0] 4 2 0 SW< 0 0% 0% [watchdog/0] 5 2 0 SW< 0 0% 0% [events/0] 55 2 0 SW< 0 0% 0% [kblockd/0] 56 2 0 SW< 0 0% 0% [ksuspend_usbd] 59 2 0 SW< 0 0% 0% [khubd] 61 2 0 SW< 0 0% 0% [kseriod] 73 2 0 SW 0 0% 0% [pdflush] 74 2 0 SW 0 0% 0% [pdflush] 75 2 0 SW< 0 0% 0% [kswapd0] 76 2 0 SW< 0 0% 0% [aio/0] nfs: server 192.168.1.19 not responding, still trying
相关文章推荐
- 字符设备驱动笔记——查询方式按键驱动(三)
- FL2440字符设备驱动开发之查询按键
- 国嵌实验:key_poll,采用查询的方式一旦按键再松开,LED亮灭一次
- 字符设备驱动学习笔记----查询方式取得按键值
- 韦东山第12课-字符设备驱动、按键查询、copy_to_user
- 字符设备驱动查询方式读取按键值
- 字符设备驱动--查询方式的按键驱动
- 跟着韦东山老师学字符设备驱动之查询方式的按键驱动程序分析
- 字符设备驱动之按键处理一(查询方式的按键驱动程序)
- 字符设备实验之按键查询
- 简单字符设备驱动程序 以及 相应测试程序
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-查询+中断+引入poll机制的按键驱动程序
- 第12课第3节 字符设备驱动程序之查询方式的按键驱动程序
- 字符设备驱动----LED驱动程序
- 嵌入式Linux驱动开发(三)——字符设备驱动之查询的方式获取按键值
- 字符设备驱动程序之查询方式的按键驱动程序
- 韦东山驱动视频笔记——1.字符设备驱动程序之查询方式的按键驱动程序
- 字符设备驱动程序之按键——查询方式
- 字符设备驱动之LED-混杂设备驱动(misc)
- 字符设备驱动之LED