该系统是基于51单片机的温度监测报警系统。由主控模块、检测模块、显示模块以及报警模块四大模块组成。主控模块使用STC89C52实验板,检测模块采用DS18B20的温度传感器监测环境温度,并将监测到的温度值传送给显示模块的LCD1602显示屏进行显示,而当温度超过设定的上限或低于设定的下限值时,控制报警模块的LED发光二极管显示并通过蜂鸣器发出警告。四大模块协同工作,主要实现对温度的检测、显示以及报警功能。
4.2 DS18B20温度监测模块
采用可编程温度传感器DS18B20进行温度检测,具有抗干扰能力强、采集进度高、不需要复杂调理电路和AD转换电路等特点,只要将DS18B20的I/O口直接与单片机的P37口相连即可实现温度的读取。
4.3 LCD温度显示模块
采用LCD1602液晶显示器将温度传感器读取的温度值显示出来,具有体积小、功耗低、显示操作简单等特点,但温度范围窄,工作温度为0-55°C,存储温度为-20~+60°C。
4.4 蜂鸣器温度报警模块
采用开发板上的无源蜂鸣器实现温度报警,单输出一个电平是不能控制使其发声的,须通过一定频率的脉冲来触发,才能使其发声。
4.5按键设置阈值及模式切换模块
温度上下限的设定以及模式切换通过独立按键来实现,首次按下K3,即进入修改状态,此时在上限处会出现 “ * ”,表示该值处于被更改状态,然后可通过K1、K2分别实现对温度上限的上调和下调;再次按下K3,即确定上限值已修改完毕,“ * ” 将移动到下限值处,同理可通过K1、K2实现对温度下限值的上调和下调;第三次按下K3即上下限修改完成;K4即对模式的切换。
输入 | 输出 | |
---|---|---|
读状态 | RS=0,RW=1,EN=1 | D0~D7=状态字 |
写指令 | RS=0,RW=0,D0~D7=指令码,EN=高脉冲 | 无 |
读数据 | RS=1,RW=1,EN=1 | D0~D7=数据 |
写数据 | RS=1,RW=0,D0~D7=数据,EN=高脉冲 | 无 |
原则上每次对控制器进行读写操作前,都必须进行读写检测,确保STA7=0,实际上,由于单片机的操作速度慢于液晶控制器的反应速度,故只需进行简短的延时即可。
3)蜂鸣器
开发板采用无源蜂鸣器,通过一个限流电阻与VCC相连,另一个管脚与ULN2003D芯片(NPN达林顿管)上的P15接口相连。也就是说,BEEP管脚是通过单片机P15接口,经过ULN2003D驱动芯片输出到蜂鸣器中,而ULN2003D芯片则起到电流放大的作用——单片机的P15端口输出一个高电平,则NPN三极管处于导通状态,于是蜂鸣器得电从而发声。
4)独立按键
四个按键的一端全部供地。默认状态下(按键未按下时),按键的各个管脚并非完全导通;按下按键后,相应的单片机端口都会被拉低(因为P3口是准双向IO口)。并且按键在闭合和断开时,触电会存在抖动现象,可通过软件消抖的方法解决即延时待其稳定后,再次判断按键是否被按下。
#include "reg52.h"
sbit keyu=P3^1; //按键加
sbit keyl=P3^0; //按键减
sbit keyh=P3^2; //按键选择调节温度上下限
sbit keym=P3^3; //按键切换模式
sbit RS=P2^6; //LCD数据/命令选择端
sbit RW=P2^5; //LCD读/写端
sbit EN=P2^7; //LCD使能端
sbit DQ=P3^7; //DS18B20接入口
sbit buzz=P1^5; //蜂鸣器接口 -
bit f=1; //正负温度标志位
unsigned char m=1,y=0,o=0; //寄存器
unsigned int sdata; //存放整数温度
unsigned char xiaoshu1; //存放小数后第一位温度数值
unsigned char xiaoshu2; //存放小数后第二位温度数值
unsigned char code huany[]=" Welcome To Use "; //欢迎使用
unsigned char code tt[] =" TEMP Monitoring"; //温度监测
unsigned char code duqu[]=" loading... "; //读取
unsigned char code tab1[]=" T: C M "; //框架
unsigned char code tab2[]="H: L: ";
unsigned char code shuzu[]="0123456789+- .*"; //0123456789+-空格.*
unsigned char u=40; //上限
char l=15,p; //下限
void delay_50us(unsigned int t)//延时
{
unsigned int j,k;
for (;t>0;t--)
{
for(j=10;j>0;j--)
{
for(k=1;k>0;k--);
}
}
}
void delay(unsigned int i)//全局延时
{
while(i--);
}
void button()//蜂鸣器
{
unsigned char k=800;
while(k--)
{
buzz=~buzz;
delay(115);
}
}
/***************LCD****************/
void write_com(unsigned com)//写操作
{
EN=0;RS=0;RW=0;
P0=com;
delay_50us(1);
EN=1;
delay_50us(5);
EN=0;
}
void write_data(unsigned char dat)//写数据
{
EN=0;RS=1;RW=0;
P0=dat;
delay_50us(1);
EN=1;
delay_50us(5);
EN=0;
}
void Init_LCD(void)//初始化
{
delay_50us(5);
write_com(0x38);//写指令38H 不检测忙信号
delay_50us(1);
write_com(0x38);
delay_50us(1);
write_com(0x38);//不检测忙信号,之后每次写指令、读/写数据操作前均需检测忙信
write_com(0x38);//显示模式设置
write_com(0x08); //只开显示
write_com(0x01); //清屏
write_com(0x06);//地址加1,当写入数据的时候光标右移
write_com(0x0C); //开显示,不显示光标
}
//初始化显示
void display0()//显示welcome to use TEMP Monitoring
{
unsigned char i,w,h=0x8f,i1,w1,h1=0xcf,w2,i2,h2,g=2;
Init_LCD();
for(w=0;w<16;w++) //显示welcome to use
{
write_com(h--);//第一行自减左移
for(i=0;i<16;i++)
{
write_data(huany[i]);
delay_50us(15);
}
}
for(w1=0;w1<16;w1++)//显示TEMP Monitoring
{
write_com(h1--);//第二行自减左移
for(i1=0;i1<16;i1++)
{
write_data(tt[i1]);
delay_50us(15);
}
}
delay_50us(5000);//显示loading
Init_LCD();
write_com(0x80);
for(w2=0;w2<16;w2++)//向右显示
{
write_data(duqu[w2]);
delay_50us(200);
}
while(g--)//小数点循环亮灭
{
write_com(0x8a);
for(i2=0;i2<3;i2++)
{
write_data(duqu[i2]);
}
write_com(0x8a);
for(h2=10;h2<14;h2++)
{
delay_50us(300);
write_data(duqu[h2]);
delay_50us(300);
}
}
}
void display1()//显示框架
{
unsigned char p,q;
Init_LCD();//全局清零
write_com(0x80);
for(q=0;q<16;q++)//显示TMHL
{
write_data(tab1[q]);
}
write_com(0xc1);
for(p=0;p<16;p++)
write_data(tab2[p]);
}
/***************DS18B20****************/
Init_DS18B20(void)//初始化
{
unsigned char x=0;
DQ=1;//DQ复位
delay(10);//稍做延时
DQ=0;//单片机将DQ拉低
delay(80);//精确延时大于480us
DQ=1;//拉高总线
delay(20);
x=DQ;//稍做延时后,若x=0则初始化成功;x=1则初始化失败
delay(30);
return x;
}
ReadOneChar(void)//读一个字节
{
unsigned char i=0;
unsigned char dat=0;
for(i=8;i>0;i--)
{
DQ=0;//给脉冲信号
dat>>=1;
DQ=1;//给脉冲信号
if(DQ)
dat|=0x80;
delay(4);
}
return(dat);
}
WriteOneChar(unsigned char dat)//写一个字节
{
unsigned char i=0;
for(i=8;i>0;i--)
{
DQ=0;
DQ=dat&0x01;
delay(5);
DQ=1;
dat>>=1;
}
return(dat);
}
void ReadTemperature(void)//读温度
{
unsigned char L=0;
unsigned char H=0;
Init_DS18B20();
WriteOneChar(0xCC);//跳过读序号列号的操作
WriteOneChar(0x44);//启动温度转换
delay(100);
Init_DS18B20();
WriteOneChar(0xCC);//跳过读序号列号的操作
WriteOneChar(0xBE);//读取温度寄存器等(共可读9个寄存器前两个就是 温度
L=ReadOneChar();
H=ReadOneChar();
if(H>0xf8) //高位前五位为1时温度是负
{
L=~L+1;
H=~H;
f=0; //读取温度为负时fg=0
sdata = L/16+H*16; //整数部分
xiaoshu1 = (L&0x0f)*10/16; //小数第一位
xiaoshu2 = (L&0x0f)*100/16%10; //小数第二位
}
//传感器返回值除16得实际温度值
//为了得到2位小数位,先乘100,再除16,考虑整型数据长度
else
{
f=1;
sdata = L/16+H*16; //整数部分
xiaoshu1 = (L&0x0f)*10/16; //小数第一位
xiaoshu2 = (L&0x0f)*100/16%10; //小数第二位
}
}
void display2()//显示上下限温度
{
write_com(0x8e);
write_data(shuzu[m/10]);//十位
write_com(0x8f);
write_data(shuzu[m%10]);//个位
if(o==1) //上限选中标志*号可操作
{
write_com(0xc0);
write_data(shuzu[14]);
write_com(0xca);
write_data(shuzu[12]);
}
else if(o==2) //下限选中标志*号可操作
{
write_com(0xca);
write_data(shuzu[14]);
write_com(0xc0);
write_data(shuzu[12]);
}
else if(o==0) //隐藏*号不可操作
{
write_com(0xca);
write_data(shuzu[12]);
write_com(0xc0);
write_data(shuzu[12]);
}
if(u/100==0) //上限100内温度
{
write_com(0xc3);
write_data(shuzu[12]);//空格
write_com(0xc4);
write_data(shuzu[u/10]);//十位
write_com(0xc5);
write_data(shuzu[u%10]);//个位
}
else if (u/100==1)//上限100外温度
{
write_com(0xc3);
write_data(shuzu[u/100]);//百位
write_com(0xc4);
write_data(shuzu[(u-100)/10]);//十位
write_com(0xc5);
write_data(shuzu[u%10]);//个位
}
//下限温度
if (l<0)//下限低于0的温度显示
{
p=-l;
write_com(0xcD);
write_data(shuzu[11]);//负号
write_com(0xcE);
write_data(shuzu[p/10]);
write_com(0xcF);
write_data(shuzu[p%10]);
}
else if(l>=0)//下限高于0的温度显示
{
write_com(0xcD);
write_data(shuzu[12]);
write_com(0xcE);
write_data(shuzu[l/10]);
write_com(0xcF);
write_data(shuzu[l%10]);
}
}
void fuhao() //温度正负子程序
{
if(f==1) //温度为正
{
write_com(0x83);
write_data(shuzu[12]);
}
else if(f==0) //温度为负,显示负号
{
write_com(0x83);
write_data(shuzu[11]);
}
}
void display(unsigned int date)//显示温度
{
if(date/100==0) //100度内
{
write_com(0x84);
write_data(shuzu[date/10]);//十位
write_com(0x85);
write_data(shuzu[date%10]);//个位
write_com(0x86);
write_data(shuzu[13]);//小数点
write_com(0x87);
write_data(shuzu[xiaoshu1]);//小数点后一位
write_com(0x88);
write_data(shuzu[xiaoshu2]); //小数点后二位
}
else if(date/100==1) //100度上
{
write_com(0x83);
write_data(shuzu[date/100]);//百位
write_com(0x84);
write_data(shuzu[(date-100)/10]);//十位
write_com(0x85);
write_data(shuzu[date%10]);//个位
write_com(0x86);
write_data(shuzu[13]);//点
write_com(0x87);
write_data(shuzu[xiaoshu1]);//小数点后一位
write_com(0x88);
write_data(shuzu[xiaoshu2]);//小数点后二位
}
}
/***************独立按键****************/
void key()//按键加减
{
if(keym==0)
{
delay_50us(100);//延时消抖
if(keym==0)
{
y++;//转换加减的数值
if(y>=3)
y=0;
switch(y)
{
case 0:m=1;break;
case 1:m=5 ;break;
case 2:m=10 ;break;
}
while(keym==0);//自锁
}
}
if(keyh==0)//上下限转换按键
{
delay_50us(100);
if(keyh==0)
{
o++;
if(o>=3)o=0;//1为上限选中,2为下限选中,0为隐藏
while(keyh==0);
}
}
if(keyu==0&o==1)//上限加按键
{
delay_50us(100);
if(keyu==0&o==1)
{
u=u+m; while(keyu==0);
}
}
if(keyl==0&o==1) //上限减按键
{
delay_50us(100);
if(keyl==0&o==1)
{
u=u-m; while(keyl==0);
}
}
if(keyu==0&o==2)//下限加按键
{
delay_50us(100);
if(keyu==0&o==2)
{
l=l+m;while(keyu==0);
}
}
if(keyl==0&o==2)//下限减按键
{
delay_50us(100);
if(keyl==0&o==2)
{
l=l-m;while(keyl==0);
}
}
}
/***************温度报警子程序****************/
void BJ()
{
if(f==1) //温度大于0的温度比较
{
if(sdata>=u)//温度大于上限,报警
{
display(sdata);
button();
}
else if(l>0&sdata<=l)//温度小于下限,报警
{
display(sdata);
button();
}
else
display(sdata);
}
else if(f==0)//温度小于0的温度比较
{
if(l>=0)
{
display(sdata);
button();
}
else if(l<0)
{
if(sdata>=-l)//温度于下限,报警
{
display(sdata);
button();
}
else if(sdata<-l)//温度大于下限不报警
{
display(sdata);
}
}
else
display(sdata);
}
}
void main()
{
buzz=1;
display0();
display1();
while(1)
{
display2();
ReadTemperature();
fuhao();
key();
BJ();
}
}
WIFI模块 | 单片机主板 |
---|---|
GND | GND |
3V3 | 3.3V |
EN | 5V |
RX | P31 |
TX | P30 |
e) 实验操作
i. 用安卓手机连接模块的wifi,名称一般以ESP开头,然后安装对应的.apk软件 。
ii. 打开软件后,直接点击连接,提示连接成功后可通过“开”,“关”来控制板载D1的亮灭。
在Keil中将代码编译,生成“.hex”文件之后,通过烧写软件,将代码烧写单片机,则温度报警系统就开始工作。初始化后默认设定的温度上限值为40度,下限值为15度,超出此温度阈值则触发报警模块工作。在此基础上可通过独立按键控制调整温度的上下限值以及不同的模式选择。实际效果符合预期设想,单片机工作时,能够实时检测外界的温度,当温度高于当前设定的温度上限值或低于下限值时,触发报警模块,使得蜂鸣器以及led灯开始工作;而当温度重新处于当前的阈值范围内时,蜂鸣器停止鸣叫并且led灯停止闪烁。
本次实验在wifi模块出现了问题,在下载.hex文件时由于之前已经将P30和P31引脚与wifi模块相连,导致引脚占用,烧写程序时一直出现写芯片超时的情况,以致后面连上wifi后一直提示当前wifi不可用且软件连接不成功。经过查阅资料等途径,将P30与P31引脚拔掉,解决了此问题。
期望:可以进一步扩展为温湿度监测报警系统,并通过wifi或蓝牙将采集到的实时数据显示到移动终端。并能运用到日常生活以及工厂环境等温湿度监控需要。实时采集当前区域的温湿度数值,并且可以设定此值的上下限,当系统检测到当前温湿度超出界限时可以通过蜂鸣器提示报警,避免因温湿度原因造成不必要的伤害。