tag 标签: 按键控制led驱动

相关博文
  • 热度 11
    2012-7-5 19:25
    1446 次阅读|
    0 个评论
    /******************************************************************************* 硬件环境:  友善之臂mini2440开发板 软件环境:  操作系统ubuntu8.04,内核版本linux2.6.29 按键驱动说明:     手动创建设备文件与自动创建设备文件     自动创建设备文件,用设备名称DEVICE_NAME buttons 自动生成设备节点     本程序按键按下消抖20ms,很稳定。但是按键抬起释放消抖不好,以后想办法     要处理好。改成下降沿和上升沿触发中断,也不理想。      作者:   ljh      时间:   2012.06.20      ********************************************************************************/ //#define DEBUG #i nclude linux/kernel.h #i nclude linux/module.h #i nclude linux/init.h #i nclude linux/fs.h #i nclude linux/errno.h #i nclude linux/poll.h #i nclude linux/interrupt.h #i nclude linux/irq.h #i nclude asm/irq.h #i nclude mach/regs-gpio.h #i nclude mach/hardware.h #i nclude linux/miscdevice.h #i nclude linux/delay.h #define DEVICE_NAME         "buttons-ctl-leds"  //设备名称 #define DEVICE_MAJOR        232                 //主设备号                #define KEY_TIMER_DELAY1    (HZ/50)             //按键按下去抖延时20毫秒        #define KEY_TIMER_DELAY2    (HZ/10)             //按键抬起去抖延时100毫秒 #define KEY_DOWN            0                   //按键按下                    #define KEY_UP              1                   //按键抬起                #define KEY_UNCERTAIN       2                   //按键不确定                    #define KEY_COUNT           6                   //6个按键                    static volatile int ev_press = 0;                //按键按下产生标志 static volatile int key_status ;       //记录6个按键的状态    static struct timer_list key_timers ;  //定义6个按键去抖动定时器 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);    //定义并初始化等待队列     //组织硬件资源结构体 struct button_irq_desc    {     int irq;            //中断号     int pin;            //引脚     int pin_setting;    //引脚配置     int number;   //编号     char *name;         //按键名称,注意这个名称,在后面的一个现象中会出现 }; //定义6个按键资源结构体数组 static struct button_irq_desc button_irqs = {  S3C2410_GPB5,     //led1  S3C2410_GPB6,     //led2  S3C2410_GPB7,     //led3  S3C2410_GPB8,     //led4 }; static unsigned int led_cfg_table == KEY_UP)       {         //设置当前按键的状态为不确定         key_status = KEY_UNCERTAIN;         //设置当前按键按下去抖定时器的延时并启动定时器         key_timers .expires= jiffies + KEY_TIMER_DELAY1; //按键按下开始延时20ms消抖           add_timer(key_timers );                 #ifdef DEBUG          printk("test come interrupt\n");           printk("number = %d\n",button-number + 1);       #endif     }         return IRQ_RETVAL(IRQ_HANDLED); } static void buttons_timer(unsigned long arg) {     //获取当前按键资源的索引     int key =arg;     //获取当前按键引脚上的电平值来判断按键是按下还是抬起     int up = s3c2410_gpio_getpin(button_irqs .pin);     if(!up)//低电平,按键按下     {         if(key_status == KEY_UNCERTAIN)      //消抖20ms,检测仍是低电平,按键判定为按下状态         {             //标识当前按键状态为按下             key_status = KEY_DOWN;                         //标识当前按键已按下并唤醒等待队列             ev_press = 1;             wake_up_interruptible(button_waitq);                         #ifdef DEBUG             printk(" %d test falling\n",key+1);     //内核打印,哪个按键按下          #endif                   }         //设置当前按键抬起去抖定时器的延时并启动定时器         key_timers .expires= jiffies + KEY_TIMER_DELAY2; //按键抬起释放消抖20ms          add_timer(key_timers );     }     else//高电平,按键抬起     {          //按键抬起释放消抖20ms     //if(key_status == KEY_UNCERTAIN)             //{            //标识当前按键状态为抬起           key_status = KEY_UP;                            #ifdef DEBUG              printk(" %d test raising\n",key+1);     //内核打印,哪个按键释放                    #endif          //}                   } } static int buttons_open(struct inode*inode, struct file *file) {     int i;     int ret;     for(i = 0; i KEY_COUNT; i++)     {         //设置6个IO口为中断触发方式         s3c2410_gpio_cfgpin(button_irqs .pin, button_irqs .pin_setting);         //设置中断下降沿为有效触发         set_irq_type(button_irqs .irq, IRQ_TYPE_EDGE_FALLING);                 //申请中断(类型为快速中断,中断服务时屏蔽所有外部中断?)      //   ret = request_irq(button_irqs .irq, buttons_interrupt, IRQF_DISABLED, button_irqs .name,(void *)i);         ret = request_irq(button_irqs .irq, buttons_interrupt, IRQF_DISABLED, button_irqs .name,(void *)button_irqs );                 if(ret)         {             break;         }         //初始化6个按键的状态为抬起         key_status = KEY_UP;         //初始化并设置6个去抖定时器         setup_timer(key_timers , buttons_timer, i);     }     if(ret)     {         //中断申请失败处理         i--;         for(; i= 0; i--)         {             //释放已注册成功的中断             disable_irq(button_irqs .irq);             free_irq(button_irqs .irq,(void *)button_irqs );         }         return -EBUSY;     }     return 0; } static int buttons_close(struct inode*inode, struct file *file) {     int i;     //释放6个定时器和中断     for(i = 0; i KEY_COUNT; i++)     {         del_timer(key_timers );         disable_irq(button_irqs .irq);         free_irq(button_irqs .irq,(void *)button_irqs );     }     return 0; } static int buttons_read(struct file *file,char __user *buf, size_t count, loff_t *offp) {     unsigned long ret;     if(!ev_press)//判断按键按下产生标识,0没有产生  {         if(file-f_flags O_NONBLOCK)         {             //应用程序若采用非阻塞方式读取则返回错误             return -EAGAIN;         }         else         {             //以阻塞方式读取且按键按下没有产生,让等待队列进入睡眠             wait_event_interruptible(button_waitq, ev_press);         }     }     //1为按键按下产生,并清除标识为0,准备给下一次判断用     ev_press = 0;     //将内核中的按键状态数据拷贝到用户空间给应用程序使用     //返回值大于0表示没有拷贝的字节数,返回0表示成功     ret = copy_to_user(buf,(void *)key_status,min(sizeof(key_status),count));       return ret ?-EFAULT : min(sizeof(key_status),count); }   //驱动程序中的轮询,用于应用程序中的轮询查询是否可对设备进行访问 static int buttons_poll(struct file *file,struct poll_table_struct *wait) {     unsigned int mask= 0;     //添加等待队列到等待队列表中(poll_table)     poll_wait(file,button_waitq, wait);     if(ev_press)     {         //标识数据可以获得         mask |= POLLIN| POLLRDNORM;     }     return mask; }     //ioctl方法,通过相同名字的系统调用,达到控制硬件的能力 static int mini2440_leds_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) {  int i=0;    switch(cmd)  {   case 0:   case 1:    if (arg 5)    {     return -EINVAL;    }       //s3c2410_gpio_setpin(led_table , !cmd);    int up = s3c2410_gpio_getpin(led_table ); //获取相应管脚电平         if(up)    {     s3c2410_gpio_setpin(led_table , 0);  //低电平led亮    }    else    {     s3c2410_gpio_setpin(led_table , 1);  //高电平led灭      }             return 0;     //自己添加四个led闪烁20s   case 55:    //延时20ms led闪烁    while(i 20)    {     s3c2410_gpio_setpin(led_table , 1); //高电平led灭      s3c2410_gpio_setpin(led_table , 1); //高电平led灭     s3c2410_gpio_setpin(led_table , 1); //高电平led灭     s3c2410_gpio_setpin(led_table , 1); //高电平led灭     mdelay(500);       //延时500ms          s3c2410_gpio_setpin(led_table , 0); //低电平led亮     s3c2410_gpio_setpin(led_table , 0); //低电平led亮     s3c2410_gpio_setpin(led_table , 0); //低电平led亮     s3c2410_gpio_setpin(led_table , 0); //低电平led亮     mdelay(500);       //延时500ms            i++;    }    return 0;        default:    return -EINVAL;  } } //设备操作列表 static struct file_operations buttons_fops= {     .owner        = THIS_MODULE,     .open         = buttons_open,     .release      = buttons_close,     .read         = buttons_read,     .poll         = buttons_poll,    .ioctl    = mini2440_leds_ioctl,   //控制led灯光   };   static struct miscdevice misc = {  .minor = MISC_DYNAMIC_MINOR,  .name = DEVICE_NAME,  .fops = buttons_fops,  }; static int __init button_init(void) {     int ret, i;     //注册字符设备    // ret = register_chrdev(DEVICE_MAJOR, DEVICE_NAME,buttons_fops); //手动创建设备文件   ret = misc_register(misc);           //动态创建设备文件        //初始化leds关闭   for (i = 0; i 4; i++)  {   s3c2410_gpio_cfgpin(led_table , led_cfg_table );  //IO配置输出   s3c2410_gpio_setpin(led_table , 1);      //输出高电平Leds灭  }           if(ret 0)     {         printk(DEVICE_NAME " register faild!\n");         return ret;     }     else     {      printk (DEVICE_NAME"\tinitialized\n");     }      return 0; } static void __exit button_exit(void) {     //注销字符设备     //unregister_chrdev(DEVICE_MAJOR, DEVICE_NAME);  misc_deregister(misc); } module_init(button_init); module_exit(button_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("ljh"); MODULE_DEION("buttons-ctl-leds driver");