• 【全志T113-S3_100ask】11-2编写驱动采集dht11数据(cdev、中断、锁)


    背景

    在文章 https://blog.csdn.net/qq_46079439/article/details/126131667 中已经实现了一种方法采集dht11的数据,但是经反馈说采集不够稳定,经常读不到数据、DHT11无响应的现象,再次展开研究,参考 https://www.pudn.com/news/623fa4a92cfc38172120c913.html 并进行了改进。

    (一)修改设备树

    本文的设备树与上一节不完全一致,使用的依然是PD14,但是更加易读。
    1、在根节点下添加:

    /*添加DHT11的设备树文件*/
    	dht11 {
    	compatible = "dht-11";
    	pinctrl-names = "default";
    	pinctrl-1 = <&dht11_pin>;
    	dht11-gpios = <&pio PD 14 GPIO_ACTIVE_HIGH>; 
    	status = "okay"; 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述
    2、在pio下添加:

    &pio {
    	/*增加dht_11的pinctrl控制*/
    	dht11_pin: dht11_pin{
    				allwinner,pins = "PD14"; /*dht11的时钟和数据线接PD14上面*/
    			};
    
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    (二)编写驱动程序

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include 
    
    typedef unsigned char uint8_t;
    
    #define DEV_DTS_NODE_PATH "/dht11"     /* 设备树节点的路径,在根节点下 */
    #define DEV_PIN_DTS_NAME "dht11-gpios" /* GPIO引脚的属性名 */
    #define DEV_NAME "dht11"               /* 设备名  /dev/dht11 */
    #define DEV_DTS_COMPATIBLE "dht-11"    /* 设备匹配属性 compatible */
    
    #define DHT11_PIN dht11_dev.gpio
    #define DHT11_IO_OUT() gpio_direction_output(DHT11_PIN, 1);
    #define DHT11_IO_IN() gpio_direction_input(DHT11_PIN)
    #define DHT11_WRITE(bit) gpio_set_value(DHT11_PIN, bit)
    #define DHT11_READ() gpio_get_value(DHT11_PIN)
    
    struct dht11
    {
        int gpio; /* gpio */
        int irq;
        dev_t dev_no; /* 设备号 */
        struct cdev chrdev;
        struct class *class;
        spinlock_t lock;
    };
    
    struct dht11 dht11_dev;
    
    static int dht11_wait_for_ready(void)
    {
        int timeout = 400;
        while (DHT11_READ() && timeout) /* 等待低电平到来 */
        {
            udelay(1);
            --timeout;
        }
        if (!timeout)
        {
            printk("[failed1] timeout %d\n", __LINE__);
            return -1; /* 超时 */
        }
    
        timeout = 1000;
        while (!DHT11_READ() && timeout) /* 等待高电平到来    */
        {
            udelay(1);
            --timeout;
        }
        if (!timeout)
        {
            printk("[failed2] timeout %d\n", __LINE__);
            return -1; /* 超时 */
        }
    
        timeout = 1000;
        while (DHT11_READ() && timeout) /* 等待高电平结束 */
        {
            udelay(1);
            --timeout;
        }
        if (!timeout)
        {
            printk("[failed3] timeout %d\n", __LINE__);
            return -1; /* 超时 */
        }
    
        return 0;
    }
    
    static int dht11_start(void)
    {
        DHT11_IO_OUT();
        DHT11_WRITE(0);
        mdelay(20);
        DHT11_WRITE(1);
        udelay(30);
        DHT11_IO_IN(); /* 设置为输入 */
        udelay(2);
    
        if (dht11_wait_for_ready())
            return -1;
        return 0;
    }
    
    static int dht11_read_byte(unsigned char *byte)
    {
        unsigned char i;
        unsigned char bit = 0;
        unsigned char data = 0;
        int timeout = 0;
    
        for (i = 0; i < 8; i++)
        {
            timeout = 1000;
            while (DHT11_READ() && timeout) /* 等待变为低电平 */
            {
                udelay(1);
                --timeout;
            }
            if (!timeout)
            {
                printk("[failed] timeout %d\n", __LINE__);
                return -1; /* 超时 */
            }
    
            timeout = 1000;
            while (!DHT11_READ() && timeout) /* 等待变为高电平 */
            {
                udelay(1);
                --timeout;
            }
            if (!timeout)
            {
                printk("[failed] timeout %d\n", __LINE__);
                return -1; /* 超时 */
            }
            udelay(40);
    
            bit = DHT11_READ();
    
            data <<= 1;
            if (bit)
            {
                data |= 0x01;
    #if 0
                timeout = 1000;
                while (DHT11_READ() && timeout)    /* 等待高电平结束 */
                {
                    udelay(1);
                    --timeout;
                }
                if (!timeout) 
                {
                    printk("timeout %d\n", __LINE__);
                    return -1;           /* 超时 */
                }
    #endif
            }
            // data <<= 1;          /* 导致错误的原因 : 移位要放前面,不能放在这里,若放在后面一旦获取最后一个位就会多移动一位导致数据不对 */
        }
    
        *byte = data;
        return 0;
    }
    
    /* 使设备只能被一个进程打开 */
    static int _drv_open(struct inode *node, struct file *file)
    {
        printk("[success] dht11 open\n");
        return 0;
    }
    
    static ssize_t _drv_read(struct file *filp, char __user *buf, size_t size, loff_t *offset)
    {
        int ret;
        int i;
        unsigned char data[5] = {0};
        unsigned long flags;
    
        if (size != 5)
            return -EINVAL;
    
        /* 关闭中断,防止时序被中断破坏 */
        spin_lock_irqsave(&dht11_dev.lock, flags);
    
        /* 启动信号 */
        if (dht11_start() != 0)
        {
            printk("[failed] dht11 start failed\n");
            ret = -EFAULT;
            goto failed1;
        }
    
        /* 读出5字节数据 */
        for (i = 0; i < 5; i++)
        {
            if (dht11_read_byte(&data[i]))
            {
                printk("[failed] data err\n");
                ret = -EAGAIN;
                goto failed1;
            }
        }
    
        /* 打开中断 */
        spin_unlock_irqrestore(&dht11_dev.lock, flags);
        /* 校验数据 */
        if (data[4] != (data[0] + data[1] + data[2] + data[3]))
        {
            printk("[failed] check data failed\n");
            ret = -EAGAIN;
            goto failed1;
        }
    
        /* 将数据拷贝回用户空间 */
        if (copy_to_user(buf, data, 5))
        {
            ret = -EFAULT;
            goto failed1;
        }
        else
        {
            ret = 5;
        }
    
        return ret;
    failed1:
        spin_unlock_irqrestore(&dht11_dev.lock, flags);
        return ret;
    }
    
    static int _drv_release(struct inode *node, struct file *file)
    {
        printk("[success] dht11 release\n");
        return 0;
    }
    
    static struct file_operations drv_file_ops = {
        .owner = THIS_MODULE,
        .open = _drv_open,
        .read = _drv_read,
        .release = _drv_release,
    };
    
    /* 设备树的匹配列表 */
    static struct of_device_id dts_match_table[] = {
        {
            .compatible = DEV_DTS_COMPATIBLE,
        }, /* 通过设备树来匹配 */
    };
    
    static int _driver_probe(struct platform_device *pdev)
    {
        int err;
        struct device *ds_dev;
        struct device_node *dev_node;
    
        struct device_node *node = pdev->dev.of_node;
    
        if (!node)
        {
            printk("dts node can not found!\r\n");
            return -EINVAL;
        }
    
        dev_node = of_find_node_by_path(DEV_DTS_NODE_PATH); /* 找到dht11的设备树节点  */
        if (IS_ERR(dev_node))
        {
            printk("dht11 DTS Node not found!\r\n");
            return PTR_ERR(dev_node);
        }
    
        dht11_dev.gpio = of_get_named_gpio(dev_node, DEV_PIN_DTS_NAME, 0); /* 获取dht11的gpio编号 */
        if (dht11_dev.gpio < 0)
        {
            printk("dht11-gpio not found!\r\n");
            return -EINVAL;
        }
    
        err = gpio_request(dht11_dev.gpio, DEV_PIN_DTS_NAME);
        if (err)
        {
            printk("gpio_request gpio is failed!\n");
            return -EINVAL;
        }
    
        printk("dht11 gpio %d\n", dht11_dev.gpio);
    
        /* 内核自动分配设备号 */
        err = alloc_chrdev_region(&dht11_dev.dev_no, 0, 1, DEV_NAME);
        if (err < 0)
        {
            pr_err("Error: failed to register mbochs_dev, err: %d\n", err);
            goto failed3;
        }
    
        cdev_init(&dht11_dev.chrdev, &drv_file_ops);
    
        cdev_add(&dht11_dev.chrdev, dht11_dev.dev_no, 1);
    
        dht11_dev.class = class_create(THIS_MODULE, DEV_NAME);
        if (IS_ERR(dht11_dev.class))
        {
            err = PTR_ERR(dht11_dev.class);
            goto failed1;
        }
    
        /* 创建设备节点 */
        ds_dev = device_create(dht11_dev.class, NULL, dht11_dev.dev_no, NULL, DEV_NAME);
        if (IS_ERR(ds_dev))
        { /* 判断指针是否合法 */
            err = PTR_ERR(ds_dev);
            goto failed2;
        }
    
        spin_lock_init(&dht11_dev.lock); /* 初始化自旋锁 */
        printk("[success] dht11 probe success\r\n");
        return 0;
    failed2:
        device_destroy(dht11_dev.class, dht11_dev.dev_no);
        class_destroy(dht11_dev.class);
    failed1:
        unregister_chrdev_region(dht11_dev.dev_no, 1);
        cdev_del(&dht11_dev.chrdev);
    failed3:
        gpio_free(dht11_dev.gpio);
        return err;
    }
    
    static int _driver_remove(struct platform_device *pdev)
    {
        device_destroy(dht11_dev.class, dht11_dev.dev_no);
        class_destroy(dht11_dev.class);
        unregister_chrdev_region(dht11_dev.dev_no, 1);
        cdev_del(&dht11_dev.chrdev);
        gpio_free(dht11_dev.gpio);
    
        printk(KERN_INFO "[success] dht11 remove success\n");
    
        return 0;
    }
    
    static struct platform_driver _platform_driver = {
        .probe = _driver_probe,
        .remove = _driver_remove,
        .driver = {
            .name = DEV_DTS_COMPATIBLE,
            .owner = THIS_MODULE,
            .of_match_table = dts_match_table, /* 通过设备树匹配 */
        },
    };
    
    /* 入口函数 */
    static int __init _driver_init(void)
    {
        int ret;
        printk("dht11 %s\n", __FUNCTION__);
    
        ret = platform_driver_register(&_platform_driver); //注册platform驱动
    
        return ret;
    }
    
    /*  出口函数 */
    static void __exit _driver_exit(void)
    {
        printk("dht11  %s\n", __FUNCTION__);
        platform_driver_unregister(&_platform_driver);
    }
    
    module_init(_driver_init);
    module_exit(_driver_exit);
    
    MODULE_AUTHOR("Fourth");
    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
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367

    (三)编写测试应用程序

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define DEV_NAME "/dev/dht11"
    
    typedef struct dht11
    {
        float temperature;
        float humidity;
    } DHT11;
    
    void sleep_ms(unsigned int ms)
    {
        struct timeval delay;
        delay.tv_sec = 0;
        delay.tv_usec = ms * 1000;
        select(0, NULL, NULL, NULL, &delay);
    }
    
    int getDht11(DHT11 *dht11_data)
    {
        int fd;
        int ret;
    
        /* 2. 打开文件 */
        fd = open(DEV_NAME, O_RDONLY); // | O_NONBLOCK
    
        if (fd < 0)
        {
            printf("[failed] can not open file %s, %d\n", DEV_NAME, fd);
            return -1;
        }
    
        uint8_t dht11_temp_data[5];
        int timeout = 5;
        while (timeout)
        {
            ret = read(fd, dht11_temp_data, sizeof(dht11_temp_data)) == sizeof(dht11_temp_data);
            if (ret)
            {
                sleep_ms(500);
                ret = read(fd, dht11_temp_data, sizeof(dht11_temp_data)) == sizeof(dht11_temp_data);
                if (ret)
                {
                    dht11_data->temperature = dht11_temp_data[2] + (float)dht11_temp_data[3] / 10.00;
                    dht11_data->humidity = dht11_temp_data[0] + dht11_temp_data[1] / 10.00;
                    printf("[success] temperture %d.%d  humi %d.%d\r\n", dht11_temp_data[2],
                           dht11_temp_data[3], dht11_temp_data[0], dht11_temp_data[1]);
                    close(fd);
                    return 0;
                }
                else
                    continue;
            }
            else
            {
                printf("[failed] tempget temp err %d\n", ret);
                timeout--;
            }
            sleep_ms(500);
        }
        close(fd);
        return -1;
    }
    
    int main(int argc, char **argv)
    {
        DHT11 dht11_data;
        if (!getDht11(&dht11_data))
        {
            printf("!!! temp %.1f  humi %.1f\n", dht11_data.temperature, dht11_data.humidity);
        }
        else
            printf("read dht11 error\n");
        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
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    (四)参考Makefile

    KERN_DIR = /disk/buildroot806/buildroot-100ask_t113-pro/buildroot/output/build/linux-origin_master
    
    
    all:
    	make -C $(KERN_DIR) M=`pwd` modules 
    	$(CROSS_COMPILE)gcc -o dht11_drv_test dht11_drv_test.c 
    
    clean:
    	make -C $(KERN_DIR) M=`pwd` modules clean
    	rm -rf modules.order
    	rm -f dht11_drv_test
    
    obj-m	+= dht11_drv.o
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    (五)测试结果

    # ls
    dht11_drv.ko    dht11_drv_test
    # chmod 777 dht11_drv_test
    # insmod dht11_drv.ko
    [ 2004.596630] dht11 _driver_init
    [ 2004.600557] dht11 gpio 110
    [ 2004.604304] [success] dht11 probe success
    # ./dht11_drv_test
    [ 2008.430245] [success] dht11 open
    [ 2008.982787] [success] dht11 release
    
    temp 30.0  humi 61.0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述
    至此,测试完毕,但是驱动程序中有bug待优化,比如读取数据的时候会存在数据的滞后性,导致第一次读取数据会发生错误。为保证调用时返回给函数是准确的数据,读取了两次,在一定程度上缓解了滞后性,但是根本问题未解决,有待优化。

    End.

  • 相关阅读:
    1688API接口接入|阿里1688-B类电商基础链路专业化体验升级
    k8s--基础--26.1--监控告警系统--prometheus--介绍
    [附源码]SSM计算机毕业设计影院售票系统JAVA
    搭建第一个区块链网络
    Python图像处理【2】探索Python图像处理库
    一文弄懂CNN中的BatchNorm
    Day26-Xpath数据解析
    【python】类方法、property类属性、单例模式
    Dubbo+Zookeeper搭建
    Java 获取显示器的尺寸,缩放比例,分辨率
  • 原文地址:https://blog.csdn.net/qq_46079439/article/details/127793228