• 嵌入式Linux驱动开发笔记(未完待续。。。)


    一、Git仓库用法

    1、linu终端输入下面命令安装

    git clone https://e.coding.net/weidongshan/linux_course/linux_basic_develop.git
    
    • 1

    2、
    进入到GIT仓库目录

    cd  /D/abc/doc_and_source_for_mcu_mpu
    
    • 1

    在doc_and_source_for_mcu_mpu目录下,执行以下命令获得资料的最新版本。

    git pull origin
    
    • 1

    二、字符设备驱动开发

    1、hello驱动程序步骤

    1. 创建 file_operations 结构体(字符设备驱动的核心)
    2. 注册字符设备设备
    3. 写入口函数(相当于main)
    4. 写退出函数

    三、字符设备驱动程序源码

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    
    static int major;
    
    static int hello_open (struct inode *node, struct file *filp)
    {
        printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
        return 0;
    }
    static ssize_t hello_read (struct file *filp, char __user *buf, size_t size, loff_t *offset)
    {
        printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
        return size;
    }    
    
    static ssize_t hello_write(struct file *filp, const char __user *buf, size_t size, loff_t *offset)
    {
        printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
        return size;
    }
    
    static int hello_release (struct inode *node, struct file *filp)
    {
        printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
        return 0;
    }
    
    /* 1. create file_operations */
    static const struct file_operations hello_drv = {
        .owner      = THIS_MODULE,
    	.read		= hello_read,
    	.write		= hello_write,
    	.open		= hello_open,
        .release    = hello_release,
    };
    
    /* 2. register_chrdev */
    
    /* 3. entry function */
    static int hello_init(void)
    {
       major = register_chrdev(0, "100ask_hello", &hello_drv);
       return 0;
    }
    
    /* 4. exit function */
    static void hello_exit(void)
    {
        unregister_chrdev(major, "100ask_hello");
    }
    
    
    module_init(hello_init);
    module_exit(hello_exit);
    MODULE_LICENSE("GPL");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    在这里插入图片描述
    在这里插入图片描述
    用户与内核传数据和创建设备文件驱动程序

    #include "asm/cacheflush.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include 
    
    
    static struct class *hello_class;		//定义一个类型,用于创建设备
    static int major;						//主设备号
    static unsigned char hello_buf[100];	//内核数据缓存
    
    static int hello_open (struct inode *node, struct file *filp)
    {
        printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
        return 0;
    }
    static ssize_t hello_read (struct file *filp, char __user *buf, size_t size, loff_t *offset)
    {
        unsigned long len = size > 100 ? 100 : size;
    
        printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    
        copy_to_user(buf, hello_buf, len);		//将内核数据发送给用户
    
        return len;
    }
    
    static ssize_t hello_write(struct file *filp, const char __user *buf, size_t size, loff_t *offset)
    {
        unsigned long len = size > 100 ? 100 : size;
    
        printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
        copy_from_user(hello_buf, buf, len);
    
        return len;
    }
    
    static int hello_release(struct inode *node, struct file *filp)
    {
        printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
        return 0;
    }
    
    /* 1. create file_operations */
    static const struct file_operations hello_drv = {
        .owner      = THIS_MODULE,
    	.read		= hello_read,
    	.write		= hello_write,
    	.open		= hello_open,
        .release    = hello_release,
    };
    
    
    /* 2. register_chrdev */
    
    /* 3. entry function */
    static int hello_init(void)
    {	//申请设备号,只能进行注测主设备号0-255个设备,次设备号全部被占用
        major = register_chrdev(0, "100ask_hello", &hello_drv);  //0代表自动寻找设备号,
    
    	hello_class = class_create(THIS_MODULE, "hello_class");		//创建一个类型
    	if (IS_ERR(hello_class)) {
    		printk("failed to allocate class\n");
    		return PTR_ERR(hello_class);
    	}
    	//创建一个名字为hello的设备
        device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");  /* /dev/hello */
    
       return 0;
    }
    
    
    /* 4. exit function */
    static void hello_exit(void)
    {
        device_destroy(hello_class, MKDEV(major, 0));
    
        class_destroy(hello_class);
    
        unregister_chrdev(major, "100ask_hello");
    }
    
    
    module_init(hello_init);
    module_exit(hello_exit);
    MODULE_LICENSE("GPL");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105

    应用

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    /* 写: ./hello_test /dev/xxx 100ask
     * 读: ./hello_test /dev/xxx
     */
    int main(int argc, char **argv)
    {
        int fd;
        int len;
        char buf[100];
    
        if (argc < 2)
        {
            printf("Usage: \n");
            printf("%s  [string]\n", argv[0]);
            return -1;
        }
    
        // open
        fd = open(argv[1], O_RDWR);
        if (fd < 0)
        {
            printf("can not open file %s\n", argv[1]);
            return -1;
        }
    
        if (argc == 3)
        {
            // write
            len = write(fd, argv[2], strlen(argv[2])+1);
            printf("write ret = %d\n", len);
        }
        else
        {
            // read
            len = read(fd, buf, 100);
            buf[99] = '\0';
            printf("read str : %s\n", buf);
        }
        
        // close
        close(fd);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    四、 APP使用驱动的4种方式

    1、驱动程序:提供能力,不提供策略

    • 非阻塞(查询)

    • 阻塞(休眠-唤醒)

    • poll(定个闹钟)

    • 异步通知
      在这里插入图片描述
      妈妈怎么知道卧室里小孩醒了?

    • 时不时进房间看一下: 查询方式

      • 简单,但是累
    • 进去房间陪小孩一起睡觉,小孩醒了会吵醒她: 休眠-唤醒

    • 不累,但是妈妈干不了活了

    • 妈妈要干很多活,但是可以陪小孩睡一会,定个闹钟: poll 方式

      • 要浪费点时间, 但是可以继续干活。
      • 妈妈要么是被小孩吵醒,要么是被闹钟吵醒。
    • 妈妈在客厅干活,小孩醒了他会自己走出房门告诉妈妈: 异步通知

      • 妈妈、小孩互不耽误

    2、中断的引入

    1. 非阻塞:没有解除睡眠立即返回错误
    2. 阻塞如下图:
      在这里插入图片描述
    3. poll机制如下图
      在这里插入图片描述
    4. 异步通知
      在这里插入图片描述

    五、 字符设备的另一种注册方法cdev

    驱动程序

    #include "asm-generic/errno-base.h"
    #include "asm/cacheflush.h"
    #include "linux/cdev.h"
    #include "linux/fs.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    
    static struct class *hello_class;	
    static struct cdev hello_cdev;
    static dev_t dev;
    
    static unsigned char hello_buf[100];
    
    static int hello_open (struct inode *node, struct file *filp)
    {
        printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
        return 0;
    }
    static ssize_t hello_read (struct file *filp, char __user *buf, size_t size, loff_t *offset)
    {
        unsigned long len = size > 100 ? 100 : size;
    
        printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    
        copy_to_user(buf, hello_buf, len);
    
        return len;
    }
    
    static ssize_t hello_write(struct file *filp, const char __user *buf, size_t size, loff_t *offset)
    {
        unsigned long len = size > 100 ? 100 : size;
    
        printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
        copy_from_user(hello_buf, buf, len);
    
        return len;
    }
    
    static int hello_release (struct inode *node, struct file *filp)
    {
        printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
        return 0;
    }
    
    /* 1. create file_operations */
    static const struct file_operations hello_drv = {
        .owner      = THIS_MODULE,
    	.read		= hello_read,
    	.write		= hello_write,
    	.open		= hello_open,
        .release    = hello_release,
    };
    
    
    /* 2. register_chrdev */
    
    /* 3. entry function */
    static int hello_init(void)
    {
        int ret;
    
        // register_chrdev
    	//参数一:分配设备号成功后用来存放分配到的设备号,分配结束后要把主设备号提取出来(major = MAJOR(devno);)因为主设备号会变所以要将变得重新赋值
    	//参数二:起始的次设备号,一般为0
    	//参数三:count:申请的设备数量,从起始设备号累加。如果在创建一个设备,主设备号跟前一个一样,次设备号为1的设备,依然可以访问,就是同一个设备。
    	//参数四:/proc/devices文件中与该设备对应的名字,方便用户层查询主次设备号
    	ret = alloc_chrdev_region(&dev, 0, 2, "hello");		//自动注册设备
    	if (ret < 0) 
    	{
    		printk(KERN_ERR "alloc_chrdev_region() failed for hello\n");
    		return -EINVAL;
    	}
    
        cdev_init(&hello_cdev, &hello_drv);	//将hello_drv与hello_cdev链接起来	
    
        ret = cdev_add(&hello_cdev, dev, 2);//将设备号添加到设备结构体
    	if (ret)
        {
    		printk(KERN_ERR "cdev_add() failed for hello\n");
    		return -EINVAL;
        }
    		
    	hello_class = class_create(THIS_MODULE, "hello_class");	
    	if (IS_ERR(hello_class)) {
    		printk("failed to allocate class\n");
    		return PTR_ERR(hello_class);
    	}
    	//创建一名字为hello的设备 
        device_create(hello_class, NULL, dev, NULL, "hello");  /* /dev/hello */
    
       return 0;
    }
    
    /* 4. exit function */
    static void hello_exit(void)
    {
        device_destroy(hello_class, dev);
    
        class_destroy(hello_class);
    
        //unregister_chrdev(major, "100ask_hello");
        cdev_del(&hello_cdev);
        unregister_chrdev_region(dev, 2);
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    MODULE_LICENSE("GPL");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130

    app

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    /* 写: ./hello_test /dev/xxx 100ask
     * 读: ./hello_test /dev/xxx
     */
    int main(int argc, char **argv)
    {
        int fd;
        int len;
        char buf[100];
    
        if (argc < 2)
        {
            printf("Usage: \n");
            printf("%s  [string]\n", argv[0]);
            return -1;
        }
        // open
        fd = open(argv[1], O_RDWR);
        if (fd < 0)
        {
            printf("can not open file %s\n", argv[1]);
            return -1;
        }
        if (argc == 3)
        {
            // write
            len = write(fd, argv[2], strlen(argv[2])+1);
            printf("write ret = %d\n", len);
        }
        else
        {
            // read
            len = read(fd, buf, 100);
            buf[99] = '\0';
            printf("read str : %s\n", buf);
        }
        // close
        close(fd);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    六、 通用框架1

    1、GPIO子系统
    在开发板上执行如下命令查看已经在使用的GPIO状态:

    # cat /sys/kernel/debug/gpio
    gpiochip0: GPIOs 0-15, parent: platform/soc:pin-controller@50002000, GPIOA:
     gpio-10  (                    |heartbeat           ) out lo
     gpio-14  (                    |shutdown            ) out hi
    
    gpiochip1: GPIOs 16-31, parent: platform/soc:pin-controller@50002000, GPIOB:
     gpio-26  (                    |reset               ) out hi ACTIVE LOW
    
    gpiochip2: GPIOs 32-47, parent: platform/soc:pin-controller@50002000, GPIOC:
    
    gpiochip3: GPIOs 48-63, parent: platform/soc:pin-controller@50002000, GPIOD:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    怎么确定GPIO引脚的编号?方法如下:

    ① 先在开发板的/sys/class/gpio目录下,找到各个gpiochipXXX目录:(这个后面的数是起始地址,不跟上面那个查到的组数一样)
    在这里插入图片描述
    ② 然后进入某个gpiochipXXX目录,查看文件label的内容,就可以知道起始号码XXX对于哪组GPIO
    那么GPIO4_14的号码是96+14=110,可以如下操作读取按键值:

    [root@100ask:~]# echo 110 > /sys/class/gpio/export              // gpio_request
    [root@100ask:~]# echo in > /sys/class/gpio/gpio110/direction    // gpio_direction_input
    [root@100ask:~]# cat /sys/class/gpio/gpio110/value              // gpio_get_value
    [root@100ask:~]# echo 110 > /sys/class/gpio/unexport            // gpio_free
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    GPIO子系统函数有新、老两套:

    descriptor-basedlegacy
    获得GPIO
    gpiod_getgpio_request
    gpiod_get_index
    gpiod_get_arraygpio_request_array
    devm_gpiod_get
    devm_gpiod_get_index
    devm_gpiod_get_array
    设置方向
    gpiod_direction_inputgpio_direction_input
    gpiod_direction_outputgpio_direction_output
    读值、写值
    gpiod_get_valuegpio_get_value
    gpiod_set_valuegpio_set_value
    释放GPIO
    gpio_freegpio_free
    gpiod_putgpio_free_array
    gpiod_put_array
    devm_gpiod_put
    devm_gpiod_put_array

    2、中断函数

    2.1 使用中断的流程

    在驱动程序里使用中断的流程如下:

    • 确定中断号

    • 注册中断处理函数,函数原型如下:

      int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev);
    
    • 1
    • 在中断处理函数里

      • 分辨中断
      • 处理中断
      • 清除中断

    2.2 函数细节

    request_irq函数的第1个参数是中断号,可以根据GPIO函数获得中断号:

    int gpio_to_irq(unsigned int gpio);
    int gpiod_to_irq(const struct gpio_desc *desc);
    
    • 1
    • 2

    request_irq函数的第2个参数是函数指针:

    enum irqreturn {
    	IRQ_NONE		= (0 << 0),
    	IRQ_HANDLED		= (1 << 0),
    	IRQ_WAKE_THREAD		= (1 << 1),
    };
    typedef enum irqreturn irqreturn_t;
    typedef irqreturn_t (*irq_handler_t)(int irq, void *dev);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    request_irq函数的第3个参数有如下取值:
    (上升沿触发、下降沿触发…)

    #define IRQF_TRIGGER_NONE	0x00000000
    #define IRQF_TRIGGER_RISING	0x00000001
    #define IRQF_TRIGGER_FALLING	0x00000002
    #define IRQF_TRIGGER_HIGH	0x00000004
    #define IRQF_TRIGGER_LOW	0x00000008
    
    #define IRQF_SHARED		0x00000080
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    request_irq函数的第4个参数是中断的名字,可以在执行cat /proc/interrupts的结果里查看。

    request_irq函数的第5个参数是给中断处理函数使用的。
    在这里插入图片描述
    2.3 代码

    driver

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    struct gpio_desc{							//定义一个中断结构体
    	int gpio;
    	int irq;
        char *name;
        int key;
    	struct timer_list key_timer;
    } ;
    
    static struct gpio_desc gpios[2] = {   		//中断结构体赋初值
        {131, 0, "gpio_100ask_1", 1,},
        {132, 0, "gpio_100ask_2", 2,},  
    };
    
    /* 主设备号                                                                 */
    static int major = 0;
    static struct class *gpio_class;
    
    /* 环形缓冲区 */
    #define BUF_LEN 128
    static int g_keys[BUF_LEN];
    static int r, w;
    
    struct fasync_struct *button_fasync;
    
    #define NEXT_POS(x) ((x+1) % BUF_LEN)
    
    static int is_key_buf_empty(void)
    {
    	return (r == w);
    }
    
    static int is_key_buf_full(void)
    {
    	return (r == NEXT_POS(w));
    }
    
    static void put_key(int key)
    {
    	if (!is_key_buf_full())
    	{
    		g_keys[w] = key;
    		w = NEXT_POS(w);
    	}
    }
    
    static int get_key(void)
    {
    	int key = 0;
    	if (!is_key_buf_empty())
    	{
    		key = g_keys[r];
    		r = NEXT_POS(r);
    	}
    	return key;
    }
    
    static DECLARE_WAIT_QUEUE_HEAD(gpio_wait);
    
    // static void key_timer_expire(struct timer_list *t)
    static void key_timer_expire(unsigned long data)
    {
    	/* data ==> gpio */
    	// struct gpio_desc *gpio_desc = from_timer(gpio_desc, t, key_timer);
    	struct gpio_desc *gpio_desc = (struct gpio_desc *)data;
    	int val;
    	int key;
    
    	val = gpio_get_value(gpio_desc->gpio);		//读取引脚  0或1
    
    	//printk("key_timer_expire key %d %d\n", gpio_desc->gpio, val);
    	key = (gpio_desc->key) | (val<<8);  //key值用来放在环形数组中,用key第八位看按键是否按下
    	put_key(key);//放入环形数组
    	wake_up_interruptible(&gpio_wait);
    	kill_fasync(&button_fasync, SIGIO, POLL_IN);
    }
    
    /* 实现对应的open/read/write等函数,填入file_operations结构体                   */
    static ssize_t gpio_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
    {
    	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	int err;
    	int key;
    
    	if (is_key_buf_empty() && (file->f_flags & O_NONBLOCK))
    		return -EAGAIN;
    	
    	wait_event_interruptible(gpio_wait,!is_key_buf_empty());
    	key = get_key();
    	err = copy_to_user(buf, &key, 4);
    	
    	return 4;
    }
    
    static ssize_t gpio_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
    {
        unsigned char ker_buf[2];
        int err;
    
        if (size != 2)
            return -EINVAL;
    
        err = copy_from_user(ker_buf, buf, size);
        
        if (ker_buf[0] >= sizeof(gpios)/sizeof(gpios[0]))
            return -EINVAL;
    
        gpio_set_value(gpios[ker_buf[0]].gpio, ker_buf[1]);
        return 2;    
    }
    
    static unsigned int gpio_drv_poll(struct file *fp, poll_table * wait)
    {
    	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	poll_wait(fp, &gpio_wait, wait);
    	return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
    }
    
    static int gpio_drv_fasync(int fd, struct file *file, int on)
    {
    	if (fasync_helper(fd, file, on, &button_fasync) >= 0)
    		return 0;
    	else
    		return -EIO;
    }
    
    /* 定义自己的file_operations结构体                                              */
    static struct file_operations gpio_key_drv = {
    	.owner	 = THIS_MODULE,
    	.read    = gpio_drv_read,
    	.write   = gpio_drv_write,
    	.poll    = gpio_drv_poll,
    	.fasync  = gpio_drv_fasync,
    };
    
    static irqreturn_t gpio_key_isr(int irq, void *dev_id)
    {
    	struct gpio_desc *gpio_desc = dev_id;
    	printk("gpio_key_isr key %d irq happened\n", gpio_desc->gpio);
    	//jiffies是全局变量  
    	mod_timer(&gpio_desc->key_timer, jiffies + HZ/5);		//消抖,每次抖动时长小于(HZ/5)*Tms,都会推迟进入中断服务程序
    	return IRQ_HANDLED;
    }
    
    /* 在入口函数 */
    static int __init gpio_drv_init(void)
    {
        int err;
        int i;
        int count = sizeof(gpios)/sizeof(gpios[0]);
        
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	
    	for (i = 0; i < count; i++)
    	{		
    		gpios[i].irq  = gpio_to_irq(gpios[i].gpio);		//调用函数获得中断号
    		//定时器初始化函数 参数一:定时器时间 参数二:中断服务程序 参数三:传入中断服务程序的参数
    		setup_timer(&gpios[i].key_timer, key_timer_expire, (unsigned long)&gpios[i]);
    	 	//timer_setup(&gpios[i].key_timer, key_timer_expire, 0);
    		gpios[i].key_timer.expires = ~0;
    		add_timer(&gpios[i].key_timer);
    		err = request_irq(gpios[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpios[i]);  //注册中断
    	}
    
    	/* 注册file_operations 	*/
    	major = register_chrdev(0, "100ask_gpio_key", &gpio_key_drv);  /* /dev/gpio_desc */
    
    	gpio_class = class_create(THIS_MODULE, "100ask_gpio_key_class");
    	if (IS_ERR(gpio_class)) {
    		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    		unregister_chrdev(major, "100ask_gpio_key");
    		return PTR_ERR(gpio_class);
    	}
    
    	device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "100ask_gpio"); /* /dev/100ask_gpio */
    	
    	return err;
    }
    
    /* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
     */
    static void __exit gpio_drv_exit(void)
    {
        int i;
        int count = sizeof(gpios)/sizeof(gpios[0]);
        
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    
    	device_destroy(gpio_class, MKDEV(major, 0));
    	class_destroy(gpio_class);
    	unregister_chrdev(major, "100ask_gpio_key");
    
    	for (i = 0; i < count; i++)
    	{
    		free_irq(gpios[i].irq, &gpios[i]);
    		del_timer(&gpios[i].key_timer);
    	}
    }
    
    /* 7. 其他完善:提供设备信息,自动创建设备节点                                     */
    
    module_init(gpio_drv_init);
    module_exit(gpio_drv_exit);
    
    MODULE_LICENSE("GPL");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230

    app

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    static int fd;
    
    /*
     * ./button_test /dev/100ask_button0
     *
     */
    int main(int argc, char **argv)
    {
    	int val;
    	struct pollfd fds[1];
    	int timeout_ms = 5000;
    	int ret;
    	int	flags;
    
    	int i;
    	
    	/* 1. 判断参数 */
    	if (argc != 2) 
    	{
    		printf("Usage: %s \n", argv[0]);
    		return -1;
    	}
    
    	/* 2. 打开文件 */
    	fd = open(argv[1], O_RDWR | O_NONBLOCK);
    	if (fd == -1)
    	{
    		printf("can not open file %s\n", argv[1]);
    		return -1;
    	}
    
    	for (i = 0; i < 10; i++) 
    	{
    		if (read(fd, &val, 4) == 4)
    			printf("get button: 0x%x\n", val);
    		else
    			printf("get button: -1\n");
    	}
    
    	flags = fcntl(fd, F_GETFL);
    	fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
    
    	while(1)
    	{
    		if (read(fd, &val, 4) == 4)
    			printf("get button: 0x%x\n", val);
    		else
    			printf("while get button: -1\n");
    	}
    	close(fd);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    非阻塞及环形读写

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    阻塞访问
    在这里插入图片描述
    在这里插入图片描述
    POLL机制
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    异步通知
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    LED驱动编写(imx6ull)
    driver

    #include "asm-generic/errno-base.h"
    #include "asm-generic/gpio.h"
    #include "asm/uaccess.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    struct gpio_desc{
    	int gpio;
    	int irq;
        char *name;
        int key;
    	struct timer_list key_timer;
    } ;
    
    static struct gpio_desc gpios[2] = {
        {131, 0, "led0", },
        //{132, 0, "led1", },
    };
    
    /* 主设备号                                                                 */
    static int major = 0;
    static struct class *gpio_class;
    
    
    /* 实现对应的open/read/write等函数,填入file_operations结构体                   */
    static ssize_t gpio_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
    {
    	char tmp_buf[2];
    	int err;
        int count = sizeof(gpios)/sizeof(gpios[0]);		//表示有多少可操作引脚
    
    	if (size != 2)
    		return -EINVAL;
    
    	err = copy_from_user(tmp_buf, buf, 1);
    
    	if (tmp_buf[0] >= count)	//大于可操作数量报错
    		return -EINVAL;
    
    	tmp_buf[1] = gpio_get_value(gpios[tmp_buf[0]].gpio);
    
    	err = copy_to_user(buf, tmp_buf, 2);
    	
    	return 2;
    }
    
    static ssize_t gpio_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
    {
        unsigned char ker_buf[2];			//内核数组
        int err;
    
        if (size != 2)					//传入的参数不是2直接退出
            return -EINVAL;
    
        err = copy_from_user(ker_buf, buf, size);	//将用户数据拷贝到内核
        
        if (ker_buf[0] >= sizeof(gpios)/sizeof(gpios[0]))		//大于课操作引脚报错
            return -EINVAL;
    
        gpio_set_value(gpios[ker_buf[0]].gpio, ker_buf[1]);
        return 2;    
    }
    
    
    
    /* 定义自己的file_operations结构体                                              */
    static struct file_operations gpio_key_drv = {
    	.owner	 = THIS_MODULE,
    	.read    = gpio_drv_read,
    	.write   = gpio_drv_write,
    };
    
    
    /* 在入口函数 */
    static int __init gpio_drv_init(void)
    {
        int err;
        int i;
        int count = sizeof(gpios)/sizeof(gpios[0]);
        
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	
    	for (i = 0; i < count; i++)
    	{		
    		/* set pin as output */
    		err = gpio_request(gpios[i].gpio, gpios[i].name);//其实就是让内核检查一下该GPIO引脚是否被其它设备占用,如果没有占用则返回0并用label做一下标记,表示被本设备占用,否则返回负数
    		if (err < 0) {
    			printk("can not request gpio %s %d\n", gpios[i].name, gpios[i].gpio);
    			return -ENODEV;
    		}
    		
    		 (gpios[i].gpio, 1);		//设置gpio输出为1
    	}
    
    	/* 注册file_operations 	*/
    	major = register_chrdev(0, "100ask_led", &gpio_key_drv);  /* /dev/gpio_desc */
    
    	gpio_class = class_create(THIS_MODULE, "100ask_led_class");
    	if (IS_ERR(gpio_class)) {
    		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    		unregister_chrdev(major, "100ask_led_class");
    		return PTR_ERR(gpio_class);
    	}
    
    	device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "100ask_led"); /* /dev/100ask_gpio */
    	
    	return err;
    }
    
    /* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
     */
    static void __exit gpio_drv_exit(void)
    {
        int i;
        int count = sizeof(gpios)/sizeof(gpios[0]);
        
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    
    	device_destroy(gpio_class, MKDEV(major, 0));
    	class_destroy(gpio_class);
    	unregister_chrdev(major, "100ask_led");
    
    	for (i = 0; i < count; i++)
    	{
    		gpio_free(gpios[i].gpio);		
    	}
    }
    
    
    /* 7. 其他完善:提供设备信息,自动创建设备节点                                     */
    
    module_init(gpio_drv_init);
    module_exit(gpio_drv_exit);
    
    MODULE_LICENSE("GPL");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    static int fd;
    
    
    //int led_on(int which);
    //int led_off(int which);
    //int led_status(int which);
    
    /*
     * ./led_test <0|1|2|..>  on 
     * ./led_test <0|1|2|..>  off
     * ./led_test <0|1|2|..>
     */
    int main(int argc, char **argv)
    {
    	int ret;
    	char buf[2];
    
    	int i;
    	
    	/* 1. 判断参数 */
    	if (argc < 2) 
    	{
    		printf("Usage: %s <0|1|2|...> [on | off]\n", argv[0]);
    		return -1;
    	}
    
    
    	/* 2. 打开文件 */
    	fd = open("/dev/100ask_led", O_RDWR);
    	if (fd == -1)
    	{
    		printf("can not open file /dev/100ask_led\n");
    		return -1;
    	}
    
    	if (argc == 3)
    	{
    		/* write */
    		buf[0] = strtol(argv[1], NULL, 0);  //将字符串内容转化成整数
    
    		if (strcmp(argv[2], "on") == 0)  //strcmp字符串比较,如果相等返回0
    			buf[1] = 0;
    		else
    			buf[1] = 1;
    		
    		ret = write(fd, buf, 2);
    	}
    	else
    	{
    		buf[0] = strtol(argv[1], NULL, 0);
    		ret = read(fd, buf, 2);
    		if (ret == 2)
    		{
    			printf("led %d status is %s\n", buf[0], buf[1] == 0 ? "on" : "off");
    		}
    	}
    	
    	close(fd);
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    SR501红外模块驱动编写(imx6ull)
    在这里插入图片描述
    驱动

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    struct gpio_desc{  		//定义一个gpio结构体
    	int gpio;
    	int irq;
        char *name;
        int key;
    	struct timer_list key_timer;
    } ;
    
    static struct gpio_desc gpios[2] = {		//赋初值
        {115, 0, "sr501", },  //io口的编号,0号中断,名称 
    };
    
    /* 主设备号                                                                 */
    static int major = 0;
    static struct class *gpio_class;  	//定义一个设备类结构体
    
    /* 环形缓冲区 */
    #define BUF_LEN 128					//
    static int g_keys[BUF_LEN];			//内核数据接收缓冲区
    static int r, w;
    
    struct fasync_struct *button_fasync;	//异步通信用的信号结构体,他可以提供一个pid用于信号通信
    
    #define NEXT_POS(x) ((x+1) % BUF_LEN)	//环形接收对数组的下标操作
    
    static int is_key_buf_empty(void)		//接收数组为空
    {
    	return (r == w);
    }
    
    static int is_key_buf_full(void)	//如果接收数组已满将
    {
    	return (r == NEXT_POS(w));	//读下标等于写下标(x)+1就代表满了
    }
    
    static void put_key(int key)	//按键按下
    {
    	if (!is_key_buf_full())		//没满
    	{
    		g_keys[w] = key;	//存按键值
    		w = NEXT_POS(w);	//写下标加一
    	}
    }
    
    static int get_key(void)	//获得按键值
    {
    	int key = 0;
    	if (!is_key_buf_empty())	//不为空
    	{
    		key = g_keys[r];		//读取按键键值
    		r = NEXT_POS(r);		//读下标加一
    	}
    	return key;		//返回按键键值
    }
    
    
    static DECLARE_WAIT_QUEUE_HEAD(gpio_wait);  //初始化gpio休眠队列
    
    
    /* 实现对应的open/read/write等函数,填入file_operations结构体                   */
    static ssize_t gpio_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)     //按键读取驱动程序,因为是电子按键所以不用消抖
    {
    	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	int err;
    	int key;
    
    	if (is_key_buf_empty() && (file->f_flags & O_NONBLOCK))  //如果非阻塞还为空直接返回
    		return -EAGAIN;
    	
    	wait_event_interruptible(gpio_wait, !is_key_buf_empty());	//等待如果不为空进行下一步
    	key = get_key();	//获取键值
    	err = copy_to_user(buf, &key, 4);	//将键值发送给用户
    	
    	return 4;
    }
    
    
    static unsigned int gpio_drv_poll(struct file *fp, poll_table * wait)  //poll机制,这次没用着
    {
    	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	poll_wait(fp, &gpio_wait, wait);		//加入等待队列
    	return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
    }
    
    static int gpio_drv_fasync(int fd, struct file *file, int on)  //构造button_fasync结构体,方便后面程序寻找pid
    {
    	if (fasync_helper(fd, file, on, &button_fasync) >= 0)
    		return 0;
    	else
    		return -EIO;
    }
    
    /* 定义自己的file_operations结构体                                              */
    static struct file_operations gpio_key_drv = {
    	.owner	 = THIS_MODULE,
    	.read    = gpio_drv_read,
    	.poll    = gpio_drv_poll,
    	.fasync  = gpio_drv_fasync,
    };
    
    static irqreturn_t gpio_key_isr(int irq, void *dev_id)  //按键中断
    {
    	struct gpio_desc *gpio_desc = dev_id;
    	int val;
    	int key;
    
    	printk("gpio_key_isr key %d irq happened\n", gpio_desc->gpio);
    
    	val = gpio_get_value(gpio_desc->gpio);
    
    	//printk("key_timer_expire key %d %d\n", gpio_desc->gpio, val);
    	key = (gpio_desc->key) | (val<<8);
    	put_key(key);
    	wake_up_interruptible(&gpio_wait);
    	kill_fasync(&button_fasync, SIGIO, POLL_IN);
    
    	return IRQ_HANDLED;
    }
    
    
    /* 在入口函数 */
    static int __init gpio_drv_init(void)
    {
        int err;
        int i;
        int count = sizeof(gpios)/sizeof(gpios[0]);
        
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	
    	for (i = 0; i < count; i++)
    	{		
    		gpios[i].irq  = gpio_to_irq(gpios[i].gpio);
    		err = request_irq(gpios[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, gpios[i].name, &gpios[i]);  //使能按键中断,中断号为gpios[i].irq,中断服务函数gpio_key_isr,触发方式为上升沿下降沿触发IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
    	}
    
    	/* 注册file_operations 	*/
    	major = register_chrdev(0, "100ask_gpio_key", &gpio_key_drv);  /* /dev/gpio_desc */
    
    	gpio_class = class_create(THIS_MODULE, "100ask_gpio_key_class");
    	if (IS_ERR(gpio_class)) {
    		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    		unregister_chrdev(major, "100ask_gpio_key");
    		return PTR_ERR(gpio_class);
    	}
    
    	device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "sr501"); /* /dev/sr501 */
    	
    	return err;
    }
    
    /* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
     */
    static void __exit gpio_drv_exit(void)
    {
        int i;
        int count = sizeof(gpios)/sizeof(gpios[0]);
        
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    
    	device_destroy(gpio_class, MKDEV(major, 0));
    	class_destroy(gpio_class);
    	unregister_chrdev(major, "100ask_gpio_key");
    
    	for (i = 0; i < count; i++)
    	{
    		free_irq(gpios[i].irq, &gpios[i]);
    	}
    }
    /* 7. 其他完善:提供设备信息,自动创建设备节点                                     */
    
    module_init(gpio_drv_init);
    module_exit(gpio_drv_exit);
    
    MODULE_LICENSE("GPL");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200

    app

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    static int fd;
    
    /*
     * ./button_test /dev/sr501
     *
     */
    int main(int argc, char **argv)
    {
    	int val;
    	struct pollfd fds[1];
    	int timeout_ms = 5000;
    	int ret;
    	int	flags;
    	int i;
    	
    	/* 1. 判断参数 */
    	if (argc != 2) 
    	{
    		printf("Usage: %s \n", argv[0]);
    		return -1;
    	}
    
    	/* 2. 打开文件 */
    	fd = open(argv[1], O_RDWR);
    	if (fd == -1)
    	{
    		printf("can not open file %s\n", argv[1]);
    		return -1;
    	}
    
    	while (1) 
    	{
    		if (read(fd, &val, 4) == 4)
    			printf("get button: 0x%x\n", val);
    		else
    			printf("get button: -1\n");
    	}
    	close(fd);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    SR04超声波测距模块驱动
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    驱动

    #include "asm-generic/gpio.h"
    #include "asm/delay.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define CMD_TRIG  100   //ioctrl任务选择常量
    
    struct gpio_desc{
    	int gpio;
    	int irq;
        char *name;
        int key;
    	struct timer_list key_timer;
    } ;
    
    static struct gpio_desc gpios[2] = {	//定义两个io口
        {115, 0, "trig", },
        {116, 0, "echo", },
    };
    
    /* 主设备号                                                                 */
    static int major = 0;
    static struct class *gpio_class;
    
    /* 环形缓冲区 */
    #define BUF_LEN 128
    static int g_keys[BUF_LEN];
    static int r, w;
    
    struct fasync_struct *button_fasync;
    
    #define NEXT_POS(x) ((x+1) % BUF_LEN)
    
    static int is_key_buf_empty(void)
    {
    	return (r == w);
    }
    
    static int is_key_buf_full(void)
    {
    	return (r == NEXT_POS(w));
    }
    
    static void put_key(int key)
    {
    	if (!is_key_buf_full())
    	{
    		g_keys[w] = key;
    		w = NEXT_POS(w);
    	}
    }
    
    static int get_key(void)
    {
    	int key = 0;
    	if (!is_key_buf_empty())
    	{
    		key = g_keys[r];
    		r = NEXT_POS(r);
    	}
    	return key;
    }
    
    static DECLARE_WAIT_QUEUE_HEAD(gpio_wait);
    
    /* 实现对应的open/read/write等函数,填入file_operations结构体                   */
    static ssize_t sr04_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
    {
    	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	int err;
    	int key;
    
    	if (is_key_buf_empty() && (file->f_flags & O_NONBLOCK))
    		return -EAGAIN;
    
    	// printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);  加上这条语句就读不出来数据了,可能是函数内部关了中断
    
    	wait_event_interruptible(gpio_wait, !is_key_buf_empty());
    	key = get_key();
    	err = copy_to_user(buf, &key, 4);
    	
    	return 4;
    }
    
    
    static unsigned int sr04_poll(struct file *fp, poll_table * wait)
    {
    	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	poll_wait(fp, &gpio_wait, wait);
    	return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
    }
    
    static int sr04_fasync(int fd, struct file *file, int on)
    {
    	if (fasync_helper(fd, file, on, &button_fasync) >= 0)
    		return 0;
    	else
    		return -EIO;
    }
    
    
    // ioctl(fd, CMD, ARG)
    static long sr04_ioctl(struct file *filp, unsigned int command, unsigned long arg)
    {
    	// send trig 
    	switch (command)
    	{
    		case CMD_TRIG:
    		{
    			//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    			gpio_set_value(gpios[0].gpio, 1);	//根据超声波传感器手册启动前要发送一个20us高电平
    			udelay(20);
    			gpio_set_value(gpios[0].gpio, 0);
    		}
    	}
    
    	return 0;
    }
    
    /* 定义自己的file_operations结构体                                              */
    static struct file_operations sr04_drv = {
    	.owner	 = THIS_MODULE,
    	.read    = sr04_read,
    	.poll    = sr04_poll,
    	.fasync  = sr04_fasync,
    	.unlocked_ioctl = sr04_ioctl,
    };
    
    
    static irqreturn_t sr04_isr(int irq, void *dev_id)
    {
    	struct gpio_desc *gpio_desc = dev_id;
    	int val;
    	static u64 rising_time = 0;
    	u64 time;
    
    	val = gpio_get_value(gpio_desc->gpio);
    	//printk("sr04_isr echo pin %d is %d\n", gpio_desc->gpio, val);如果加上打印会超时
    
    	if (val)
    	{
    		/* 上升沿记录起始时间 */
    		rising_time = ktime_get_ns();
    	}
    	else
    	{
    		if (rising_time == 0)
    		{
    			//printk("missing rising interrupt\n");
    			return IRQ_HANDLED;
    		}
    
    		/* 下降沿记录结束时间, 并计算时间差, 计算距离 */
    		time = ktime_get_ns() - rising_time;
    		rising_time = 0;
    
    		put_key(time);
    
    		wake_up_interruptible(&gpio_wait);
    		kill_fasync(&button_fasync, SIGIO, POLL_IN);	
    	}
    
    	return IRQ_HANDLED;
    }
    
    
    /* 在入口函数 */
    static int __init sr04_init(void)
    {
        int err;
        
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	
    	// trig pin
    	err = gpio_request(gpios[0].gpio, gpios[0].name);
    	gpio_direction_output(gpios[0].gpio, 0);
    
    	// echo pin
    	{		
    		gpios[1].irq  = gpio_to_irq(gpios[1].gpio);  //获取中断号
    
    		err = request_irq(gpios[1].irq, sr04_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, gpios[1].name, &gpios[1]);  //初始化按键中断
    	}
    
    	/* 注册file_operations 	*/
    	major = register_chrdev(0, "100ask_sr04", &sr04_drv);  /* /dev/gpio_desc */
    
    	gpio_class = class_create(THIS_MODULE, "100ask_sr04_class");
    	if (IS_ERR(gpio_class)) {
    		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    		unregister_chrdev(major, "100ask_sr04");
    		return PTR_ERR(gpio_class);
    	}
    
    	device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "sr04"); /* /dev/sr04 */
    	
    	return err;
    }
    
    /* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
     */
    static void __exit sr04_exit(void)
    {
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    
    	device_destroy(gpio_class, MKDEV(major, 0));
    	class_destroy(gpio_class);
    	unregister_chrdev(major, "100ask_sr04");
    
    	// trig pin
    	gpio_free(gpios[0].gpio);
    
    	// echo pin
    	{
    		free_irq(gpios[1].irq, &gpios[1]);
    	}
    }
    
    
    /* 7. 其他完善:提供设备信息,自动创建设备节点                                     */
    
    module_init(sr04_init);
    module_exit(sr04_exit);
    
    MODULE_LICENSE("GPL");
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define CMD_TRIG  100
    
    static int fd;
    
    /*
     * ./button_test /dev/sr04
     *
     */
    int main(int argc, char **argv)
    {
    	int val;
    	struct pollfd fds[1];
    	int timeout_ms = 5000;
    	int ret;
    	int	flags;
    
    	int i;
    	
    	/* 1. 判断参数 */
    	if (argc != 2) 
    	{
    		printf("Usage: %s \n", argv[0]);
    		return -1;
    	}
    
    
    	/* 2. 打开文件 */
    	fd = open(argv[1], O_RDWR);
    	if (fd == -1)
    	{
    		printf("can not open file %s\n", argv[1]);
    		return -1;
    	}
    
    	while (1)
    	{
    		ioctl(fd, CMD_TRIG);
    		printf("I am goning to read distance: \n");
    		if (read(fd, &val, 4) == 4)
    			printf("get distance: %d cm\n", val*17/1000000);
    		else
    			printf("get distance err\n");
    
    		sleep(1);	//根据硬件时序图不能太快发送高电平
    	}
    
    	close(fd);
    	
    	return 0;
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    超声波测距程序改进(在app加入poll机制,或在驱动iocontrl里面加一个定时器)

    #include "asm-generic/errno.h"
    #include "asm-generic/gpio.h"
    #include "asm/delay.h"
    #include "linux/jiffies.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define CMD_TRIG  100
    
    struct gpio_desc{
    	int gpio;
    	int irq;
        char *name;
        int key;
    	struct timer_list key_timer;
    } ;
    
    static struct gpio_desc gpios[2] = {
        {115, 0, "trig", },
        {116, 0, "echo", },
    };
    
    /* 主设备号                                                                 */
    static int major = 0;
    static struct class *gpio_class;
    
    /* 环形缓冲区 */
    #define BUF_LEN 128
    static int g_keys[BUF_LEN];
    static int r, w;
    
    struct fasync_struct *button_fasync;
    
    #define NEXT_POS(x) ((x+1) % BUF_LEN)
    
    static int is_key_buf_empty(void)
    {
    	return (r == w);
    }
    
    static int is_key_buf_full(void)
    {
    	return (r == NEXT_POS(w));
    }
    
    static void put_key(int key)
    {
    	if (!is_key_buf_full())
    	{
    		g_keys[w] = key;
    		w = NEXT_POS(w);
    	}
    }
    
    static int get_key(void)
    {
    	int key = 0;
    	if (!is_key_buf_empty())
    	{
    		key = g_keys[r];
    		r = NEXT_POS(r);
    	}
    	return key;
    }
    
    
    static DECLARE_WAIT_QUEUE_HEAD(gpio_wait);
    
    /* 实现对应的open/read/write等函数,填入file_operations结构体                   */
    static ssize_t sr04_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
    {
    	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	int err;
    	int key;
    
    	if (is_key_buf_empty() && (file->f_flags & O_NONBLOCK))
    		return -EAGAIN;
    
    	// printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    
    	wait_event_interruptible(gpio_wait, !is_key_buf_empty());
    	key = get_key();
    
    	if (key == -1)
    		return -ENODATA;
    
    	err = copy_to_user(buf, &key, 4);
    	
    	return 4;
    }
    
    static unsigned int sr04_poll(struct file *fp, poll_table * wait)
    {
    	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	poll_wait(fp, &gpio_wait, wait);
    	return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
    }
    
    static int sr04_fasync(int fd, struct file *file, int on)
    {
    	if (fasync_helper(fd, file, on, &button_fasync) >= 0)
    		return 0;
    	else
    		return -EIO;
    }
    
    // ioctl(fd, CMD, ARG)
    static long sr04_ioctl(struct file *filp, unsigned int command, unsigned long arg)
    {
    	// send trig 
    	switch (command)
    	{
    		case CMD_TRIG:
    		{
    			//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    			gpio_set_value(gpios[0].gpio, 1);
    			udelay(20);
    			gpio_set_value(gpios[0].gpio, 0);
    			// start timer
    			mod_timer(&gpios[1].key_timer, jiffies + msecs_to_jiffies(50));  //50ms后进入定时器服务程序
    		}
    	}
    	return 0;
    }
    
    /* 定义自己的file_operations结构体                                              */
    static struct file_operations sr04_drv = {
    	.owner	 = THIS_MODULE,
    	.read    = sr04_read,
    	.poll    = sr04_poll,
    	.fasync  = sr04_fasync,
    	.unlocked_ioctl = sr04_ioctl,
    };
    
    
    static irqreturn_t sr04_isr(int irq, void *dev_id)
    {
    	struct gpio_desc *gpio_desc = dev_id;
    	int val;
    	static u64 rising_time = 0;
    	u64 time;
    
    	val = gpio_get_value(gpio_desc->gpio);
    	//printk("sr04_isr echo pin %d is %d\n", gpio_desc->gpio, val);
    
    	if (val)
    	{
    		/* 上升沿记录起始时间 */
    		rising_time = ktime_get_ns();
    	}
    	else
    	{
    		if (rising_time == 0)
    		{
    			//printk("missing rising interrupt\n");
    			return IRQ_HANDLED;
    		}
    
    		/* 下降沿记录结束时间, 并计算时间差, 计算距离 */
    
    		// stop timer
    		del_timer(&gpios[1].key_timer);
    
    		time = ktime_get_ns() - rising_time;
    		rising_time = 0;
    
    		put_key(time);
    
    		wake_up_interruptible(&gpio_wait);
    		kill_fasync(&button_fasync, SIGIO, POLL_IN);
    	}
    
    	return IRQ_HANDLED;
    }
    
    static void sr04_timer_func(unsigned long data)  //如果超时还没有接收到数据进入此函数
    {
    	put_key(-1);					//在数组里写入-1
    	wake_up_interruptible(&gpio_wait);	//唤醒睡眠,将-1发出去
    	kill_fasync(&button_fasync, SIGIO, POLL_IN);
    }
    
    /* 在入口函数 */
    static int __init sr04_init(void)
    {
        int err;
        
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	
    	// trig pin
    	err = gpio_request(gpios[0].gpio, gpios[0].name);
    	gpio_direction_output(gpios[0].gpio, 0);
    
    	// echo pin
    	{		
    		gpios[1].irq  = gpio_to_irq(gpios[1].gpio);
    
    		err = request_irq(gpios[1].irq, sr04_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, gpios[1].name, &gpios[1]);
    
    		setup_timer(&gpios[1].key_timer, sr04_timer_func, (unsigned long)&gpios[1]);
    	}
    
    	/* 注册file_operations 	*/
    	major = register_chrdev(0, "100ask_sr04", &sr04_drv);  /* /dev/gpio_desc */
    
    	gpio_class = class_create(THIS_MODULE, "100ask_sr04_class");
    	if (IS_ERR(gpio_class)) {
    		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    		unregister_chrdev(major, "100ask_sr04");
    		return PTR_ERR(gpio_class);
    	}
    
    	device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "sr04"); /* /dev/sr04 */
    	
    	return err;
    }
    
    /* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
     */
    static void __exit sr04_exit(void)
    {
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    
    	device_destroy(gpio_class, MKDEV(major, 0));
    	class_destroy(gpio_class);
    	unregister_chrdev(major, "100ask_sr04");
    
    	// trig pin
    	gpio_free(gpios[0].gpio);
    
    	// echo pin
    	{
    		free_irq(gpios[1].irq, &gpios[1]);
    		del_timer(&gpios[1].key_timer);
    	}
    }
    
    
    /* 7. 其他完善:提供设备信息,自动创建设备节点                                     */
    
    module_init(sr04_init);
    module_exit(sr04_exit);
    
    MODULE_LICENSE("GPL");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define CMD_TRIG  100
    
    static int fd;
    
    /*
     * ./button_test /dev/sr04
     *
     */
    int main(int argc, char **argv)
    {
    	int val;
    	struct pollfd fds[1];
    	int timeout_ms = 5000;
    	int ret;
    	int	flags;
    	int i;
    	
    	/* 1. 判断参数 */
    	if (argc != 2) 
    	{
    		printf("Usage: %s \n", argv[0]);
    		return -1;
    	}
    
    	/* 2. 打开文件 */
    	fd = open(argv[1], O_RDWR);
    	if (fd == -1)
    	{
    		printf("can not open file %s\n", argv[1]);
    		return -1;
    	}
    
    	while (1)
    	{
    		ioctl(fd, CMD_TRIG);
    		printf("I am goning to read distance: \n");
    		
    		fds[0].fd = fd;
    		fds[0].events = POLLIN;
    
    		if (1 == poll(fds, 1, 5000))  //poll函数有数据返回的是个正数,数值为设备个数,超过5s会跳出阻塞返回值为0
    		{
    			if (read(fd, &val, 4) == 4)
    				printf("get distance: %d cm\n", val*17/1000000);
    			else
    				printf("get distance err\n");
    		}
    		else
    		{
    			printf("get distance poll timeout/err\n");
    		}
    		sleep(1);
    	}
    	close(fd);
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    内核不同调用的函数不一样(内核哪里在入门视频第五章有讲)
    在这里插入图片描述
    步进电机控制原理与接线
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    编程思路
    在这里插入图片描述
    编程

    #include "asm-generic/gpio.h"
    #include "asm/gpio.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    struct gpio_desc{
    	int gpio;
    	int irq;
        char *name;
        int key;
    	struct timer_list key_timer;
    } ;
    
    static struct gpio_desc gpios[] = {
        {115, 0, "motor_gpio0", },
        {116, 0, "motor_gpio1", },
        {117, 0, "motor_gpio2", },
        {118, 0, "motor_gpio3", },
    };
    
    /* 主设备号                                                                 */
    static int major = 0;
    static struct class *gpio_class;
    
    /* 马达引脚设置数字 */
    static int g_motor_pin_ctrl[8]= {0x2,0x3,0x1,0x9,0x8,0xc,0x4,0x6};
    static int g_motor_index = 0;
    
    void set_pins_for_motor(int index)
    {
    	int i;
    	for (i = 0; i < 4; i++)
    	{
    		gpio_set_value(gpios[i].gpio, g_motor_pin_ctrl[index] & (1<<i) ? 1 : 0);
    	}
    }
    
    void disable_motor(void)
    {
    	int i;
    	for (i = 0; i < 4; i++)
    	{
    		gpio_set_value(gpios[i].gpio, 0);
    	}
    }
    
    /* int buf[2];
     * buf[0] = 步进的次数, > 0 : 逆时针步进; < 0 : 顺时针步进
     * buf[1] = mdelay的时间
     */
    static ssize_t motor_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
    {
        int ker_buf[2];
        int err;
    	int step;
    	
        if (size != 8)
            return -EINVAL;
    
        err = copy_from_user(ker_buf, buf, size);
         
    	if (ker_buf[0] > 0)
    	{
    		/* 逆时针旋转 */
    		for (step = 0; step < ker_buf[0]; step++)
    		{
    			set_pins_for_motor(g_motor_index);
    			mdelay(ker_buf[1]);
    			g_motor_index--;
    			if (g_motor_index == -1)
    				g_motor_index = 7;
    		}
    	}
    	else
    	{
    		/* 顺时针旋转 */
    		ker_buf[0] = 0 - ker_buf[0];
    		for (step = 0; step < ker_buf[0]; step++)
    		{
    			set_pins_for_motor(g_motor_index);
    			mdelay(ker_buf[1]);
    			g_motor_index++;
    			if (g_motor_index == 8)
    				g_motor_index = 0;
    		} 
    	}
    
    	/* 改进:旋转到位后让马达不再消耗电源 */
    	disable_motor();
    
        return 8;    
    }
    
    /* 定义自己的file_operations结构体                                              */
    static struct file_operations gpio_key_drv = {
    	.owner	 = THIS_MODULE,
    	.write   = motor_write,
    };
    
    /* 在入口函数 */
    static int __init motor_init(void)
    {
        int err;
        int i;
        int count = sizeof(gpios)/sizeof(gpios[0]);
        
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	
    	for (i = 0; i < count; i++)
    	{
    		err = gpio_request(gpios[i].gpio, gpios[i].name);
    		gpio_direction_output(gpios[i].gpio, 0);
    	}
    
    	/* 注册file_operations 	*/
    	major = register_chrdev(0, "100ask_gpio_key", &gpio_key_drv);  /* /dev/gpio_desc */
    
    	gpio_class = class_create(THIS_MODULE, "100ask_gpio_key_class");
    	if (IS_ERR(gpio_class)) {
    		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    		unregister_chrdev(major, "100ask_gpio_key");
    		return PTR_ERR(gpio_class);
    	}
    
    	device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "motor"); /* /dev/motor */
    	
    	return err;
    }
    
    /* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
     */
    static void __exit motor_exit(void)
    {
        int i;
        int count = sizeof(gpios)/sizeof(gpios[0]);
        
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    
    	device_destroy(gpio_class, MKDEV(major, 0));
    	class_destroy(gpio_class);
    	unregister_chrdev(major, "100ask_gpio_key");
    
    	for (i = 0; i < count; i++)
    	{
    		gpio_free(gpios[i].gpio);
    	}
    }
    /* 7. 其他完善:提供设备信息,自动创建设备节点                                     */
    module_init(motor_init);
    module_exit(motor_exit);
    
    MODULE_LICENSE("GPL");
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    static int fd;
    
    /*
     * ./button_test /dev/motor -100  1
     *
     */
    int main(int argc, char **argv)
    {
    	int buf[2];
    	int ret;
    	
    	/* 1. 判断参数 */
    	if (argc != 4) 
    	{
    		printf("Usage: %s   \n", argv[0]);
    		return -1;
    	}
    
    
    	/* 2. 打开文件 */
    	fd = open(argv[1], O_RDWR | O_NONBLOCK);
    	if (fd == -1)
    	{
    		printf("can not open file %s\n", argv[1]);
    		return -1;
    	}
    
    	buf[0] = strtol(argv[2], NULL, 0);
    	buf[1] = strtol(argv[3], NULL, 0);
    
    	ret = write(fd, buf, 8);
    	close(fd);
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    DHT11驱动程序编写
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    驱动

    #include "asm-generic/errno-base.h"
    #include "asm-generic/gpio.h"
    #include "linux/jiffies.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    struct gpio_desc{
    	int gpio;
    	int irq;
        char *name;
        int key;
    	struct timer_list key_timer;
    } ;
    
    static struct gpio_desc gpios[] = {
        {115, 0, "dht11", },
    };
    
    /* 主设备号  */
    static int major = 0;
    static struct class *gpio_class;
    
    static u64 g_dht11_irq_time[84];
    static int g_dht11_irq_cnt = 0;
    
    /* 环形缓冲区 */
    #define BUF_LEN 128
    static char g_keys[BUF_LEN];
    static int r, w;
    
    struct fasync_struct *button_fasync;
    
    static irqreturn_t dht11_isr(int irq, void *dev_id);
    static void parse_dht11_datas(void);
    
    #define NEXT_POS(x) ((x+1) % BUF_LEN)
    
    static int is_key_buf_empty(void)
    {
    	return (r == w);
    }
    
    static int is_key_buf_full(void)
    {
    	return (r == NEXT_POS(w));
    }
    
    static void put_key(char key)
    {
    	if (!is_key_buf_full())
    	{
    		g_keys[w] = key;
    		w = NEXT_POS(w);
    	}
    }
    
    static char get_key(void)
    {
    	char key = 0;
    	if (!is_key_buf_empty())
    	{
    		key = g_keys[r];
    		r = NEXT_POS(r);
    	}
    	return key;
    }
    
    
    static DECLARE_WAIT_QUEUE_HEAD(gpio_wait);
    
    // static void key_timer_expire(struct timer_list *t)
    static void key_timer_expire(unsigned long data)
    {
    	// 解析数据, 放入环形buffer, 唤醒APP
    	parse_dht11_datas();
    }
    
    
    /* 实现对应的open/read/write等函数,填入file_operations结构体                   */
    static ssize_t dht11_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
    {
    	int err;
    	char kern_buf[2];
    
    	if (size != 2)
    		return -EINVAL;
    
    	g_dht11_irq_cnt = 0; 
    
    	/* 1. 发送18ms的低脉冲 */
    	err = gpio_request(gpios[0].gpio, gpios[0].name);
    	gpio_direction_output(gpios[0].gpio, 0);
    	gpio_free(gpios[0].gpio);
    
    	mdelay(18);
    	gpio_direction_input(gpios[0].gpio);  /* 引脚变为输入方向, 由上拉电阻拉为1 */
    
    	/* 2. 注册中断 */ 
    	err = request_irq(gpios[0].irq, dht11_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, gpios[0].name, &gpios[0]);
    	mod_timer(&gpios[0].key_timer, jiffies + 10);  //超时后进入定时器中断服务程序,如果没超时(也就是接收到了84个脉冲)会在外部中断里把这个定时器删除
    
    	/* 3. 休眠等待数据 */
    	wait_event_interruptible(gpio_wait, !is_key_buf_empty());
    
    	free_irq(gpios[0].irq, &gpios[0]);
    
    	//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    
    	/* 设置DHT11 GPIO引脚的初始状态: output 1 */
    	err = gpio_request(gpios[0].gpio, gpios[0].name);
    	if (err)
    	{
    		printk("%s %s %d, gpio_request err\n", __FILE__, __FUNCTION__, __LINE__);
    	}
    	gpio_direction_output(gpios[0].gpio, 1);
    	gpio_free(gpios[0].gpio);  
    
    	/* 4. copy_to_user */
    	kern_buf[0] = get_key();	//只得到湿度跟温度的整数部分一共两个字节
    	kern_buf[1] = get_key();
    
    	printk("get val : 0x%x, 0x%x\n", kern_buf[0], kern_buf[1]);
    	if ((kern_buf[0] == (char)-1) && (kern_buf[1] == (char)-1))  //必须强转为char因为arm-gcc编译器把char转成unsigned char
    	{
    		printk("get err val\n");  //在终端输入dmesg可以查看
    		return -EIO;
    	}
    
    	err = copy_to_user(buf, kern_buf, 2);
    	
    	return 2;
    }
    
    static int dht11_release (struct inode *inode, struct file *filp)
    {
    	return 0;
    }
    
    /* 定义自己的file_operations结构体                                              */
    static struct file_operations dht11_drv = {
    	.owner	 = THIS_MODULE,
    	.read    = dht11_read,
    	.release = dht11_release,
    };
    
    static void parse_dht11_datas(void)
    {
    	int i;
    	u64 high_time;
    	unsigned char data = 0;
    	int bits = 0;
    	unsigned char datas[5];
    	int byte = 0;
    	unsigned char crc;
    
    	/* 数据个数: 可能是81、82、83、84 */
    	if (g_dht11_irq_cnt < 81)
    	{
    		/* 出错 */
    		put_key(-1);
    		put_key(-1);
    
    		// 唤醒APP
    		wake_up_interruptible(&gpio_wait);
    		g_dht11_irq_cnt = 0;
    		return;
    	}
    
    	// 解析数据
    	for (i = g_dht11_irq_cnt - 80; i < g_dht11_irq_cnt; i+=2)
    	{
    		high_time = g_dht11_irq_time[i] - g_dht11_irq_time[i-1];
    
    		data <<= 1;
    
    		if (high_time > 50000) /* data 1 */
    		{
    			data |= 1;
    		}
    
    		bits++;
    
    		if (bits == 8)
    		{
    			datas[byte] = data;
    			data = 0;
    			bits = 0;
    			byte++;
    		}
    	}
    
    	// 放入环形buffer
    	crc = datas[0] + datas[1] + datas[2] + datas[3];
    	if (crc == datas[4])
    	{
    		put_key(datas[0]);
    		put_key(datas[2]);
    	}
    	else
    	{
    		put_key(-1);
    		put_key(-1);
    	}
    
    	g_dht11_irq_cnt = 0;
    	// 唤醒APP
    	wake_up_interruptible(&gpio_wait);
    }
    
    static irqreturn_t dht11_isr(int irq, void *dev_id)
    {
    	struct gpio_desc *gpio_desc = dev_id;
    	u64 time;
    	
    	/* 1. 记录中断发生的时间 */
    	time = ktime_get_ns();
    	g_dht11_irq_time[g_dht11_irq_cnt] = time;
    
    	/* 2. 累计次数 */
    	g_dht11_irq_cnt++;  
    
    	/* 3. 次数足够: 解析数据, 放入环形buffer, 唤醒APP */
    	if (g_dht11_irq_cnt == 84)
    	{
    		del_timer(&gpio_desc->key_timer);  //干掉超时限制的定时器
    		parse_dht11_datas();
    	}
    
    	return IRQ_HANDLED;
    }
    
    /* 在入口函数 */
    static int __init dht11_init(void)
    {
        int err;
        int i;
        int count = sizeof(gpios)/sizeof(gpios[0]);
        
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    	
    	for (i = 0; i < count; i++)
    	{		
    		gpios[i].irq  = gpio_to_irq(gpios[i].gpio);
    
    		/* 设置DHT11 GPIO引脚的初始状态: output 1 */
    		err = gpio_request(gpios[i].gpio, gpios[i].name);
    		gpio_direction_output(gpios[i].gpio, 1);
    		gpio_free(gpios[i].gpio);
    
    		setup_timer(&gpios[i].key_timer, key_timer_expire, (unsigned long)&gpios[i]);
    	 	//timer_setup(&gpios[i].key_timer, key_timer_expire, 0);
    		//gpios[i].key_timer.expires = ~0;
    		//add_timer(&gpios[i].key_timer);
    		//err = request_irq(gpios[i].irq, dht11_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpios[i]);
    	}
    
    	/* 注册file_operations 	*/
    	major = register_chrdev(0, "100ask_dht11", &dht11_drv);  /* /dev/gpio_desc */
    
    	gpio_class = class_create(THIS_MODULE, "100ask_dht11_class");
    	if (IS_ERR(gpio_class)) {
    		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    		unregister_chrdev(major, "100ask_dht11");
    		return PTR_ERR(gpio_class);
    	}
    
    	device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "mydht11"); /* /dev/mydht11 */
    	return err;
    }
    
    /* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
     */
    static void __exit dht11_exit(void)
    {
        int i;
        int count = sizeof(gpios)/sizeof(gpios[0]);
        
    	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    
    	device_destroy(gpio_class, MKDEV(major, 0));
    	class_destroy(gpio_class);
    	unregister_chrdev(major, "100ask_dht11");
    
    	for (i = 0; i < count; i++)
    	{
    		//free_irq(gpios[i].irq, &gpios[i]);
    		//del_timer(&gpios[i].key_timer);
    	}
    }
    
    /* 7. 其他完善:提供设备信息,自动创建设备节点                                     */
    
    module_init(dht11_init);
    module_exit(dht11_exit);
    
    MODULE_LICENSE("GPL");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320

    应用

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    static int fd;
    
    /*
     * ./button_test /dev/mydht11
     *
     */
    int main(int argc, char **argv)
    {
    	char buf[2];
    	int ret;
    
    	int i;
    	 
    	/* 1. 判断参数 */
    	if (argc != 2) 
    	{
    		printf("Usage: %s \n", argv[0]);
    		return -1;
    	}
    
    	/* 2. 打开文件 */
    	fd = open(argv[1], O_RDWR | O_NONBLOCK);
    	if (fd == -1)
    	{
    		printf("can not open file %s\n", argv[1]);
    		return -1;
    	}
    
    	while (1)
    	{
    		if (read(fd, buf, 2) == 2)
    			printf("get Humidity: %d, Temperature : %d\n", buf[0], buf[1]);
    		else
    			printf("get dht11: -1\n");
    
    		sleep(5);
    	}
    	close(fd); 
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
  • 相关阅读:
    20221205今天的世界发生了什么
    HTML5期末大作业:旅游网页设计与实现——旅游风景区网站HTML+CSS+JavaScript 景点静态网页设计 学生DW静态网页设计
    前端面试系列之webpack优化
    EF Core学习笔记:额外的外键属性 / 单项导航属性
    电脑硬盘数据恢复一般需要收费多少钱
    2022年深圳杯A题破除“尖叫效应”与“回声室效应”走出“信息茧房”
    编程创作纪念日:探索创造力与技术的融合
    聊聊基于Alink库的随机森林模型
    [附源码]计算机毕业设计JAVA基于web的电子产品网络购物平台
    Dataset之GermanCreditData:GermanCreditData数据集的简介、下载、使用方法之详细攻略
  • 原文地址:https://blog.csdn.net/afddasfa/article/details/128031288