linux内核定时器与基于gpio子系统完成LED灯驱动

1.在内核模块中启用定时器,定时1s,让led1—秒亮、一秒灭

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/timer.h>

struct device_node *dnode;
struct gpio_desc* gpiono;
struct timer_list mytimer;


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

static int __init mycdev_init(void)
{
    //初始化定时器
    mytimer.expires = jiffies+HZ;
    timer_setup(&mytimer,timer_callback,0);
    //解析设备树节点信息
    dnode = of_find_node_by_path("/myleds");
    if(dnode == NULL)
    {
        printk("解析设备树节点信息失败\n");
        return -1;
    }
    printk("解析设备树节点信息成功\n");
    //申请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);
    }
    printk("申请gpio成功\n");
    add_timer(&mytimer);
    //设置gpio输出高电平,灯亮
    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灯驱动的注册,应用程序测试

head.h

#ifndef __HEAD_H__
#define __HEAD_H__

#define LED_ON _IO('l', 1)
#define LED_OFF _IO('l', 0)

#endif

led.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include "head.h"

unsigned int major; // 主设备号
struct class *cls;
struct device *dev;
struct device_node *dnode;
struct gpio_desc *gpiono1, *gpiono2, *gpiono3;

// 封装操作方法
int myled_open(struct inode *inode, struct file *file)
{
    int mi = MINOR(inode->i_rdev);
    file->private_data = (void *)mi;
    return 0;
}

long myled_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int mi = (int)file->private_data;
    switch (mi)
    {
    case 0: // LED1
        switch (cmd)
        {
        case LED_OFF:
            gpiod_set_value(gpiono1, 0);
            break;
        case LED_ON:
            gpiod_set_value(gpiono1, 1);
            break;
        }
        break;
    case 1: // LED2
        switch (cmd)
        {
        case LED_OFF:
            gpiod_set_value(gpiono2, 0);
            break;
        case LED_ON:
            gpiod_set_value(gpiono2, 1);
            break;
        }
        break;
    case 2: // LED3
        switch (cmd)
        {
        case LED_OFF:
            gpiod_set_value(gpiono3, 0);
            break;
        case LED_ON:
            gpiod_set_value(gpiono3, 1);
            break;
        }
        break;
    }
    return 0;
}

int myled_close(struct inode *inode, struct file *file)
{
    return 0;
}

struct file_operations fops =
    {
        .open = myled_open,
        .unlocked_ioctl = myled_ioctl,
        .release = myled_close,
};



static int __init mycdev_init(void)
{
    int i;
    // 字符设备驱动注册
    major = register_chrdev(0, "led", &fops);
    if (major < 0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    // 向上提交设备节点目录
    cls = class_create(THIS_MODULE, "led");
    if (IS_ERR(cls))
    {
        printk("向上提交设备节点目录失败\n");
        return -PTR_ERR(cls);
    }
    // 向上提交设备节点信息
    for (i = 0; i < 3; i++)
    {
        dev = device_create(cls, NULL, MKDEV(major, i), NULL, "led%d", i);
        if (IS_ERR(dev))
        {
            printk("向上提交设备节点信息失败\n");
            return -PTR_ERR(dev);
        }
    }

    // 解析设备树节点信息
    dnode = of_find_node_by_path("/myleds");
    if (dnode == NULL)
    {
        printk("解析设备树节点信息失败\n");
        return -1;
    }
    // 根据设备树节点信息解析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);
    }
    // 根据设备树节点信息解析led2 gpio结构体并向内核中注册
    gpiono2 = gpiod_get_from_of_node(dnode, "led2", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpiono2))
    {
        printk("申请gpio失败\n");
        return -PTR_ERR(gpiono2);
    }
    // 根据设备树节点信息解析led3 gpio结构体并向内核中注册
    gpiono3 = gpiod_get_from_of_node(dnode, "led3", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpiono3))
    {
        printk("申请gpio失败\n");
        return -PTR_ERR(gpiono3);
    }

    printk("LED准备完成\n");
    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);

    gpiod_put(gpiono1);
    gpiod_put(gpiono2);
    gpiod_put(gpiono3);

    // 注销设备节点信息  
    for (i = 0; i < 3; i++)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    // 注销设备节点目录
    class_destroy(cls);
    // 注销字符设备驱动
    unregister_chrdev(major, "/dev/led");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

test.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "head.h"

void do_led(int num)
{
    char pathname[128] = "";
    int key;
    sprintf(pathname, "/dev/led%d", num-1);
    int fd = open(pathname, O_RDWR);
    if (fd < 0)
    {
        printf("打开文件失败\n");
        return;
    }
    printf("0(灭灯) 1(亮灯) >");
    scanf("%d", &key);
    switch (key)
    {
    case 0:
        ioctl(fd, LED_OFF);
        break;
    case 1:
        ioctl(fd, LED_ON);
        break;
    default:
        printf("输入错误\n");
        return;
    }
    close(fd);
}

int main(int argc, const char *argv[])
{
    int num;
    while (1)
    {
        printf("请选择要控制的LED灯 1(LED1) 2(LED2) 3(LED3) >");
        scanf("%d", &num);
        do_led(num);
    }

    return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值