基于ATmega128的DHT11溫濕度傳感器的使用
DHT11和DS18B20一樣,都是單總線芯片,同DHT10不同,它的四根引腳中有一條是空腳,與DS18B20相似,對(duì)時(shí)序的要求比較高,不同之處在于寫(xiě)程序的時(shí)候數(shù)據(jù)的采集必須間隔1s以上,不然采集會(huì)失敗。
還有,DHT11的數(shù)據(jù)口最好要接一個(gè)上拉電阻,或者單片機(jī)內(nèi)部上拉也可以。
DHT11的數(shù)據(jù)手冊(cè)網(wǎng)上有,上面有時(shí)序操作的詳細(xì)介紹。個(gè)人建議寫(xiě)這個(gè)程序的時(shí)候要一邊寫(xiě)一邊檢測(cè)(比如寫(xiě)完復(fù)位子程序之后就在主函數(shù)中調(diào)用它一次,看它是否執(zhí)行成功。。。),不然很可能到最后找不到錯(cuò)誤出在哪里,本人就是一直寫(xiě)完然后不好使,最后又重寫(xiě)的!
閑話不說(shuō)了,下面幫助大家分析一下DHT11的時(shí)序圖(數(shù)據(jù)手冊(cè)上有),因?yàn)镈HT11對(duì)時(shí)序的要求很高,所以很可能寫(xiě)完程序不好使。本人建議:延時(shí)子函數(shù)最好自己用示波器檢測(cè)一下,自己算出來(lái)的在10us下誤差會(huì)很大的。
進(jìn)入正題:下面我說(shuō)的話可以參照下面的程序看。
數(shù)據(jù)手冊(cè)前面的一些內(nèi)容自己了解就可以了,先看數(shù)據(jù)手冊(cè)上主機(jī)復(fù)位信號(hào)和DHT11相應(yīng)信號(hào)那部分。
主機(jī)先控制總線,拉低至少18ms,然后再拉高20~40us,(這時(shí)如果硬件沒(méi)有問(wèn)題的話DHT11會(huì)有響應(yīng)的)所以現(xiàn)在主機(jī)釋放總線(把DDRXN 寄存器清零),等待DHT11的響應(yīng),如果成功DHT11會(huì)產(chǎn)生40~50us的低電平,和40~50us的高電平。這里可以由程序完成檢測(cè)。
接下來(lái)在一次采集中,把總線一直交給DHT11,它會(huì)給主機(jī)傳送一個(gè)40位的二進(jìn)制數(shù),前0~7位是濕度的整數(shù)部分,8~15位是濕度的小數(shù)部分;16~23位是溫度的整數(shù)部分,24~31位是溫度的小數(shù)部分;最后八位是校驗(yàn)位。這些數(shù)據(jù)要通過(guò)程序進(jìn)行處理,轉(zhuǎn)換成溫濕度的實(shí)際值,并由顯示部分顯示出來(lái)。(本人用的是數(shù)碼管,建議用1602顯示會(huì)更方便一些)。
后面的處理部分我就不一一講解了,我在程序中是有注釋的,自己把程序加入到工程中看效果會(huì)好很多的,也可以用專門(mén)的閱讀軟件來(lái)看(source insignte),不然字體都一個(gè)顏色非常亂。
================================================
//這里是delay.h /*************我開(kāi)發(fā)板的晶振是16M的,具體的延時(shí)子函數(shù)要自己仔細(xì)寫(xiě)*************/
#ifndef __DELAY_H
#define __DELAY_H
void delay_us(unsigned int xus);
void delay_ms(unsigned int xms);
#endif
================================================
//這里是delay.c
#include"delay.h"
#include
//延時(shí)微妙子函數(shù)
void delay_us(unsigned int xus)
{
unsigned int i,j;
for(i=0;i
{
NOP();NOP();NOP();NOP();NOP();NOP();
NOP();NOP();NOP();NOP();
}
}
//延時(shí)毫秒子函數(shù)
void delay_ms(unsigned int xms)
{
unsigned int i,j;
for(i=0;i
{
for(j=0;j<2288;j++);
}
}
================================================
//這里是dht11.h
#ifndef __DHT11_H
#define __DHT11_H
#ifndef __IOM128V_H
#include
#endif
#ifndef __MACROS_H
#include
#endif
#define DDR_1 DDRC|=BIT(PC0)
#define DDR_0 DDRC&=~BIT(PC0)
#define PORTC_1 PORTC|=BIT(PC0)
#define PORTC_0 PORTC&=~BIT(PC0)
#define DQ (PINC&0x01)
void caiji(void);
long int dht(void);
void init_dht11(void);
//void ceshi(void);
#endif
================================================
//這里是dht11.c
#include"dht11.h"
unsigned char dht_data[5],a,b;
unsigned int s1,s0,t1,t0,sd,wd,wsd;
void caiji(void)
{
unsigned char i,j;
//delay_ms(900);
for(i=0;i<5;i++)
{
dht_data[i]=0x00; //數(shù)組清零
for(j=0;j<8;j++)
{
while(!DQ); //判斷是否為高電平
//延時(shí)50us若為高電平則為一,否則為零
delay_us(50);
if(DQ)
{
dht_data[i]|=BIT(7-j); //保存數(shù)據(jù)
while(DQ);//低電平檢測(cè)
}
}
}
}
void init_dht11(void)
{
DDR_1; //設(shè)置主機(jī)輸出
PORTC_0; //總線拉低至少18ms
delay_ms(20);
PORTC_1; //總線由主機(jī)拉高大約30us
delay_us(30);
DDR_0; //主機(jī)設(shè)置為輸入,檢測(cè)從機(jī)信號(hào)
while(DQ);
}
long int dht(void)
{
init_dht11();
if(!DQ)
{
while(!DQ);
while(DQ); //經(jīng)以上兩句后開(kāi)始接收信號(hào)
caiji();
DDR_1;
PORTC_1;
//校驗(yàn)
a=
(
dht_data[0]+dht_data[1]+dht_data[2]+dht_data[3]
);
if(a==dht_data[4])
{
s1=dht_data[0];
s0=dht_data[1];
t1=dht_data[2];
t0=dht_data[3];
}
//s為濕度,t為溫度
sd=s1;
sd<<=8;
sd|=s0;
wd=t1;
wd<<=8;
wd|=t0;
wsd=sd<<16;
wsd|=wd;
}
return wsd;
}
================================================
//這里是xianshi.h
#ifndef __XIANSHI_H
#define __XIANSHI_H
#ifndef __IOM128V_H
#include
#endif
#define SCK_0 PORTB&=~(1<
#define SCK_1 PORTB|=(1<
#define LCK_0 PORTB&=~(1<
#define LCK_1 PORTB|=(1<
#define SDI_0 PORTB&=~(1<
#define SDI_1 PORTB|=(1<
void init(void);
void send_595(unsigned char dat);
void digitron_show(unsigned int int_part,unsigned int float_part);
#endif
================================================
//這里是xianshi.c
#include"xianshi.h"
#ifndef __DELAY_H
#include"delay.h"
#endif
#ifndef __DHT11_H
#include"dht11.h"
#endif
//數(shù)碼管顯示數(shù)組定義
const unsigned char table[]=
{
0x3F,// 0
0x06,// 1
0x5B,// 2
0x4F,// 3
0x66,// 4
0x6D,// 5
0x7D,// 6
0x07,// 7
0x7F,// 8
0x6F,// 9
0x3F+0x80,// 0.
0x06+0x80,// 1.
0x5B+0x80,// 2.
0x4F+0x80,// 3.
0x66+0x80,// 4.
0x6D+0x80,// 5.
0x7D+0x80,// 6.
0x07+0x80,// 7.
0x7F+0x80,// 8.
0x6F+0x80// 9.
};
unsigned int s,t,st,int_part,float_part,temp,SH;
//發(fā)送一字節(jié)數(shù)據(jù)到595
void send_595(unsigned char dat)
{
unsigned char i;
LCK_0;
SDI_1;
SCK_0;
//上面的三條語(yǔ)句為了初始化端口狀態(tài)
for(i=0;i<8;i++)
{
LCK_0;//時(shí)鐘線拉低
if(dat&0x80)
SDI_1;
else SDI_0;
dat=dat<<1;
delay_us(100);
LCK_1; //時(shí)鐘線拉高將數(shù)據(jù)讀入595的移位寄存器
delay_us(100);
}
SCK_1; //發(fā)送數(shù)據(jù)到并行端口
SCK_0;
}
void show(void)
{
unsigned char temp_shi,temp_ge,SH_shi,SH_ge,x,y;
unsigned int i;
st=dht();
t=st&0x0000ffff;
s=st&0xffff0000;
s=s>>16;
//下面為把溫度和濕度換算成十進(jìn)制并且四舍五入
temp=(t>>8);
temp_shi=temp/10;
temp_ge=temp%10;
SH=(s>>8);
SH_shi=SH/10;
SH_ge=SH%10;
int_part=SH_shi*10+SH_ge;
float_part=0;
for(i=0;i<50;i++)
{
digitron_show(int_part,float_part);
}
}
void digitron_show(unsigned int int_part,unsigned int float_part)
{
PORTA=0x01;
send_595(table[float_part/10]);
send_595(0x00);
delay_ms(5);
PORTA=0x02;
send_595(table[(int_part%10)+10]);
send_595(0x00);
delay_ms(5);
PORTA=0x04;
send_595(table[int_part/10]);
send_595(0x00);
delay_ms(5);
}
================================================
//這里是MAIN.C
#include
#include
#include"delay.h"
#include"dht11.h"
#include"xianshi.h"
#pragma interrupt_handler Timer0_COMP:16
#define uchar unsigned char
uchar k=0;
void init(void);
void main()
{
init();//初始化
TCCR0=0X0F;
DDRA=0XFF;
TCCR0=0X0f;//CTC模式
OCR0=145;//10ms
TIMSK=0X02;
SEI();
while(1);
}
//初始化子函數(shù)
void init(void)
{
DDRA=0XFF;
DDRB=0XFF;
}
void Timer0_COMP(void)
{
TCCR0=0X08;
CLI();
k++;
if(k==255)
{
k=0;
show();
}
TCCR0=0X0f;//重置初值
SEI();
}