zl程序教程

您现在的位置是:首页 >  其它

当前栏目

基于物联网的智能家居控制系统【100010619】

基于 联网 智能家居 控制系统
2023-09-11 14:17:49 时间

智能家居控制系统

一、摘要

智能家居作为家庭信息化的实现方式,已经成为社会信息化发展的重要组成部分,物联网其巨大的应用前景,是智能家居产业发展过程中一个比较现实的突破口,对智能家居的产业发展具有重大意义。本文基于容易实现,方便操作,贴近使用的设计理念,设计的智能家居控制系统是以 STC89C52 单片机为主控器件,通过按键和红外通讯模块进行数据交换。主控器件为核心,通过键盘输入和修改门禁密码、关锁,以及人工控制灯和风扇的开关;通过红外通讯远程开锁和人工开关风扇;用传感器和时钟模块获取温度和时间,并利用 LCD1602 液晶屏显示温度时间以及输入密码的‘*’和修改的密码。

二、题目要求

基于物联网的智能家居控制系统。

可涉及到的部分核心元器件:51 单片机、运算放大器、稳压管、电位器、电阻电容(不限)、继电器、二/三极管、数码管、轻触按键、IC 插座、双列直插、红外接收器,计数芯片、数码管显示芯片、GPS 定位模块、GSM 通信模块、新型太阳能电池板、高精度视频识别摄像头、语音识别与存储模块、LED 显示模块。

三、方案说明

以 STC89C52 为主控芯片,以矩阵键盘输入密码,以独立按键确认、清除、进入修改密码界面和锁门(关密码锁),输入密码错误 3 次以后进行蜂鸣器报警,并锁定键盘,只能用红外遥控开锁;修改密码后会用 EEPROM 进行保存;以矩阵键盘和红外遥控共同人工控制灯和风扇的开关,用 DS1302 时钟芯片进行计时,用 DS18B20 数字温度传感器获取温度,当温度和时间达到设定的值时,会自动开启风扇和灯,智能开启的灯和风扇是可自动调节的,风扇的转速会比人工开启的稍慢,而灯会根据光强自动调节亮度,其中风扇使用 ULN2003 直流电机驱动模块控制,灯光的调节是通过 PCF8591 数模转换模块和光敏电阻控制。开密码所后,会显示当前温度时间和是否开启灯和风扇;显示部分使用的是 LCD1602 液晶,红外接收用的是 HS0038 红外接收模块。

四、软硬件设计

4.1 主控电路部分:

4.2 功能电路部分:

4.2.1 红外通讯:

利用单片机 P3.2IO 口接收红外数据。

红外模块代码:

由于这里代码都有例程,所以仅贴出.h 部分。

# ifndef__INFRARED_H
# define__INFRARED_H
# include"Sys.h"
voidinit();//对红外通讯所使用到的外部中断0和定时器0初始化
voidIRcordpro();//把提取的33次脉宽解码NEC协议
# endif

4.2.2 DS18B20:

利用单片机 P2.2IO 口控制其收发数据。

DS18B20 模块代码:

由于这里代码都有例程,所以仅贴出.h 部分。

# ifndef__DS18B20_H
# define__DS18B20_H
# include"Sys.h"
sbitds=P2^2;
voiddsInit();//单总线初始化时序
voiddsWait();//延时37.95us等待18B20发回存在信号
bitreadBit();//读一位数据
unsignedcharreadByte();//读一个字节数据
voidwriteByte(unsignedchardat);//写一个字节数据
voidsendChangeCmd();//发送温度转换命令
voidsendReadCmd();//发送读命令
intgetTmpValue();//获取温度
voiddisplayTemp(intv);//用LCD1602显示温度
# endif

4.2.3 DS1302:

DS1302 模块代码:

由于这里代码都有例程,所以仅贴出.h 部分。

# ifndef__DS1302_H
# define__DS1302_H
# include"Sys.h"
sbitTSCLK=P1^0;//时钟
sbitTIO=P1^1;//数据
sbitTRST=P1^2;//使能
# defineMAIN_Fosc11059200UL//宏定义主时钟HZ
# defineDS1302_W_ADDR0x80//写时钟日历寄存器起始地址
# defineDS1302_R_ADDR0x81//读时钟日历寄存器起始地址
voidSet_DS1302_Time(ucharaddr);//设置时间
voidRead_DS1302_Time(ucharaddr);//读取时间
ucharDat_Chg_BCD(uchardat);//10进制数据转BCD
ucharBCD_Chg_Dat(uchardat);//BCD转10进制数据
# endif

4.2.4 LCD1602:

LCD1602 模块代码:

这里对例程代码进行了扩充,所以放出完整代码。

1.	#ifndef __LCD1602_H  
2.	#define __LCD1602_H  
3.	#include "Sys.h"  
4.	#define LCD1602_DB  P0      //data bus 数据总线  
5.	sbit LCD1602_RS = P3^5;  
6.	sbit LCD1602_RW = P3^6;  
7.	sbit LCD1602_EN = P3^4;    
8.	void Read_Busy();           //忙检测函数,判断bit7是0,允许执行;1禁止  
9.	void Lcd1602_Write_Cmd(unsigned char cmd);     //写命令  
10.	void Lcd1602_Write_Data(unsigned char dat);   //写数据  
11.	void LcdSetCursor(unsigned char x,unsigned char y);   //设置坐标  
12.	void DisplayOneChar (uchar X,uchar Y,uchar DData); // 写一个字节  
13.	void DisplayOneStr (uchar X,uchar Y,uchar DData);//显示一个字节字符  
14.	void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str);     //显示字符串  
15.	void InitLcd1602();              //1602初始化  
16.	#endif 
1.	#include "Sys.h"  
2.	void Read_Busy()           //忙检测函数,判断bit7是0,允许执行;1禁止  
3.	{  
4.	    unsigned char sta;      //  
5.	    LCD1602_DB = 0xff;  
6.	    LCD1602_RS = 0;  
7.	    LCD1602_RW = 1;  
8.	    do  
9.	    {  
10.	        LCD1602_EN = 1;  
11.	        sta = LCD1602_DB;  
12.	        LCD1602_EN = 0;    //使能,用完就拉低,释放总线  
13.	    }while(sta & 0x80);  
14.	}  
15.	void Lcd1602_Write_Cmd(unsigned char cmd)     //写命令  
16.	{  
17.	    Read_Busy();  
18.	    LCD1602_RS = 0;  
19.	    LCD1602_RW = 0;  
20.	    LCD1602_DB = cmd;  
21.	    LCD1602_EN = 1;  
22.	    LCD1602_EN = 0;      
23.	}  
24.	void Lcd1602_Write_Data(unsigned char dat)   //写数据  
25.	{  
26.	      Read_Busy();  
27.	      LCD1602_RS = 1;  
28.	      LCD1602_RW = 0;  
29.	      LCD1602_DB = dat;  
30.	      LCD1602_EN = 1;  
31.	      LCD1602_EN = 0;  
32.	}  
33.	void LcdSetCursor(unsigned char x,unsigned char y)  //设置坐标  
34.	{  
35.	    unsigned char addr;  
36.	    if(y == 0)  
37.	        addr = 0x00 + x;  
38.	    else  
39.	        addr = 0x40 + x;  
40.	      
41.	    Lcd1602_Write_Cmd(addr|0x80);  
42.	}  
43.	void DisplayOneChar (uchar X,uchar Y,uchar DData)//显示一个字节数据  
44.	{  
45.	 if(Y) X|=0X40;   //Y=1显示第二行,Y=0显示第一行  
46.	 X|=0X80;  
47.	 Lcd1602_Write_Cmd(X); //X用来选择哪一位  
48.	 Lcd1602_Write_Data(DData); //DData用来写数据  
49.	}  
50.	//显示一个字节字符  
51.	void DisplayOneStr (uchar X,uchar Y,uchar DData)  
52.	{  
53.	    DisplayOneChar (X++,Y,DData/16 + '0');  
54.	    DisplayOneChar (X,Y,DData%16 + '0');  
55.	}  
56.	void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str)     //显示字符串  
57.	{  
58.	    LcdSetCursor(x,y);      //当前字符的坐标  
59.	    while(*str != '\0')  
60.	    {  
61.	        Lcd1602_Write_Data(*str++);  
62.	    }  
63.	}  
64.	void InitLcd1602()              //1602初始化  
65.	{  
66.	    Lcd1602_Write_Cmd(0x38);    //打开,5*8,8位数据  
67.	    Lcd1602_Write_Cmd(0x0c);  
68.	    Lcd1602_Write_Cmd(0x06);  
69.	    Lcd1602_Write_Cmd(0x01);    //清屏   
70.	}  

4.2.5 ULN2003:

ULN2003 可直接驱动继电器等负载,所以我们用来驱动风扇电机,否则电机直接接在单片机 IO 口是不转的,ULN2003 内部是 7 个独立的非门电路。

ULN2003 模块代码:

由于这里代码都有例程,所以仅贴出.h 部分。

# ifndef__ULN2003_H
# define__ULN2003_H
# include"Sys.h"
sbit_4IN=P2^7;
# endif

4.2.6 IIC 及 EEPROM(使用 IIC 协议交换数据):

利用单片机 P2.0 和 P2.1 分别作为通信的数据线和时钟线。

由于这里代码都有例程,所以仅贴出.h 部分。

# ifndef__IIC_H
# define__IIC_H
# include"Sys.h"
# defineAT24C02_ADDR0xa0//AT24C02地址
/*I2CIO口定义*/
sbitSDA=P2^0;
sbitSCL=P2^1;
voidI2C_init();//I2C初始化
voidI2C_Start();/*I2C起始信号*/
voidI2C_Stop();/*I2C终止信号*/
voidMaster_ACK(biti);/*主机发送应答*/
bitTest_ACK();/*检测从机应答*/
voidI2C_send_byte(ucharbyte);/*发送一个字节*/
ucharI2C_read_byte();/*I2C读一字节*/
bitI2C_TransmitData(ucharADDR,ucharDAT);//I2C发送数据
ucharI2C_ReceiveData(ucharADDR);//I2C接收数据
# endif

4.2.7 PCF8591(使用 IIC 通信协议交换数据):

利用单片机 P2.0 和 P2.1 分别作为通信的数据线和时钟线。

PCF8591 模块代码:

由于这里代码都有例程,所以仅贴出.h 部分。

# ifndef__PCF8591_H
# define__PCF8591_H
# include"Sys.h"
# definePCF8591_ADDR0x90//PCF8591地址
# defineDACOUT_EN0x40//DAC输出使能
bitDAC_OUT(ucharDAT);//DAC输出
bitADC_Read(ucharCON);//读AD数据
# endif

4.2.8 蜂鸣器:

利用单片机 P2.3IO 口控制蜂鸣器,低电平响,高电平不响。代码过于简单,不再单独展出。

4.2.9 矩阵键盘和独立键盘:

使用 P3IO 口,此次使用的单片机的 LCD1602 也是用 P3,所以相冲突,故对例程代码进行了修改。

1.	#ifndef __KEY_H  
2.	#define __KEY_H  
3.	#include "Sys.h"  
4.	uchar KeyScan();    //带返回值的子函数  
5.	#endif 
1.	#include "Sys.h"  
2.	void delay(uint z)  
3.	{  
4.	    uint x,y;  
5.	    for(x = z; x > 0; x--)  
6.	        for(y = 114; y > 0 ; y--);  
7.	}  
8.	//将例程中按键扫描修改,先扫描行,再扫描列,不然会与LCD1602冲突  
9.	uchar KeyScan() //带返回值的子函数  
10.	{  
11.	    uchar KeyValue=22;  
12.	    P3 = 0x0f;//判断哪一行被按下  
13.	    if(P3 != 0x0f)  
14.	    {  
15.	        delay(5);//软件消抖  
16.	        if( P3 != 0x0f)  
17.	        {  
18.	            switch(P3)  
19.	            {  
20.	                case 0x0e:  KeyValue = 0;   break;  
21.	                case 0x0d:  KeyValue = 4;   break;  
22.	                case 0x0b:  KeyValue = 8;   break;  
23.	                case 0x07:  KeyValue = 12;  break;  
24.	            }  
25.	            P3 = 0xf0;//判断哪一列被按下  
26.	            switch(P3)  
27.	            {  
28.	                case 0xe0:  KeyValue = KeyValue;    break;  
29.	                case 0xd0:  KeyValue += 1;  break;  
30.	                case 0xb0:  KeyValue += 2;  break;  
31.	                case 0x70:  KeyValue += 3;  break;  
32.	            }  
33.	            while(P3 != 0xf0);//松手检测  
34.	        }             
35.	    }  
36.	    P3 = 0xff;//判断独立按键  
37.	    if(P3 != 0xff)  
38.	    {  
39.	        delay(5);//软件消抖  
40.	        if( P3 != 0xff)  
41.	        {  
42.	            switch(P3)  
43.	            {  
44.	                case 0xfe:  KeyValue = 16;  break;  
45.	                case 0xfd:  KeyValue = 17;  break;  
46.	                case 0xfb:  KeyValue = 18;  break;  
47.	                case 0xf7:  KeyValue = 19;  break;  
48.	            }  
49.	            while(P3 != 0xff);//松手检测  
50.	        }     
51.	    }     
52.	    if(KeyValue!=22&&(KeyValue>9&&KeyValue<16))//a~f,+39  
53.	    {  
54.	        KeyValue+=39;  
55.	    }  
56.	    return KeyValue;  
57.	}  

4.3 主要头文件:

采用多文件的方法编程,利于阅读、修改和移植,将所有头文件放于 Sys 中,每个.c 中仅需加入 Sys.h 头文件。

# ifndef__SYS_H
# define__SYS_H
# defineucharunsignedchar
# defineuintunsignedint
# defineLightOn255
# defineLightOff0
# defineFanOn1
# defineFanOff0
# defineHuman1
# defineMachine0
# include<reg52.h>
# include"Delay.h"
# include"Key.h"
# include"InfraRed.h"
# include"Secret.h"
# include<intrins.h>
# include"LCD1602.h"
# include<string.h>
# include"DS18B20.h"
# include<math.h>
# include"DS1302.h"
# include"IIC.h"
# include"PCF8591.h"
# include"ULN2003.h"
sbitDUAN=P2^6;
sbitWEI=P2^7;
sbitBeep=P2^3;
# endif

4.4 功能模块调用以及主要逻辑部分:

4.4.1 Secret.h、Secret.c:

# ifndef__SECRET_H
# define__SECRET_H
# include"Sys.h"
# defineLockOff1
# defineLockOn0
voidKeyAction();
intmake_sure();
ucharchangesecret();
# endif
1.	#include "Sys.h"  
2.	#include <string.h>  
3.	  
4.	  
5.	uchar password_original[5]={1,2,3,4,5};//原密码  
6.	uchar temp_password[5]={0,0,0,0,0};  
7.	  
8.	  
9.	uchar chance=3;  
10.	uchar Lock=LockOn;  
11.	uint Beeptime;  
12.	  
13.	extern uchar choosemode;  
14.	  
15.	void KeyAction()  
16.	{  
17.	    uchar Input=22;  
18.	    static uchar keyWei=0;  
19.	      
20.	    Input=KeyScan();  
21.	    if(Input!=22&&keyWei<5&&Input!=16&&Input!=17&&Input!=18&&Input!=19)  
22.	    {     
23.	        temp_password[keyWei]=Input;  
24.	        DisplayOneChar(6+keyWei,1,'*');  
25.	        keyWei++;  
26.	    }  
27.	    if(Input==16)//密码确认  
28.	    {  
29.	        keyWei=0;  
30.	        if(make_sure()==0)//输入错误  
31.	        {  
32.	            LcdShowStr(6,1,"     ");  
33.	            chance--;  
34.	            Beeptime=0;  
35.	        }  
36.	        else//输入正确  
37.	        {  
38.	            keyWei=0;  
39.	            choosemode=1;  
40.	            chance=3;  
41.	            Lock=LockOff;  
42.	        }  
43.	    }  
44.	    if(Input==17)//清除  
45.	    {  
46.	        uchar i=0;  
47.	        keyWei=0;  
48.	        Lcd1602_Write_Cmd(0x80);  
49.	        for(i=0;i<5;i++)  
50.	        {  
51.	            LcdShowStr(6,1,"     ");  
52.	            temp_password[i]=0;  
53.	        }  
54.	    }  
55.	}  
56.	  
57.	int make_sure()  
58.	{  
59.	    unsigned char i=0;  
60.	    for(i;i<5;i++)  
61.	    {  
62.	        if(temp_password[i]!=password_original[i])  
63.	        {  
64.	            return 0;  
65.	        }  
66.	    }  
67.	    return 1;  
68.	}  
69.	  
70.	uchar changesecret()  
71.	{  
72.	    uchar Input=22;  
73.	    static uchar keyWei=0;  
74.	    Input=KeyScan();  
75.	    if(Input!=22&&keyWei<5&&Input!=16&&Input!=17&&Input!=18&&Input!=19)  
76.	    {     
77.	        temp_password[keyWei]=Input;  
78.	        DisplayOneChar(11+keyWei,1,Input+'0');  
79.	        keyWei++;  
80.	    }  
81.	    if(Input==16&&keyWei==5)  
82.	    {  
83.	        uchar i;  
84.	        keyWei=0;  
85.	        strcpy(password_original,temp_password);  
86.	        for(i=0;i<5;i++)  
87.	        {  
88.	            temp_password[i]=0;  
89.	        }  
90.	        Lcd1602_Write_Cmd(0x01);  
91.	        for(i=1;i<6;i++)  
92.	        {  
93.	            I2C_TransmitData(i,password_original[i-1]);  
94.	            Delayms(5);  
95.	        }  
96.	        LcdShowStr(0,0,"Changed.");  
97.	        Delayms(3000);  
98.	        Lcd1602_Write_Cmd(0x01);  
99.	        choosemode=1;  
100.	        return 1;  
101.	    }  
102.	    if(Input==17)  
103.	    {  
104.	        uchar i=0;  
105.	        keyWei=0;  
106.	        Lcd1602_Write_Cmd(0x01);  
107.	        for(i=0;i<5;i++)  
108.	        {  
109.	            temp_password[i]=0;  
110.	        }  
111.	    }  
112.	    return 0;  
113.	}  

main.c

1.	//由于红外和独立、矩阵键盘都是用的P3(红外P3.2),所以当开锁后使用红外,然后关锁后,第一次输入密码会在后面一点  
2.	  
3.	#include "Sys.h"  
4.	int temp=0;//接收到的温度值,有正负,用于判断  
5.	extern uchar password_original[5];//原密码  
6.	extern uchar IRcord[4]; //储存解码后的4个字节数据,用户码,用户码,数据码,数据反码  
7.	extern uchar IRdata[33];//包含起始码在内的33位数据  
8.	extern uchar Lock;  
9.	extern uchar chance;  
10.	extern uint Beeptime;  
11.	uchar choosemode=0;  
12.	extern bit IRpro_ok;    //解码后4个字节数据接收完成标志位  
13.	extern bit IRok;//33位数据接收完成标志位  
14.	extern uchar TimeData[7];  
15.	uchar readflag=0;//是否读取温度和时间  
16.	extern uchar AD_Value;  //存储AD转换回的数字量  
17.	extern unsigned char pwm_motor_val;//左右电机占空比值,越小快  
18.	extern unsigned char pwm_t;//周期  
19.	extern unsigned char datas[5];//温度值  
20.	uchar LightControl=Machine;  
21.	//等于Human:人为控制,LightHuman有效,LightMachine失效,等于Machine:智能控制,LightMachine失效,LightMachine有效  
22.	uchar LightHuman=LightOff;  
23.	uchar LightMachine=LightOff;  
24.	  
25.	uchar FanControl=Machine;  
26.	//等于Human:人为控制,LightHuman有效,LightMachine失效,等于Machine:智能控制,LightMachine失效,LightMachine有效  
27.	uchar FanHuman=FanOff;  
28.	uchar FanMachine=FanOff;  
29.	  
30.	void choose(uchar i);  
31.	//void openstring();  
32.	void Timer1Init();  
33.	sbit LED1= P1^0;   //读取AD的值是否成功(亮成功,灭失败)  
34.	sbit LED2= P1^1;   //DAC成功输出(亮成功,灭失败)  
35.	void main()  
36.	{  
37.	      
38.	    uchar i=0;  
39.	    Timer1Init();  
40.	    InitLcd1602();  
41.	    I2C_init();  
42.	//  while(1)//测试光敏电阻和DA输出  
43.	//  {  
44.	//        
45.	//      if (ADC_Read(0x00)) LED1 = 0;   else    LED1 = 1;     
46.	//      AD_Value=LightOff;  
47.	//      if (DAC_OUT(AD_Value))  LED2 = 0;   else    LED2 = 1;  
48.	//      DisplayOneChar(0,0,AD_Value);  
49.	//      Delayms(5);  
50.	//  }  
51.	  
52.	//  for(i=1;i<6;i++)//用于写第一次的密码到EEPROM  
53.	//  {  
54.	//      I2C_TransmitData(i,password_original[i-1]);  
55.	//      Delayms(5);  
56.	//  }  
57.	      
58.	    Delayms(5);  
59.	    for(i=1;i<6;i++)  
60.	    {  
61.	        password_original[i-1]=I2C_ReceiveData(i);//从EEPROM读取密码,一次一位,一共5次  
62.	        Delayms(5);  
63.	    }  
64.	    init();//红外线定时器0和外部中断0初始化  
65.	    DUAN=0;  
66.	    WEI=0;  
67.	  
68.	    Set_DS1302_Time(DS1302_W_ADDR); //先写入时钟日历寄存器起始地址再设置时钟日历初值  
69.	    while(1)  
70.	    {  
71.	        choose(choosemode);  
72.	    }  
73.	}  
74.	  
75.	void choose(uchar i)  
76.	{  
77.	      
78.	    uchar Input=22;  
79.	    switch(i)  
80.	    {  
81.	        case 0://*******************************************************已关门,输入密码  
82.	            Lcd1602_Write_Cmd(0x01);//清除上一次所显示的模式的内容  
83.	            LcdShowStr(0,0,"Input secret.");  
84.	            while(1)  
85.	            {  
86.	                if(IRok)  
87.	                {  
88.	                    IRcordpro();//根据脉宽解码出4个字节数据  
89.	                    IRok=0;//清零脉宽检查完成标志位等待下一次脉宽检查  
90.	                    if(IRpro_ok)//判断是否解码完成  
91.	                    {  
92.	                        if(IRcord[2]==0x45)//开锁  
93.	                        {  
94.	                            Lock=LockOff;  
95.	                            choosemode=1;  
96.	                        }  
97.	                        else if(IRcord[2]==0x0c)//开灯  
98.	                        {  
99.	                            LightControl=Human;  
100.	                            LightHuman=LightOn;  
101.	                        }  
102.	                        else if(IRcord[2]==0x18)//关灯  
103.	                        {  
104.	                            LightControl=Human;  
105.	                            LightHuman=LightOff;  
106.	                        }  
107.	                        else if(IRcord[2]==0x5e)//智能灯  
108.	                        {  
109.	                            LightControl=Machine;  
110.	                            LightHuman=LightOff;  
111.	                        }  
112.	                        else if(IRcord[2]==0x08)//开风扇  
113.	                        {  
114.	                            FanControl=Human;  
115.	                            FanHuman=FanOn;  
116.	                        }  
117.	                        else if(IRcord[2]==0x1c)//关风扇  
118.	                        {  
119.	                            FanControl=Human;  
120.	                            FanHuman=FanOff;  
121.	                        }  
122.	                        else if(IRcord[2]==0x5a)//智能风扇  
123.	                        {  
124.	                            FanControl=Machine;  
125.	                            FanHuman=FanOff;  
126.	                        }  
127.	                        IRpro_ok=0;//清零解码完成标志位  
128.	                    }  
129.	                }  
130.	                if(LightControl==Human)  
131.	                {  
132.	                    AD_Value=LightHuman;  
133.	                }  
134.	                else if(LightControl==Machine)  
135.	                {  
136.	                    AD_Value=LightOff;  
137.	                }  
138.	                DAC_OUT(AD_Value);  
139.	                  
140.	                if(chance>0)  
141.	                {  
142.	                    LcdShowStr(0,1,"Input:");  
143.	                    DisplayOneChar(15,0,chance+'0');  
144.	                    KeyAction();  
145.	                }  
146.	                else  
147.	                {  
148.	                    LcdShowStr(0,0,"Only Inred open!");  
149.	                    LcdShowStr(0,1,"      ");  
150.	                      
151.	                      
152.	                    if(Beeptime==0)  
153.	                    {  
154.	                        Beep=0;//蜂鸣器报警  
155.	                    }  
156.	                    if(Beep==0)  
157.	                    {  
158.	                        Beeptime++;  
159.	                        if(Beeptime>100)  
160.	                            Beep=1;//蜂鸣器停止  
161.	                    }  
162.	                }  
163.	                if(Lock==LockOff)  
164.	                {  
165.	                    InitLcd1602();  
166.	                    break;  
167.	                }  
168.	            }         
169.	            break;  
170.	        case 1://**********************************************************已开门,显示温度时间  
171.	//          Timer1Init();  
172.	//      ET1=1;  
173.	//      TR1=1;  
174.	            while(1)  
175.	            {  
176.	                  
177.	                Input=22;  
178.	//              openstring();  
179.	                Input=KeyScan();  
180.	                if(IRok)  
181.	                {  
182.	                    IRcordpro();//根据脉宽解码出4个字节数据  
183.	                    IRok=0;//清零脉宽检查完成标志位等待下一次脉宽检查  
184.	                    if(IRpro_ok)//判断是否解码完成  
185.	                    {  
186.	                        if(IRcord[2]==0x0c)  
187.	                        {  
188.	                            LightControl=Human;  
189.	                            LightHuman=LightOn;  
190.	                        }  
191.	                        else if(IRcord[2]==0x18)  
192.	                        {  
193.	                            LightControl=Human;  
194.	                            LightHuman=LightOff;  
195.	                        }  
196.	                        else if(IRcord[2]==0x5e)  
197.	                        {  
198.	                            LightControl=Machine;  
199.	                            LightHuman=LightOff;  
200.	                        }  
201.	                        else if(IRcord[2]==0x08)//开风扇  
202.	                        {  
203.	                            FanControl=Human;  
204.	                            FanHuman=FanOn;  
205.	                        }  
206.	                        else if(IRcord[2]==0x1c)//关风扇  
207.	                        {  
208.	                            FanControl=Human;  
209.	                            FanHuman=FanOff;  
210.	                        }  
211.	                        else if(IRcord[2]==0x5a)//智能灯  
212.	                        {  
213.	                            FanControl=Machine;  
214.	                            FanHuman=FanOff;  
215.	                        }  
216.	                        else if(IRcord[2]==0x47)  
217.	                        {  
218.	                            choosemode=0;  
219.	                            chance=3;  
220.	                            Lock=LockOn;  
221.	                            ET1=0;TR1=0;  
222.	                            LightControl=Machine;  
223.	                            AD_Value=LightOff;  
224.	                            break;  
225.	                        }  
226.	                        IRpro_ok=0;//清零解码完成标志位  
227.	                    }  
228.	                }  
229.	                if(readflag==1)//达到1秒进行读取温度、日期和时间  
230.	                {  
231.	                    readflag=0;  
232.	                    //温度显示  
233.	                    temp=getTmpValue();  
234.	                    displayTemp(temp);  
235.	                    sendChangeCmd();//温度转换,给下一次用  
236.	//                  DisplayOneChar(13,1,'*');  
237.	                      
238.	                    //时间显示  
239.	                    Read_DS1302_Time(DS1302_R_ADDR); //先写入时钟日历寄存器起始地址再读出时钟日历写入到TimeData数组中  
240.	                    DisplayOneStr (8,0,TimeData[6]); //年  
241.	                    DisplayOneChar (10,0,'-');       //-  
242.	                    DisplayOneStr (11,0,TimeData[4]); //月  
243.	                    DisplayOneChar (13,0,'-');       //-  
244.	                    DisplayOneStr (14,0,TimeData[3]);//日  
245.	                      
246.	                    DisplayOneStr (0,1,TimeData[2]); //时  
247.	                    DisplayOneChar (2,1,':');        //:  
248.	                    DisplayOneStr (3,1,TimeData[1]); //分  
249.	                    DisplayOneChar (5,1,':');        //:  
250.	                    DisplayOneStr (6,1,TimeData[0]);//秒  
251.	                      
252.	//                  DisplayOneChar(10,1,'o');  
253.	                }  
254.	                if(Input==0)//开灯  
255.	                {  
256.	                    LightControl=Human;  
257.	                    LightHuman=LightOn;  
258.	                }  
259.	                else if(Input==1)//关灯  
260.	                {  
261.	                    LightControl=Human;  
262.	                    LightHuman=LightOff;  
263.	                }  
264.	                else if(Input==2)//智能灯  
265.	                {  
266.	                    LightControl=Machine;  
267.	                    LightHuman=LightOff;  
268.	                }  
269.	                else if(Input==4)//开风扇  
270.	                {  
271.	                    FanControl=Human;  
272.	                    FanHuman=FanOn;  
273.	                }  
274.	                else if(Input==5)//关风扇  
275.	                {  
276.	                    FanControl=Human;  
277.	                    FanHuman=FanOff;  
278.	                }  
279.	                else if(Input==6)//智能风扇  
280.	                {  
281.	                    FanControl=Machine;  
282.	                    FanHuman=FanOff;  
283.	                }  
284.	                  
285.	                if(LightControl==Human)  
286.	                {  
287.	                    AD_Value=LightHuman;  
288.	                }  
289.	                else if(LightControl==Machine)  
290.	                {  
291.	                    uchar Hour;  
292.	                    ADC_Read(0x00);  
293.	                    Hour=BCD_Chg_Dat(TimeData[2]);  
294.	                    if(!(Hour>20&&Hour<23))  
295.	                    {  
296.	                        AD_Value=LightOff;  
297.	                    }  
298.	                }  
299.	                DAC_OUT(AD_Value);  
300.	                if(Input==18)//修改密码  
301.	                {  
302.	                    choosemode=2;  
303.	                    Lcd1602_Write_Cmd(0x01);  
304.	//                  ET1=0;  
305.	//                  TR1=0;  
306.	                    break;  
307.	                }  
308.	                  
309.	                else if(Input==19)//关锁(门)  
310.	                {  
311.	                    choosemode=0;  
312.	                    chance=3;  
313.	                    Lock=LockOn;  
314.	//                  ET1=0;  
315.	//                  TR1=0;  
316.	                    LightControl=Machine;  
317.	                    FanControl=Machine;  
318.	                    AD_Value=LightOff;  
319.	                    _4IN=FanOff;  
320.	                    break;  
321.	                }  
322.	                if(_4IN==FanOn)  
323.	                {  
324.	                    DisplayOneChar(13,1,'*');  
325.	                }  
326.	                else if(_4IN==FanOff)  
327.	                {  
328.	                    DisplayOneChar(13,1,' ');  
329.	                }  
330.	                if(AD_Value!=LightOff)  
331.	                {  
332.	                    DisplayOneChar(10,1,'o');  
333.	                }  
334.	                else  
335.	                {  
336.	                    DisplayOneChar(10,1,' ');  
337.	                }  
338.	            }  
339.	            break;  
340.	        case 2://**************************************************************修改密码  
341.	            Lcd1602_Write_Cmd(0x01);  
342.	            while(1)  
343.	            {  
344.	                uchar change=0;  
345.	                LcdShowStr(0,0,"Change secret.");  
346.	                LcdShowStr(0,1,"New secret:");  
347.	                change=changesecret();  
348.	                if(change==1)  
349.	                {  
350.	                      
351.	                    break;  
352.	                }  
353.	            }  
354.	            break;  
355.	    }  
356.	}  
357.	/*  
358.	void openstring()  
359.	{  
360.	//  LcdShowStr(0,0,"Open");  
361.	    Delayms(1000); //温度转换时间需要750ms以上  
362.	    displayTemp(getTmpValue());  
363.	    sendChangeCmd();  
364.	    LcdShowStr(13,0,"Off");  
365.	//  sendChangeCmd();  
366.	//  Delayms(1000);  
367.	//  displayTemp(getTmpValue);  
368.	      
369.	}  
370.	*/  
371.	void Timer1Init()  
372.	{  
373.	    EA=1;  
374.	    ET1=1;  
375.	    TMOD|=0x10;  
376.	    TH1=(65536-50000)/256;  
377.	    TL1=(65536-50000)%256;  
378.	    TR1=1;  
379.	}  
380.	  
381.	void Timer1() interrupt 3  
382.	{  
383.	    static timer1num=0;  
384.	  
385.	    TH1=(65536-50000)/256;  
386.	    TL1=(65536-50000)%256;  
387.	    timer1num++;  
388.	      
389.	//  ET1=0;TR1=0;  
390.	    if(timer1num==20)  
391.	    {  
392.	        timer1num=0;  
393.	        readflag=1;  
394.	        /* 
395.	        //读取放在中断服务函数中会干扰定时器计时 
396.	        //温度显示 
397.	        displayTemp(getTmpValue()); 
398.	        sendChangeCmd(); 
399.	        DisplayOneChar(13,1,'*'); 
400.	         
401.	        //时间显示 
402.	        Read_DS1302_Time(DS1302_R_ADDR); //先写入时钟日历寄存器起始地址再读出时钟日历写入到TimeData数组中 
403.	        DisplayOneStr (8,0,TimeData[6]); //年 
404.	        DisplayOneChar (10,0,'-');       //- 
405.	        DisplayOneStr (11,0,TimeData[4]); //月 
406.	        DisplayOneChar (13,0,'-');       //- 
407.	        DisplayOneStr (14,0,TimeData[3]);//日 
408.	         
409.	        DisplayOneStr (0,1,TimeData[2]); //时 
410.	        DisplayOneChar (2,1,':');        //: 
411.	        DisplayOneStr (3,1,TimeData[1]); //分 
412.	        DisplayOneChar (5,1,':');        //: 
413.	        DisplayOneStr (6,1,TimeData[0]);//秒 
414.	         
415.	        DisplayOneChar(10,1,'o'); 
416.	        */  
417.	    }  
418.	//  ET1=1;TR1=1;  
419.	      
420.	    pwm_t++;//风扇控制  
421.	    if(pwm_t == 255)  
422.	        FanMachine = FanOff;  
423.	    else if(pwm_t==pwm_motor_val)  
424.	        FanMachine = FanOn;   
425.	//  _4IN=FanMachine;  
426.	    if(choosemode==0)  
427.	    {  
428.	        _4IN = FanHuman;  
429.	    }  
430.	    if(choosemode==1||choosemode==2)  
431.	    {  
432.	        if(FanControl==Machine)  
433.	        {  
434.	            if(temp>0&&datas[1]>=3&&datas[2]>=1)  
435.	            {  
436.	                _4IN=FanMachine;  
437.	            }  
438.	            else  
439.	                _4IN=FanOff;  
440.	        }  
441.	//      else if(FanControl==Human)  
442.	//      {  
443.	//          _4IN=FanHuman;  
444.	//      }  
445.	  
446.	    }  
447.	      
448.	    if(FanControl==Human)  
449.	    {  
450.	        _4IN=FanHuman;  
451.	    }  
452.	  
453.	} 

五、存在问题及解决方法

  • 键盘引脚和 LCD1602 键盘冲突。
    解决方法:先扫描行再扫描列。

  • 键盘引脚和红外接收模块引脚冲突。
    解决方法:更改电路图,更换红外接收所用引脚。

  • 直流电机驱动风扇不能慢速转动,如果不是全速转动而是慢速转动,将变成时停时转。

    原因:红外和 DS1302 以及 DS18B20 已经将定时器 0 和定时器 1 用完,而 52 单片机的定时器 2 过于复杂,故不尝试使用,所以导致直流电机驱动模块不能单独使用一个定时器调节转速(即 IO 口翻转频率),而与 DS18B20 和 DS1302 共同使用定时器 1,所以其频率过低。

    解决方法:使用其他定时器多的单片机,例如 stc12 和 stm32,或者学习使用 52 单片机的定时器 2。

六、总结

用过这次课程设计,学会了使用 Proteus 软件画电路图,熟练掌握了 51 单片机和各种功能模块的使用,如 DS18B20、DS1302、红外接收模块等,熟练掌握了绝大部分单片机通信协议,有 SPI、IIC、串行异步通信、并行通信,学会了根据时序图编写通信协议,同时也熟练掌握了多文件编程的方式,对已学习的 STM32 单片机有了更深刻的了解。通过在这次项目中解决自己和其他队伍的困难,使自己解决问题的能力进一步提升,在与同伴的交流合作中,了解到团队合作的重要作用。个人感觉 51 单片机是十分基础和简单的,这次项目的制作仅用了 3 天半就全部完成了,但越是基础的东西越该熟练地掌握,否则在进一步的学习中会愈发困难。

♻️ 资源

在这里插入图片描述

大小: 54.6MB
➡️ 资源下载:https://download.csdn.net/download/s1t16/87415719