- 课程设计要求
- 可以显示温湿度,进行自动调温和灌溉。
- 可以手机控制手动灌溉。
- 主要设计思想
利用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或易安卓自行开发