将DHT11与PIC16F877A连接进行温度和湿度的测量

描述

  温度和湿度测量通常在家庭自动化、环境监测、气象站等许多应用中很有用。LM35旁边最常用的温度传感器是 DHT11,我们之前通过与Arduino和Raspberry连接构建了许多DHT11 项目Pi和许多其他开发板。在本文中,我们将学习如何将此DHT11 与 PIC16F87A连接,这是一个 8 位 PIC 微控制器。我们将使用这个微控制器通过 DHT11 读取温度和湿度的值并将其显示在液晶显示器上。

  DHT11 – 规范和工作

  DHT11 传感器以模块形式或传感器形式提供。在本教程中,我们使用的是传感器,两者之间的唯一区别在于,在模块形式中,传感器具有一个滤波电容和一个连接到传感器输出引脚的上拉电阻。因此,如果您正在使用该模块,则无需在外部添加它们。传感器形式的 DHT11 如下所示。

DHT11

  DHT11 传感器带有蓝色或白色外壳。 在这个外壳内,我们有两个重要的组件 可以帮助我们感知相对湿度和温度。 第一个组件是一对电极;这两个电极之间的电阻由保持水分的基板决定。所以测得的电阻与环境的相对湿度成反比。相对湿度越高,电阻值越低,反之亦然。另外,请注意相对湿度与实际湿度不同。相对湿度测量空气中相对于空气温度的水含量。

  另一个组件是表面贴装的 NTC 热敏电阻。术语 NTC 代表负温度系数,随着温度的升高,电阻值将减小。传感器的输出经过工厂校准,因此作为程序员,我们不必担心校准传感器。1-Wire通信给出的传感器输出,我们看一下这个传感器的引脚和连接图。

DHT11

  该产品采用 4pin 单排封装。第 1 个引脚跨接 VDD,第 4 个引脚跨接 GND。第二个引脚是数据引脚,用于通信目的。该数据引脚需要一个 5k 的上拉电阻。但是,也可以使用其他上拉电阻,例如 4.7k 到 10k。第 3 个引脚没有连接任何东西。所以它被忽略了。

  数据表提供了技术规格以及可以在下表中看到的接口信息 -

DHT11

  上表显示了温度和湿度的测量范围和精度。它可以测量 0-50 摄氏度的温度,精度为 +/- 2 摄氏度,测量相对湿度 20-90%RH,精度为 +/- 5%RH。详细规格见下表。

DHT11

  与 DHT11 传感器通信

  如前所述,为了使用 PIC 从DHT11读取数据,我们必须使用PIC 单线通信协议。有关如何执行此操作的详细信息,可以从其数据表中的 DHT 11 的接口图了解,如下所示。

DHT11

  DHT11 需要来自 MCU 的启动信号来启动通信。因此,每次 MCU 都需要向 DHT11 Sensor 发送启动信号,要求其发送温度和湿度值。在完成启动信号后,DHT11 会发送一个 包含温度和湿度信息的响应信号。数据通信采用单总线数据通信协议。全数据长度为 40 位,传感器先发送高位数据。

DHT11

  由于上拉电阻,数据线在空闲模式下始终保持在 VCC 电平。MCU 需要将此电压从高到低拉低至少 18 毫秒。在此期间,DHT11 传感器检测到启动信号,微控制器将数据线拉高 20-40us。这 20-40us 的时间称为 DHT11 开始响应的等待期。在这个等待期之后,DHT11 将数据发送到微控制器单元。

  DHT11 传感器数据格式

  数据由组合在一起的小数部分和整数部分组成。传感器遵循以下数据格式 -

  8bit 积分 RH 数据 + 8bit 十进制 RH 数据 + 8bit 积分 T 数据 + 8bit 十进制 T 数据 + 8bit 校验和。

  可以通过使用接收到的数据检查校验和值来验证数据。可以这样做是因为,如果一切正常,并且传感器已经传输了正确的数据,那么校验和应该是“8 位 RH 积分数据+8 位十进制 RH 数据+8 位积分 T 数据+8 位十进制 T 数据”之和。

  所需组件

  对于这个项目,需要以下内容 -

  PIC单片机(8位)编程设置。

  面包板

  5V 500mA 电源装置。

  4.7k电阻2个

  1k电阻

  PIC16F877A

  20mHz晶体

  33pF电容2个

  16x2 字符 LCD

  DHT11传感器

  跳线

  示意图

  将DHT11 与 PIC16F877A连接的电路图如下所示。

DHT11

  我们使用16x2 LCD来显示我们从 DHT11 测量的温度和湿度值。LCD 采用4 线模式连接,传感器和 LCD 均由 5V 外部电源供电。我使用面包板进行所有必需的连接,并使用了外部 5V 适配器。您还可以使用此面包板电源板为您的电路板供电 5V。

DHT11

  电路准备好后,我们要做的就是上传本页底部给出的代码,我们可以开始读取温度和湿度,如下所示。如果您想知道代码是如何编写的以及它是如何工作的,请进一步阅读。您还可以在本页底部的视频中找到该项目的完整工作。

DHT11

DHT11 with PIC MPLABX 代码说明

代码使用 MPLABX IDE 编写,并使用 XC8 编译器编译,两者均由 Microchip 提供,可免费下载和使用。请参考基础教程了解编程基础知识,下面只讨论与 DHT11 传感器通信所需的三个重要功能。功能是 -

 

无效 dht11_init(); 
无效查找响应();
char read_dht11();

 

第一个函数用于dht11 的启动信号。如前所述,与 DHT11 的每次通信都以启动信号开始,这里首先更改引脚方向以将数据引脚配置为微控制器的输出。然后数据线被拉低,一直等待18mS。之后,微控制器再次将线路设为高电平,并一直等待长达 30us。等待时间过后,数据引脚设置为微控制器的输入以接收数据。

 

无效 dht11_init(){ 
DHT11_Data_Pin_Direction= 0; //配置RD0为输出
DHT11_Data_Pin = 0; //RD0向传感器发送0 
__delay_ms(18); 
DHT11_Data_Pin = 1;//RD0向传感器发送1 
__delay_us(30); 
DHT11_Data_Pin_Direction = 1;//配置RD0为输入
}

 

下一个函数用于根据数据引脚状态设置校验位。它用于检测 DHT11 传感器的响应。

 

无效 find_response(){ 
Check_bit = 0; 
__delay_us(40); 
if (DHT11_Data_Pin == 0){ 
__delay_us(80); 
if (DHT11_Data_Pin == 1){ 
            Check_bit = 1; 
}           
__delay_us(50);} 
}

 

最后是dht11读取函数;此处数据被读取为 8 位格式,其中数据通过位移操作返回,具体取决于数据引脚状态。

 

char read_dht11(){ 
char 数据,for_count; 
for(for_count = 0; for_count < 8; for_count++){ 
            while(!DHT11_Data_Pin); 
            __delay_us(30); 
            if(DHT11_Data_Pin == 0){ 
            data&= ~(1<<(7 - for_count)); //清除位 (7-b) 
            } 
            else{ 
            data|= (1 << (7 - for_count)); //设置位 (7-b) 
            while(DHT11_Data_Pin); 
            } 
            }
返回数据;
}

 

​​​

之后,一切都在 main 函数中完成。首先,系统初始化在 LCD 被初始化并将 LCD 引脚端口方向设置为输出的地方完成。应用程序在主函数内部运行

 

无效 main() { 
system_init(); 
while(1){ 
            __delay_ms(800); 
            dht11_init(); 
            查找响应();
            if(Check_bit == 1){ 
            RH_byte_1 = read_dht11(); 
            RH_byte_2 = read_dht11(); 
            Temp_byte_1 = read_dht11(); 
            Temp_byte_2 = read_dht11(); 
            求和 = read_dht11(); 
            if(Summation == ((RH_byte_1+RH_byte_2+Temp_byte_1+Temp_byte_2) & 0XFF)){
            湿度 = Temp_byte_1; 
            RH = RH_byte_1;                                
            lcd_com (0x80);                       
            lcd_puts("温度:");
            //lcd_puts(""); 
            lcd_data(48 + ((湿度/10) % 10)); 
            lcd_data(48 + (湿度 % 10)); 
            液晶数据(0xDF);
            lcd_puts("C"); 
            lcd_com (0xC0);          
            lcd_puts("湿度:"); 
            //lcd_puts(""); 
            lcd_data(48 + ((RH / 10) % 10)); 
            lcd_data(48 + (RH % 10)); 
            lcd_puts("%"); 
            } 
            else{ 
            lcd_puts("校验和错误"); 
            } 
            }
            其他 { 
            clear_screen(); 
            lcd_com (0x80);
            lcd_puts("错误!!!"); 
            lcd_com (0xC0); 
            lcd_puts("没有反应。"); 
            } 
            __delay_ms(1000); 
} 
}

 

  与 DHT11 传感器的通信是在while循环中完成的,在该循环中将启动信号提交给传感器。之后,触发find_response函数。如果Check_bit为 1,则进行进一步的通信,否则 LCD 将显示错误对话框。

  根据 40 位数据,read_dht11被调用 5 次(5 次 x 8 位),并按照数据表中提供的数据格式存储数据。校验和状态也被检查,如果发现错误,它也会在 LCD 中通知。最后,数据被转换并传输到 16x2 字符 LCD。

#include

#include


#include "supporting_cfile/lcd.h"


#pragma config FOSC = HS // 振荡器选择位(HS 振荡器)

#pragma config WDTE = OFF // 看门狗定时器使能位(WDT 禁用)

#pragma config PWRTE = ON // 上电定时器使能位(PWRT 使能)

# pragma config BOREN = ON // 欠压复位使能位(BOR 使能)

#pragma config LVP = OFF // 低电压(单电源)在线串行编程使能位(RB3 为数字 I/O,HV 开启MCLR 必须用于编程)

#pragma config CPD = OFF // 数据 EEPROM 存储器代码保护位(数据 EEPROM 代码保护关闭)

#pragma config WRT = OFF // 闪存程序存储器写使能位(写保护关闭;所有程序存储器可由 EECON 控制写入)

#pragma config CP = OFF // Flash 程序存储器代码保护位(代码保护关闭)



/*

程序流程相关定义

*/

#define DHT11_Data_Pin PORTDbits.RD5

#define DHT11_Data_Pin_Direction TRISDbits.TRISD5

#define FIRST_LINE 0x80

#define SECOND_LINE 0xC0



#define _XTAL_FREQ 20000000 //20 Mhz


unsigned char Check_bit, Temp_byte_1, Temp_byte_2, RH_byte_1, RH_byte_2;

unsigned char Himudity, RH, Sumation ;


//dht11相关定义


无效 dht11_init();

无效查找响应();

char read_dht11();


// 系统相关定义


无效系统初始化(无效);

无效介绍屏幕(无效);

无效清除屏幕(无效);


无效 main() {

system_init();



while(1){

__delay_ms(800);

dht11_init();

查找响应();

if(Check_bit == 1){

RH_byte_1 = read_dht11();

RH_byte_2 = read_dht11();

Temp_byte_1 = read_dht11();

Temp_byte_2 = read_dht11();

求和 = read_dht11();

if(Sumation == ((RH_byte_1+RH_byte_2+Temp_byte_1+Temp_byte_2) & 0XFF)){

Himudity = Temp_byte_1;

RH = RH_byte_1;

lcd_com (0x80);

lcd_puts("温度:");

//lcd_puts("");

lcd_data(48 + ((Himudity / 10) % 10));

lcd_data(48 + (湿度 % 10));

液晶数据(0xDF);

lcd_puts("C");

lcd_com (0xC0);

lcd_puts("湿度:");

//lcd_puts("");

lcd_data(48 + ((RH / 10) % 10));

lcd_data(48 + (RH % 10));

lcd_puts("%");

}

else{

lcd_puts("校验和错误");

}

}

其他 {

clear_screen();

lcd_com (0x80);

lcd_puts("错误!!!");


lcd_puts("没有反应。");

}

__delay_ms(1000);

}

}


/*

* 这将初始化 dht22 传感器。

*/


无效 dht11_init(){

DHT11_Data_Pin_Direction= 0; //配置RD0为输出

DHT11_Data_Pin = 0; //RD0向传感器发送0

__delay_ms(18);

DHT11_Data_Pin = 1;//RD0向传感器发送1

__delay_us(30);

DHT11_Data_Pin_Direction = 1;//配置RD0为输入

}


/*

* 这将发现 dht22 传感器是否工作。

*/


无效 find_response(){

Check_bit = 0;

__delay_us(40);

if (DHT11_Data_Pin == 0){

__delay_us(80);

if (DHT11_Data_Pin == 1){

Check_bit = 1;

}

__delay_us(50);}

}



/*

此函数用于读取 dht22。

*/



char read_dht11(){

char data, for_count;

for(for_count = 0; for_count < 8; for_count++){

while(!DHT11_Data_Pin);

__delay_us(30);

if(DHT11_Data_Pin == 0){

data&= ~(1<<(7 - for_count)); //清除位 (7-b)

}

else{

data|= (1 << (7 - for_count)); //设置位 (7-b)

while(DHT11_Data_Pin);

} //等到 PORTD.F0 变低

}

返回数据;

}



void system_init(){

TRISB = 0; // LCD 引脚设置为输出。

液晶初始化();

介绍屏幕();

//dht11_init();

}



/*

这个函数是为了在没有命令的情况下清除屏幕。

*/


void clear_screen(void){

lcd_com(FIRST_LINE);

lcd_puts("");

lcd_com(第二行);

lcd_puts("");

}




/*

此函数用于播放介绍。

*/


void Introduction_screen(void){

lcd_com(FIRST_LINE);

lcd_puts("欢迎来到");

lcd_com(第二行);

lcd_puts("电路文摘");

__delay_ms(1000);

__delay_ms(1000);

清除屏幕();

lcd_com(FIRST_LINE);

lcd_puts("DHT11 传感器");

lcd_com(第二行);

lcd_puts("用 PIC16F877A");

__delay_ms(1000);

__delay_ms(1000);

}

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分