利用GPIO子系统与ioctl控制led灯闪烁(一次性)

 GPIO子系统的API

1.解析设备树节点
        struct device_node *of_find_node_by_path(const char *path)
        功能:通过节点路径获取设备节点
        参数:
        path:节点路径("/mynode@0x12345678")
        返回值:成功返回指向设备节点信息结构体空间的指针,失败返回NULL

#include<linux/of_gpio.h>
2.获取GPIO编号
        int of_get_named_gpio(struct device_node *np,
                                           const char *propname, int index)
        功能:根据gpio设备节点获取gpio编号
        np:设备树节点指针(node_p)
        propname:键名
        index:索引号
        返回值:成功返回gpio编号,失败返回错误码

#include<linux/gpio.h>
3.int gpio_request(unsigned gpio, const char *label)
        功能:申请要使用的gpio编号(要使用得到的gpio号,需要先申请)
        参数:
        gpio:gpio编号
        label:不用,填NULL

        返回值:成功返回0,失败返回错误码

4. int gpio_direction_input(unsigned gpio)
        功能:设备引脚为输入模式(direction:方向)
        参数:GPIO编号
        返回值:成功返回0,失败返回错误码
5.int gpio_direction_output(unsigned gpio, int value)
        功能:设备引脚为输出模式
        参数:
        gpio:GPIO编号
        value:1(高电平)  0(低电平)
        返回值:成功返回0,失败返回错误码

6.void gpio_set_value(unsigned gpio, int value)
        功能:设备引脚输出的电平值
        参数:
        gpio:GPIO编号
        value:1:高电平  0(低电平)

7.int gpio_get_value(unsigned gpio)
        功能:获取gpio电平值
        参数:gpio编号
        返回值:0(低电平) 1(高电平)

8.void gpio_free(unsigned gpio)
        功能:释放gpio编号
        参数:目标gpio编号

ioctlAPI

系统调用函数:
#include <sys/ioctl.h>

       int ioctl(int fd, unsigned long request, ...);
         功能:通过功能码实现设备的控制
         参数:
         fd:设备文件的文件描述符
         request:功能码
         ...:可以写参数,也可以不写,写参数的时候写地址
         返回值:成功返回0,失败返回错误码     
  An ioctl() request has encoded in it whether the argument is  an  in  parameter  or  out
       parameter, and the size of the argument argp in bytes.   
  
   struct file_operations {
           long (*unlocked_ioctl) (struct file *, unsigned int cmd, unsigned long arg);
           //将应用层request传递给cmd,
           //将应用层的...传给arg
   };           

ioctl功能代码

 

#define _IOC(dir,type,nr,size) \
        (((dir)  << _IOC_DIRSHIFT) | \
         ((type) << _IOC_TYPESHIFT) | \
         ((nr)   << _IOC_NRSHIFT) | \
         ((size) << _IOC_SIZESHIFT))
      dir<<30|size<<16|type<<8|nr<<0   

#define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size)  _IOC(_IOC_READ,(type),(nr),sizeof(size))
#define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))

//如果想要得到一个具有某种特定含义的功能码只需要_IO\_IOW\_IOR\_IOWR就可以得到
ex:以灯的开和关为例
#define LED_ON _IOW('a',1,int)
LED_ON  01 00000000000100 01100001 00000001
#define LED_OFF _IOW('a',0,int)
LED_OFF 01 00000000000100 01100001 00000000

#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include "myled.h"
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/timer.h>
#include <linux/of_gpio.h>
#define CNAME  "myled"

int major;  //定义变量接受主设备号
char kbuf[128] = {};    //定义数组用于存放和用户之间拷贝的数据
struct class *cls;//句柄
struct device *dev;

//定义一个指向设备节点的指针
struct device_node *node;
struct property *pr;    //属性结构体指针
struct gpio_desc *desc;

//给定时器分配对象
struct timer_list mytimer;

//定时器处理函数
void timer_handler(struct timer_list *timer)
{
    //电位翻转
    gpiod_set_value(desc, !gpiod_get_value(desc));
    //再次使用定时器
    mod_timer(&mytimer, jiffies+HZ);
}

long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int ret, witch;
    ret = copy_from_user(&witch, (void*)arg, sizeof(int));    if(ret)
    {
        printk("拷贝失败\n");
        return -EIO;
    }
    switch (witch)
    {
    case 1:
        //获取gpio编号
        desc = gpiod_get_from_of_node(node, "led1", 0, GPIOD_OUT_LOW, NULL);
        if (IS_ERR(desc))
        {
            printk("获取gpio编号失败\n");
            return PTR_ERR(desc);
        }
        // printk("获取gpio编号成功\n");
        //添加定时器
        add_timer(&mytimer);
        break;
    case 2:
        //获取gpio编号
        desc = gpiod_get_from_of_node(node, "led2", 0, GPIOD_OUT_LOW, NULL);
        if (IS_ERR(desc))
        {
            printk("获取gpio编号失败\n");
            return PTR_ERR(desc);
        }
        // printk("获取gpio编号成功\n");
        //添加定时器
        add_timer(&mytimer);
        break;
    case 3:
        //获取gpio编号
        desc = gpiod_get_from_of_node(node, "led3", 0, GPIOD_OUT_LOW, NULL);
        if (IS_ERR(desc))
        {
            printk("获取gpio编号失败\n");
            return PTR_ERR(desc);
        }
        // printk("获取gpio编号成功\n");
        //添加定时器
        add_timer(&mytimer);
        break;
    default:
        printk("功能码错误\n");
        break;
    }
    return 0;
}
struct file_operations fops=
{
    .unlocked_ioctl = ioctl,
};

//入口函数
static int __init mycdev_init(void)
{
   //根据设备节点路径获取设备节点信息
    node = of_find_node_by_path("/myleds");
    if (node == NULL)
    {
        printk("获取节点信息失败\n");
        return ENODATA;
    }
    printk("获取节点信息成功\n");

    //动态注册字符设备驱动
    major=register_chrdev(0,CNAME,&fops);
    if(major<0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功major=%d\n",major);
    //向上提交节点目录
    cls=class_create(THIS_MODULE,"LED");
    if(IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        return PTR_ERR(cls);
    }
     printk("向上提交目录成功\n");
     //创建设备节点
     dev=device_create(cls,NULL,MKDEV(major,0),NULL,"myled");
     if(IS_ERR(dev))
     {
        printk("创建节点失败\n");
        return PTR_ERR(dev);
     }
     printk("创建节点成功\n");

    //初始化定时器
    mytimer.expires = jiffies + HZ; //定时1s
    timer_setup(&mytimer, timer_handler, 0);

    return 0;
}
//出口函数
static void __exit mycdev_exit(void)
{
    //删除定时器
    del_timer(&mytimer);
    //释放gpio编号
    gpiod_set_value(desc, 0);
    gpiod_put(desc);
}

module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include <sys/ioctl.h>
#include "myled.h"

int main(int argc, char const *argv[])
{
    int fd1 = open("/dev/myled",O_RDWR);    //打开设备文件
    int which;
    if(fd1 < 0)
    {

        printf("打开设备文件失败\n");
        exit(-1);
    }
    printf("设备文件打开成功\n");
    //在终端输入
    while(1)
    {
        printf("请选择要操作:\n1-->led1\n2-->led2\n3-->led3\n");
        scanf("%d", &which);
        getchar();
        if(which==1 || which==2 || which==3) 
            ioctl(fd1, 0, &which);        //输入为1、2、3时,把输入的数用which传入内核
    }
    close(fd1);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老K殿下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值