基于51单片机的温湿度检测设计,有蓝牙向手机传输功能
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
电路原理图如下:
注释很详细的单片机源程序如下:
- #include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
- #include<intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- #define lcddata P0 //数据端口;
- sbit io=P1^0; //dht11data端接单片机的P1^0口//
- sbit SPK =P1^1; //蜂鸣器;
- sbit LED =P1^2; //报警灯 ;
- sbit JDQ_WenDu =P1^3; // 控制风扇的继电器;
- sbit JDQ_ShiDu =P1^4; // 控制风扇的继电器;
- sbit K1=P3^2; //手动/自动复位功能;
- sbit K2=P3^3; //页面选择;
- sbit K3=P3^4; //修改min,按键加1;
- sbit K4=P3^5; //修改max,按键加1;
- sbit RS = P2^0; //Pin4 数据命令选择; 高电平时为数据寄存器,低电平是为选择指令寄存器;
- sbit RW = P2^1; //Pin5 读写模式选择;
- sbit E = P2^2; //Pin6 使能信号;
- bit di=1;
- bit flag_300ms ;
- unsigned char s[3]={0,0,'\0'}; //只读取两个字节,读到第三个结束;
- unsigned char table[]={0,1,2,3,4,5,6,7,8,9};
- unsigned int j=40,i=0,sum=0;
- int tempeature; //整型变量 tempeature:温度
- uchar yemian=0; //(定义变量)
- uchar flat=1;
- unsigned char WenDu=20,ShiDu=40;//报警的温度和湿度
- typedef bit BOOL; //此声明一个布尔型变量即真或假//
- uchar data_byte;
- uchar RH,RL,TH,TL;
- void receive(); //接收数据//
- /******************************************************************/
- void DelayUs(unsigned char us)//delay us
- {
- unsigned char uscnt;
- uscnt=us>>1; /*12MHz频率*/
- while(--uscnt);
- }
- /******************************************************************/
- /* 毫秒函数声明 */
- /******************************************************************/
- void DelayMs(unsigned int ms)
- {
- while(--ms)
- {
- DelayUs(250);
- DelayUs(250);
- DelayUs(250);
- DelayUs(250);
- }
- }
- //***************延时函数*************************************
- void delay(uchar ms) //延时模块//
- {
- uchar i;
- while(ms--)
- for(i=0;i<100;i++);
- }
- void delay1() //一个for循环大概需要8个多机器周期 一个机器周期为1us 晶振为12MHz 也就是说本函数延时8us多 此延时函数必须德稍微精确一点
- {
- uchar i;
- for(i=0;i<1;i++);
- }
- // 对液晶经行写指令;
- void wr_i_lcd(uchar content)
- {
- DelayMs(5);//操作前短暂延时,保证信号稳定
- E=0; //E端的由高电平跳变成低电平时,液晶模块执行命令; 此处位E端清零操作
- RS=0;
- RW=0;
- E=1;
- lcddata=content;
- E=0;
- }
- // 液晶初始化,清除显示,归为地址;
- void lcd_csh()
- {
- // wr_i_lcd(0x01); //清除显示;
- // wr_i_lcd(0x30); //地址归位; 30H:设定8位控制界面;
- // // 00H:基本指令集;
- // // 34H:设定扩展指令集;
- // wr_i_lcd(0x0c); //开显示,无光标,光标不闪烁; 0x0e:开显示,有光标,光标不闪烁; 0x0f:开显示,有光标,光标闪烁;
- // wr_i_lcd(0x10); //光标向左移;
- // wr_i_lcd(0x06); /*光标的移动方向 */
-
- DelayMs(15);
- wr_i_lcd(0x38);
- DelayMs(5);
- wr_i_lcd(0x38);
- DelayMs(5);
- wr_i_lcd(0x38);
- DelayMs(5);
- wr_i_lcd(0x0c);
- DelayMs(5);
- wr_i_lcd(0x06);
- DelayMs(5);
- wr_i_lcd(0x01);
- DelayMs(5);
- }
- // 对液晶进行写数据;
- void wr_d_lcd(uchar content)
- {
- DelayMs(5); //操作前短暂延时,保证信号稳定
- E=0;
- RS=1;
- RW=0;
- E=1;
- lcddata=content;
- E=0;
- RS=0;
- }
-
- // 显示坐标位置的函数;
- void gotoxy(uchar y,uchar x)
- {
- if(y==1) //第一行第一列;
- wr_i_lcd(0x80|x); //对液晶经行写指令;
-
- if(y==2) //第二行第一列;
- wr_i_lcd(0xc0|x); //对液晶经行写指令;
- }
- // printf输入字符串操作;
- void printf(uchar *str)
- {
- while(*str!='\0')
- {
- wr_d_lcd(*str);
- str++;
- }
- }
- // 液晶显示主程序操作; 初始显示welcome
- void show()
- {
- gotoxy(1,4);
- printf("welcome");
- }
- void shezhi() //对里面的数值进行修改
- {
- if(!K3) //温湿度数据大小加++;
- {
- DelayMs(50);
- if(!K3)
- {
- while(K3==0);
- if(yemian==1)
- {
- WenDu+=1;
- if(WenDu>99) { WenDu=99; } //温度上限加
-
- }
- if(yemian==2)
- {
- ShiDu+=1;
- if(ShiDu>99) { ShiDu=99; } //湿度下限加
- }
- }
- }
- if(!K4)
- {
- DelayMs(50);
- if(!K4)
- {
- while(K4==0); //按一次,防止按下不松,加多次
- if(yemian==1)
- {
- if(WenDu<1) {WenDu=1; }
- WenDu-=1; //湿度下限减
- }
- if(yemian==2)
- {
- if(ShiDu<1) { ShiDu=1; }
- ShiDu-=1; //湿度下限减
- }
- }
- }
- }
- // 中断初始化
- void Int()
- {
- EA=1;
- EX0=1;
- IT0=1;
-
- PX0=1; //(中断0为最高优先级)
-
- EX1=1;
- IT1=1;
- }
- // 报警部分
- void warn()
- {
-
- // if((ShiDu>RH)||(WenDu<TH))
- // {
- // SPK=1;
- // LED=1;
- // }
- // else
- // {
- // SPK=0;
- // LED=0;
- // }
-
- if(ShiDu<RH)
- {
- JDQ_ShiDu =1; // 控制加湿器的继电器;
- SPK=1;
- LED=1;
- }
- else
- {
- JDQ_ShiDu =0; // 控制加湿器的继电器;
- SPK=0;
- LED=0;
- }
-
- DelayMs(200);
- if(WenDu>TH) //WenDu为设定值,TH测量值;
- {
- SPK=1;
- LED=1;
- JDQ_WenDu =1; // 控制风扇的继电器;
- }
- else
- {
- SPK=0;
- LED=0;
- JDQ_WenDu =0; // 控制风扇的继电器;
- }
-
- }
- /***************************选择界面工作状态*********************************/
- void Xuanze()
- {
- // key();
- //====================yemian==0时 进入工作状态=================================
- if(yemian==0)
- {
- if(flat==1)
- {
- flat=0;
- lcd_csh(); //初始化
-
- gotoxy(1,0);
- printf("Temp:00");
-
- gotoxy(1,8);
- s[0]=0xdf; //由一个字符串转化为一个字符;
- s[1]=0x43;
- printf(s);
-
- gotoxy(2,0);
- printf("Humi:00");
-
- gotoxy(2,7);
- printf("%RH");
-
- gotoxy(1,12);
- printf("T:");
-
- s[0]=WenDu/10+0x30; //由一个字符串转化为一个字符;
- s[1]=WenDu%10+0x30;
- printf(s);
- // display(0x0e,WenDu/10+0x30); //报警温度
- // display(0x0f,WenDu%10+0x30);
-
- gotoxy(2,12);
- printf("H:");
- s[0]=ShiDu/10+0x30; //由一个字符串转化为一个字符;
- s[1]=ShiDu%10+0x30;
- printf(s);
- // display(0x4e,ShiDu/10+0x30); //报警湿度
- // display(0x4f,ShiDu%10+0x30);
-
- }
- // ***********DHT11读取显示部分************
- receive();
- gotoxy(1,5);
- s[0]=TH/10+0x30; //由一个字符串转化为一个字符;
- s[1]=TH%10+0x30;
- printf(s);
-
- gotoxy(2,5);
- s[0]=RH/10+0x30; //由一个字符串转化为一个字符;
- s[1]=RH%10+0x30;
- printf(s);
- }
- //====================yemian==1 温度设置===========================
- if(yemian==1) //温度
- {
- if(flat==1)
- {
- flat=0;
- lcd_csh(); //初始化
- // bee=1;
- gotoxy(1,0);
- printf("Temp max:");
- }
- shezhi();
- gotoxy(2,7);
- s[0]=WenDu/10+0x30; //由一个字符串转化为一个字符;
- s[1]=WenDu%10+0x30;
- printf(s);
-
- SPK=1;
- LED=1;
- }
- //====================yemian==1湿度设置==========================
- if(yemian==2) //湿度设置
- {
- if(flat==1)
- {
- flat=0;
- // bee=1;
- lcd_csh(); //初始化
- gotoxy(1,0);
- printf("Humi min:");
- }
- shezhi();
- gotoxy(2,7);
- s[0]=ShiDu/10+0x30; //由一个字符串转化为一个字符;
- s[1]=ShiDu%10+0x30;
- printf(s);
-
- SPK=1;
- LED=1;
- }
- }
- //**************************dht11测试某块*************************************//
- void start() //开始信号
- {
- io=1;
- delay1();
- io=0;
- delay(30); // 主机把总线拉低必须大于18ms 保证DHT11能检测到起始信号
- io=1; //发送开始信号结束后 拉高电平延时20-40us
-
- delay1(); //以下三个延时函数差不多为24us 符合要求
- delay1();
- delay1();
-
- delay1();
- delay1();
- }
- uchar receive_byte() //接收一个字节//
- {
- uchar i,temp;
- for(i=0;i<8;i++) //接收8bit的数据
- {
- while(!io); //等待50us的低电平开始信号结束
- delay1(); //开始信号结束之后 延时26us-28us 以下三个延时函数
- delay1();
- delay1();
- temp=0; //时间为26us-28us 表示接收的为数据'0'
- if(io==1)
- temp=1; //如果26us-28us之后 还为高电平 则表示接收的数据为'1'
- while(io); //等待数据信号高电平 '0'为26us-28us '1'为70us
- data_byte<<=1; //接收的数据为高位在前 右移
- data_byte|=temp;
- }
- return data_byte;
- }
- void receive() //接收数据//
- {
- uchar T_H,T_L,R_H,R_L,check,num_check,i;
- start(); //开始信号//
- io=1; //主机设为输入 判断从机 DHT11 响应信号
- if(!io) //判断从机是否有低电平响应信号//
- {
- while(!io); //判断从机发出 80us 的低电平响应信号是否结束//
- while(io); //判断从机发出 80us 的高电平是否结束 如结束则主机进入数据接收状态
- R_H=receive_byte(); //湿度高位
- R_L=receive_byte(); //湿度低位
- T_H=receive_byte(); //温度高位
- T_L=receive_byte(); //温度低位
- check=receive_byte(); //校验位
- io=0; //当最后一bit数据接完毕后 从机拉低电平50us//
- for(i=0;i<7;i++) //差不多50us的延时
- delay1();
- io=1; //总线由上拉电阻拉高 进入空闲状态
- num_check=R_H+R_L+T_H+T_L;
- if(num_check==check) //判断读到的四个数据之和是否与校验位相同
- {
- RH=R_H;
- RL=R_L;
- TH=T_H;
- TL=T_L;
- check=num_check;
- }
- }
- }
- /*************************串口初始化*********************************/
- void UsartConfiguration()
- {
- SCON=0x50; //设置位方式1; REN=1(接收允许)
- TMOD=0x20; //计数器工作方式2; 计数器T1
- PCON=0x00; //SMOD=0;
- TH1=0xfd; //波特率位9600bit/s;
- TL1=0xfd;
- TR1=1; //打开计数器;
- ES=1; //打开接收中断;
- EA=1; //打开总中断;
- }
- /***************************主程序*********************************/
- void main()
- {
- SPK=1;
- LED=1;
- Int(); //中断初始化;
- lcd_csh(); //LCD1602初始化;
- UsartConfiguration(); //串口初始化;
- show();
- DelayMs(1000); //3s以后,进入主程序部分,初始化部分结束;
- while(1)
- {
-
- RI=1;
- Xuanze();
- DelayMs(200);
- if(yemian==0) { warn(); }
- }
- }
- /*********************页面选择*****************************/
- void int0(void) interrupt 0 //
- {
-
- if(!K1) //页面选择;
- {
- DelayMs(20); //程序消抖;
- if(!K1)
- {
- yemian++;
- flat++;
- while(!K1);
- if(yemian>=3) { yemian=0; }
- }
- }
- }
- //************手机APP发送端*************
- void uart() interrupt 4
- {
-
- //************发送湿度部分***************************
- RI=0; // //清除收到中断标志位;
- SBUF=RH/10+0x30; //将接收到的数据放回发送缓存器;
- while(!TI); //等待发送数据完成;
- TI=0; //清除发送中断标志位;
-
- RI=0; //清除收到中断标志位;
- SBUF=RH%10+0x30; //将接收到的数据放回发送缓存器;
- while(!TI); //等待发送数据完成;
- TI=0; //清除发送中断标志位;
-
- RI=0; // % //清除收到中断标志位;
- SBUF=37; //将接收到的数据放回发送缓存器;
- while(!TI); //等待发送数据完成;
- TI=0; //清除发送中断标志位;
-
- RI=0; // R //清除收到中断标志位;
- SBUF=82; //将接收到的数据放回发送缓存器;
- while(!TI); //等待发送数据完成;
- TI=0;
-
- RI=0; // H //清除收到中断标志位;
- SBUF=72; //将接收到的数据放回发送缓存器;
- while(!TI); //等待发送数据完成;
- TI=0; //清除发送中断标志位;
-
- for(i=0;i<10;i++)
- {
- RI=0; //空格 //清除收到中断标志位;
- SBUF=32; //将接收到的数据放回发送缓存器;
- while(!TI); //等待发送数据完成;
- TI=0;
- }
- //************发送温度部分***************************
- RI=0; // //清除收到中断标志位;
- SBUF=TH/10+0x30; //将接收到的数据放回发送缓存器;
- while(!TI); //等待发送数据完成;
- TI=0; //清除发送中断标志位;
-
- RI=0; //清除收到中断标志位;
- SBUF=TH%10+0x30; //将接收到的数据放回发送缓存器;
- while(!TI); //等待发送数据完成;
- TI=0;
- //清除发送中断标志位;
- RI=0; //清除收到中断标志位;
- SBUF=96; //将接收到的数据放回发送缓存器;
- while(!TI); //等待发送数据完成;
- TI=0; //清除发送中断标志位;
-
- RI=0; //清除收到中断标志位;
- SBUF=67; //将接收到的数据放回发送缓存器;
- while(!TI); //等待发送数据完成;
- TI=0; //清除发送中断标志位;
- SBUF=10; // (换行)
- while(!TI); //等待发送数据完成;
- TI=0; //清除发送中断标志位;
-
- }
复制代码
所有资料51hei提供下载:
无限温湿度检测f(仿真).zip
(25.01 KB, 下载次数: 125)
温湿度测量程序.zip
(48.43 KB, 下载次数: 130)
|