48 www.ele169.com
制作项目 MAKE PROJECT
自制温湿度计
作者 / 李前江
在食品加工,工业生产,农业,养殖业等很多领域都
需要对温度湿度进行严格控制。本制作是用AM2301温湿
度传感器,基于单片机AT89S52和LCD1602字符型液晶
显示模块制作的具有体积小,成本低并能满足常规要求的
温湿度计。本制作主要用于室内温度和湿度的测量,也可
用于仓库和种植蔬菜的塑料大棚。冬季气温寒冷,天气干
燥。放一个温湿度计在房间,为加湿提供参考,也可让大
家知道天冷到什么程度。
AM2301是一款含有已校准数字信号输出的温湿度复
合传感器。它应用专用的数字模块采集技术和温湿度传感
技术,确保产品具有极高的可靠性与卓越的长期稳定性。
小体积,低功耗,单总线接口使系统集成简单。信号传输
距离可达20m以上,能满足各类场合应用要求。
AM2301特性及引脚说明
AM2301湿度分辨率为0.1%RH,精度±3%最大误差
±5%。温度分辨率为0.1℃,精度最大误差±1℃。采样
周期建议2s,连接线长度短于20m时建议用5k上拉电阻。
引脚分配如图1。
1. VCC:电源引脚,工作时接+5V
2. OUT:单总线接口用于与MCU通信
3. GND:电源地
492012.01
MCU单片机制作
图1
图2
T2/P1.01
T2EX/P1.12
P1.23
P1.34
P1.45
MOSI/P1.56
MISO/P1.67
SCK/P1.78
RESET9
RXD/P3.010
TXD/P3.111
INT0/P3.212
INT1/P3.313
TO/P3.414
T1/P3.515
WR/P3.616
RD/P3.717
XTAL218
XTAL119
GND20 P2.0/A8 21
P2.1/A9 22
P2.2/A10 23
P2.3/A11 24
P2.4/A12 25
P2.5/A13 26
P2.6/A14 27
P2.7/A15 28
PSEN 29
ALE/PROG 30
EA/VPP 31
P0.7/AD7 32
P0.6/AD6 33
P0.5/AD5 34
P0.4/AD4 35
P0.3/AD3 36
P0.2/AD2 37
P0.1/AD1 38
P0.0/AD0 39
VCC 40
U1
AT89S52
G
N
D
1
D
Q
2
V
C
C
3
U2
AM2301
R1
5k
VCC VCC
R2
10k
+C1
10μF
VCC
VCC
Y1
12MHz
C2
30p
C3
30p
VCC
GND1
VCC2
VL3
RS4
R/W5
EN6
D07
D18
D29
D310
D411
D512
D613
D714
BLA15
BLK16
LCD1602R3
10k
VCC
P1.2
P1.3
P1.4
P1.2
P1.3
P1.4
空闲时总线为高电平,通讯开始时单片机拉低总线500μs后释
放总线,延时20~40μs后单片机机开始检测AM2301的响应信号。
AM2301的响应信号是一个80μs左右的低电平,随后AM2301在拉
高总线80μs左右代
即将进入数据传送。时序如图4。
高电平后就是数据位,每1bit数据都是由一个低电平时隙和一个
高电平组成。低电平时隙就是一个50μs左右的低电平,它代表数据
位的起始,其后的高电平的长度决定数据位所代表的数值,较长的
高电平代表1,较短的高电平代表0。共40bit数据,当最后一Bit数据
传送完毕后,AM2301将再次拉低总线50μs左右,随后释放总线,
由上拉电阻拉高。数字信号1的表示方法如图5。数字信号0的表示方
法如图6。
搞清楚了AM2301时序,接着开始写驱动程序,程序代码如下:
4. NC(TEST):正常使用时悬空
注:AM2301上电之后,要等待1s 以越过不稳定
状态在此期间无需发送任何指令。传感器与单片机一
次通讯时间5ms左右,数据传输为40bit,高位前。
数据格式: 40bit数据=16bit湿度数据+16bit温度
数据+8bit校验和主机从AM2301读取的温湿度数据总
是前一次的测量值,如两次测量间隔时间很长,需连
续读两次以获得实时的温湿度。
单片机及LCD1602说明
单片机选用性价比较高的AT89S52具有8K字节
在系统可编程Flash存储器和32个可编程I/O,三个16
位定时器/计数器等。在此制作中充分满足要求且还
有富余,实际制作时可以选用合适的单片机以降低成
本。
显 示 部 分 选 用 L C D 1 6 0 2 字 符 型 液 晶 显 示 模
块,操作简便。此三者结合起来可组成一个显示
简洁大方的温湿计。
硬件电路设计
本温湿计电路简单,易于制作。硬件电路
如图2。
AM2301底层操作
单片机发送一次开始信号后,AM2301
从低功耗模式转换到高速模式,等待单片机
开始信号结束后,AM2301发送响应信号,送
出40bi t的数据,并触发一次信号采集。时
序如图3。
图3
图4
50 www.ele169.com
制作项目 MAKE PROJECT
图5
图6
首先定义接口和读回的数据存储空间声明
sbit DQ = P1^0; //传感器对应单片机引脚
unsigned char AM2301_Data[5]={0x00,0x00,0x00,0x00,0x00};
//用于接收40bit数据
/**********************************************
*函数功能:微秒级延时
**********************************************/
void delay_10us(unsigned int t)
{
while(t--)
{
_nop_();
}
}
/**********************************************
*函数功能:读取AM2301发送的单字节数据
**********************************************/
unsigned char Read_AM2301_Byte(void)
{
unsigned char i,dat,temp;
for(i = 0; i < 8; i ++)
{
while(!DQ);
//检测上次低电平是否结束
delay_10us(2);
//延时跳过数据0的高电平
temp = 0;
if(DQ)
{
temp = 1;
}
while(DQ); //等待高电平结束
dat <<= 1; //高位在前
dat |= temp;
}
return (dat);
}
/**********************************************
*函数功能:读取AM2301完成一次检测发送的40bit数据
**********************************************/
void Read_AM2301(void)
{
unsigned char i;
DQ = 0; //单片机拉低总线
delay_10us(40); //拉低总线时间至少500us
DQ = 1; //单片机释放总线
delay_10us(2); //延时等待AM2301响应
if(DQ == 0) //如果AM2301响应,接着开始传送数据
{
while(!DQ); //等待传感器80us低电平响应结束
while(DQ); //等待传感器80us高电平结束
for(i = 0; i < 5; i ++) //正式开始读取40bit数据
{
AM2301_Data[i] = Read_AM2301_Byte();
}
}
}
512012.01
MCU单片机制作
LCD1602底层操作
传感器AM2301还是很好操作的,写好AM2301底层驱动后,紧接
着操作LCD1602液晶显示模块。LCD1602是字符型液晶,并且是并行
接口,操作起来很简单。其读操作时序如图7。
图7
图8
对LCD1602液晶操作之前需先检测是否处于忙状态。接口定义如
下:
sbit RS = P1^4; //LCD的RS对应单片机引脚
sbit RW = P1^3; //LCD的RW对应单片机引脚
sbit EN = P1^2; //LCD的EN对应单片机引脚
/****************************************函数功能:忙检测
/**********************************************/
void LCD_Busy(void)
{
P2 = 0xff;
RS = 0; //RS=0 RW=1 E=高电平
RW = 1;
EN = 1;
while((P2 & 0x80) == 1);
//D7=0 表示LCD控制器空闲,则退出检测
EN = 0;
}
/*********************************************
*函数功能:写命令或数据到液晶显示器
*********************************************/
void LCD_Write(bit x,unsigned char com)
{
LCD_Busy(); //忙检测
RS = x; //RS=0 RW=0 E=1,为写命令
RW = 0;
//RS=1 RW=0 E=1,为写数据
P2 = com;
EN = 1;
_nop_();
EN = 0;
}
/*********************************************
*函数功能:在LCD1602两行的任何位置显示需要的数
据
*********************************************/
void LCD_Show(unsigned char y,unsigned char
x,unsigned char *value)
{
unsigned char add;
switch (y)
{
case 1 : add = 0x80 + x; break;
case 2 : add = 0xc0 + x; break;
default : break;
}
LCD_Write(write_comm,add);
while(*value != '\0')
{
LCD_Write(write_data,*value);
value ++;
}
}
/*********************************************
*函数功能:自建一个字型,摄氏度左上角的小圆
*********************************************/
void Write_CGRAM(void)
{
52 www.ele169.com
制作项目 MAKE PROJECT
unsigned char i;
unsigned char tmp = 0x40; //操作CGRAM的命令码
for(i = 0; i < 8; i ++) // 8 个字节生成 1 个字符点阵
{
LCD_Write(write_comm,tmp + i); //写入CGRAM地址
LCD_Write(write_data,Pat[i]); //写入数据
}
}
到此液晶底层操作完成,下一步就是主函数的编写。
主程序
在写主程序之前一般先画出流程图,本程序主要是从
AM2301读取数据,然后送LCD1602显示,流程简单所以
就不画流程图了。在写主函数之前还需对LCD1602进行
初始化和对从AM2301读回的数据进行处理。AM2301建
议打样周期为2s,本程序用定时器0精确定时,实现2s采
样一次。
所有程序代码如下:
#include
#include
#define write_comm 0 //LCD写命令
#define write_data 1 //LCD写数据
unsigned char code Pat[8]={0X03,0X03,0x00,0x00,0x00,0x00,0x00,0x0
0};
//自建字形用
unsigned char AM2301_Data[5] = {0X00,0X00,0X00,0X00,0X00};
//用于接收40bit数据
unsigned char AM2301_Check; //校验和
unsigned int DATA; //数据处理用
unsigned char cont = 0; //定时器计数
/**********************************************
*函数功能:延时函数
**********************************************/
void delay_ms(void) //延时3MS子程序,实际时间需实际调整
{
unsigned char i,j;
for(i = 0; i < 3; i ++)
for(j = 0; j < 170; j ++);
}
/**********************************************
*函数功能:液晶显示器初始化
**********************************************/
void LCD_INIT(void)
{ //1602的显示模式字为0x38
LCD_Write(write_comm,0x38); //显示模式设置第一次
delay_ms(); //延时3MS
LCD_Write(write_comm,0x38); //显示模式设置第二次
delay_ms(); //延时3MS
LCD_Write(write_comm,0x38); //显示模式设置第三次
delay_ms(); //延时3MS
LCD_Write(write_comm,0x38); //显示模式设置第四次
delay_ms(); //延时3MS
LCD_Write(write_comm,0x08); //显示关闭
LCD_Write(write_comm,0x01); //清屏
delay_ms(); //延时3MS
LCD_Write(write_comm,0x06); //显示光标移动设置
LCD_Write(write_comm,0x0C); //显示开及光标设置
LCD_Show(1,4,"TEMP/RH%");
//第一行,第四个位置起显TEMP/RH%
LCD_Show(2,0,"T:");
Write_CGRAM(); //在第二行,第六七个位置显示℃
LCD_Write(write_comm,0xc6);
LCD_Write(write_data,0); //写入自建字形
LCD_Show(2,7,"C");
LCD_Show(2,9,"R:");
LCD_Show(2,15,"%");
}
/**********************************************
*函数功能:数据处理,送液晶显示
**********************************************/
void Data_Process(unsigned char add,unsigned int date)
{
unsigned char shi,ge,xiao; //声明变量十位,个位 ,小数位
shi = date / 100 % 10; //分离出十位
ge = date / 10 % 10; //分离出个位
xiao = date % 10; //分离出小数位
LCD_Write(write_comm,add); //显示坐标设置
LCD_Write(write_data,shi + 0x30); //显示十位
LCD_Write(write_comm,add+1);
LCD_Write(write_data,ge + 0x30); //显示个位
LCD_Write(write_comm,add+2);
LCD_Write(write_data,'.'); //显示小数点
532012.01
MCU单片机制作
LCD_Write(write_comm,add+3);
LCD_Write(write_data,xiao + 0x30); //显示小数位
}
/**********************************************
*函数功能:显示函数
**********************************************/
void Display(void)
{
Read_AM2301(); //采样一次,读取数据
AM2301_Check = AM2301_Data[0] + AM2301_Data[1] + AM2301_
Data[2] + AM2301_Data[3];//校验和
if(AM2301_Check == AM2301_Data[4]) //如果校验成功
{
DATA = ((AM2301_Data[2] * 256) + AM2301_Data[3]);
//16bit温度数据整合
Data_Process(0xc2,DATA); //送数据处理函数处理
delay_ms(); //延时
DATA = ((AM2301_Data[0] * 256) + AM2301_Data[1]);
//16bit湿度数据整合
Data_Process(0xcb,DATA); //送数据处理函数处理
}
else
//如果校验失败重新读取采样数据
{
Read_AM2301();
}
}
/**********************************************
*函数功能:主函数
**********************************************/
void main(void)
{
IE=0X82; //定时器0的一些配置
TMOD=0X01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TR0=1;
LCD_INIT();
while(1)
{
if(cont==40) //中断40次,2S时间到
{
cont=0; //清计数次数
Display(); //调用显示函数
}
}
}
/**********************************************
*函数功能:定时器0中断函数
**********************************************/
void Timer_0(void)interrupt 1
{
TH0=(65536-50000)/256; //重新赋初值
TL0=(65536-50000)%256;
cont++; //计数
}
制作过程
在绘制完原理图,写好程序并调试好后,将程序烧入
单片机中。就可以制作电路部分了。由于本电路简单元器
件不多,制作时可直接用洞洞板焊接。具体制作过程就不
一一列出了。
备注:制作时传感器,建议接上5k上拉电阻。使用场
合需注意,参见其数据手册,化学气体会对传感器产生干
扰,不建议在有化学气体的场合使用。液晶显示器在零度
以下无法正常工作,温度低的场合使用建议用数码管代替
液晶。在湿度高的场合需对电路部分进行隔离保护。
最终制作显示效果如9图所示。秋冬季节天气干燥,
注意保湿!
图9