【全志T113-S3_100ask】11-编写驱动采集dht11数据
背景
继上一节飞线控制继电器之后,蠢蠢欲动,想要再向lcd借一个io来采集温湿度数据。
想使用内核自带的dht11驱动程序,但是不知道为啥开启 IIO 后就会编译不通过?所以采用原始的驱动编写方案。
本节参考 https://www.freesion.com/article/37271307334/
(一)寻找合适的IO、处理
本节使用的GPIO为 PD14 ,飞线~
接上dht11。
(二)DHT11简介
1、外观
2、电路
引脚说明
pin | 名称 | 注释 |
---|---|---|
1 | VDD | 供电 3-5.5VDC |
2 | DATA | 串行数据,单总线 |
3 | NC | 空脚 |
4 | GND | 接地,电源负极 |
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
至此测试完毕