驱动GPIO子系统作业

该代码示例展示了如何在Linux内核模块中启用一个1秒周期的定时器来控制LED灯的亮灭。通过解析设备树节点获取GPIO描述符,然后使用`gpiod_set_value`函数改变LED的状态。此外,还提供了一个基于字符设备驱动的用户空间应用程序,用于通过输入控制LED灯的开关。
摘要由CSDN通过智能技术生成
  • 1.在内核模块中启用定时器,定时1s,让led1 一秒亮、一秒灭
​
#include <linux/init.h>
#include <linux/module.h>
#include<linux/of.h>
#include<linux/gpio.h>
#include<linux/of_gpio.h>
#include<linux/timer.h>
/*
   myleds{
       led1=<&gpioe 10 0>;    
       led2=<&gpiof 10 0>; 
       led3=<&gpioe 8 0>;  
    };
*/
struct device_node *dnode;
struct gpio_desc *gpiono;
struct timer_list mytimer;


void mytimer_func(struct timer_list *timer)
{
   if(gpiod_get_value(gpiono) == 0)
    {
        //亮灯
        gpiod_set_value(gpiono,1);
        mod_timer(timer,jiffies+HZ);
    }
    else if(gpiod_get_value(gpiono) == 1)
    {
        //灭灯
        gpiod_set_value(gpiono,0);
        mod_timer(timer,jiffies+HZ);
    }
}

static int __init mycdev_init(void)
{
    int ret;
     //初始化定时器对象
    mytimer.expires=jiffies+HZ;
    timer_setup(&mytimer,mytimer_func,0);
    

    //解析led灯的设备树节点
    dnode=of_find_node_by_path("/myleds");
    if(dnode==NULL)
    {
    printk("解析设备树节点失败\n");
    return -ENXIO;
    }
    printk("解析设备树节点成功\n");
      //根据设备树节点解析led1 gpio结构体并向内核注册
   gpiono=gpiod_get_from_of_node(dnode,"led1",0,GPIOD_OUT_LOW,NULL); 
   if(IS_ERR(gpiono))
   {
    printk("申请gpio失败\n");
    return -PTR_ERR(gpiono);
   }  
   //将定时器对象注册进内核
    add_timer(&mytimer);
   //亮灯
   gpiod_set_value(gpiono,1);
  
    return 0;
}
static void __exit mycdev_exit(void)
{
   //灭灯
   gpiod_set_value(gpiono,0);
   //注销gpio信息
   gpiod_put(gpiono);
   del_timer(&mytimer);

}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

​
  • 2.基于gpio子系统完成LED灯驱动的注册,应用程序测试
  • myled.c
  • #include <linux/init.h>
    #include <linux/module.h>
    #include<linux/of.h>
    #include<linux/gpio.h>
    #include<linux/of_gpio.h>
    #include<linux/timer.h>
    
    struct {
        char led_num;
        int led_type;
    }led;
    /*
       myleds{
           led1=<&gpioe 10 0>;    
           led2=<&gpiof 10 0>; 
           led3=<&gpioe 8 0>;  
        };
    */
    struct class *cla;
    struct device *dev;
    int major;//用于保存主设备号
    struct device_node *dnode;
    struct gpio_desc *gpiono1, *gpiono2, *gpiono3;
    struct timer_list mytimer; // 定义计时器对象
    
    
    int mycdev_open(struct inode *inode, struct file *file)
    {
        printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
        return 0;
    }
     
    ssize_t mycdev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
    {
        int ret;
        ret = copy_from_user(&led,ubuf, size);
        if (ret)
        {
            printk("copy_from_user filed\n");
            return -EIO;
        }
        printk("type = %c\n", led.led_num);
        printk("num = %d\n", led.led_type);
        if (led.led_num == 'a')
        {
            if (led.led_type == 1) // 开灯
            {
                gpiod_set_value(gpiono1, 1);
            }
            else if (led.led_type == 0) // 关灯
            {
                gpiod_set_value(gpiono1, 0);
            }
        }
        else if (led.led_num == 'b')
        {
            if (led.led_type == 1) // 开灯
            {
                gpiod_set_value(gpiono2, 1);
            }
            else if (led.led_type == 0) // 关灯
            {
                gpiod_set_value(gpiono2, 0);
            }
        }
        else if (led.led_num == 'c')
        {
            if (led.led_type == 1) // 开灯
            {
                gpiod_set_value(gpiono3, 1);
            }
            else if (led.led_type == 0) // 关灯
            {
                gpiod_set_value(gpiono3, 0);
            }
        }
        else if (led.led_num == 'd')
        {
            if (led.led_type == 1) // 开灯
            {
                gpiod_set_value(gpiono1, 1);
                gpiod_set_value(gpiono2, 1);
                gpiod_set_value(gpiono3, 1);
            }
            else if (led.led_type == 0) // 关灯
            {
                gpiod_set_value(gpiono1, 0);
                gpiod_set_value(gpiono2, 0);
                gpiod_set_value(gpiono3, 0);
            }
        }
        printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
        return 0;
    }
     
    // 操作方法结构体的初始化
    struct file_operations fops =
        {
            .open = mycdev_open,
            .write = mycdev_write,
    };
     
    static int __init mycdev_init(void)
    {
        int i;
        // 字符设备驱动注册
        major = register_chrdev(0, "mychrdev", &fops);
        if (major < 0)
        {
            printk("字符设备驱动注册失败\n");
            return major;
        }
        printk("字符设备驱动注册成功major=%d\n", major);
     
        // 向上提交目录
        cla = class_create(THIS_MODULE, "mychrdev");
        if (IS_ERR(cla))
        {
            printk("向上提交目录失败\n");
            return -PTR_ERR(cla);
        }
        printk("向上提交目录成功\n");
        // 向上提交设备节点信息,为三盏灯创建三个设备文件
        for (i = 0; i < 3; i++)
        {
            dev = device_create(cla, NULL, MKDEV(major, i), NULL, "mychrdev%d", i);
            if (IS_ERR(dev))
            {
                printk("向上提交设备节点信息失败\n");
                return -PTR_ERR(dev);
            }
            printk("向上提交设备节点%d信息成功\n", i);
        }
        // 解析led灯的设备树节点
        dnode = of_find_node_by_path("/myleds");
        if (dnode == NULL)
        {
            printk("解析设备树节点失败\n");
            return -ENXIO;
        }
        printk("解析设备树节点成功\n");
        // 根据设备树节点解析led1 gpio结构体并向内核注册
        gpiono1 = gpiod_get_from_of_node(dnode, "led1", 0, GPIOD_OUT_LOW, NULL);
        if (IS_ERR(gpiono1))
        {
            printk("申请gpio失败\n");
            return -PTR_ERR(gpiono1);
        }
        gpiono2 = gpiod_get_from_of_node(dnode, "led2", 0, GPIOD_OUT_LOW, NULL);
        if (IS_ERR(gpiono2))
        {
            gpiod_put(gpiono1);
            printk("申请gpio失败\n");
            return -PTR_ERR(gpiono2);
        }
        gpiono3 = gpiod_get_from_of_node(dnode, "led3", 0, GPIOD_OUT_LOW, NULL);
        if (IS_ERR(gpiono3))
        {
            gpiod_put(gpiono1);
            gpiod_put(gpiono2);
            printk("申请gpio失败\n");
            return -PTR_ERR(gpiono3);
        }
        // 亮灯
        gpiod_set_value(gpiono1, 1);
        gpiod_set_value(gpiono2, 1);
        gpiod_set_value(gpiono3, 1);
     
        return 0;
    }
    static void __exit mycdev_exit(void)
    {
        int i;
        // 灭灯
        gpiod_set_value(gpiono1, 0);
        gpiod_set_value(gpiono2, 0);
        gpiod_set_value(gpiono3, 0);
        // 注销gpio信息
        gpiod_put(gpiono1);
        gpiod_put(gpiono2);
        gpiod_put(gpiono3);
        // 销毁设备节点信息
        for (i = 0; i < 3; i++)
        {
            device_destroy(cla, MKDEV(major, i));
        }
        class_destroy(cla);
        // 字符设备驱动的注销
        unregister_chrdev(major, "mychrdev");
    }
    module_init(mycdev_init);
    module_exit(mycdev_exit);
    MODULE_LICENSE("GPL");
    
    
    

    test.c

  • #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <string.h>
    struct
    {
            char led_num;
            int led_type;
    }led;
     
    int main(int argc, char const *argv[])
    {
        int fd = open("/dev/mychrdev0", O_RDWR);
        if (fd < 0)
        {
            printf("打开设备文件失败\n");
            exit(-1);
        }
        while (1)
        {
            LOOP:
            printf("请选择灯(a(key1)  b(key2)  c(key3)  d(all led)  q(Quit)");
            scanf("%c", &led.led_num);
            if(led.led_num < 'a' || led.led_num > 'd' && led.led_num != 'q')
            {
                printf("输入错误,请重新输入!!!\n");
                goto LOOP;
            }
            getchar();
            if(led.led_num == 'q')
                break;
            printf("请选择灯的亮灭(0:关灯 1:开灯): ");
            scanf("%d", &led.led_type);
            if(led.led_type != 1 && led.led_type != 0)
            {
                printf("输入错误,请重新输入!!!\n");
                goto LOOP;
            }
            getchar();
            write(fd, &led, sizeof(led));
        }
        close(fd);
        return 0;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值