s5pv210使用查询方式实现按键灯操作
2014-11-07 01:42
956 查看
用TQ210写了个使用查询的方法实现按键灯的操作,具体实现方法如下:
1、原理图
由原理图可知,按键不按下的时候CPU检测到的是高电平,按下时处于低电平,以KEY1为例,KEY1连的是XIENT0,查芯片手册
由芯片手册可知XEINT0连的是GPH0_0脚,因此需要配置GPH0_0为输入脚,在此就不详述怎么配置输入了同时可看LED灯原理图
由原理图可知要使LED1灯亮,则必须使GPC0_3输出低电平,在知道上面原理后则可写出程序了,以下的程序则实现按按键1则1灯亮2灯灭,按KEY2则2灯亮1灯灭,驱动程序如下:
接下来是测试程序:
1、原理图
由原理图可知,按键不按下的时候CPU检测到的是高电平,按下时处于低电平,以KEY1为例,KEY1连的是XIENT0,查芯片手册
由芯片手册可知XEINT0连的是GPH0_0脚,因此需要配置GPH0_0为输入脚,在此就不详述怎么配置输入了同时可看LED灯原理图
由原理图可知要使LED1灯亮,则必须使GPC0_3输出低电平,在知道上面原理后则可写出程序了,以下的程序则实现按按键1则1灯亮2灯灭,按KEY2则2灯亮1灯灭,驱动程序如下:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> #include <linux/device.h> typedef struct { struct class *leddrv_class; struct device *leddrv_class_dev; int irq; int major; }CharLedDrive; static CharLedDrive led_info; volatile unsigned long virt, phys;//用于存放虚拟地址和物理地址 volatile unsigned long *GPC0CON, *GPC0DAT;//用与存放两个个寄存器的地址 volatile unsigned long *GPH0CON, *GPH0DAT;//按键 static void all_led_off(void); static void led_config(void) { phys = 0xE0200060; //0xE020_0C00 gph0con //在虚拟地址空间中申请一块长度为0x10的连续空间 //这样,物理地址phys到phys+0x10对应虚拟地址virt到virt+0x10 virt =(unsigned long)ioremap(phys, 0xf00); GPC0CON = (unsigned long *)(virt + 0x00);//指定需要操作的三个寄存器的地址 GPC0DAT = (unsigned long *)(virt + 0x04); GPH0CON = (unsigned long *)(virt + 0xc00-0x60); //keY1配置为输入 GPH0DAT = (unsigned long *)(virt + 0xc00-0x60+0x04); *GPC0CON &= ~(0xFF << 12); *GPC0CON |= 0x11 << 12; // 配置GPC0_3和GPC0_4为输出 *GPH0CON &= ~0x0F; //配置为输入 all_led_off(); } static void led1_on(void) { *GPC0DAT |= 1 << 3; *GPC0DAT &= ~(0x01 << 4); } static void led2_on(void) { *GPC0DAT |= 1 << 4; *GPC0DAT &= ~(0x01 << 3); } static void led_on(void) { *GPC0DAT |= 1 << 3; // 点亮LED1 *GPC0DAT |= 1 << 4; // 点亮LED2 } static void all_led_off(void) { *GPC0DAT &= ~(0x3 << 3); // 熄灭LED1和LED2 } static int led_drv_open(struct inode *inode, struct file *file) { printk("led_drv_open\n"); led_config(); all_led_off(); // led_on(); return 0; } static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) { char val = 0; //printk("first_drv_write\n"); int ret = -1; ret = copy_from_user(&val, buf, count); // copy_to_user(); if(ret) { printk("write ret= %x\n",ret); } printk("led process %c\n",val); switch(val) { case '1': *GPC0DAT |= 1 << 3; // 点亮LED1 *GPC0DAT &= ~(1 << 4); //灭2 break; case '2': *GPC0DAT |= 1 << 4; *GPC0DAT &= ~(1 << 3); break; case '3': led_on(); break; case '4': all_led_off(); break; default: all_led_off(); break; } printk("2222\n"); return 0; } static ssize_t led_drv_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { unsigned int key[4]; unsigned int temp; int ret =-1; temp = *GPH0DAT; //下面是获取按键状态,按下时为低电平0 key[0] = (!(temp & (0x1<<0)))?1:0; key[1] = (!(temp & (0x1<<1)))?2:0; key[2] = (!(temp & (0x1<<2)))?3:0; key[3] = (!(temp & (0x1<<4)))?4:0; ret=copy_to_user(buf, key, sizeof(key));//从内核向用户空间传数据 if(ret) { printk("ret = %x\n",ret); } if(!(temp&0x01) && (temp&0x02)) { led1_on(); printk("led1_on\n"); } else if((temp&0x01) && !(temp&0x02)) { led2_on(); printk("led2_on\n"); } else { all_led_off(); } return 0; } static struct file_operations led_drv_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = led_drv_open, .write = led_drv_write, .read = led_drv_read, }; //static irqreturn_t led_handler(int irq, void *dev_id) static int led_drv_init(void) { led_info.major = register_chrdev(0, "led_drv", &led_drv_fops); // 注册, 告诉内核 led_info.leddrv_class = class_create(THIS_MODULE, "leddrv"); led_info.leddrv_class_dev = device_create(led_info.leddrv_class, NULL, MKDEV(led_info.major, 0), NULL, "led"); /* /dev/xyz */ /* if(request_irq(led_info.led_irq,led_handler, unsigned long flags, const char *name, void *dev)) { printk(KERN_WARNING "Led: Unable to allocate IRQ\n"); led_info.led_irq = 0; } */ //gpbcon = (volatile unsigned long *)ioremap(0xE0200060, 16); //gpbdat = gpbcon + 1; return 0; } static void led_drv_exit(void) { all_led_off(); unregister_chrdev(led_info.major, "led_drv"); // 卸载 device_unregister(led_info.leddrv_class_dev); class_destroy(led_info.leddrv_class); iounmap((void *)virt); //撤销映射关系 } module_init(led_drv_init); module_exit(led_drv_exit); MODULE_LICENSE("GPL");
接下来是测试程序:
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include <unistd.h> int main(int argc,char **argv) { int fd = -1; char val = 0; char buf[10]={0}; int temp= 0; char *s = malloc(100); unsigned int key[4]; fd = open("/dev/led_drv",O_RDWR); if(fd<0) printf("can't open \n"); /* while(1) { printf("输入1:1灯亮\n输入2:2灯亮\n输入3:所有灯亮\n输入4:所有灯灭\n输入5:退出\n请输入"); scanf("%s",s); getchar(); val = s[0]; write(fd,&val,1); if(val == '5') break; } */ while(1) { val++; read(fd,key,sizeof(key)); temp =key[0]?1:(key[1]?2:(key[2]?3:(key[3]?4:0))); if(temp) printf("pressed key is key[%x]\n",temp); temp = 0; } free(s); return 0; }以上是查询方式实现的,查询方式消耗cpu资源比较严重,下一篇将用中断方式实现
相关文章推荐
- c# 使用linq查询子句方式实现 字符串数组统计操作
- 使用mysql函数实现多步查询中的回滚操作
- Android中使用4种方式实现按钮点击操作
- PHP中使用jQuery+Ajax实现分页查询多功能操作
- 顺序存储结构的基本操作实现(以类的方式实现)----插入、删除、查询
- 在非SQL客户端使用命令行方式定期连接SQL Server 服务器并模拟用户查询操作,同时输出信息内容
- sparkSQL里 sql语句,dataframe,Thrift Server JDBC都可以实现对数据的查询,过滤等操作, 哪这3种情况分别是什么情况下使用
- MyBatis之自查询使用递归实现 N级联动效果(两种实现方式)
- c++使用sendinput函数实现模拟键盘按键操作
- 使用Map集合开发电话簿程序,以电话号码为key,姓名为value,实现电话号码的添加,查询和删除 操作
- Windows API实现的栈及使用(支持线程安全,以原子方式操作)
- RTTI、虚函数和虚基类的实现方式、开销分析及使用指导(虚函数的开销很小,就2次操作而已)
- 使用bootstraptable插件实现表格记录的查询、分页、排序操作
- PHP中使用jQuery+Ajax实现分页查询多功能操作(示例讲解)
- pb对Web Service的操作可使用两种方式实现
- 初学JDBC(五)-使用ResultSet结果集对数据库表内容实现查询操作
- 使用PreparedStatement实现查询操作系列一-----用户登录操作
- 使用基于Android网络通信的OkHttp库实现Get和Post方式简单操作服务器JSON格式数据
- 使用JDBC实现查询和转账操作
- MyBatis之自查询使用递归实现 N级联动效果(两种实现方式)