搜索
bottom↓
回复: 16

AVR单片机操作温湿度传感器AM2301(又名DHT21)

[复制链接]

出0入0汤圆

发表于 2010-7-29 15:46:12 | 显示全部楼层 |阅读模式
AM2301是国产的温湿度传感器,想较瑞士的SHT1X,价格低廉,但性能有所降低,在对性能 要求不是很高的情况下,可以考虑用该款温湿度传感器。
       单片机对AM2301的操作非常简单,通过AM2301的数据手册,便可写出访问它的程序,例程如下,期望能达到抛砖引玉的目的,以AVR系列的Mega16为例:
        一、头文件
/***********************************************************************************************
文件:am2301.h
作者:wxxujian
用途:温湿度传感器AM2301(又名:DHT21)的驱动程序
MCU: AVR Mega16        晶振:8MHz
编译器:WinAVR2010
版本:1.0(创建日期:2010-7-27)                能正常显示湿度,仅能显示正温度
      1.1(修改日期:2010-7-28)                能正常显示湿度和温度(正、负温度均可)
日期:2010-7-27
***********************************************************************************************/

#include <avr/io.h>

#ifndef        AM2301_H
#define AM2301_H

//////////////////////////////   宏定义(须根据实际情况而修改)  ///////////////////////////////

//功能:定义与AM2301的数据位相连的单片机的端口及数据位
//注意:这些宏须随着实际的硬件电路情况而修改

#define AM2301_DATA_DDR                DDRD
#define AM2301_DATA_PORT        PORTD
#define AM2301_DATA_PIN                PIND
#define AM2301_DATA_BIT                PD2

//////////////////////////////   宏定义(结束)  ///////////////////////////////


//////////////////////////////      函数声明    //////////////////////////////////////////////////
//说明:共2个函数,分别是:
//                                                        AM2301_CollectCharData(int *pvHumidity,int *pvTemperature)
//                                                        AM2301_CollectFloatData(float *pvHumidity,float *pvTemperature)
//详细内容如下:


/********************************************************************************
函数名:AM2301_CollectCharData(int *pvHumidity,int *pvTemperature)
功  能:获得数据(湿度、温度),获得的数据保存于形参所提供的指针所指向的变量中
返回值:
                0:数据校验正确;
                1:数据校验错误
                2:获取数据错误
                3: 等待响应信号错误
参  数:
                pvHumidity:   湿度变量的指针,用于保存采集到的湿度,数据类型为:signed char,得到的数据仅为湿度的整数部分,小数部分自动舍弃
                pvTemperature:温度变量的指针,用于保存采集到的温度,数据类型为:signed char,得到的数据仅为温度的整数部分,小数部分自动舍弃


说  明:建议执行此函数的间隔为2秒,绝不能小1秒。若间隔时间很长,建议采集2次,以2次为准
        当发生错误,即返回值为1、2或3时,应间隔2秒后重新读取数据
注  意:因为:WinAVR默认将char 视为unsigned char
        所以:参数必须定义为signed char,-128<signed char<127,足以保存所得到的数据
原  理:详见AM2301的数据手册
*********************************************************************************/
unsigned char AM2301_CollectCharData(signed char *pvHumidity,signed char *pvTemperature);

/********************************************************************************
函数名:AM2301_CollectFloatData(float *pvHumidity,float *pvTemperature)
功  能:获得数据(湿度、温度),获得的数据保存于形参所提供的指针所指向的变量中
返回值:
                0:数据校验正确;
                1:数据校验错误
                2:获取数据错误
                3: 等待响应信号错误
参  数:
                pvHumidity:   湿度变量的指针,用于保存采集到的湿度,数据类型为:float,得到的数据为完整的数据,但不要用此float数据去比较
                pvTemperature:温度变量的指针,用于保存采集到的温度,数据类型为:float,得到的数据为完整的数据,但不要用此float数据去比较


说  明:建议执行此函数的间隔为2秒,绝不能小1秒。若间隔时间很长,建议采集2次,以2次为准
        当发生错误,即返回值为1、2或3时,应间隔2秒后重新读取数据
原  理:详见AM2301的数据手册
*********************************************************************************/
unsigned char AM2301_CollectFloatData(float *pvHumidity,float *pvTemperature);

//////////////////////////////      函数声明(结束)    //////////////////////////////////////////////////

#endif

        二、实现文件
/***********************************************************************************************
文件:am2301.c
作者:wxxujian
用途:温湿度传感器AM2301(又名:DHT21)的驱动程序
MCU: AVR Mega16        晶振:8MHz
编译器:WinAVR2010
版本:1.0(创建日期:2010-7-27)                能正常显示湿度,仅能显示正温度
          1.1(修改日期:2010-7-28)                能正常显示湿度和温度(正、负温度均可)
日期:2010-7-27
***********************************************************************************************/

#include "am2301.h"
#include <util/delay.h>
#include "common.h"
#include "display.h"


//////////////////////////////   宏定义(函数样式)   ///////////////////////////////////////////

//功能:操作与am2301的数据位相连的单片机端口与相应位,包括:输入、输出、置1和清0
//注意:这些宏只供此文件使用
#define        SetDataBitOutput()        SetBit(AM2301_DATA_DDR,AM2301_DATA_BIT)
#define        SetDataBitInput()        ClearBit(AM2301_DATA_DDR,AM2301_DATA_BIT)
#define        SetDataBit()                SetBit(AM2301_DATA_PORT,AM2301_DATA_BIT)
#define        ClearDataBit()                ClearBit(AM2301_DATA_PORT,AM2301_DATA_BIT)
#define TestDataBit()                TestBit(AM2301_DATA_PIN,AM2301_DATA_BIT)

//////////////////////////////   宏定义(结束)   ///////////////////////////////////////////


//////////////////////////////      函数实现    //////////////////////////////////////////////////
//说明:共3个函数,分别是:
//                                                        AM2301_ReadByte(unsigned char *pvData)
//                                                        AM2301_CollectCharData(int *pvHumidity,int *pvTemperature)
//                                                        AM2301_CollectFloatData(float *pvHumidity,float *pvTemperature)
//详细内容如下:

/********************************************************************************
函数名:AM2301_ReadByte(unsigned char *pvData)
功  能:读取1个字节的数据
返回值:0:成功;2:读数据错误
参  数:pvData:所读取的数据
条  件:与am2301的数据位相连的单片机端口为“输入模式”
注  意:此函数为辅助函数,仅供本文件使用,外部无法访问
原  理:数据是从高位往低位依次读取,读得数据的顺序为:湿度高位+湿度低位+温度高位+温度低位+校验位
*********************************************************************************/
unsigned char        AM2301_ReadByte(unsigned char *pvData)
{
        unsigned char lvReturn=0,lvI,lvCount,lvBit;
       
        for(lvI=0;lvI<8;lvI++)                                                                //循环8次,得到1个字节(含8个数据位)的数据
        {
                lvCount=1;
                while( ! TestDataBit()  && lvCount>0 )                                        //判断丛机是否发来50us的低电平信号,若超时返回2
                        lvCount++;
                if(lvCount==0)
                {
                        lvReturn=2;
                        break;
                }

                _delay_us(35);                                                                //延时35us
               
                //判断数据是0或1
                lvBit=0;
                if(TestDataBit())
                        lvBit=1;

                lvCount=1;
                while( TestDataBit()  && lvCount>0 )                                        //判断丛机是否发来26-28us的高电平信号,若超时返回2
                        lvCount++;
                if(lvCount==0)
                {
                        lvReturn=2;
                        break;
                }

                //把得到的每一位数据保存于pvData中
                if(lvBit)
                        *pvData |= 1<<(7-lvI);
                else
                        *pvData &= ~1<<(7-lvI);

        }

        return lvReturn;
}


/********************************************************************************
函数名:AM2301_CollectCharData(int *pvHumidity,int *pvTemperature)
功  能:获得数据(湿度、温度),获得的数据保存于形参所提供的指针所指向的变量中
返回值:
                0:数据校验正确;
                1:数据校验错误
                2:获取数据错误
                3: 等待响应信号错误
参  数:
                pvHumidity:   湿度变量的指针,用于保存采集到的湿度,数据类型为:signed char,得到的数据仅为湿度的整数部分,小数部分自动舍弃
                pvTemperature:温度变量的指针,用于保存采集到的温度,数据类型为:signed char,得到的数据仅为温度的整数部分,小数部分自动舍弃


说  明:建议执行此函数的间隔为2秒,绝不能小1秒。若间隔时间很长,建议采集2次,以2次为准
        当发生错误,即返回值为1、2或3时,应间隔2秒后重新读取数据
注  意:因为:WinAVR默认将char 视为unsigned char
        所以:参数必须定义为signed char,-128<signed char<127,足以保存所得到的数据
原  理:详见AM2301的数据手册
*********************************************************************************/
unsigned char AM2301_CollectCharData(signed char *pvHumidity,signed char *pvTemperature)
{
        unsigned char lvReturn=3,lvCount;
        unsigned int  lvTemp16;
        int        lvTemp;

        unsigned char        lvHumidityHigh;                                                                //湿度高位
        unsigned char        lvHumidityLow;                                                                //湿度低位
        unsigned char        lvTemperatureHigh;                                                        //温度高位
        unsigned char        lvTemperatureLow;                                                        //温度低位
        unsigned char        lvCheck;                                                                //校验位


        //主机的操作
        SetDataBitOutput();
        ClearDataBit();                                                                                //拉低总线
        _delay_us(500);                                                                                //持续500us
        SetDataBit();                                                                                //释放总线

        //主机检测丛机
        SetDataBitInput();
        _delay_us(40);

        if(! TestDataBit())
        {
                lvCount=1;
                while( ! TestDataBit() && lvCount >0)                                                 //判断丛机是否发送了80us的高电平信号
                        lvCount++;
                if(lvCount==0)
                        return 3;

                lvCount=1;
                while( TestDataBit() && lvCount >0)                                                 //判断丛机是否发送了80us的高电平信号
                        lvCount++;
                if(lvCount==0)return 3;
               
                if(AM2301_ReadByte(&lvHumidityHigh))                                                //获得湿度高位
                        return 2;

                if(AM2301_ReadByte(&lvHumidityLow))                                                //获得湿度高位
                        return 2;

                if(AM2301_ReadByte(&lvTemperatureHigh))                                                //获得湿度高位
                        return 2;

                if(AM2301_ReadByte(&lvTemperatureLow))                                                //获得湿度高位
                        return 2;

                if(AM2301_ReadByte(&lvCheck))                                                        //获得湿度高位
                        return 2;

                lvCount=lvHumidityHigh+lvHumidityLow+lvTemperatureHigh+lvTemperatureLow;//计算湿度高位+湿度低位+温度高位+温度低位的和

                if(lvCount==lvCheck)                                                        //数据校验,若正确则获得正确的湿度和温度,并返回1
                {
                        //lvTemperatureHigh |=0x80;
                       
                        //把湿度的高位和地位组合,得到完整的湿度
                        lvTemp16=lvHumidityHigh;
                        lvTemp16 <<=8;
                        lvTemp16 |= lvHumidityLow;
                        *pvHumidity=lvTemp16/10;

                        //把温度的高位和地位组合,得到完整的温度
                        lvTemp16=lvTemperatureHigh;
                        lvTemp16 <<=8;
                        lvTemp16 |= lvTemperatureLow;

                        if(lvTemp16 & 0x8000)                                                        //如果温度是负值,则转化
                        {
                                lvTemp16 &=0x7FFF;
                                lvTemp=0-lvTemp16;
                        }
                        *pvTemperature=lvTemp /10 ;

                        lvReturn=0;
                }
                else                                                                        //数据校验,若错误,则返回1
                        lvReturn=1;

        }
        return lvReturn;

}
/********************************************************************************
函数名:AM2301_CollectFloatData(float *pvHumidity,float *pvTemperature)
功  能:获得数据(湿度、温度),获得的数据保存于形参所提供的指针所指向的变量中
返回值:
                0:数据校验正确;
                1:数据校验错误
                2:获取数据错误
                3: 等待响应信号错误
参  数:
                pvHumidity:   湿度变量的指针,用于保存采集到的湿度,数据类型为:float,得到的数据为完整的数据,但不要用此float数据去比较
                pvTemperature:温度变量的指针,用于保存采集到的温度,数据类型为:float,得到的数据为完整的数据,但不要用此float数据去比较


说  明:建议执行此函数的间隔为2秒,绝不能小1秒。若间隔时间很长,建议采集2次,以2次为准
        当发生错误,即返回值为1、2或3时,应间隔2秒后重新读取数据
原  理:详见AM2301的数据手册
*********************************************************************************/
unsigned char AM2301_CollectFloatData(float *pvHumidity,float *pvTemperature)
{
        unsigned char lvReturn=0;
        signed   char lvHumidity;                                                        //湿度
        signed   char lvTemperature;                                                        //温度

        lvReturn=AM2301_CollectCharData(&lvHumidity,&lvTemperature);
        if(lvReturn)                                                                        //若出错,则直接返回
                return lvReturn;

        //若正确读取了数据,则转化为float型数据
        *pvHumidity=lvHumidity/10;
        *pvTemperature=lvTemperature/10;

        return lvReturn;
}


//////////////////////////////      函数实现(结束)    //////////////////////////////////////////////////

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2010-7-29 16:15:33 | 显示全部楼层
mark!

出0入0汤圆

发表于 2010-7-29 21:10:34 | 显示全部楼层
正好要用,谢谢.

出0入0汤圆

发表于 2010-9-29 17:14:45 | 显示全部楼层
mark!

出0入0汤圆

发表于 2010-9-29 17:43:33 | 显示全部楼层
记号

出0入0汤圆

发表于 2010-9-29 17:57:43 | 显示全部楼层
这和DHT11有什么不同呢,感觉时序上是一样的,但是DHT11返回的低位数据全部为0!!

出0入0汤圆

发表于 2010-10-8 17:05:41 | 显示全部楼层
AM2301的传输距离最远为多少?传输出来的是什么信号,TTL信号or电流信号?50米可以吗?

出0入0汤圆

发表于 2010-10-8 18:46:00 | 显示全部楼层
Mark

出0入0汤圆

发表于 2010-10-9 18:56:55 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-10-16 21:54:09 | 显示全部楼层
有51的吗?

出0入0汤圆

发表于 2010-10-16 21:56:43 | 显示全部楼层
谢谢楼主,留个记号

出0入0汤圆

发表于 2010-10-17 22:16:13 | 显示全部楼层
谢谢分享!

出0入0汤圆

发表于 2010-11-16 19:36:47 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-1-10 02:21:34 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-7-26 15:57:34 | 显示全部楼层
MARK MARK MARK !!!!

出0入0汤圆

发表于 2012-10-16 13:18:03 | 显示全部楼层
我淘到的带外壳的温湿度传感器组件为何为三芯线?

出0入0汤圆

发表于 2012-10-16 13:20:15 | 显示全部楼层
dht11有用过,dht21跟他有什么区别吗
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 04:15

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表