一、功能介绍

1)使用如图所示NEC协议的红外遥控器(键码见下图)及单片机开发板实现模拟多功能智能家居红外安全防控系统;
2)将热释电人体红外感应模块HC-SR501 布防在阳台和窗户,在主人离开家之前,用遥控器按下“1”,开启布防。当有人从阳台和窗户入侵时,HC-SR501输出高电平给单片机,单片机控制蜂鸣器发出警报声,,警报声音频请查阅资料;
3)当主人回家后,按下“2”键,撤销布防,不接收HC-SR501信号;
4)控制器在闲时(未布防,或者布防后未检测到入侵)可作为万年历使用。读出实时时钟芯片DS1302中的年月日、星期、时间,用LCD1602显示;
5)在撤销布防后可做家居多功能遥控器使用。按下“4” 键,继电器吸合,按下“5” 键继电器断开,模拟自动窗帘和电磁锁的动作。
6)按下“7”键,将DS18B20采集的环境温度,或DHT11采集的室内温湿度 显示在LCD1602;
本设计以STC89C52RC单片机为核心,通过HC-SR501检测红外信号,然后通过继电器吸合断开模拟窗帘的张合程度。用温湿度传感器DHT11检测当前室内温湿度,DS1302时钟芯片制作数字时钟并用液晶显示器LCD1602显示时间和温湿度。

二、系统测试及原理图

2.1 系统测试

运行结果:
1)将热释电人体红外感应模块HC-SR501 布防在阳台和窗户,在主人离开家之前,用遥控器按下“1”,开启布防。当有人从阳台和窗户入侵时,HC-SR501输出高电平给单片机,单片机控制蜂鸣器发出警报声
布防
报警
功能一运行结果正确,能够进入布防,并准确识别人体红外线并发出警报声;

2)当主人回家后,按下“2”键,撤销布防,不接收HC-SR501信号;
3)控制器在闲时(未布防,或者布防后未检测到入侵)可作为万年历使用。读出实时时钟芯片DS1302中的年月日、星期、时间,用LCD1602显示;
闲时
功能二、三运行结果均正常,能够退出布防,并用LCD1602正常显示万年历;
(此外,本程序也可以手动调整系统的时间)

4)在撤销布防后可做家居多功能遥控器使用。按下“4” 键,继电器吸合,按下“5” 键继电器断开,模拟自动窗帘和电磁锁的动作。
继电器吸合
功能四运行结果正常,能够正确控制继电器开关(听到嗒的一声)

5)按下“7”键,将DS18B20采集的环境温度,或DHT11采集的室内温湿度 显示在LCD1602;
温度
功能五运行结果正常,能够正确显示环境温度(且误差在5%以内)

2.2 原理图

原理图
原理图

三、程序(使用keil5编程)

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
//******************************主函数
#include <REGX52.H>
#include <intrins.h>
#include "LCD1602.h"
#include "DS1302.h"
#include "DS18B20.h"
#include "IR.h"

#define uchar unsigned char
#define uint unsigned int
#define year DS1302_Time[0]
#define mon DS1302_Time[1]
#define day DS1302_Time[2]
#define hour DS1302_Time[3]
#define min DS1302_Time[4]
#define sec DS1302_Time[5]

uchar Num,Address,Command;
uchar MODE,TimeSetSelect,key,TimeSetFlashFlag=1,time,k,TFlag=0;
float T;
sbit diola=P2^5;
sbit dula=P2^6;
sbit wela=P2^7;
sbit beep=P2^3;
sbit RL=P0^6;
sbit HC=P2^0;
//sbit S2=P3^4;和lcd引脚冲突
//sbit S3=P3^5;

void delay(uint z)
{
uint y;
for(;z>0;z--)
for(y=114;y>0;y--);
}

void delay2() //大概0.5ms左右的延时,用于产生报警声
{
uchar a;
for(a=450;a>0;a--)
{
_nop_();
}
}

void TimeShow()
{
DS1302_ReadTime();
LCD_ShowNum(1,1,year,2);
LCD_ShowNum(1,4,mon,2);
LCD_ShowNum(1,7,day,2);
LCD_ShowNum(2,1,hour,2);
LCD_ShowNum(2,4,min,2);
LCD_ShowNum(2,7,sec,2);

if(DS1302_Time[6]==0){LCD_ShowString(1,11,"SUN ");}
if(DS1302_Time[6]==1){LCD_ShowString(1,11,"MON ");}
if(DS1302_Time[6]==2){LCD_ShowString(1,11,"TUE ");}
if(DS1302_Time[6]==3){LCD_ShowString(1,11,"WED ");}
if(DS1302_Time[6]==4){LCD_ShowString(1,11,"THU ");}
if(DS1302_Time[6]==5){LCD_ShowString(1,11,"FRI ");}
if(DS1302_Time[6]==6){LCD_ShowString(1,11,"SAT ");}

LCD_ShowString(2,10," ");
}

void TShow()
{
LCD_ShowString(1,1,"Temperature: ");
DS18B20_ConvertT(); //转换温度
T=DS18B20_ReadT(); //读取温度
if(T<0) //如果温度小于0
{
LCD_ShowChar(2,1,'-'); //显示负号
T=-T; //将温度变为正数
}
else //如果温度大于等于0
{
LCD_ShowChar(2,1,'+'); //显示正号
}
LCD_ShowNum(2,2,T,3); //显示温度整数部分(因为会强制转换成无符号整形)
LCD_ShowChar(2,5,'.'); //显示小数点
LCD_ShowNum(2,6,(unsigned long)(T*100)%100,2);//显示温度小数部分
LCD_ShowChar(2,8,0xdf);
LCD_ShowChar(2,9,'C');
}

void Defend()
{
LCD_ShowString(1,1,"Defense program");
LCD_ShowString(2,1,"By JAS ");
LCD_ShowNum(2,10,HC,4);
if(HC==1)//报警声
{
uint m;
for(m=800;m>0;m--) //持续时间0.5ms*800
{
beep=~beep;
delay2(); //2000HZ的信号。
}
for(m=500;m>0;m--) //持续时间0.5ms*2*500
{
beep=~beep;
delay2();
delay2(); //1000HZ的信号。
}
}
}

void TimeSet()
{
diola=1;
P1=0xfe;
diola=0;
if(key==3)//按键3按下
{
TimeSetSelect++;//设置选择位加1
TimeSetSelect%=6;//越界清零
}
if(key==10)//按键10按下
{
DS1302_Time[TimeSetSelect]++;//时间设置位数值加1
if(year>99){year=0;}//年越界判断
if(mon>12){mon=1;}//月越界判断
if( mon==1 || mon==3 || mon==5 || mon==7 ||
mon==8 || mon==10 || mon==12)//日越界判断
{
if(day>31){day=1;}//大月
}
else if(mon==4 || mon==6 || mon==9 || mon==11)
{
if(day>30){day=1;}//小月
}
else if(mon==2)
{
if(year%4==0)
{
if(day>29){day=1;}//闰年2月
}
else
{
if(day>28){day=1;}//平年2月
}
}
if(hour>23){hour=0;}//时越界判断
if(min>59){min=0;}//分越界判断
if(sec>59){sec=0;}//秒越界判断
}
if(key==11)//按键11按下
{
DS1302_Time[TimeSetSelect]--;//时间设置位数值减1
if(year<0){year=99;}//年越界判断
if(mon<1){mon=12;}//月越界判断
if( mon==1 || mon==3 || mon==5 || mon==7 ||
mon==8 || mon==10 || mon==12)//日越界判断
{
if(day<1){day=31;}//大月
if(day>31){day=1;}
}
else if(mon==4 || mon==6 || mon==9 || mon==11)
{
if(day<1){day=30;}//小月
if(day>30){day=1;}
}
else if(mon==2)
{
if(year%4==0)
{
if(day<1){day=29;}//闰年2月
if(day>29){day=1;}
}
else
{
if(day<1){day=28;}//平年2月
if(day>28){day=1;}
}
}
if(hour<0){hour=23;}//时越界判断
if(min<0){min=59;}//分越界判断
if(sec<0){sec=59;}//秒越界判断
}
DS1302_Time[6]=(day+1+2*mon+3*(mon+1)/5+year+year/4-year/100+year/400)%7;//基姆拉尔森计算星期几的公式
//以下为闪烁
if(TimeSetSelect==0 && TimeSetFlashFlag==1){LCD_ShowString(1,1," ");}
else {LCD_ShowNum(1,1,year,2);}
if(TimeSetSelect==1 && TimeSetFlashFlag==1){LCD_ShowString(1,4," ");}
else {LCD_ShowNum(1,4,mon,2);}
if(TimeSetSelect==2 && TimeSetFlashFlag==1){LCD_ShowString(1,7," ");}
else {LCD_ShowNum(1,7,day,2);}
if(TimeSetSelect==3 && TimeSetFlashFlag==1){LCD_ShowString(2,1," ");}
else {LCD_ShowNum(2,1,hour,2);}
if(TimeSetSelect==4 && TimeSetFlashFlag==1){LCD_ShowString(2,4," ");}
else {LCD_ShowNum(2,4,min,2);}
if(TimeSetSelect==5 && TimeSetFlashFlag==1){LCD_ShowString(2,7," ");}
else {LCD_ShowNum(2,7,sec,2);}
DS1302_SetTime();
}

char keyscan()
{
key=-1;
P3_2=1;
P3_1=1;
P3_0=0;
if(P3_6==0)
{
delay(10);
if(P3_6==0)
{
while(!P3_6);
key=2;
}
}
else if(P3_7==0)
{
delay(10);
if(P3_7==0)
{
while(!P3_7);
key=3;
}
}
P3_2=0;
P3_1=1;
P3_0=1;
if(P3_6==0)
{
delay(10);
if(P3_6==0)
{
while(!P3_6);
key=10;
}
}
else if(P3_7==0)
{
delay(10);
if(P3_7==0)
{
while(!P3_7);
key=11;
}
}
return key;
}
timer1() interrupt 3
{
TH1=(65536-46080)/256;//(65536-50000*11.0592/12)/256
TL1=(65536-46080)%256;
time++;
if(time==10)
{
TimeSetFlashFlag=~TimeSetFlashFlag;
time=0;
}
}
void main()
{
dula=0;
wela=0;
diola=0;
LCD_Init();
DS1302_Init();
LCD_ShowString(1,1," - - DAY: ");
LCD_ShowString(2,1," : : ");
IR_Init();
DS18B20_ConvertT(); //上电先转换一次温度,防止第一次读数据错误
delay(50); //等待转换完成
DS1302_SetTime();
key=-1;
TMOD &= 0x0F;
TMOD |= 0x10;
TH1=(65536-46080)/256;
TL1=(65536-46080)%256;
ET1=1;
EA=1;
TR1=1;
while(1)
{
if(IR_GetDataFlag() || IR_GetRepeatFlag()) //如果收到数据帧或者收到连发帧
{
Address=IR_GetAddress(); //获取遥控器地址码
Command=IR_GetCommand(); //获取遥控器命令码
if(Command==0x0C)
{
MODE=3;
diola=1;
P1=0xef;
diola=0;
}
else if(Command==0x18)
{
MODE=0;
diola=1;
P1=0xff;
diola=0;
LCD_ShowString(1,1," - - ");
LCD_ShowString(2,1," : : ");
}
if(Command==0x42)
{
MODE=2;
diola=1;
P1=0xff;
diola=0;
TFlag++;
}
if(Command==0x08)
{
LCD_ShowString(1,1,"Opening relay ");
LCD_ShowString(2,1,"By JAS ");
diola=1;
P1=0xfe;
for(k=0;k<8;k++)
{
delay(200);
P1=_crol_(P1,1);
}
diola=0;
LCD_ShowString(1,1," - - ");
LCD_ShowString(2,1," : : ");
wela=1;
P0_0=1;P0_1=1;P0_2=1;P0_3=1;P0_4=1;P0_5=1;
RL=0;
wela=0;
}
if(Command==0x1C)
{
LCD_ShowString(1,1,"Closing relay ");
LCD_ShowString(2,1,"By JAS ");
delay(1000);
wela=1;
P0=0xff;
wela=0;
delay(2);
diola=1;
P1=0xff;
diola=0;
LCD_ShowString(1,1," - - ");
LCD_ShowString(2,1," : : ");
}
}
key=keyscan();
if(key==2)//第一排第三个按键(按键2)按下
{
key=-1;
if(MODE==0){MODE=1;TimeSetSelect=0;}//功能切换
else if(MODE==1)
{
MODE=0;
DS1302_SetTime();
diola=1;
P1=0xff;
diola=0;
}
}
if(TFlag==4)
{
TFlag=0;
MODE=0;
LCD_ShowString(1,1," - - DAY: ");
LCD_ShowString(2,1," : : ");
}
switch(MODE)
{
case 0:TimeShow();break;
case 1:TimeSet();break;
case 2:TShow();break;
case 3:Defend();break;
}
}
}

LCD1602.h

1
2
3
4
5
6
7
8
9
10
11
#ifndef __LCD1602_H__
#define __LCD1602_H__
#define uchar unsigned char
#define uint unsigned int

void LCD_Init();
void LCD_ShowChar(uchar hang,uchar lie,char Char);
void LCD_ShowString(uchar hang,uchar lie,char *String);
void LCD_ShowNum(uchar hang,uchar lie,uint Number,uchar Length);

#endif

LCD1602.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <REGX52.H>

sbit LCD_RS=P3^5;
//sbit LCD_RW=; 开发板没接
sbit LCD_EN=P3^4;
#define LCD_DataPort P0
#define uchar unsigned char
#define uint unsigned int

void LCD_Delay()
{
uchar p,o;
for(p=1;p>0;p--)
for(o=114;o>0;o--);
}

void LCD_WriteCommand(uchar Command)
{
LCD_RS=0;
LCD_DataPort=Command;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}

void LCD_WriteData(uchar Data)
{
LCD_RS=1;
LCD_DataPort=Data;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}

void LCD_SetCursor(uchar hang,uchar lie)//LCD1602设置光标位置
{
if(hang==1)
{
LCD_WriteCommand(0x80|(lie-1));
}
else if(hang==2)
{
LCD_WriteCommand(0x80|(lie-1+0x40));
}
}

void LCD_Init()
{
LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
LCD_WriteCommand(0x01);//光标复位,清屏
}

void LCD_ShowChar(uchar hang,uchar lie,char Char)//在LCD1602指定位置上显示一个字符
{
LCD_SetCursor(hang,lie);
LCD_WriteData(Char);
}


void LCD_ShowString(uchar hang,uchar lie,char *String)//在LCD1602指定位置开始显示所给字符串
{
uchar i;
LCD_SetCursor(hang,lie);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}

int LCD_Pow(int X,int Y)
{
uchar i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}

void LCD_ShowNum(uchar hang,uchar lie,uint Number,uchar Length)
{
uchar i;
LCD_SetCursor(hang,lie);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
}
}

DS18B20.h

1
2
3
4
5
6
//******************************DS18B20.h
#ifndef __DS12B20_H__
#define __DS12B20_H__
void DS18B20_ConvertT(void);
float DS18B20_ReadT(void);
#endif

DS18B20.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <REGX52.H>
sbit DS=P2^2;
#define uchar unsigned char
#define DS18B20_SKIP_ROM 0xCC
#define DS18B20_CONVERT_T 0x44
#define DS18B20_READ_SCRATCHPAD 0xBE

//单总线
uchar DS_Init(void)//单总线初始化
{
uchar i;
uchar AckBit;//存放IO口数据
DS=1;
DS=0;
i = 247;while (--i);
DS=1;
i = 32;while (--i);
AckBit=DS;
i = 247;while (--i);
return AckBit;
}

void DS_SendBit(uchar Bit)//单总线发送一位 Bit 要发送的位
{
uchar i;
DS=0;
i = 4;while (--i);
DS=Bit;
i = 24;while (--i);
DS=1;
}
uchar DS_ReceiveBit(void)//单总线接收一位
{
uchar i;
uchar Bit;
DS=0;
i = 2;while (--i);
DS=1;
i = 2;while (--i);
Bit=DS;
i = 24;while (--i);
return Bit;
}

void DS_SendByte(uchar Byte)//单总线发送一个字节 8次发送
{
uchar i;
for(i=0;i<8;i++)
{
DS_SendBit(Byte&(0x01<<i));
}
}

uchar DS_ReceiveByte(void)//单总线接收一个字节 8次接收
{
uchar i;
uchar Byte=0x00;
for(i=0;i<8;i++)
{
if(DS_ReceiveBit()){Byte|=(0x01<<i);}
}
return Byte;
}

//DS18B20指令

void DS18B20_ConvertT(void)//DS18B20开始温度变换
{
DS_Init();
DS_SendByte(DS18B20_SKIP_ROM);
DS_SendByte(DS18B20_CONVERT_T);
}

float DS18B20_ReadT(void)//DS18B20读取温度
{
uchar TLSB,TMSB;
int Temp;
float T;
DS_Init();
DS_SendByte(DS18B20_SKIP_ROM);
DS_SendByte(DS18B20_READ_SCRATCHPAD);
TLSB=DS_ReceiveByte();
TMSB=DS_ReceiveByte();
Temp=(TMSB<<8)|TLSB;//组合高八位与第八位
T=Temp/16.0;//因为低四位用来储存小数,所以整个数(Temp)实际上是扩大了2^4倍,为了保留精度所以加了.0
return T;
}

DS1302.h

1
2
3
4
5
6
7
8
9
10
11
12
13
//******************************DS1302.h
#ifndef __DS1302_H__
#define __DS1302_H__

extern char DS1302_Time[];//外部使用声明,加extern

void DS1302_Init();
void DS1302_WriteByte(unsigned char Command,Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_ReadTime();
void DS1302_SetTime();

#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//******************************DS1302.c
#include <REGX52.H>
sbit DS1302_SCLK=P1^7;
sbit DS1302_IO=P1^6;
sbit DS1302_CE=P2^4;

#define DS1302_SECOND 0x80 //寄存器写入地址/指令定义
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8E
#define year DS1302_Time[0]
#define mon DS1302_Time[1]
#define day DS1302_Time[2]
#define hour DS1302_Time[3]
#define min DS1302_Time[4]
#define sec DS1302_Time[5]


char DS1302_Time[]={21,06,17,8,55,00,4};
//时间数组,分别为年、月、日、时、分、秒、星期,设置为有符号的便于<0的判断

void DS1302_Init()
{
DS1302_CE=0;
DS1302_SCLK=0;
}
//模仿时序,写读写指令
void DS1302_WriteByte(unsigned char Command,Data)
{
unsigned char i;
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i);
DS1302_SCLK=1;//我们的单片机一个机器周期不少于200ns,无需延时
DS1302_SCLK=0;
}
for(i=0;i<8;i++)
{
DS1302_IO=Data&(0x01<<i);
DS1302_SCLK=1;
DS1302_SCLK=0;
}
DS1302_CE=0;
}
unsigned char DS1302_ReadByte(unsigned char Command)
{
unsigned char i,Data=0x00;
Command|=0x01;//将指令转换为读指令,用Command控制最低位,可以节省一个全局变量
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i);
DS1302_SCLK=0;
DS1302_SCLK=1;
}
for(i=0;i<8;i++)
{
DS1302_SCLK=1;
DS1302_SCLK=0;
if(DS1302_IO)
Data|=(0x01<<i);
}
DS1302_CE=0;
DS1302_IO=0;//读取后将IO设置为0,避免读出的数据出错(不稳定)
return Data;
}

void DS1302_SetTime()//DS1302_Time数组的数字设置到DS1302中
{
DS1302_WriteByte(DS1302_WP,0x00);
DS1302_WriteByte(DS1302_YEAR,year/10*16+year%10);//十进制转BCD码后写入
DS1302_WriteByte(DS1302_MONTH,mon/10*16+mon%10);
DS1302_WriteByte(DS1302_DATE,day/10*16+day%10);
DS1302_WriteByte(DS1302_HOUR,hour/10*16+hour%10);
DS1302_WriteByte(DS1302_MINUTE,min/10*16+min%10);
DS1302_WriteByte(DS1302_SECOND,sec/10*16+sec%10);
DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
DS1302_WriteByte(DS1302_WP,0x80);
}

void DS1302_ReadTime()//DS1302中的数据读取到DS1302_Time数组中
{
unsigned char Temp;
Temp=DS1302_ReadByte(DS1302_YEAR);
year=Temp/16*10+Temp%16;//BCD码转十进制后读取
Temp=DS1302_ReadByte(DS1302_MONTH);
mon=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_DATE);
day=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_HOUR);
hour=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_MINUTE);
min=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_SECOND);
sec=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_DAY);
DS1302_Time[6]=Temp/16*10+Temp%16;
}

IR.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//******************************IR.h//红外
#ifndef __IR_H__
#define __IR_H__
#define IR_POWER 0x45
#define IR_MODE 0x46
#define IR_MUTE 0x47
#define IR_START_STOP 0x44
#define IR_PREVIOUS 0x40
#define IR_NEXT 0x43
#define IR_EQ 0x07
#define IR_VOL_MINUS 0x15
#define IR_VOL_ADD 0x09
#define IR_0 0x16
#define IR_RPT 0x19
#define IR_USD 0x0D
#define IR_1 0x0C
#define IR_2 0x18
#define IR_3 0x5E
#define IR_4 0x08
#define IR_5 0x1C
#define IR_6 0x5A
#define IR_7 0x42
#define IR_8 0x52
#define IR_9 0x4A
#define uchar unsigned char
void IR_Init(void);
uchar IR_GetDataFlag(void);
uchar IR_GetRepeatFlag(void);
uchar IR_GetAddress(void);
uchar IR_GetCommand(void);
#endif

IR.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <REGX52.H>
#define uchar unsigned char
#define uint unsigned int

uint IR_Time;
uchar IR_State;
uchar IR_Data[4];
uchar IR_pData;
uchar IR_DataFlag;
uchar IR_RepeatFlag;
uchar IR_Address;
uchar IR_Command;

void Int1_Init(void)
{
IT1=1;
IE1=0;
EX1=1;
EA=1;
PX1=1;
}
void Timer0_Init(void)
{
TMOD &= 0xF0;
TMOD |= 0x01;
TL0 = 0;
TH0 = 0;
TF0 = 0;
TR0 = 0;
}
void Timer0_SetCounter(unsigned int Value)
{
TH0=Value/256;
TL0=Value%256;
}
unsigned int Timer0_GetCounter(void)//定时器0获取计数器值
{
return (TH0<<8)|TL0;
}
void Timer0_Run(unsigned char Flag)//定时器0启动停止控制
{
TR0=Flag;
}

void IR_Init(void)
{
Timer0_Init();
Int1_Init();
}
unsigned char IR_GetDataFlag(void)//红外遥控获取收到数据帧标志位
{
if(IR_DataFlag)
{
IR_DataFlag=0;
return 1;
}
return 0;
}
unsigned char IR_GetRepeatFlag(void)//红外遥控获取收到连发帧标志位
{
if(IR_RepeatFlag)
{
IR_RepeatFlag=0;
return 1;
}
return 0;
}
unsigned char IR_GetAddress(void)//红外遥控获取收到的地址数据
{
return IR_Address;
}
unsigned char IR_GetCommand(void)//红外遥控获取收到的命令数据
{
return IR_Command;
}


void Int1_Routine(void) interrupt 2
{
if(IR_State==0)
{
Timer0_SetCounter(0);
Timer0_Run(1);
IR_State=1;
}
else if(IR_State==1)
{
IR_Time=Timer0_GetCounter();
Timer0_SetCounter(0);
if(IR_Time>12442-300 && IR_Time<12442+300)
{
IR_State=2;
}
else if(IR_Time>10368-300 && IR_Time<10368+300)
{
IR_RepeatFlag=1;
Timer0_Run(0);
IR_State=0;
}
else
{
IR_State=1;
}
}
else if(IR_State==2)
{
IR_Time=Timer0_GetCounter();
Timer0_SetCounter(0);
if(IR_Time>1032-300 && IR_Time<1032+300)
{
IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8));
IR_pData++;
}
else if(IR_Time>2074-300 && IR_Time<2074+300)
{
IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8));
IR_pData++;
}
else
{
IR_pData=0;
IR_State=1;
}
if(IR_pData>=32)
{
IR_pData=0;
if((IR_Data[0]==~IR_Data[1]) && (IR_Data[2]==~IR_Data[3])) //数据验证
{
IR_Address=IR_Data[0]; //转存数据
IR_Command=IR_Data[2];
IR_DataFlag=1; //置收到连发帧标志位为1
}
Timer0_Run(0); //定时器停止
IR_State=0; //置状态为0
}
}
}

四、总结

经过近两周的单片机课程设计我完成了一个多功能智能家居红外安全防控系统。本次课程设计中也涉及到许多比较困难的芯片和协议,虽然困难重重,但与此同时我也积累了许多宝贵的经验。
因为课程设计既是对课程理论内容的一次复习巩固,也是一次对自己程序设计能力的考验。所以这次课程设计也耗费了我挺多时间来进行学习的。在做本次课程设计的过程中,我感触最深的当属查阅芯片资料了。为了让自己的设计更加完善,查阅芯片资料是十分必要的,同时也是必不可少的。
软件编程前,我有了一个清晰的思路和一个完整的的软件流程图之后才着手设计。在设计程序时,反复修改、不断改进是程序设计的必经之路,我在写红外模块的程序时也参考了一下视频网站上面的教程,过程比较磕磕绊绊,出现了许许多多的问题,不过最后都一一解决了。
这次课程设计涉及的代码还是比较多的,不像之前上课布置的那些作业都是一个文件就搞定,这次算是大型的程序设计,所以我也学会了分模块化编程,获得了宝贵的设计经验,取得了长足的进步。我也总结了一些经验:要把理论基础知识过过关,芯片的工作原理以及驱动方法,不光要看懂,还要会自己运用;模块与模块之间相关联的方法等等。
此次的课程设计让我深深的认识到了学习单片机要有电子技术方面的数字电路和模拟电路等方面的理论基础,特别是数字电路和c语言。老师的教诲也同样重要,同时也要多次进行验证测试,将理论与实践相结合,锻炼自己的动手能力,促进自己的进步与发展。当然做出这个多功能智能家居红外安全防控系统还是让我很有成就感的。