- 课程设计要求
- 可以显示温湿度,进行自动调温和灌溉。
- 可以手机控制手动灌溉。
- 主要设计思想
利用DHT11进行湿度检测、18B20用于温度检测
灌溉使用电机
用手机控制可以使用蓝牙或者2.4G远程控制
主要考察51单片机的综合应用能力 - 主要代码
DHT11.c
#include "DHT11.h"
#define uchar unsigned char
#define uint unsigned int
sbit DHT11_DQ_OUT=P3^2;
void delay(uint i)
{
while(i--);
}
void delay_ms(uint i)
{
while(i--)
delay(90);
}
//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
uchar DHT11_Read_Data(uchar *temp, uchar *humi)
{
uchar buf[5];
uchar i;
DHT11_Rst();
if(DHT11_Check()==0)
{
for(i=0;i<5;i++)//读取40位数据
{
buf[i]=DHT11_Read_Byte();
}
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
{
*humi=buf[0];
*temp=buf[2];
}
}else return 1;
return 0;
}
//复位DHT11
void DHT11_Rst()
{
DHT11_DQ_OUT=0; //拉低DQ
delay_ms(20); //拉低至少18ms
DHT11_DQ_OUT=1; //DQ=1
delay(3); //主机拉高20~40us
}
//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
uchar DHT11_Check()
{
uchar retry=0;
while (DHT11_DQ_OUT&&retry<100)//DHT11会拉低40~50us
{
retry++;
_nop_();
};
if(retry>=100)return 1;
else retry=0;
while (!DHT11_DQ_OUT&&retry<100)//DHT11拉低后会再次拉高40~50us
{
retry++;
_nop_();
};
if(retry>=100)return 1;
return 0;
}
//DHT11初始化
//返回0:初始化成功,1:失败
uchar DHT11_Init()
{
DHT11_Rst();
return DHT11_Check();
}
//从DHT11读取一个位
//返回值:1/0
uchar DHT11_Read_Bit(void)
{
uchar retry=0;
while(DHT11_DQ_OUT&&retry<100)//等待变为低电平 12-14us 开始
{
retry++;
_nop_();
}
retry=0;
while((!DHT11_DQ_OUT)&&retry<100)//等待变高电平 26-28us表示0,116-118us表示1
{
retry++;
_nop_();
}
delay(1);//等待40us
if(DHT11_DQ_OUT)return 1;
else return 0;
}
//从DHT11读取一个字节
//返回值:读到的数据
uchar DHT11_Read_Byte(void)
{
uchar i,dat=0;
for (i=0;i<8;i++)
{
dat<<=1;
dat|=DHT11_Read_Bit();
}
return dat;
}
DHT11.h
#ifndef __DHT11_H__
#define __DHT11_H__
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
void delay(uint i);
void delay_ms(uint i);
uchar DHT11_Read_Data(uchar *temp, uchar *humi);
void DHT11_Rst();
uchar DHT11_Check();
uchar DHT11_Init();
uchar DHT11_Read_Bit(void);
uchar DHT11_Read_Byte(void);
#endif
18B20.c
#include"delay.h"
#include"18b20.h"
/*18b20初始化*/
bit Init_DS18B20(void)
{
bit dat=0;
DQ = 1; //DQ复位
DelayUs2x(5); //稍做延时
DQ = 0; //单片机将DQ拉低
DelayUs2x(200); //精确延时 大于 480us 小于960us
DelayUs2x(200);
DQ = 1; //拉高总线
DelayUs2x(50); //15~60us 后 接收60-240us的存在脉冲
dat=DQ; //如果x=0则初始化成功, x=1则初始化失败
DelayUs2x(25); //稍作延时返回
return dat;
}
/*读取一个字节*/
unsigned char 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;
DelayUs2x(25);
}
return(dat);
}
/*写入一个字节*/
void WriteOneChar(unsigned char dat)
{
unsigned char i=0;
for (i=8; i>0; i--)
{
DQ = 0;
DQ = dat&0x01;
DelayUs2x(25);
DQ = 1;
dat>>=1;
}
DelayUs2x(25);
}
/*读取温度*/
unsigned int ReadTemperature(void)
{
unsigned char a=0;
unsigned int b=0;
unsigned int t=0;
Init_DS18B20();
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换
DelayMs(10);
Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
a=ReadOneChar(); //低位
b=ReadOneChar(); //高位
b<<=8;
t=a+b;
return(t);
}
18B20.H
#ifndef __DS18B20_H__
#define __DS18B20_H__
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include<intrins.h>
#define uchar unsigned char
sbit DQ=P1^3;//ds18b20 端口
unsigned int ReadTemperature(void);
bit Init_DS18B20(void);
unsigned char ReadOneChar(void);
void WriteOneChar(unsigned char dat);
#endif
delay.h和delay.c、1602.c和1602.h见这篇文章
main.c
#include<reg52.h>
#include "DHT11.h"
#include "1602.h"
#include "delay.h"
#include "18b20.h"
#define uchar unsigned char
#define uint unsigned int
sbit k1=P3^3; //模式
sbit k2=P2^1; //加
sbit k3=P2^2; //减
sbit led1=P3^6;
sbit led2=P3^7;
sbit dq=P2^0;
sbit relay=P1^4; //加热设备
sbit moto=P1^5; //电机散热
sbit auto_moto=P1^6; //自动灌溉电机
uchar mode=0,xian;
char temph=50,templ=20;
char humih=80,humil=20;
uchar temp,humi;
uchar flag; //设定报警标志
uchar auto_flag; //设置自动、手动灌溉标志
uchar a,c,t,tempvalue;
uchar code num[10]="0123456789";
uchar code str1[]="Temp:"; //温度
uchar code str2[]="Humi:"; //湿度
uchar code str3[]="Error";
uchar code str4[]="Success ";
uchar code str5[]="%RH";
uchar code str6[]="TempH:"; //设定温度上限显示
uchar code str7[]="TempL:"; //设定温度下限显示
uchar code str8[]="HumiH:"; //设定湿度上限显示
uchar code str9[]="HumiL:"; //设定湿度下限显示
void key_pros() //按键处理函数
{
if(k1==0)
{
delay(1000);
if(k1==0)
{
mode++;
if(mode==5)mode=0;
LCD_Write_Com(0x01);
}
while(!k1);
}
if(mode==1) //对温度上限设定
{
if(k2==0) //加
{
delay(1000);
if(k2==0)
{
temph++;
if(temph>=80)temph=80;
}
while(!k2);
}
if(k3==0) //减
{
delay(1000);
if(k3==0)
{
temph--;
if(temph<=0)temph=0;
}
while(!k3);
}
}
if(mode==2) //对温度下限设定
{
if(k2==0) //加
{
delay(1000);
if(k2==0)
{
templ++;
if(templ>=80)templ=80;
}
while(!k2);
}
if(k3==0) //减
{
delay(1000);
if(k3==0)
{
templ--;
if(templ<=0)templ=0;
}
while(!k3);
}
}
if(mode==3) //对湿度上限设定
{
if(k2==0) //加
{
delay(1000);
if(k2==0)
{
humih++;
if(humih>=80)humih=80;
}
while(!k2);
}
if(k3==0) //减
{
delay(1000);
if(k3==0)
{
humih--;
if(humih<=0)humih=0;
}
while(!k3);
}
}
if(mode==4) //对湿度下限设定
{
if(k2==0) //加
{
delay(1000);
if(k2==0)
{
humil++;
if(humil>=80)humil=80;
}
while(!k2);
}
if(k3==0) //减
{
delay(1000);
if(k3==0)
{
humil--;
if(humil<=0)humil=0;
}
while(!k3);
}
}
}
void lcd_init_display() //LCD初始化显示
{
uchar i;
for(i=0;i<5;i++)
{
LCD_Write_Com(0x80+i);
LCD_Write_Data(str1[i]);
}
for(i=0;i<5;i++)
{
LCD_Write_Com(0xc0+i);
LCD_Write_Data(str2[i]);
}
}
void data_pros() //数据处理函数
{
uchar i;
uchar temp_buf[2],humi_buf[2];
uchar temphbuf[2],templbuf[2],humihbuf[2],humilbuf[2];
float dio;
uint k;
tempvalue=ReadTemperature();
DHT11_Read_Data(&temp,&humi);
temp_buf[0]=temp/10+0x30;
temp_buf[1]=temp%10+0x30;
humi_buf[0]=humi/10+0x30;
humi_buf[1]=humi%10+0x30;
dio=a*0.0625;
k=dio*10000;//取小数点后两位有效数字
temphbuf[0]=temph/10+0x30;
temphbuf[1]=temph%10+0x30;
templbuf[0]=templ/10+0x30;
templbuf[1]=templ%10+0x30;
humihbuf[0]=humih/10+0x30;
humihbuf[1]=humih%10+0x30;
humilbuf[0]=humil/10+0x30;
humilbuf[1]=humil%10+0x30;
if(mode==0)
{
lcd_init_display();
LCD_Write_Com(0x85);
LCD_Write_Data(num[tempvalue%100/10]);
LCD_Write_Data(num[tempvalue%100%10]);
LCD_Write_Data('.');
LCD_Write_Data(num[k/1000]);
LCD_Write_Data(0xdf);
LCD_Write_Data('C');
for(i=0;i<2;i++)
{
LCD_Write_Com(0Xc5+i);
LCD_Write_Data(humi_buf[i]);
}
for(i=0;i<3;i++)
{
LCD_Write_Com(0Xc7+i);
LCD_Write_Data(str5[i]);
}
}
if(mode==1) //温度上限显示
{
LCD_Write_Com(0x80);
for(i=0;i<6;i++)
{
LCD_Write_Data(str6[i]);
}
LCD_Write_Data(temphbuf[0]);
LCD_Write_Data(temphbuf[1]);
}
if(mode==2) //温度下限显示
{
LCD_Write_Com(0x80);
for(i=0;i<6;i++)
{
LCD_Write_Data(str7[i]);
}
LCD_Write_Data(templbuf[0]);
LCD_Write_Data(templbuf[1]);
}
if(mode==3) //湿度上限显示
{
LCD_Write_Com(0x80);
for(i=0;i<6;i++)
{
LCD_Write_Data(str8[i]);
}
LCD_Write_Data(humihbuf[0]);
LCD_Write_Data(humihbuf[1]);
}
if(mode==4) //湿度下限显示
{
LCD_Write_Com(0x80);
for(i=0;i<6;i++)
{
LCD_Write_Data(str9[i]);
}
LCD_Write_Data(humilbuf[0]);
LCD_Write_Data(humilbuf[1]);
}
}
void baojinpros() //报警处理
{
if(tempvalue>=temph||humi>=humih) //检测温度或者湿度高于设定上限值 降温湿
{
led1=1; //降温湿指示灯
led2=0;
moto=1;
relay=1;
if(humi>=humih&&auto_flag==0) //湿度过高,自动停止灌溉
{
auto_moto=0;
}
}
if(tempvalue<=templ||humi<=humil) //检测温度或者湿度低于设定下限值 升温湿
{
led1=0; //升高温湿指示灯
led2=1;
moto=0;
relay=0;
if(humi<=humih&&auto_flag==0) //湿度过低,自动开始灌溉
{
auto_moto=1;
}
}
if((tempvalue>templ&&tempvalue<temph)&&(humi>humil&&humi<humih))
{
led1=0;
led2=0;
moto=0;
relay=1;
if(auto_flag==0) //自动开始灌溉
{
auto_moto=1;
}
}
}
void sss() interrupt 4
{
if(RI)
{
t=SBUF;
if(t=='1') //相当于按键k1
{
k1=0;
key_pros();
k1=1;
}
if(t=='2') //相当于按键k2
{
k2=0;
key_pros();
k2=1;
}
if(t=='3') //相当于按键k3
{
k3=0;
key_pros();
k3=1;
}
if(t=='4') auto_flag=~auto_flag; //手动、自动灌溉
RI=0;
}
}
void main()
{
uchar i=0;
led1=0; //各模块初始化
led2=0;
relay=1;
moto=0;
auto_moto=0;
auto_flag=0;
LCD_Init();
TMOD=0X20; //串口初始化
TH1=0XFD;
TL1=0XFD;
TR1=1;
SCON=0X50;
ES=1;
EA=1;
while(DHT11_Init()) //检测DHT11是否存在
{
for(i=0;i<5;i++)
{
LCD_Write_Com(0x80+i);
LCD_Write_Data(str3[i]);
}
}
LCD_Write_Com(0x01);
lcd_init_display(); //LCD初始化显示
i=0;
while(1)
{
i++;
key_pros(); //按键处理
baojinpros(); //报警处理
if(i==15)
{
i=0;
data_pros(); //读取一次DHT11数据最少要大于100ms
}
delay(1000);
}
}
安卓界面的代码略,读者可用Java或易安卓自行开发