【全志T113-S3_100ask】11-编写驱动采集dht11数据

背景

继上一节飞线控制继电器之后,蠢蠢欲动,想要再向lcd借一个io来采集温湿度数据。
想使用内核自带的dht11驱动程序,但是不知道为啥开启 IIO 后就会编译不通过?所以采用原始的驱动编写方案。
本节参考 https://www.freesion.com/article/37271307334/

(一)寻找合适的IO、处理

本节使用的GPIO为 PD14 ,飞线~
在这里插入图片描述
接上dht11。
在这里插入图片描述

(二)DHT11简介

1、外观
在这里插入图片描述

2、电路
在这里插入图片描述
引脚说明

pin名称注释
1VDD供电 3-5.5VDC
2DATA串行数据,单总线
3NC空脚
4GND接地,电源负极

3、量程精度
DHT11是一款有已校准数字信号输出的温湿度传感器。 其精度湿度±5%RH, 温度±2℃,量程湿度5~95%RH, 温度-20~+60℃。

4、电气特性
供电 电压3.3~5.5V DC
输出 单总线数字信号

(三)修改设备树

添加一级子节点

/*添加DHT11的设备树文件*/
 dht11{
     pinctrl-1 =<&dth_11_pin>;/*dht11的pin管脚属性来自dtsi文件*/
     compatible = "dth-11";
     pinctrl-names = "default";
     status = "okay";
     dht11_pin@1{
         /*配置dht11所属管脚的io口*/
         gpios = <&pio PD 14 GPIO_ACTIVE_HIGH>;/*管脚是接在gpk3-0上面*/
         label = "dht_11";
         linux,default-trigger = "heartbeat";
         linux,default-trigger-delay-ms = <0>;
     };
 };

添加引脚控制

/*增加dht_11的pinctrl控制*/
dth_11_pin:dht_11_pin{
	allwinner,pins = "PD14"; /*dht11的时钟和数据线接PD14上面*/
};

实例:
在这里插入图片描述

(四)编写驱动程序

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>

#include <linux/of_gpio.h>

#define DEVICE_NAME	"dht11_ctl"//设备名称
#define DRIVER_NAME "dht11_ctl"

uint32_t dth11_pin = 0;//定义dht11的管脚属性
struct dht11_data
{
    u_int16_t temp;//温度
    u_int16_t hmi;//湿度
};


#define delay_us(x)		udelay(x)
#define delay_ms(x)		msleep(x)

static u8 dht11_read_io(void)    
{
	gpio_direction_input(dth11_pin);
	return gpio_get_value(dth11_pin);
}

//复位DHT11
static void dht11_rst(void)   
{                 
	gpio_direction_output(dth11_pin, 0);
	msleep (20);  //拉低至少18ms
	gpio_direction_output(dth11_pin, 1); //DQ=1 
	delay_us (30);  //主机拉高20~40us
}

//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
static u8 dht11_check(void)    
{   
	u8 retry=0;//定义临时变量
	gpio_direction_input(dth11_pin);//设置io口为输入模式
	while ((dht11_read_io()==1)&&retry<100)//DHT11会拉低40~80us
	{
		retry++;
		delay_us(1);
	}; 
	if(retry>=100)return 1;
	else retry=0;
	while ((dht11_read_io()==0)&&retry<100)//DHT11拉低后会再次拉高40~80us
	{
		retry++;
		delay_us(1);
	};
	if(retry>=100)return 1;    
	return 0;
}

//从DHT11读取一个位
//返回值:1/0
static u8 dht11_read_bit(void)  
{
	u8 retry=0;
	while((dht11_read_io()==1)&&retry<100)//等待变为低电平
	{
		retry++;
		delay_us(1);
	}
	retry=0;
	while((dht11_read_io()==0)&&retry<100)//等待变高电平
	{
		retry++;
		delay_us(1);
	}
	delay_us(40);//等待40us
	if(dht11_read_io()==1)
	return 1;
	else 
	return 0;   
}
/*读取一个byte*/
static u8 dht11_read_byte(void)    
{        
    u8 i,dat;
    dat=0;
	for (i=0;i<8;i++) 
	{
		dat<<=1; 
		dat|=dht11_read_bit();//读取一个位
	}    
	return dat;
}
 
/*从DHT11中取出温度和湿度数据*/
static u8 dht11_read_data(u_int16_t *temp,u_int16_t *humi)    
{        
	u8 buf[5];
	u8 i;
	dht11_rst();
	if(dht11_check()==0)
	{
		for(i=0;i<5;i++)//读取40位数据
		{
			buf[i]=dht11_read_byte();//读取一个数据
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
		{
			*humi=buf[0]<<8|buf[1];
			*temp=buf[2]<<8|buf[3];
			printk("readout data:buf=%d,%d,%d,%d,%d\n",buf[0],buf[1],buf[2],buf[3],buf[4]);
		} else printk("readout data[error]:buf=%d,%d,%d,%d,%d\n",buf[0],buf[1],buf[2],buf[3],buf[4]);
	}else return 1;
	return 0;    
}


/*检测dht11所连接的io口的状态*/
static void dht11_init(void)
{     
	dht11_rst();  //复位DHT11
	dht11_check();//等待DHT11的回应
}



/*dht11读函数*/
ssize_t dht11_read(struct file *file, char __user *user, size_t bytesize, loff_t *this_loff_t)
{
    struct dht11_data this_data;//得到当前的温度和湿度信息
	if(dht11_read_data(&this_data.temp,&this_data.hmi) == 0);//读取温湿度值 
	{
        //将温度和湿度信息拷贝到user指针中
		if ( copy_to_user(user,&this_data,sizeof(this_data)) )
		{
			return EFAULT ;
		}
	}
}


/*dht11设备节点打开函数*/
int dht11_open(struct inode *inode, struct file *file)
{
    printk("--------------%s--------------\n",__FUNCTION__);
	return 0;
}

/*设备节点关闭*/
int dht11_close(struct inode *inode, struct file *file)
{
    return 0;//返回0
}
/*ioctl读取函数*/
long dht11_ioctl(struct file *file, unsigned int item, unsigned long long_item)
{
    return 0;
}

/*dht11文件结构体*/
static struct file_operations dht11_ops = {
	.owner			= THIS_MODULE,
	.open			= dht11_open,
	.release		= dht11_close, 
	.unlocked_ioctl	= dht11_ioctl,
	.read			= dht11_read
};

/*将DHT11注册为杂项*/
static struct miscdevice dht11_misc_dev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEVICE_NAME,
	.fops = &dht11_ops,
};


/*probe 函数*/
static int dht11_probe(struct platform_device *pdev)
{
	int ret;
    enum of_gpio_flags flag;//(flag == OF_GPIO_ACTIVE_LOW) ?
    struct device_node *dht11_gpio_node = pdev->dev.of_node; 
	
	dth11_pin = of_get_named_gpio_flags(dht11_gpio_node->child, "gpios", 0, &flag); 

	if (!gpio_is_valid(dth11_pin)) 
	{
    	printk("dht11-gpio: %d is invalid\n", dth11_pin); 
		return -ENODEV;
    }
	else
		printk("dht11-gpio: %d is valid!\n", dth11_pin);
	if (gpio_request(dth11_pin, "dht11-gpio")) 
	{ 
        printk("gpio %d request failed!\n", dth11_pin); 
        gpio_free(dth11_pin); 
        return -ENODEV;
    }
	else
		printk("gpio %d request success!\n", dth11_pin);

    /**/
    ret = misc_register(&dht11_misc_dev);//注册设备为杂项设备
    msleep(100);//延时100毫秒
    printk(DEVICE_NAME "\tinitialized\n");
    dht11_init();//初始化一次系统
	return 0;
}


static int dht11_remove (struct platform_device *pdev)
{
	misc_deregister(&dht11_misc_dev);
	gpio_free(dth11_pin);	

	return 0;
}

static int dht11_suspend (struct platform_device *pdev, pm_message_t state)
{
	printk("dht11 suspend off\n");
	return 0;
}

static int dht11_resume (struct platform_device *pdev)
{
	printk("dht11 resume on!\r\n");
	return 0;
}

/*匹配设备树驱动*/
static const struct of_device_id dht11_of_match[] = {
        { .compatible = "dth-11" },
        { /* sentinel */ }
};
/**/
MODULE_DEVICE_TABLE(of, dht11_of_match);

/*注册平台驱动*/
static struct platform_driver dht11_driver = {
	.probe = dht11_probe,
	.remove = dht11_remove,
	.suspend = dht11_suspend,
	.resume = dht11_resume,
	.driver = {
		.name = DRIVER_NAME,
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(dht11_of_match),
	},
};

/*设备驱动挂载函数*/
static int __init dht11_dev_init(void) {
    printk("dht 11 driver config successfully\r\n");
	return platform_driver_register(&dht11_driver);
}

/*设备驱动退出函数*/
static void __exit dht11_dev_exit(void) {
	platform_driver_unregister(&dht11_driver);
}

module_init(dht11_dev_init);
module_exit(dht11_dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhu");

(五)编写测试程序

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

typedef unsigned char u8;
typedef unsigned short u16;

typedef struct DHT11_SENSOR_DATA
{
    u16 temp; //温度
    u16 hum;  //湿度
} dht11_data;

int main(void)
{
    int fd;
    int retval;
    dht11_data Curdht11_data;
    fd = open("/dev/dht11_ctl", O_RDONLY);
    if (fd == -1)
    {
        perror("open dht11 error\n");
        exit(-1);
    }
    printf("open /dev/dht11 successfully\n");
    sleep(2);
    while (1)
    {
        sleep(1);
        retval = read(fd, &Curdht11_data, sizeof(Curdht11_data));
        if (retval == -1)
        {
            perror("read dht11 error");
            printf("read dht11 error");
            exit(-1);
        }
        if (Curdht11_data.temp != 0xffff)
            printf("Temperature:%d.%d C,Humidity:%d.%d %%RH\n", Curdht11_data.temp >> 8, Curdht11_data.temp & 0xff,
                   Curdht11_data.hum >> 8, Curdht11_data.hum & 0xff);
    }
    close(fd);
}

(六)测试

1、加载驱动

# ls
dht11_drv.ko    dht11_drv_test

# insmod dht11_drv.ko
[   96.495500] dht11_drv: loading out-of-tree module taints kernel.
[   96.502984] dht 11 driver config successfully
[   96.508621] dht11-gpio: 110 is valid!
[   96.513480] gpio 110 request success!
[   96.629170] dht11_ctl        initialized

2、采集数据

./dht11_drv_test

[  104.381110] --------------dht11_open--------------
open /dev/dht11 successfully
[  107.423020] readout data:buf=43,0,28,4,75
Temperature:28.4 C,Humidity:43.0 %RH
[  108.462984] readout data:buf=37,0,29,6,72
Temperature:29.6 C,Humidity:37.0 %RH
[  109.503063] readout data:buf=37,0,29,7,73
Temperature:29.7 C,Humidity:37.0 %RH
[  110.542978] readout data:buf=37,0,29,6,72
Temperature:29.6 C,Humidity:37.0 %RH
[  111.583015] readout data:buf=37,0,29,6,72
Temperature:29.6 C,Humidity:37.0 %RH
[  112.623035] readout data:buf=37,0,29,5,71
Temperature:29.5 C,Humidity:37.0 %RH
[  113.662978] readout data:buf=37,0,29,6,72
Temperature:29.6 C,Humidity:37.0 %RH
[  114.703069] readout data:buf=37,0,29,5,71
Temperature:29.5 C,Humidity:37.0 %RH

至此测试完毕

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

第四维度4

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值