OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 12168|回复: 27

自制阿尔法开发板的DHT11驱动,求助(搞好了,我发出来给大家成品)

[复制链接]

5

主题

32

帖子

0

精华

初级会员

Rank: 2

积分
76
金钱
76
注册时间
2019-5-26
在线时间
27 小时
发表于 2020-3-10 18:21:46 | 显示全部楼层 |阅读模式
因为找过客服,说没有DHT11的驱动,就决定自己来写了。

使用设备树,但是不适用platform平台,VCC接5V,DATA线接的是印出来的GPIO4(也就是GPIO1的4引脚)

D:/%E8%BF%85%E9%9B%B7%E4%B8%8B%E8%BD%BD/%E6%9C%89%E9%81%93%E4%BA%91%E7%AC%94%E8%AE%B0/weixinobU7VjjxUyTq6DZEwdprcCWTODLk/4c297d47bf1f4234aa90fb2419074e55/clipboard.png

首先是设备树的编写,使用了pin-func头文件里面的宏定义,就省去一些功夫了,只需要配置PAD寄存器的值即可,但是这个PAD寄存器的值有点模糊,对硬件不是太了解,所以是参考着LED输出和KEY输入来配置的。

1、添加pinctrl节点

最后PAD配置的是结合了输出输入的0xF080(这个不是直接合并的,也是对着位一步一步来的。)
  1. pinctrl_key: keygrp {
  2.                         fsl,pins = <
  3.                                 MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0xF080 /* KEY0 */
  4.                         >;
  5.                 };

  6.                 pinctrl_dht11:dht11grp {
  7.                         fsl,pins = <
  8.                                 MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0xF0B0        /* dht11 */
  9.                         >;                       
  10.                 };
  11.        
  12.                 pinctrl_beep: beepgrp {
  13.                         fsl,pins = <
  14.                         MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x10B0         /* beep */
  15.                         >;               
  16.                 };
复制代码




2、接着是添加DHT11设备节点,使用上面所添加的pin。
这里也有一个不确定dht11-gpio的属性值,因为我这个需要输出输入,也会输出高低电平,所以我选择了GPIO_ACTIVE_LOW,因为DATA线默认需要上拉,所以我选择低电平为有效电平。有错的大家可以帮忙纠正吗,谢谢你们了!
  1. dht11 {
  2.                 #address-cells = <1>;
  3.                 #size-cells = <1>;
  4.                 compatible = "atkalpha-dht11";
  5.                 pinctrl-names = "default";
  6.                 pinctrl-0 = <&pinctrl_dht11>;
  7.                 dht11-gpio = <&gpio1 4 GPIO_ACTIVE_LOW>;      //follow KEY0
  8.                 status = "okay";
  9.         };       
复制代码


3、检查了,设备树中没有其他设备使用这个IO。设备树编译通过。

驱动编写:
(时序我多次检查了,但是还是卡在了start这里,也就是启动不了,第一个循环就超时了
没有编写write函数,因为读就可以了,编译是通过的,初始化也没有报错,就是应用程序调用read函数获取数据的时候,会卡死在启动函数。
  1. #include <linux/types.h>
  2. #include <linux/kernel.h>
  3. #include <linux/delay.h>
  4. #include <linux/ide.h>
  5. #include <linux/init.h>
  6. #include <linux/module.h>
  7. #include <linux/errno.h>
  8. #include <linux/gpio.h>
  9. #include <linux/cdev.h>
  10. #include <linux/device.h>
  11. #include <linux/of.h>
  12. #include <linux/of_address.h>
  13. #include <linux/of_gpio.h>
  14. #include <asm/mach/map.h>
  15. #include <asm/uaccess.h>
  16. #include <asm/io.h>

  17. #define DHT11_CNT                        1                /* 设备号个数 */

  18. #define DHT11_NAME                        "dht11"        /* 名字 */

  19. /* dht11设备结构体 */



  20. struct dht11_dev{

  21.         dev_t devid;                        /* 设备号          */

  22.         struct cdev cdev;                /* cdev         */

  23.         struct class *class;        /* 类                 */

  24.         struct device *device;        /* 设备          */

  25.         int major;                                /* 主设备号          */

  26.         int minor;                                /* 次设备号   */

  27.         struct device_node        *nd; /* 设备节点 */

  28.         int dht11_gpio;                        /* dht11所使用的GPIO编号                */

  29. };


  30. struct dht11_dev dht11;                /* dht11设备 */


  31. /*

  32. * @description                : 打开设备
  33. * @param - inode         : 传递给驱动的inode
  34. * @param - filp         : 设备文件,file结构体有个叫做private_data的成员变量
  35. *                                           一般在open的时候将private_data指向设备结构体。
  36. * @return                         : 0 成功;其他 失败
  37. */



  38. static int dht11_open(struct inode *inode, struct file *filp)
  39. {
  40.         filp->private_data = &dht11; /* 设置私有数据 */
  41.         return 0;
  42. }



  43. /*

  44. *@description                :根据原理编写启动信号

  45. *@description                :使用gpio的API函数

  46. */

  47. static int Dht11_Start(struct file *filp)
  48. {
  49.         unsigned int t =0,ret =0;        //用于计算超时

  50.         struct dht11_dev *dev = filp->private_data;

  51.        
  52.         //先设置为输出,初值先设置为1吧,因为是有上拉电阻

  53.         ret = gpio_direction_output(dht11.dht11_gpio, 1);
  54.         if(ret < 0) {           

  55.                 printk("can't set output!\r\n");

  56.             }       

  57.         //启动信号
  58.         //gpio_set_value(dev->dht11_gpio, 1);        /* 高电平持续5us */
  59.         //udelay(5);

  60.         gpio_set_value(dev->dht11_gpio, 0);        /* 低电平持续20us */
  61.         udelay(20);
  62.        
  63.         gpio_set_value(dev->dht11_gpio, 1);        /* 高电平持续30us */
  64.         udelay(30);

  65.         //【G9设置为输入】-----接收响应信号
  66.         gpio_direction_input(dht11.dht11_gpio);
  67.         t =0;
  68.         while( gpio_get_value(dev->dht11_gpio) != 0)
  69.         {
  70.                 udelay(1);
  71.                 t++;       
  72.                
  73.                 if(t>100)
  74.                         return -1;
  75.         }
  76.        
  77.        
  78.        
  79.         //过滤低电平
  80.         t = 0;
  81.         while( gpio_get_value(dev->dht11_gpio) == 0)
  82.         {
  83.                 udelay(1);
  84.                 t++;               

  85.                 if(t>100)
  86.                         return -2;

  87.         }

  88.        

  89.         //过滤高电平
  90.         t = 0;
  91.         while( gpio_get_value(dev->dht11_gpio) == 1)
  92.         {
  93.                 udelay(1);
  94.                 t++;       

  95.                 if(t>100)
  96.                         return -3;
  97.         }


  98.         //如果都正常,返回0,走人
  99.         //上面其实是在接收模块传回来的反馈信号
  100.         return 0;

  101. }



  102. /*

  103.   * @description        : 读取一个字节
  104.   
  105.   * @return                 : 读取到的字节数据

  106. */

  107. //返回0为异常
  108. static unsigned char Dht11_Read_Byte(struct file *filp)
  109. {

  110.         unsigned char i, t = 0, data = 0;

  111.         struct dht11_dev *dev = filp->private_data;
  112.        

  113.         for(i=0; i<8; i++)
  114.         {
  115.                 //过渡低电平
  116.         //无论是【0】还是【1】,【一开始都是低电平】
  117.                 t = 0;

  118.                 while( gpio_get_value(dev->dht11_gpio) == 0)
  119.                 {
  120.                         udelay(1);
  121.                         t++;
  122.                         if(t>100)
  123.                                 return -EINVAL;

  124.                 }       
  125.                 //高电平出现,退出上面的循环

  126.                 //延时45us,再判断电平,就可以知道是1还是0
  127.                 udelay(45);

  128.                 //延时之后还是高电平,就说明是“1”
  129.                 if(gpio_get_value(dev->dht11_gpio) == 1)                //表示收到1
  130.                 {
  131.                         data |= 1<<(7-i);

  132.                         //过滤掉剩下的高电平
  133.                         t = 0;
  134.                         while( gpio_get_value(dev->dht11_gpio) == 1)
  135.                         {
  136.                                 udelay(1);
  137.                                 t++;               

  138.                                 if(t>100)
  139.                                         return -EINVAL;
  140.                         }       

  141.                 }               
  142.                 //如果是0,不用处理,本来初值就是0

  143.         }       

  144.         return data;
  145. }



  146. /*

  147. * @description                : 读函数

  148. * @param - filp         : 要关闭的设备文件(文件描述符)

  149. * @return                         : 0 成功;其他 失败

  150. */



  151. static ssize_t dht11_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
  152. {

  153.          int ret = 0;

  154.          unsigned char value[5];

  155.          struct dht11_dev *dev = filp->private_data;

  156.          ret = Dht11_Start(filp);
  157.                
  158.          //读取4个值

  159.          if(ret == 0)
  160.          {
  161.                 printk("<4>""kernel_read\r\n");
  162. value[0] = Dht11_Read_Byte(filp);
  163.                 value[1] = Dht11_Read_Byte(filp);

  164.                 value[2] = Dht11_Read_Byte(filp);
  165.                 value[3] = Dht11_Read_Byte(filp);

  166.                 value[4] = Dht11_Read_Byte(filp);

  167.                 printk("<4>""%d.%d,%d.%d",value[0],value[1],value[2],value[3]);

  168.                 //把这5个值返回给应用程序

  169.                 ret = copy_to_user(buf, &value, sizeof(value));
  170.         }
  171.         else
  172.                 printk("<4>""start error.number:%d,\r\n",ret);

  173.         return ret;
  174. }









  175. /*

  176. * @description                : 关闭/释放设备

  177. * @param - filp         : 要关闭的设备文件(文件描述符)

  178. * @return                         : 0 成功;其他 失败

  179. */
  180. static int dht11_release(struct inode *inode, struct file *filp)
  181. {

  182.         return 0;

  183. }


  184. /* 设备操作函数 */
  185. static struct file_operations dht11_fops = {
  186.         .owner = THIS_MODULE,

  187.         .open = dht11_open,

  188.         .read = dht11_read,

  189.         .release =         dht11_release,
  190. };







  191. /*
  192. * @description        : 驱动出口函数

  193. * @param                 : 无

  194. * @return                 : 无
  195. */

  196. static int __init dht11_init(void)
  197. {

  198.         int ret = 0;

  199.         /* 设置DHT11所使用的GPIO */

  200.         /* 1、获取设备节点:dht11 */

  201.         dht11.nd = of_find_node_by_path("/dht11");

  202.         if(dht11.nd == NULL) {

  203.                 printk("dht11 node not find!\r\n");

  204.                 return -EINVAL;

  205.         } else {

  206.                 printk("dht11 node find!\r\n");

  207.         }

  208.         /* 2、 获取设备树中的gpio属性,得到DHT11所使用的DHT11编号 */

  209.         dht11.dht11_gpio = of_get_named_gpio(dht11.nd, "dht11-gpio", 0);

  210.         if(dht11.dht11_gpio < 0) {

  211.                 printk("can't get dht11-gpio");
  212.                 return -EINVAL;

  213.         }

  214.         printk("dht11-gpio num = %d\r\n", dht11.dht11_gpio);

  215.         /* 3、设置GPIO为输出,并且输出高电平 */

  216.         ret = gpio_direction_output(dht11.dht11_gpio, 1);



  217.         if(ret < 0) {

  218.                 printk("can't set gpio!\r\n");
  219.         }


  220.         /* 注册字符设备驱动 */

  221.         /* 1、创建设备号 */
  222.         if (dht11.major) {                /*  定义了设备号 */
  223.                 dht11.devid = MKDEV(dht11.major, 0);

  224.                 register_chrdev_region(dht11.devid, DHT11_CNT, DHT11_NAME);

  225.         } else {                                                /* 没有定义设备号 */

  226.                 alloc_chrdev_region(&dht11.devid, 0, DHT11_CNT, DHT11_NAME);        /* 申请设备号 */

  227.                 dht11.major = MAJOR(dht11.devid);        /* 获取分配号的主设备号 */

  228.                 dht11.minor = MINOR(dht11.devid);        /* 获取分配号的次设备号 */
  229.         }

  230.         printk("dht11 major=%d,minor=%d\r\n",dht11.major, dht11.minor);       


  231.         /* 2、初始化cdev */
  232.         dht11.cdev.owner = THIS_MODULE;
  233.        
  234.         cdev_init(&dht11.cdev, &dht11_fops);


  235.         /* 3、添加一个cdev */

  236.         cdev_add(&dht11.cdev, dht11.devid, DHT11_CNT);

  237.         /* 4、创建类 */
  238.         dht11.class = class_create(THIS_MODULE, DHT11_NAME);

  239.         if (IS_ERR(dht11.class)) {
  240.                 return PTR_ERR(dht11.class);
  241.         }


  242.         /* 5、创建设备 */
  243.         dht11.device = device_create(dht11.class, NULL, dht11.devid, NULL, DHT11_NAME);

  244.         if (IS_ERR(dht11.device)) {
  245.                 return PTR_ERR(dht11.device);
  246.         }

  247.         return 0;

  248. }



  249. /*

  250. * @description        : 驱动出口函数

  251. * @param                 : 无

  252. * @return                 : 无

  253. */


  254. static void __exit dht11_exit(void)
  255. {

  256.         /* 注销字符设备驱动 */

  257.         cdev_del(&dht11.cdev);/*  删除cdev */

  258.         unregister_chrdev_region(dht11.devid, DHT11_CNT); /* 注销设备号 */

  259.         device_destroy(dht11.class, dht11.devid);

  260.         class_destroy(dht11.class);
  261. }

  262. module_init(dht11_init);
  263. module_exit(dht11_exit);
  264. MODULE_LICENSE("GPL");
  265. MODULE_AUTHOR("zuozhongkai");
复制代码




D:/%E8%BF%85%E9%9B%B7%E4%B8%8B%E8%BD%BD/%E6%9C%89%E9%81%93%E4%BA%91%E7%AC%94%E8%AE%B0/weixinobU7VjjxUyTq6DZEwdprcCWTODLk/4c297d47bf1f4234aa90fb2419074e55/clipboard.png

D:/%E8%BF%85%E9%9B%B7%E4%B8%8B%E8%BD%BD/%E6%9C%89%E9%81%93%E4%BA%91%E7%AC%94%E8%AE%B0/weixinobU7VjjxUyTq6DZEwdprcCWTODLk/4c297d47bf1f4234aa90fb2419074e55/clipboard.png

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

8

帖子

0

精华

新手上路

积分
23
金钱
23
注册时间
2020-3-28
在线时间
6 小时
发表于 2020-4-26 10:17:50 | 显示全部楼层
回复 支持 1 反对 0

使用道具 举报

5

主题

32

帖子

0

精华

初级会员

Rank: 2

积分
76
金钱
76
注册时间
2019-5-26
在线时间
27 小时
 楼主| 发表于 2020-3-10 18:22:38 | 显示全部楼层
顶一下,谢谢大家
回复 支持 反对

使用道具 举报

2

主题

712

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2178
金钱
2178
注册时间
2018-8-27
在线时间
258 小时
发表于 2020-3-10 18:49:06 | 显示全部楼层

回帖奖励 +2 金钱

谢谢分享!
森罗万象
回复 支持 反对

使用道具 举报

5

主题

32

帖子

0

精华

初级会员

Rank: 2

积分
76
金钱
76
注册时间
2019-5-26
在线时间
27 小时
 楼主| 发表于 2020-3-10 19:35:01 | 显示全部楼层

这个还不是成品哦,有问题,而且查不出来
回复 支持 反对

使用道具 举报

4

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
175
金钱
175
注册时间
2018-8-3
在线时间
36 小时
发表于 2020-3-10 21:44:46 | 显示全部楼层
这个时序不太对吧,起始信号低电平保持时间不能小于18ms,我看楼主都是us,然后过滤高低电平看的我有点懵,t>100的依据是啥?我觉的直接读40位,先读取是否是50us的低电平,如果是则有效,然后在判断持续26~28us表示0,如果超过,看是否持续70us,表示1。然后组合一下就好了。好像还有校验位,我看楼主没有写出来。
回复 支持 反对

使用道具 举报

5

主题

32

帖子

0

精华

初级会员

Rank: 2

积分
76
金钱
76
注册时间
2019-5-26
在线时间
27 小时
 楼主| 发表于 2020-3-11 00:09:53 | 显示全部楼层
顶一下,真的很需要大家的帮助
回复 支持 反对

使用道具 举报

5

主题

32

帖子

0

精华

初级会员

Rank: 2

积分
76
金钱
76
注册时间
2019-5-26
在线时间
27 小时
 楼主| 发表于 2020-3-11 10:31:18 | 显示全部楼层
tim5529519 发表于 2020-3-10 21:44
这个时序不太对吧,起始信号低电平保持时间不能小于18ms,我看楼主都是us,然后过滤高低电平看的我有点懵, ...

哈哈哈哈,昨晚没看到这个,我早上也发现了18ms的问题,刚刚改了,可以了。我之后把源代码贡献出来。
t>100是因为要防止超时啦,这个是我STM32的代码改过来的,校验位也会给到应用程序,所以我是在应用程序检验的,但是还是谢谢您,真的很感谢您
回复 支持 反对

使用道具 举报

5

主题

32

帖子

0

精华

初级会员

Rank: 2

积分
76
金钱
76
注册时间
2019-5-26
在线时间
27 小时
 楼主| 发表于 2020-3-11 11:33:52 | 显示全部楼层
程序来了,果然还是时序的问题,谢谢5楼的老哥,还有,谢谢不放弃的自己
回复 支持 反对

使用道具 举报

5

主题

32

帖子

0

精华

初级会员

Rank: 2

积分
76
金钱
76
注册时间
2019-5-26
在线时间
27 小时
 楼主| 发表于 2020-3-11 11:36:01 | 显示全部楼层
以下是驱动源码
使用的DATA线接的是GPIO1的4引脚,也就是Linux开发板的GPIO4
关于设备树的配置,按我上面的就可以了

  1. #include <linux/types.h>
  2. #include <linux/kernel.h>
  3. #include <linux/delay.h>
  4. #include <linux/ide.h>
  5. #include <linux/init.h>
  6. #include <linux/module.h>
  7. #include <linux/errno.h>
  8. #include <linux/gpio.h>
  9. #include <linux/cdev.h>
  10. #include <linux/device.h>
  11. #include <linux/of.h>
  12. #include <linux/of_address.h>
  13. #include <linux/of_gpio.h>
  14. #include <asm/mach/map.h>
  15. #include <asm/uaccess.h>
  16. #include <linux/semaphore.h>
  17. #include <asm/io.h>






  18. #define DHT11_CNT                        1                /* 设备号个数 */

  19. #define DHT11_NAME                        "dht11"        /* 名字 */

  20. /* dht11设备结构体 */



  21. struct dht11_dev{

  22.         dev_t devid;                        /* 设备号          */

  23.         struct cdev cdev;                /* cdev         */

  24.         struct class *class;        /* 类                 */

  25.         struct device *device;        /* 设备          */

  26.         int major;                                /* 主设备号          */

  27.         int minor;                                /* 次设备号   */

  28.         struct device_node        *nd; /* 设备节点 */

  29.         int dht11_gpio;                        /* dht11所使用的GPIO编号                */
  30.        
  31.         //struct mutex dht11_mutex;        //定义一个互斥锁的结构体

  32. };


  33. struct dht11_dev dht11;                /* dht11设备 */


  34. /*

  35. * @description                : 打开设备
  36. * @param - inode         : 传递给驱动的inode
  37. * @param - filp         : 设备文件,file结构体有个叫做private_data的成员变量
  38. *                                           一般在open的时候将private_data指向设备结构体。
  39. * @return                         : 0 成功;其他 失败
  40. */



  41. static int dht11_open(struct inode *inode, struct file *filp)
  42. {
  43.         filp->private_data = &dht11; /* 设置私有数据 */
  44.         return 0;
  45. }



  46. /*

  47. *@description                :根据原理编写启动信号

  48. *@description                :使用gpio的API函数

  49. */

  50. static int Dht11_Start(struct dht11_dev *dev)
  51. {
  52.         unsigned int t =0,ret =0;        //用于计算超时
  53.        
  54.         //先设置为输出,初值先设置为1吧,因为是有上拉电阻

  55.         ret = gpio_direction_output(dev->dht11_gpio, 1);
  56.         if(ret < 0) {           

  57.                 printk("can't set output!\r\n");

  58.             }       

  59.         //启动信号
  60.         gpio_set_value(dev->dht11_gpio, 1);        /* 高电平持续5us */
  61.         udelay(5);

  62.         gpio_set_value(dev->dht11_gpio, 0);        /* 低电平持续18【ms】 */
  63.         //udelay(20);
  64.         mdelay(20);                //应该是拉低18ms以上啊
  65.        
  66.         gpio_set_value(dev->dht11_gpio, 1);        /* 高电平持续30us */
  67.         udelay(30);

  68.         //【G9设置为输入】-----接收响应信号
  69.         gpio_direction_input(dev->dht11_gpio);
  70.        
  71.         t =0;
  72.         while(gpio_get_value(dev->dht11_gpio)!= 0)
  73.         {
  74.                 udelay(1);
  75.                 t++;       
  76.                
  77.                 if(t>100)
  78.                         return -1;
  79.         }
  80.        
  81.        
  82.        
  83.         //过滤低电平
  84.         t = 0;
  85.         while(gpio_get_value(dev->dht11_gpio) == 0)
  86.         {
  87.                 udelay(1);
  88.                 t++;               

  89.                 if(t>100)
  90.                         return -2;
  91.         }

  92.        

  93.         //过滤高电平
  94.         t = 0;
  95.         while(gpio_get_value(dev->dht11_gpio) == 1)
  96.         {
  97.                 udelay(1);
  98.                 t++;       

  99.                 if(t>100)
  100.                         return -3;
  101.         }


  102.         //如果都正常,返回0,走人
  103.         //上面其实是在接收模块传回来的反馈信号
  104.         return 0;

  105. }



  106. /*

  107.   * @description        : 读取一个字节
  108.   
  109.   * @return                 : 读取到的字节数据

  110. */

  111. //返回0为异常
  112. static unsigned char Dht11_Read_Byte(struct dht11_dev *dev)
  113. {
  114.         //上锁
  115.         //mutex_lock(&dev->dht11_mutex);
  116.        
  117.        
  118.         unsigned char i, t = 0, data = 0;

  119.        
  120.         for(i=0; i<8; i++)
  121.         {
  122.                 //过渡低电平
  123.         //无论是【0】还是【1】,【一开始都是低电平】
  124.                 t = 0;

  125.                 while(gpio_get_value(dev->dht11_gpio) == 0)
  126.                 {
  127.                         udelay(1);
  128.                         t++;
  129.                         if(t>100)
  130.                         {
  131.                                 //mutex_unlock(&dev->dht11_mutex);
  132.                                 return -EINVAL;
  133.                         }

  134.                 }       
  135.                 //高电平出现,退出上面的循环

  136.                 //延时45us,再判断电平,就可以知道是1还是0
  137.                 udelay(45);

  138.                 //延时之后还是高电平,就说明是“1”
  139.                 if(gpio_get_value(dev->dht11_gpio) == 1)                //表示收到1
  140.                 {
  141.                         data |= 1<<(7-i);

  142.                         //过滤掉剩下的高电平
  143.                         t = 0;
  144.                         while( gpio_get_value(dev->dht11_gpio) == 1)
  145.                         {
  146.                                 udelay(1);
  147.                                 t++;               

  148.                                 if(t>100)
  149.                                 {
  150.                                         //mutex_unlock(&dev->dht11_mutex);
  151.                                         return -EINVAL;
  152.                                 }
  153.                         }       

  154.                 }               
  155.                 //如果是0,不用处理,本来初值就是0

  156.         }       
  157.         //mutex_unlock(&dev->dht11_mutex);
  158.         return data;
  159. }



  160. /*

  161. * @description                : 读函数

  162. * @param - filp         : 要关闭的设备文件(文件描述符)

  163. * @return                         : 0 成功;其他 失败

  164. */

  165. static ssize_t dht11_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
  166. {

  167.          int ret = 0;

  168.          unsigned char value[5]={0,0,0,0,0};
  169.        
  170.          
  171.          struct dht11_dev *dev = filp->private_data;

  172.          ret = Dht11_Start(dev);
  173.                
  174.          //读取4个值
  175.          gpio_direction_input(dev->dht11_gpio);
  176.          if(ret == 0)
  177.          {
  178.                 //printk("<4>""kernel_read\r\n");
  179.                 value[0] = Dht11_Read_Byte(dev);
  180.                 value[1] = Dht11_Read_Byte(dev);

  181.                 value[2] = Dht11_Read_Byte(dev);
  182.                 value[3] = Dht11_Read_Byte(dev);

  183.                 value[4] = Dht11_Read_Byte(dev);

  184.                 printk("<4>""%d.%d,%d.%d——%d",value[0],value[1],value[2],value[3],value[4]);

  185.                 //把这5个值返回给应用程序

  186.                 ret = copy_to_user(buf, &value, sizeof(value));
  187.         }
  188.         else
  189.                 printk("<4>""start error.number:%d,\r\n",ret);

  190.         return ret;
  191. }




  192. /*

  193. * @description                : 关闭/释放设备

  194. * @param - filp         : 要关闭的设备文件(文件描述符)

  195. * @return                         : 0 成功;其他 失败

  196. */
  197. static int dht11_release(struct inode *inode, struct file *filp)
  198. {

  199.         return 0;

  200. }


  201. /* 设备操作函数 */
  202. static struct file_operations dht11_fops = {
  203.         .owner = THIS_MODULE,

  204.         .open = dht11_open,

  205.         .read = dht11_read,

  206.         .release =         dht11_release,
  207. };







  208. /*
  209. * @description        : 驱动入口函数

  210. * @param                 : 无

  211. * @return                 : 无
  212. */

  213. static int __init dht11_init(void)
  214. {

  215.         int ret = 0;

  216.        
  217.        
  218.        
  219.         /* 设置DHT11所使用的GPIO */

  220.         /* 1、获取设备节点:dht11 */

  221.         dht11.nd = of_find_node_by_path("/dht11");

  222.         if(dht11.nd == NULL) {

  223.                 printk("dht11 node not find!\r\n");

  224.                 return -EINVAL;

  225.         } else {

  226.                 printk("dht11 node find!\r\n");

  227.         }

  228.         /* 2、 获取设备树中的gpio属性,得到DHT11所使用的DHT11编号 */

  229.         dht11.dht11_gpio = of_get_named_gpio(dht11.nd, "dht11-gpio", 0);

  230.         if(dht11.dht11_gpio < 0) {

  231.                 printk("can't get dht11-gpio");
  232.                 return -EINVAL;

  233.         }

  234.         printk("dht11-gpio num = %d\r\n", dht11.dht11_gpio);

  235.         /* 3、设置GPIO为输出,并且输出高电平 */

  236.         ret = gpio_direction_output(dht11.dht11_gpio, 1);



  237.         if(ret < 0) {

  238.                 printk("can't set gpio!\r\n");
  239.         }


  240.         /* 注册字符设备驱动 */

  241.         /* 1、创建设备号 */
  242.         if (dht11.major) {                /*  定义了设备号 */
  243.                 dht11.devid = MKDEV(dht11.major, 0);

  244.                 register_chrdev_region(dht11.devid, DHT11_CNT, DHT11_NAME);

  245.         } else {                                                /* 没有定义设备号 */

  246.                 alloc_chrdev_region(&dht11.devid, 0, DHT11_CNT, DHT11_NAME);        /* 申请设备号 */

  247.                 dht11.major = MAJOR(dht11.devid);        /* 获取分配号的主设备号 */

  248.                 dht11.minor = MINOR(dht11.devid);        /* 获取分配号的次设备号 */
  249.         }

  250.         printk("dht11 major=%d,minor=%d\r\n",dht11.major, dht11.minor);       


  251.         /* 2、初始化cdev */
  252.         dht11.cdev.owner = THIS_MODULE;
  253.        
  254.         cdev_init(&dht11.cdev, &dht11_fops);


  255.         /* 3、添加一个cdev */

  256.         cdev_add(&dht11.cdev, dht11.devid, DHT11_CNT);

  257.         /* 4、创建类 */
  258.         dht11.class = class_create(THIS_MODULE, DHT11_NAME);

  259.         if (IS_ERR(dht11.class)) {
  260.                 return PTR_ERR(dht11.class);
  261.         }


  262.         /* 5、创建设备 */
  263.         dht11.device = device_create(dht11.class, NULL, dht11.devid, NULL, DHT11_NAME);

  264.         if (IS_ERR(dht11.device)) {
  265.                 return PTR_ERR(dht11.device);
  266.         }

  267.        
  268.         //mutex_init(&dht11.dht11_mutex);                        //利用初始化函数,初始化这个结构体
  269.        
  270.        
  271.        
  272.         return 0;

  273. }



  274. /*

  275. * @description        : 驱动出口函数

  276. * @param                 : 无

  277. * @return                 : 无

  278. */


  279. static void __exit dht11_exit(void)
  280. {

  281.         /* 注销字符设备驱动 */

  282.         cdev_del(&dht11.cdev);/*  删除cdev */

  283.         unregister_chrdev_region(dht11.devid, DHT11_CNT); /* 注销设备号 */

  284.         device_destroy(dht11.class, dht11.devid);

  285.         class_destroy(dht11.class);
  286. }

  287. module_init(dht11_init);
  288. module_exit(dht11_exit);
  289. MODULE_LICENSE("GPL");
  290. MODULE_AUTHOR("zuozhongkai");
复制代码
回复 支持 反对

使用道具 举报

5

主题

32

帖子

0

精华

初级会员

Rank: 2

积分
76
金钱
76
注册时间
2019-5-26
在线时间
27 小时
 楼主| 发表于 2020-3-11 11:36:33 | 显示全部楼层
以下是测试App程序

  1. #include "stdio.h"
  2. #include "unistd.h"
  3. #include "sys/types.h"
  4. #include "sys/stat.h"
  5. #include "fcntl.h"
  6. #include "stdlib.h"
  7. #include "string.h"


  8. /*
  9. * @description                : main主程序

  10. * @param - argc         : argv数组元素个数

  11. * @param - argv         : 具体参数

  12. * @return                         : 0 成功;其他 失败

  13. */

  14. int main(int argc, char *argv[])
  15. {
  16.         int fd, retvalue;

  17.         unsigned char databuf[5]={0,0,0,0,0};
  18.        
  19.        
  20.         char *filename = "/dev/dht11";

  21.         /* 打开dht11驱动 */
  22.         fd = open(filename, O_RDWR);

  23.         if(fd < 0){

  24.                 printf("file %s open failed!\r\n", filename);
  25.                 return -1;
  26.         }

  27.         while(1)
  28.         {
  29.                 /* 向/dev/dht11文件写入数据 */
  30.                 retvalue = read(fd, databuf, sizeof(databuf));
  31.                 if(retvalue < 0){
  32.                         printf("DHT11 Read Failed!\r\n");
  33.                        
  34.                         close(fd);
  35.                         return -1;
  36.                 }

  37.                 if(databuf[4] == databuf[0]+databuf[1]+databuf[2]+databuf[3])
  38.                         printf("ansewr is right!\n");
  39.                 else
  40.                         printf("wrong answer\n");
  41.                
  42.                 printf("======================\n");
  43.        
  44.                 printf("H = %d.%d\n",databuf[0],databuf[1]);
  45.                 printf("T = %d.%d\n",databuf[2],databuf[3]);
  46.                 printf("cheak = %d",databuf[4]);
  47.                
  48.                
  49.                 //每隔两秒采集一次
  50.                 sleep(2);

  51.         }

  52.         retvalue = close(fd); /* 关闭文件 */
  53.         if(retvalue < 0){
  54.                 printf("file %s close failed!\r\n", argv[1]);
  55.                 return -1;
  56.         }

  57.         return 0;

  58. }
复制代码
回复 支持 反对

使用道具 举报

5

主题

32

帖子

0

精华

初级会员

Rank: 2

积分
76
金钱
76
注册时间
2019-5-26
在线时间
27 小时
 楼主| 发表于 2020-3-11 11:37:40 | 显示全部楼层
最后放一段结果吧,发图不方便,就发复制的文本吧

  1. /project # insmod dht11.ko

  2. dht11 node find!
  3. dht11-gpio num = 4
  4. dht11 major=249,minor=0
  5. /project # ./dht11App
  6. <4>45.0,21.6——72ansewr is right!
  7. ======================
  8. H = 45.0
  9. T = 21.6
  10. <4>45.0,21.1——67cheak = 72ansewr is right!
  11. ======================
  12. H = 45.0
  13. T = 21.1
  14. <4>47.0,42.2——234cheak = 67wrong answer
  15. ======================
  16. H = 47.0
  17. T = 42.2
  18. <4>47.0,21.1——69cheak = 234ansewr is right!
  19. ======================
  20. H = 47.0
  21. T = 21.1
  22. <4>47.0,21.1——69cheak = 69ansewr is right!
  23. ======================
  24. H = 47.0
  25. T = 21.1
  26. ^C
  27. /project #
复制代码
回复 支持 反对

使用道具 举报

0

主题

201

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2552
金钱
2552
注册时间
2019-12-5
在线时间
352 小时
发表于 2020-4-26 13:17:22 | 显示全部楼层
顶一个,再学习一下
回复 支持 反对

使用道具 举报

1

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
53
金钱
53
注册时间
2020-3-9
在线时间
17 小时
发表于 2020-5-3 13:01:07 | 显示全部楼层
tql  nb
回复 支持 反对

使用道具 举报

2

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2020-5-15
在线时间
39 小时
发表于 2020-6-10 09:05:32 | 显示全部楼层
赞一个,好帖
回复 支持 反对

使用道具 举报

5

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
186
金钱
186
注册时间
2020-5-13
在线时间
20 小时
发表于 2020-6-10 13:41:19 | 显示全部楼层
很棒棒哦,顶一下
回复 支持 反对

使用道具 举报

2

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
87
金钱
87
注册时间
2020-5-15
在线时间
39 小时
发表于 2020-12-12 16:44:26 | 显示全部楼层
很好,帮顶
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2021-4-26
在线时间
11 小时
发表于 2021-5-20 12:41:41 | 显示全部楼层
好哥们顶你
回复 支持 反对

使用道具 举报

9

主题

890

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
2390
金钱
2390
注册时间
2019-9-25
在线时间
397 小时
发表于 2021-5-27 16:08:45 | 显示全部楼层
可以哦,顶
回复 支持 反对

使用道具 举报

70

主题

6697

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
12687
金钱
12687
注册时间
2012-11-26
在线时间
3710 小时
发表于 2021-5-27 16:38:28 | 显示全部楼层
顶个  有空看看
学无止境
回复 支持 反对

使用道具 举报

0

主题

4

帖子

0

精华

新手入门

积分
11
金钱
11
注册时间
2022-10-17
在线时间
1 小时
发表于 2022-10-17 23:24:09 | 显示全部楼层
牛批,博主,,多谢分享
回复 支持 反对

使用道具 举报

0

主题

201

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2552
金钱
2552
注册时间
2019-12-5
在线时间
352 小时
发表于 2022-10-19 08:53:07 | 显示全部楼层
Great, just do it .
回复 支持 反对

使用道具 举报

0

主题

201

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2552
金钱
2552
注册时间
2019-12-5
在线时间
352 小时
发表于 2022-10-19 08:54:35 | 显示全部楼层
just do it
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
3
金钱
3
注册时间
2023-4-7
在线时间
0 小时
发表于 2023-4-8 08:57:09 | 显示全部楼层
想问一下设备树更改以后是怎么到开发板上的呀
回复 支持 反对

使用道具 举报

0

主题

6

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2022-1-22
在线时间
13 小时
发表于 2023-5-19 22:11:18 | 显示全部楼层
谢谢博主,抱拳了!
回复 支持 反对

使用道具 举报

18

主题

155

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3882
金钱
3882
注册时间
2016-7-8
在线时间
817 小时
发表于 2023-7-25 16:59:38 | 显示全部楼层
受益匪浅
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
18
金钱
18
注册时间
2024-4-22
在线时间
6 小时
发表于 2024-6-26 16:05:53 | 显示全部楼层
顶顶楼主
回复 支持 反对

使用道具 举报

1

主题

2

帖子

0

精华

新手入门

积分
17
金钱
17
注册时间
2022-5-18
在线时间
2 小时
发表于 2024-8-13 23:29:19 | 显示全部楼层
顶一个
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 08:18

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表