本设计以STC89C52单片机为核心控制器,加上其他的模块一起组成智能窗户的整个系统,其中包含中控部分、输入部分和输出部分。中控部分采用了STC89C5单片机,其主要作用是获取输入的部分数据,经过内部处理,控制输出部分。输入由七部分组成,第一部分是温度检测模块,通过该模块检测室内温度;第二部分是风速和ADC配合构成的模块,用来检测风速;第三部分是甲烷模块和ADC配合构成的甲烷检测模块,用来检测甲烷值;第四部分是雨量检测模块和ADC配合,用来检测是否下雨;第五部分是烟雾检测模块和ADC配合,用来检测烟雾浓度;第六部分是按键模块,用来切换界面和设置最值;第七部分是供电模块,通过该模块可给整个系统进行供电。输出由五部分组成,第一部分时LCD1602显示模块,显示检测值和设置值;第二部分是步进电机模块通过该模块控制窗户的开关;第三部分是继电器,通过该模块,控制通风;第四部分是报警模块,当检测值大于设置值进行声光报警;当检测异常时将发送短信到手机,并且可以使用手机发送指令控制窗户,控制加热、切换自动模式,系统框图如图3.1所示。
DZ002-基于51单片机的智能多功能窗户仿真_哔哩哔哩_bilibili
图3.1 系统框图
系统程序设计
4.1 编程软件介绍
本设计所用到的编程软件为Keil5,其界面如图4-1所示:
图4-1 Keil5开发界面
本设计所使用的编程环境是Keil5,相对于其他软件编程环境,Keil5更加的轻便快捷,操作更加的简单,深受广大嵌入式软件开发者的喜爱。Keil5支持多种芯片,包括51单片机、STM32、HC32、NXP等,生成的HEX文件,可通过烧录器直接烧录到单片机中,非常方便。另外,Keil5编译有三种,一种是单编,一种是部分编译,还有一种是全部编译,这样给开发人员更多的选择,并且编译的结果,显示在界面的最下方,供开发者查找错误。
4.2 主程序流程设计
系统的主流程图如图4-2所示;在主程序中,首先对各个模块进行初始化,随后进入while主循环,在主循环中,首先进入第一个函数按键函数,通过按键扫描检测按键是否按下,通过按键进行模式切换、设置温度最小值、设置烟雾最大值、设置瓦斯最大值、设置风速最大值、设置雨量最大值等;然后进入第二个函数监测函数,通过温度传感器检测环境温度,通过烟雾浓度检测烟雾值,通过瓦斯监测模块检测瓦斯,通过雨量检测模块检测雨量,并将检测的数据通过蓝牙发送到手机;然后进入第三个函数显示函数,根据不同的显示模式标志位,显示不同的界面,界面0:显示温度烟雾值瓦斯值风速值雨量值自动/手动 开窗/关窗 状态,界面1:显示设置温度最小值,界面2:显示设置烟雾最大值;界面3:显示设置瓦斯最大值,界面4:显示设置风速最大值,界面5:显示设置雨量最大值;然后进入第四个函数出来函数,进入测量显示界面,当温度小于设置的最小值或风速值或者雨量大于设置的最大值,如果之前是开窗状态则关窗,如果烟雾值大于设定的最大值或者甲烷值大于设定的最大值打开蜂鸣器打开窗户继电器打开风扇开启,如果之前是关窗状态则开窗,蓝牙发送指令“A”,切换自动模式;蓝牙发送指令“B”,控制开窗户;蓝牙发送指令“C”,控制关窗户;蓝牙发送指令“D”,控制加热;蓝牙发送指令“E”,控制风扇。
图4-2 程序总体流程图
4.3 按键函数流程设计
按键函数子流程图如图4-3所示;通过按键扫描,获取按键值,执行相应的处理,检测到按键1按下时,切换设置界面;检测到按键2按下时,在界面1,温度最大值+1,在界面2,温度最小值+1;检测到按键3按下时,在界面1,温度最大值-1,在界面2,温度最小值-1。
图4-3 按键函数子流程图
4.4 显示函数流程设计
显示函数子流程如图4-4所示;通过不同的显示模式标志位,在界面O显示显示温度 烟雾值瓦斯值风速值雨量值自动/手动开窗/关窗状态,界面1:显示设置温度最小值;在界面1显示设置温度最大值。在界面2,显示设置温度最小值;界面2:显示设置烟雾最大值;显示设置瓦斯最大值;显示设置风速最大值。
图4-4 显示函数子流程图
4.5 处理状态函数流程设计
处理状态子函数流程图如图4-5所示,然后进入第四个函数处理函数,进入测量显示界面,当温度小于设置的最小值或风速值或者雨量大于设置的最大值,如果之前是开窗状态则关窗,如果烟雾值大于设定的最大值或者甲烷值大于设定的最大值打开蜂鸣器打开窗户继电器打开风扇开启,如果之前是关窗状态则开窗,蓝牙发送指令“A”,切换自动模式;蓝牙发送指令“B”,控制开窗户;蓝牙发送指令“C”,控制关窗户;蓝牙发送指令“D”,控制加热;蓝牙发送指令“E”,控制风扇。
图4-5 处理函数子流程图
详细代码如下:
/**********************************
作者:单片机定制之家
VX:MCU-wldz
**********************************/
/**********************************
包含头文件
**********************************/
#include "main.h"
#include "lcd1602.h"
#include "key.h"
#include "timer.h"
#include "ds18b20.h"
#include "motor_bujin.h"
#include "adc.h"
#include "uart.h"
/**********************************
变量定义
**********************************/
uchar key_num = 0; //按键扫描标志位
uint time_num = 0; //10ms计时变量
uchar flag_display = 0; //显示界面标志位
uchar flag_lanya = 2; //蓝牙传输标志位
bit flag_window = 1; //窗户开关标志位 默认关闭窗户
bit flag_mode = 0; //模式 自动模式和手动模式
int temp_value = 0; //温度值
int temp_min = 10; //温度最小值
uint smog_value = 0; //烟雾值
uint smog_max = 150; //烟雾最大值
uint gas_value = 0; //瓦斯值
uint gas_max = 150; //瓦斯最大值
uint wind_value = 0; //风速值
uint wind_max = 10; //风速最大值
uint rain_value = 0; //雨量值
uint rain_max = 150; //雨量最大值
uchar send_buf[28]; //发送数组
/**********************************
函数声明
**********************************/
void Delay_function(uint x); //延时函数(ms)
void Key_function(void); //按键函数
void Monitor_function(void); //监测函数
void Display_function(void); //显示函数
void Manage_function(void); //处理函数
/****
******* 主函数
*****/
void main()
{
Lcd1602_Init(); //LCD1602初始化
Delay_function(50); //延时50ms
lcd1602_clean(); //清屏
Delay_function(50); //延时50ms
Uart_Init(); //串口初始化函数 蓝牙要用
Delay_function(50); //延时50ms
Ds18b20_Init(); //DS18B20初始化
Delay_function(50); //延时50ms
Timer0_Init(); //定时器0初使化函数
Delay_function(50); //延时50ms
while(1)
{
Key_function(); //按键函数
Monitor_function(); //监测函数
Display_function(); //显示函数
Manage_function(); //处理函数
Delay_function(10); //延时10ms
time_num++; //计时变量+1
if(time_num == 5000)
{
time_num = 0;
}
}
}
/****
******* 延时 x ms函数
*****/
void Delay_function(uint x)
{
uint m,n;
for(m=x;m>0;m--)
for(n=110;n>0;n--);
}
/****
*******按键函数
*****/
void Key_function(void)
{
key_num = Chiclet_Keyboard_Scan(0); //按键扫描
if(key_num != 0) //有按键按下
{
switch(key_num)
{
case 1: //按键1,切换设置界面
flag_display++;
if(flag_display >= 6) //包括显示检测界面一共6个界面
flag_display = 0;
lcd1602_clean(); //清屏
break;
case 2: //按键2
switch(flag_display)
{
case 0: //界面0:切换模式
flag_mode = ~flag_mode;
break;
case 1: //界面1:温度最小值+1
if(temp_min < 99)
temp_min++;
break;
case 2: //界面2:烟雾最大值+1
if(smog_max < 250)
smog_max++;
break;
case 3: //界面3:瓦斯最大值+1
if(gas_max < 250)
gas_max++;
break;
case 4: //界面4:湿风速最大值+1
if(wind_max < 99)
wind_max++;
break;
case 5: //界面5:雨量最大值+1
if(rain_max < 500)
rain_max++;
break;
default:
break;
}
break;
case 3: //按键3
switch(flag_display)
{
case 0:
if( flag_window == 0 ) //如果之前是开窗状态 则关窗且标志位置1
{
Motor_Foreward(); //关窗
flag_window=1; //已经关窗==1
}
else if( flag_window == 1 ) //如果之前是关窗状态 则开窗 标志位置0
{
Motor_Reversal();
flag_window = 0;
}
flag_mode = 1; //按下按键视为切换到手动模式
break;
case 1: //界面1:温度最小值-1
if(temp_min > 0)
temp_min--;
break;
case 2: //界面2:烟雾最大值-1
if(smog_max > 0)
smog_max--;
break;
case 3: //界面3:瓦斯最大值-1
if(gas_max > 0)
gas_max--;
break;
case 4: //界面4:风速最大值-1
if(wind_max > 0)
wind_max--;
break;
case 5: //界面5:雨量最大值-1
if(rain_max > 0)
rain_max--;
break;
}
break;
default:
break;
}
}
}
/****
*******监测函数
*****/
void Monitor_function(void)
{
if(time_num % 10 == 0) //100ms检测一次
{
temp_value = Ds18b20_Read_Temp(); //获取温度
smog_value = 50*((Adc0832_Get_Value(1)/255.0)*5); //获取烟雾浓度
gas_value = 50*((Adc0832_Get_Value1(1)/255.0)*5); //获取瓦斯值
wind_value = (10*((Adc0832_Get_Value1(0)/255.0)*5)); //获取风速值
rain_value = (500-100*((Adc0832_Get_Value(0)/255.0)*5)); //获取雨量值最大值设为500mm
}
if(time_num % 100 == 0) //1000ms发送一次
{
sprintf(send_buf,"Temp:%d.%dC\r\nSmog:%dppm\r\n",temp_value/10,temp_value%10,smog_value);
Uart_Sent_Str(send_buf); //发送温度和烟雾值
sprintf(send_buf,"Gas:%dppm\r\n",gas_value);
Uart_Sent_Str(send_buf); //发送瓦斯值和风速值
sprintf(send_buf,"Wind:%dm/s\r\nRain:%dmm\r\n",wind_value,rain_value);
Uart_Sent_Str(send_buf); //发送瓦斯值和风速值
if(flag_window == 0)
Uart_Sent_Str("window is open\r\n");
else
Uart_Sent_Str("window is closed\r\n");
}
}
/****
*******显示函数
*****/
void Display_function(void)
{
switch(flag_display) //根据不同的显示模式标志位,显示不同的界面
{
case 0: //界面0:显示温度 烟雾值 瓦斯值 风速值 雨量值 自动/手动 开窗/关窗 状态
{
lcd1602_display_str(1,0,"T:");
lcd1602_display_temp(1,2,temp_value);
lcd1602_display_str(1,8,"S:");
lcd1602_display_gas(1,10,smog_value);
lcd1602_display_str(2,0,"G:");
lcd1602_display_gas(2,2,gas_value);
lcd1602_display_str(2,5,"W:");
lcd1602_display_wind(2,7,wind_value);
lcd1602_display_str(2,10,"R:");
lcd1602_display_rain(2,12,rain_value);
if(flag_mode == 0)
lcd1602_display_str(2,15,"A");
else
lcd1602_display_str(2,15,"M");
if(flag_window==0)
lcd1602_display_str(1,15,"O");
else if(flag_window==1)
lcd1602_display_str(1,15,"C");
}
break;
case 1: //界面1:显示设置温度最小值 屏幕第二行闪烁显示
lcd1602_display_str(1,2,"Set Temp Min");
if(time_num % 20 == 0)
{
lcd1602_display_num(2,7,temp_min);
}
if(time_num % 40 == 0)
{
lcd1602_display_str(2,7," ");
}
break;
case 2: //界面2:显示设置烟雾最大值 屏幕第二行闪烁显示
lcd1602_display_str(1,2,"Set Smog Max");
if(time_num % 20 == 0)
{
lcd1602_display_num(2,7,smog_max);
}
if(time_num % 40 == 0)
{
lcd1602_display_str(2,7," ");
}
break;
case 3: //界面3:显示设置瓦斯最大值 屏幕第二行闪烁显示
lcd1602_display_str(1,2,"Set Gas Max");
if(time_num % 20 == 0)
{
lcd1602_display_num(2,7,gas_max);
}
if(time_num % 40 == 0)
{
lcd1602_display_str(2,7," ");
}
break;
case 4: //界面4:显示设置风速最大值 屏幕第二行闪烁显示
lcd1602_display_str(1,2,"Set Wind Max");
if(time_num % 20 == 0)
{
lcd1602_display_num(2,7,wind_max);
}
if(time_num % 40 == 0)
{
lcd1602_display_str(2,7," ");
}
break;
case 5: //界面5:显示设置雨量最大值 屏幕第二行闪烁显示
lcd1602_display_str(1,2,"Set Rain Max");
if(time_num % 20 == 0)
{
lcd1602_display_num(2,7,rain_max);
}
if(time_num % 40 == 0)
{
lcd1602_display_str(2,7," ");
}
break;
default:
break;
}
}
/****
*******处理函数
*****/
void Manage_function(void)
{
if(flag_display == 0) //进入测量显示界面
{
/* 以下是测量显示界面的 自动控制模式 */
if(flag_mode == 0) //如果是自动模式
{
if( ( (temp_value < temp_min*10) || (wind_value > wind_max) || (rain_value >rain_max) ) && (smog_value < smog_max) && (gas_value < gas_max) ) //当温度小于设置的最小值 或 风速值或者雨量大于设置的最大值 且其他值都正常时 报警并且关闭窗户
{
if( flag_window == 0 ) //如果之前是开窗状态 则关窗 标志位置1
{
BEEP=0;
Motor_Foreward(); Delay_function(1000); //延时50ms
BEEP=1;
flag_window=1;
}
}
if( (smog_value >= smog_max) || (gas_value >= gas_max) ) //如果烟雾值大于设定的最大值 或者 甲烷值大于设定的最大值 打开蜂鸣器 打开窗户 继电器打开风扇开启
{
BEEP = 0;
if( flag_window == 1 ) //如果之前是关窗状态 则开窗 标志位置0此时是开窗状态
{
Motor_Reversal();
flag_window = 0;
}
JDQ = 0;
}
else //继电器关闭 蜂鸣器关闭
{
JDQ = 1;
BEEP = 1;
}
}
/* 以下是测量显示界面的 自动控制模式 */
else //如果是手动模式
{
if( flag_lanya == 1 ) //如果蓝牙发送 开窗户指令 打开窗户 同时蓝牙标志位置2
{
flag_lanya = 2;
if( flag_window == 1 ) //如果之前是关窗状态 则开窗 窗户标志位置0
{
Motor_Reversal();
flag_window = 0;
}
}
else if( flag_lanya == 0 ) //如果蓝牙发送 关窗指令 则关闭窗户 同时蓝牙标志位置2
{
flag_lanya = 2;
if( flag_window == 0 ) //如果之前是开窗状态 则关窗 标志位置0
{
Motor_Foreward();
flag_window=1;
}
}
}
}
else //进入设置界面 继电器关闭此时继电器控制的风扇关闭 蜂鸣器关闭
{
JDQ = 1;
BEEP = 1;
}
}