Qt实现天气预报与PM2.5监测系统(4)DHT11模块驱动
硬件模块说明
器件(奥松 dht11)
DC:3.3-5.5v
温度:0 - 50°C (±2°C)
湿度:20 - 95 %RH(±5%)
DHT11应用电路
在使用时应在数据端加一个5K的上拉电阻。
工作时序图
初始化时序
读取数据0时序
读取数据1时序
DHT11驱动开发问题
不同频率CPU引起的时序操作问题
1.初始化时序不要加入无关操作,如调试,输出,减少对时序的影响。
2.时序操作连续化,单片机上可多次调用函数读取,但在高主频的CPU上要一次读取全部数据后再进行后期处理。
驱动程序
dht11驱动程序
nanopi2开发板的驱动开发流程可参考文档 :基于NanoPi2的Linux3.4内核GPIO驱动
/********************************************
功能:DHT21 在nanopi2 s5p4418上驱动程序
GPIO=GPB26
********************************************/
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <mach/platform.h>
#include <mach/devices.h>
#define DEVICE_NAME "dht11"
//nanopi2 4418
unsigned int GPIO = PAD_GPIO_B + 26;//模块GPIO脚
#define DPRINTK(x...) printk("<0>"x);
//#define DPRINTK(x...)
typedef unsigned char U8;
U8 U8comdata,U8temp[40],U8_data[5];
int init_dht(void)
{
int l_flag=0,h_flag=0,flag=0;
int i=0,j=0;
int bit_flag[40];
unsigned tmp;
DPRINTK("DHT11 init...");
//GPIO设置为输出
gpio_direction_output(GPIO, 0);//设置输出
//输出0
gpio_set_value(GPIO, 0); //输出低电平
//延时19ms
mdelay(20);
//输出1
gpio_set_value(GPIO, 1); //输出高电平
//延时30us
udelay(40);
//设置为输入
gpio_direction_input(GPIO);//设置输入
//读GPIO
tmp = gpio_get_value(GPIO) ;
// DPRINTK("gpio=%d\n",tmp);
if(!tmp)
{
while(!(gpio_get_value(GPIO)) ){
if((l_flag++)>85) break;
udelay(1);
}//从机80us低电平
while(gpio_get_value(GPIO)){
if((h_flag++)>85) break;
udelay(1);
}//从机80us高电平
//read 40bit data
for(i=0;i<40;i++){
flag = 0;
while(!(gpio_get_value(GPIO)) ){
if((flag++)>70) break;
udelay(1);
}//从机50us低电平
flag =0;
while(gpio_get_value(GPIO) ){
if((flag++)>90) break;
udelay(1);
}//从机高电平//高电平大于70us为"1",否则26-28us为"0"
if(flag>30){
U8temp[i]=1;
}else{
U8temp[i]=0;
}
bit_flag[i]=flag;
}
for(i=0;i<40;i++){
U8comdata<<=1;
U8comdata|=U8temp[i];
if((i+1)%8 == 0){
U8_data[j]=U8comdata;
j++;
}
DPRINTK("[%d]flag=%d,val=%d--",i,bit_flag[i],U8temp[i]);
}
DPRINTK("L 80us flag=%d\n",l_flag);
DPRINTK("H 80us flag=%d \n",h_flag);
}else{DPRINTK("L err..\n");}
return 0;
}
static int dht_read(struct file *file, char * buffer, size_t count, loff_t * ppos)
{
init_dht();
count = copy_to_user(buffer, U8_data, count);
return count;
}
static struct file_operations dht_fops={
read:dht_read,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dht_fops,
};
static int __init my_dht_init(void)
{
int ret;
ret = misc_register(&misc);
printk(DEVICE_NAME " initialized\n");
return 0;
}
static void __exit my_dht_exit(void)
{
misc_deregister(&misc);
}
module_init(my_dht_init);
module_exit(my_dht_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("TONY");
驱动模块加载到内核
1. 在主机的linux系统编译好驱动模块 :4418_dht11.ko
2. 传文件到开发板 :sudo scp 4418_dht11.ko fa@192.168.199.109:/home/fa
3. 在开发板设置文件权限:sudo chmod 111 4418_dht11.ko
4. 通过insmod命令加载模块到内核,结果如下图。
dht11数据读取测试程序
#include<stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#define DEV_F_DHT "/dev/dht11"
int get_dht_data(const int fd,float* temp,float* humi);
int main(int argc,char* argv[])
{
float ftemp=0.0,fhumi=0.0;
int fd_dht = -1;
if( (fd_dht = open(DEV_F_DHT,O_RDWR)) < 0){
printf("dht11 init error...\n");
return -1;
}else{
printf("dht11 init...\n");
}
while(1){
if(get_dht_data(fd_dht,&ftemp,&fhumi)==0){
//读取到数据,可进行后续操作
}
sleep(3);
}
}
int get_dht_data(const int fd,float* temp,float* humi)
{
char crr;
int s;
char data[5];
int temp_d=0,humi_d=0;
bzero(data,5);
read(fd,data,5);
crr = 0;
for(s=0;s<4;s++){
printf("data[%d]=%x\n",s,data[s]);
crr+=data[s];
}
printf("data[4]=%x,crr=%x\n",data[4],crr);
if(crr==data[4]){
humi_d = data[0];
temp_d = data[2];
*humi = humi_d;
*temp = temp_d;
printf("\n+---RH=%d %%,T=%d oC.\n",humi_d,temp_d);
}else{
printf("crr err %X\n",crr);
return -1;
}
return 0;
}
测试程序运行结果