s5pv210使用查询方式实现按键灯操作

       用TQ210写了个使用查询的方法实现按键灯的操作,具体实现方法如下:

      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资源比较严重,下一篇将用中断方式实现 



猜你喜欢

转载自blog.csdn.net/humanspider1/article/details/40878563
今日推荐