tiny4412 Linux驱动4个按键控制4个LED

 开发板上有4个按键,4个可控的LED灯,本次学习目标是对应按键控制对应LED灯,每按下一下按键,对灯的状态进行翻转。

1.硬件原理:

LED1连接GPM4.0,LED2连接GPM4.1,LED3连接GPM4.2,LED4连接GPM4.3,灯亮:输出低电平;灯灭:输出高电平

按键硬件:

按键按下,下降沿触发。

查看数据手册

按键寄存器地址都已经封装好了,我们可以在驱动了通过宏直接调用。

2.gpio库函数

//申请一个GPIO
int gpio_request(unsigned gpio, const char *label)
//申请一组
int gpio_request_array(const struct gpio *array, size_t num)
//释放一个GPIO
void gpio_free(unsigned gpio)
//释放一组GPIO
void gpio_free_array(const struct gpio *array, size_t num)
//把gpio定义成输出模式
int gpio_direction_output(unsigned gpio, int value)
//把gpio定义成输入模式,很多时候这个函数都是有问题的,慎用
int gpio_direction_input(unsigned gpio)
//获取io的电平值
int gpio_get_value(unsigned gpio)
//设置io的电平
void gpio_set_value(unsigned gpio, int value)
//把gpio转成对应的irq号(前提是该io支持irq)
int gpio_to_irq(unsigned gpio)
//把irq号转成gpio口号(前提是该io支持irq)
int irq_to_gpio(unsigned irq)

参数的意思:

gpio: gpio口号,在头文件里
label: 别名
array: gpio数组
num: gpio数组的元素个数
value: 默认的电平值
irq: irq号

返回值:失败小于0

驱动代码:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/delay.h>

#define LED1_GPIO EXYNOS4X12_GPM4(0)
#define LED2_GPIO EXYNOS4X12_GPM4(1)
#define LED3_GPIO EXYNOS4X12_GPM4(2)
#define LED4_GPIO EXYNOS4X12_GPM4(3)

struct key_desc{
    char *name;
    int gpio;
    int int_flag;      // 中断触发方式
};

 int irq_key[4]={0};
 int led_gpio[4]={LED1_GPIO,LED2_GPIO,LED3_GPIO,LED4_GPIO};
 int value[4]={1,1,1,1};
 
// 定义所有按键的信息集合, GPX3_2, 3_3, 3_4, 3_5.
/*
IRQF_DISABLED: 禁止中断嵌套
IRQF_SHARED:这个中断可以申请多次,这个标志位不能和下面的所有标志位同时使用,否则会出问题
IRQF_TRIGGER_RISING: 上升沿触发
IRQF_TRIGGER_FALLING: 下降沿触发
IRQF_TRIGGER_HIGH: 高电平触发
IRQF_TRIGGER_LOW: 低电平触发
IRQF_TRIGGER_MASK: 全部触发
*/
struct key_desc all_keys[] = {
    [0] = {
        .name = "key1_button",
        .gpio = EXYNOS4_GPX3(2),
        .int_flag = IRQF_TRIGGER_FALLING | IRQF_DISABLED,
    },
    [1] = {
        .name = "key2_button",
        .gpio = EXYNOS4_GPX3(3),
        .int_flag = IRQF_TRIGGER_FALLING | IRQF_DISABLED,
    },
    [2] = {
        .name = "key3_button",
        .gpio = EXYNOS4_GPX3(4),
        .int_flag = IRQF_TRIGGER_FALLING | IRQF_DISABLED,
    },
    [3] = {
        .name = "key4_button",
        .gpio = EXYNOS4_GPX3(5),
        .int_flag = IRQF_TRIGGER_FALLING | IRQF_DISABLED,
    },
};

static struct gpio led_gpio_array[] = {
{ LED1_GPIO, GPIOF_OUT_INIT_HIGH,  "LED1" },
{ LED2_GPIO, GPIOF_OUT_INIT_HIGH,  "LED2" }, 
{ LED3_GPIO, GPIOF_OUT_INIT_HIGH,  "LED3" }, 
{ LED4_GPIO, GPIOF_OUT_INIT_HIGH,  "LED4" },
};

//中断上文
irqreturn_t key_irq(int irq, void *args)
{
#if 0
	int i=0;
	static int num = 0;

	if(num==2){
		for(i = 0; i < 4; i++){
			if(irq==irq_key[i]){
			 printk("key%d Down!\n", i+1);	
			value[i]^=1;
			gpio_set_value(led_gpio[i],value[i]);
			}
		}
		num=0;
	}
	num++;
#else 
	int i;
	static int n = 0;
	struct key_desc *p = (struct key_desc *)args;
	udelay(20);
	if(gpio_get_value(p->gpio)){    // 弹起
        printk(" %s UP!\n", p->name);
    } else {    // 按下
        printk(" %s Down!\n", p->name);
		for(i = 0; i < ARRAY_SIZE(all_keys); i++)
		{
			n++;
			if(p->gpio == EXYNOS4_GPX3(i+2))
			{
				gpio_set_value(led_gpio_array[i].gpio, n%2);//亮
			}
			if(n%5==0) n=0;
		}
    }
#endif
	return IRQ_HANDLED;
}

static int __init tiny4412_key_init(void)
{
	int ret;
	int i = 0;
    for(i = 0; i < ARRAY_SIZE(all_keys); i++)
    {
    	irq_key[i]=gpio_to_irq(all_keys[i].gpio);
    	ret =  request_irq(irq_key[i], key_irq, all_keys[i].int_flag,all_keys[i].name, &all_keys[i]);
		if(ret < 0){
            printk("request irq failed!\n");
			return ret;
		}
	}
	return 0;
}

static void __exit tiny4412_key_exit(void)
{
	int i;
    for(i = 0; i < ARRAY_SIZE(all_keys); i++)
        free_irq(gpio_to_irq(all_keys[i].gpio), &all_keys[i]);
	gpio_free_array(led_gpio_array,ARRAY_SIZE(led_gpio_array));
}

module_init(tiny4412_key_init);
module_exit(tiny4412_key_exit);

MODULE_LICENSE("GPL");

Makefile:

obj-m += up_and_down.o

KERN_DIR=/root/work/tiny4412/linux/linux-3.5
PWD := $(shell pwd)

modules:
	$(MAKE) ARCH=arm -C $(KERN_DIR) M=$(PWD) modules

clean:
	$(MAKE) ARCH=arm -C $(KERN_DIR) M=$(PWD) modules clean

在linux中make一下,把编译生成的up_and_down.ko复制到开发中。

在开发板平台,xshell串口助手中安装驱动,指令:

insmod up_and_down.ko

当按下第一个按键时,第一个灯会亮,在按时会翻转,第二第三个灯也是如此,哈哈~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章