5.操作led

模版使用之前的hello驱动程序。
想要操作led,首先要找到原理图,查找GPIO对应的GPIO引脚
从图中能看出来LED2对应的GPIO是GPIO5_3,同时可以得知这个LED2是低电平点亮。查看cat /sys/kernel/debug/gpio可得知GPIO5_3(第四组GPIO的第三个引脚)的引脚编号是131。

确定好GPIO编号后,接下来就是要确定led驱动程序的功能,这里我希望它能开关led,以及能读取led的状态。所以可以去掉file_operations结构体中的open和release,只保留read和write。
接下来就是GPIO操作,套路如下

1.请求 GPIO: 使用gpio_request请求所需的 GPIO 引脚。

2.配置 GPIO: 请求成功后,可以配置 GPIO 的方向(输入或输出)和初始状态。
gpio_direction_input输入,gpio_direction_output输出。

3.使用 GPIO: 根据需要读写 GPIO 引脚的值。gpio_get_value读,gpio_set_value写。

4.释放 GPIO: 完成使用后,调用gpio_free函数释放该 GPIO 引脚。

 套用到我们的驱动程序中就是,在init函数中请求GPIO并设置方向为输出,在exit函数中释放GPIO,在read函数中获取GPIO的值,在write中设置GPIO的值。代码如下:

#include "asm-generic/gpio.h"
#include "asm/gpio.h"
#include "asm/uaccess.h"
#include "linux/printk.h"
#include "linux/scatterlist.h"
#include "linux/types.h"
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mman.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/raw.h>
#include <linux/tty.h>
#include <linux/capability.h>
#include <linux/ptrace.h>
#include <linux/device.h>
#include <linux/highmem.h>
#include <linux/backing-dev.h>
#include <linux/shmem_fs.h>
#include <linux/splice.h>
#include <linux/pfn.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/uio.h>
#include <linux/module.h>
 
#include <linux/uaccess.h>
 
#define DEVICE_NAME "led_device"
#define LED2_NUM	131
#define LED2_ON		0
#define LED2_OFF	1
static struct class *led_class;
static struct device *led_device;
static int major;

 
//ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
//参数含义依次为 要读取的文件指针 用户保存数据的buf 读取数据大小 文件内容的偏移量
static ssize_t led_read (struct file * filp, char __user *buf, size_t size, loff_t *offset)
{  
	unsigned long int ret;
	char value[1];
	value[0] = gpio_get_value(LED2_NUM) == LED2_ON ? 1 : 0;
	ret = copy_to_user(buf, value, 1);

	return 1;
}
 
//ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
//参数含义依次为 要写入的文件指针 用户要写入的数据buf 写入数据大小 文件内容的偏移量
static ssize_t led_write (struct file *filp, const char __user *buf, size_t size, loff_t *offset)
{
	unsigned long int  ret;
  	char value[1];
    ret = copy_from_user(value, buf, 1);
	if(1 == value[0])
		gpio_set_value(LED2_NUM, LED2_ON);
	else
		gpio_set_value(LED2_NUM, LED2_OFF);

	return 1;
}
 
/*构建file_operations结构体*/
static const struct file_operations led_fops = {
    .owner      = THIS_MODULE,
	.read		= led_read,
	.write		= led_write
};
 
/*init函数,实现register_chrdev*/
static int __init led_init(void)
{
	int ret;
    ret = gpio_request(LED2_NUM, "LED2");
	if(ret < 0)
	{
		printk("Failed to request GPIO:%d, ERRNO:%d\n", LED2_NUM, ret);
		return ret;
	}
	gpio_direction_output(LED2_NUM, LED2_OFF);


	//数含义依次为 主设备号,如果为0,内核会自动分配一个可用的。设备名,会在/proc/devices中显示。 file_operations结构体
    //注册成功就返回主设备号
    major = register_chrdev(0, DEVICE_NAME, &led_fops);
 
    //为这个模块创建一个名为led的类  在/sys/class/下会生成led目录
  	led_class = class_create(THIS_MODULE, "led");
	if (IS_ERR(led_class)) {
		pr_err("failed to allocate class\n");
		return PTR_ERR(led_class);
	}
 
    //在/sys/class/led类下创建一个led设备,同时在/dev/下创建一个led节点
    led_device = device_create(led_class, NULL, MKDEV(major, 0), NULL, "led");
    if (IS_ERR(led_device)) {
        pr_err("failed to allocate device\n");
		return PTR_ERR(led_device);
    }
    printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    return 0;
}
 
/*exit函数unregister_chrdev*/
static void __exit led_exit(void)
{
	gpio_free(LED2_NUM);
    //先销毁设备,后销毁类
    device_destroy(led_class, MKDEV(major, 0));
    class_destroy(led_class);
 
    unregister_chrdev(major, DEVICE_NAME);
    
    printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}
 
module_init(led_init);
module_exit(led_exit);
//遵循GPL协议
MODULE_LICENSE("GPL");

配套的应用程序写入1代表开灯,写入0代表关灯,没有参数代表读取led状态。
 

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <poll.h>
#include <signal.h>

static int fd;

/*
 * ./led_test on 
 * ./led_test off
 * ./led_test
 */
int main(int argc, char **argv)
{
	int ret;
	char buf[1];
	int i;
	
	/* 2. 打开文件 */
	fd = open("/dev/led", O_RDWR);
	if (fd == -1)
	{
		printf("can not open file /dev/led\n");
		return -1;
	}

	if (argc == 2)
	{
		/* write */
		buf[0] = strcmp(argv[1], "on") == 0 ? 1 : 0;
		ret = write(fd, buf, 1);
	}
	else
	{
		ret = read(fd, buf, 1);
		printf("led status is %s\n", buf[0] == 1 ? "on" : "off");
		
	}
	
	close(fd);
	
	return 0;
}

上机测试如下

 

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值