单片机控制单总线协议湿度温度传感器DHT11之模块化编程(持续更新中)

这里将我写的STC12C5A60S2单片机控制湿度温度传感DHT11的程序共享一下,是为了让前辈给予斧正。

更新: 

2014/06/29 09:01 在结构体DHT11_info中定义了DHT11_CRC,实际上此校验不属于CRC校验,定义名称不合适,

需要修改,这里只做声明,请自行修改

2014/05/31 提供修改方法,适用于不同型号的51单片机(文章最后)

2014/05/27 10:07(DHT11ReadByte(void)函数修改,修改内容已在DHT11.C中Modification部分讲述,为了便于理解修改细节,不涉及功能调试)

2014/04/26 18:04 (重新调试完成)

2014/04/26 17:50 (发现程序有问题,湿度整数部分超过100,重新调试)

2014/04/03 11:25

2014/03/31 15:17

(补充:以下代码只需要修改.h文件中含有 “选择” 字样的部分,就可以达到复用的效果)

对于串口调试部分,请参考《单片机程序协助调试方法(一)串口调试点击进入

实验对象:

实验现象:


 



测试程序:

#include <reg52.h>
#include "common.h"
#include "uart.h"
#include "DHT11.h"


void main(void)
{ 
	UB8 i=0;	
	DHT11_info  dataCode ;

	UartInit() ;

#if 0 //临时测试DHT11的存在与否
	P1=0x00 ;//led
	if(DHT11Init() <0)	 //未检测到DHT11
		P1=0x01 ;
	else				 //检测到DHT11
		P1=0x02 ;

	while(1);
#endif

	while(1)
	{

		if(DHT11Init()==DHT11_EXISTENCT) 
		{
	
			i=0; /*错误记录:忘记了给i清零,导致前几次测量数据正确,后面的数据都错误(一定要注意)*/
	
			while((DHT11_DATA_BIT )&& (i < 250))
			{
				i++; //临时,具体见调试
				     /*经过试验,这里250足够大了*/
			}
			
			/*临时试验,真正试验时必须屏蔽,否则影响后面数据的读取*/
			//UartSendString("ready to send data.\r\n") ;
		
	
			DHT11ReadInfo(&dataCode) ;
	
			UartSendValue("Humidity_H : ",dataCode.Humidity_H);
			UartSendValue("Humidity_L : ",dataCode.Humidity_L);
			UartSendValue("Temperature_H : ",dataCode.Temperature_H);
			UartSendValue("Temperature_L : ",dataCode.Temperature_L);
			UartSendValue("DHT11_CRC : " ,dataCode.DHT11_CRC);
			UartSendString("\r\n\r\n") ;
		}
		else
		{
			UartSendString("No DHT11 existence.\r\n");
		}
	}
}


/*################DHT11.h start################*/

#ifndef __DHT11_H__
#define __DHT11_H__

#include "common.h"
#include "reg52.h"

sbit DHT11_DATA_BIT	 = P2^0 ;/*根据具体硬件选择*/

typedef struct {
	UB8 Humidity_H ;
	UB8 Humidity_L ;
	UB8 Temperature_H ;
	UB8 Temperature_L ;
	UB8 DHT11_CRC;
}DHT11_info ;

#define DHT11_EXISTENCT		0 	/*DHT11存在*/
#define DHT11_NOT_EXISTENCT -1	/*DHT11不存在*/


/*****************外部接口函数******************/
extern SB8  DHT11Init(void) ;
extern void DHT11ReadInfo(DHT11_info *temp) ;
/**********************************************/


#endif  /*__DHT11_H__*/

/*################DHT11.h end################*/

 

/*################DHT11.C start################*/

/***************************************************************************
Module	:DHT11.c

Purpose	:Implementation of DHT11 module.

Version	:0.01							2014/02/03 12:00(OK)

Complier:Keil 8051 C complier V9.01

MCU		:STC12C5A60S2

Author	:yangrui

QQ		:279729201

Email	:yangrui90s@163.com


Modification:

=================
	2014/05/17 10:04
	Reason:
		1.将函数static UB8  DHT11ReadByte(void)内部的
			if (DHT11_DATA_BIT)	
			{	
				datCode |= 0x01;
			}
			j=0 ;
			while((DHT11_DATA_BIT) &&(j<250)) ;
			{
				j++ ; 		 
			}
			修改为
			if (DHT11_DATA_BIT)	
			{	
				datCode |= 0x01;

				j=0 ;
				while((DHT11_DATA_BIT) &&(j<250)) ;
				{
					j++ ; 		 
				}
			}
			因为只有当某一bit数据位高电平时,才需要等待电平拉低
			(每一bit数据发送之前都是以低电平开始,所以这等待是必须的),
			虽然第一种算法没有错误,但是方法二更好理解。	
=================

=================
	2014/04/03 11:01
	Reason:
		1.修改void DHT11ReadInfo(UB8 table[])的入参"UB8 table[]"形式
		为DHT11_info *temp,这样的结构更加紧凑。
=================

=================
	2014/03/31 10:48
	Reason:
		1.在DHT11ReadInfo(UB8 table[])中增加了延时部分,在没有延时的情况下。
		发现main函数中有时竟然不发送数据,或者复位后发送一次数据,这是因为
		DHT11在采集完数据之后会恢复到空闲状态,如果需要继续采集,需要一个启
		动过程。在main函数中添加延时,正常。
		但为了安全和方便,直接将延时加载采集数据的函数内部较好。
		

=================
***************************************************************************/


#include "DHT11.H"
#include <intrins.h>

/*外部接口函数在DHT11.H中声明*/

/*****************内部函数******************/
static void delay20msForDHT11(void) ;
static void delay10usForDHT11(void) ;
static UB8  DHT11ReadByte(void) ;		//读取DHT11字节数据
/**********************************************/

/******************************************************
Function	:delay20msForDHT11
Input		:N/A
Output		:N/A
Return		:N/A
Description	:N/A
Note		:由STC-ISP V6.67软件针对相应MCU生成,若MCU不同
			最好也要修改此函数。
******************************************************/
static void delay20msForDHT11(void)	//@11.0592MHZ
{
	unsigned char i, j, k;

	i = 1;
	j = 216;
	k = 35;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

/******************************************************
Function	:delay10usForDHT11
Input		:N/A
Output		:N/A
Return		:N/A
Description	:N/A
Note		:由STC-ISP V6.67软件针对相应MCU生成,若MCU不同
			最好也要修改此函数。
******************************************************/
static void delay10usForDHT11(void)
{
	unsigned char i;

	_nop_();
	i = 25;
	while (--i);
}

/******************************************************
Function	:DHT11Init
Input		:N/A
Output		:N/A
Return		: 0(DHT1 existence) 
			 -1(DHT11 not existenct)
Description	:检测DHT11的存在与否
Note		:1.本函数中,等待DHT11的低电平回应结束后才会跳出。

			 2.为了防止DHT11的未安装或接触不良导致的程序"卡死"
			 情况的发生,在等待电平转换的同时增加了时间限制,
			 并且这个时间设置的是较长的,经过试验,在正常连接
			 DHT11的情况下,还未等到"最后时间的到来",就已经
			 发生了电平转换,这在大工程中是非常必要的。
******************************************************/
SB8  DHT11Init(void)
{
	SB8 existenceFlag ; 
	UB8 i=0 ;
	
	DHT11_DATA_BIT = HIGH_LEVEL ;
	_nop_() ;
	_nop_() ;
	
	DHT11_DATA_BIT = LOW_LEVEL ;
	delay20msForDHT11() ;
	
	DHT11_DATA_BIT = HIGH_LEVEL ;
	delay10usForDHT11() ;
	delay10usForDHT11() ;
	delay10usForDHT11() ;
	delay10usForDHT11() ;
	delay10usForDHT11() ;

	if( !DHT11_DATA_BIT)
	{
		existenceFlag = DHT11_EXISTENCT ;
	}
	else
	{
		existenceFlag = DHT11_NOT_EXISTENCT ;
	}

	while((!DHT11_DATA_BIT) && (i<250)) 
	{
		i++ ; //暂时,具体见调试
			  /*经过调试,这里250足够大了*/
	}

	return existenceFlag ;
}

/******************************************************
Function	:DHT11ReadByte
Input		:N/A
Output		:N/A
Return		:byte-data which is read from DHT11
Description	:N/A
Note		:为了防止DHT11的未安装或接触不良导致的程序"卡死"
			 情况的发生,在等待电平转换的同时增加了时间限制,
			 并且这个时间设置的是较长的,经过试验,在正常连接
			 DHT11的情况下,还未等到"最后时间的到来",就已经
			 发生了电平转换,这在大工程中是非常必要的。
修改:把if之后的j=0 ,while(){}部分修改到if内部			 
******************************************************/
static UB8  DHT11ReadByte(void)
{
	UB8 j=0 ;
	UB8 i, datCode;

	for(i=0;i<8;i++)	 	
	{	
	    datCode <<= 1;
	    /*每一bit数据都以50us低电平时隙开始,这里直接等待DHT11把数据线拉到高电平*/
		j=0 ;
  		while( (! DHT11_DATA_BIT) && (j<250))			
  		{
			j++ ; //暂时,具体见调试
			 		 /*经过调试,这里250足够大了*/ 
  		}
		delay10usForDHT11() ;
		delay10usForDHT11() ;
		delay10usForDHT11() ;
		delay10usForDHT11() ;
		if (DHT11_DATA_BIT)	
		{	
			datCode |= 0x01;

			j=0 ;
			while((DHT11_DATA_BIT) &&(j<250)) ;
			{
				j++ ; //暂时,具体见调试
		 	 		 /*经过调试,这里250足够大了*/ 
			}
		}
		
	}
	return datCode;	

}

/******************************************************
Function	:DHT11ReadInfo
Input		:N/A
Output		:DHT11_infor struct 
Return		:N/A
Description	:读取DHT11采集到的数据
Note		:注意增加延时的意义。见"Modification"的
			"2014/03/31 10:48"部分。
******************************************************/
void DHT11ReadInfo(DHT11_info *temp)
{
	temp->Humidity_H 	= DHT11ReadByte() ; //Humidity_H
	temp->Humidity_L 	= DHT11ReadByte() ; //Humidity_L
	temp->Temperature_H = DHT11ReadByte() ; //Temperature_H
	temp->Temperature_L = DHT11ReadByte() ; //Temperature_L
	temp->DHT11_CRC 	= DHT11ReadByte() ; //DHT11_CRC

	delay20msForDHT11() ;
	delay20msForDHT11() ;
	delay20msForDHT11() ;
	delay20msForDHT11() ;
	delay20msForDHT11() ;
	delay20msForDHT11() ;
	delay20msForDHT11() ;
	delay20msForDHT11() ;
	delay20msForDHT11() ;
	delay20msForDHT11() ;
}


/*################DHT11.C end################*/


补充:common.h

#ifndef __COMMON_H__
#define __COMMON_H__

typedef unsigned char UB8 ;
typedef unsigned short int UW16 ;
typedef unsigned long UL32 ;

typedef char SB8;
typedef short int SW16 ;
typedef long SL32 ;
	
#define HIGH_LEVEL 1	
#define LOW_LEVEL  0


#endif	/*__COMMON_H__*/



后期:

1.针对不同的IO:

修改DHT11.h的

sbit DHT11_DATA_BIT	 = P2^0 ;/*根据具体硬件选择*/

即可!!


2.针对不同MCU修改:

修改DHT11.c中的static void delay20msForDHT11(void)和static void delay10usForDHT11(void),因为这里的延时函是利用STC-ISP软件自带的工具生成的,是针对STC12C5A60S2的,所以,若用于不同的51单片机,需要修改延时函数,过程截图:



3.对于串口打印:参考http://blog.csdn.net/yagnruinihao/article/details/22662145,这里需要使用11.0592MHZ晶振,直接拷贝uart.h和uart.c,加入工程直接编译即可,如果不同,只需稍作修改。


3.程序的拷贝:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

刺客阿瑞

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

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

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

打赏作者

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

抵扣说明:

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

余额充值