多功能数字钟

多功能数字钟

lczhuigz Lv1

多功能数字钟项目

简介

本项目是一个基于普中51单片机试验仪(STC89C52RC MCU)的多功能数字钟设计,集成了时间显示、闹钟设置和温度检测等功能。通过使用LCD1602显示屏、DS1302实时时钟模块以及DS18B20温度传感器,实现了这些复杂的硬件交互。

硬件框图

多功能数字钟硬件框图

电路原理图

多功能数字钟电路原理图

软件功能框图

多功能数字钟软件功能框图

程序流程图

多功能数字钟程序流程图

效果演示

多功能数字钟效果演示

主要功能

  • 实时时间显示(年、月、日、时、分、秒及星期)
  • 闹钟设置功能
  • 温度显示功能
  • 秒表功能(启动/暂停、清零)

硬件连接

  • LCD1602
    • RS -> P2.6
    • WR -> P2.5
    • EN -> P2.7
    • DataPort -> P0
  • DS1302
    • SCLK -> P3.6
    • IO -> P3.4
    • CE -> P3.5
  • DS18B20
    • IO -> P3.7
  • BEEP
    • BEEP -> P1.5
  • Independent Key
    • KEY1 -> P3.0
    • KEY2 -> P3.1
    • KEY3 -> P3.2
    • KEY4 -> P3.3
    • KEY5 -> P1.0
    • KEY6 -> P1.1
    • KEY7 -> P1.2
    • KEY8 -> P1.3

软件功能

闹钟功能

  • 通过AlarmTime数组设置闹钟时间。
  • CheckAlarm函数中检查当前时间是否与闹钟时间匹配,匹配时触发蜂鸣器。

秒表功能

  • 使用StopwatchControl函数进行秒表的控制。
  • 显示秒表计时值,单位为分钟、秒和毫秒。
  • 开始/暂停秒表计时,清零秒表示数。

温度显示功能

  • 初始化DS18B20,发送转换命令并读取温度。
  • 使用DS18B20_ReadT函数读取温度数据,并将其显示在LCD1602上。

按键功能

  • 按键功能通过Key函数读取键码。
  • 模式切换、时间设置、秒表控制等功能通过按键触发。
  • 按键具体功能
    • KEY1 -> 进入/退出时间设置模式
    • KEY2 -> 选择调整的位
    • KEY3 -> 数值加1
    • KEY4 -> 数值减1
    • KEY5 -> 时钟/秒表/闹钟设置模式切换
    • KEY6 -> 开始/暂停秒表计时
    • KEY7 -> 清零秒表计时
    • KEY8 -> 暂时未使用

定时器功能

  • 使用T0定时器实现100ms中断,用于控制秒表计时和闪烁效果。

代码结构

以下为本项目中主要的函数声明及其实现:

  • LCD1602

    • LCD_Init:初始化LCD1602显示屏。
    • LCD_WriteCommand:向LCD1602写入命令。
    • LCD_WriteData:向LCD1602写入数据。
    • LCD_SetCursor:设置LCD1602光标位置。
    • LCD_ShowChar:在指定位置显示一个字符。
    • LCD_ShowString:在指定位置显示字符串。
    • LCD_ShowNum:在指定位置显示数字。
    • LCD_Pow:用于LCD1602的乘方运算。
  • DS1302

    • DS1302_Init:初始化DS1302实时时钟模块。
    • DS1302_WriteByte:向DS1302写入一个字节。
    • DS1302_ReadByte:从DS1302读取一个字节。
    • DS1302_SetTime:设置DS1302的时间。
    • DS1302_ReadTime:从DS1302读取时间。
  • DS18B20

    • DS18B20_Init:初始化DS18B20温度传感器。
    • DS18B20_ConvertT:转换温度。
    • DS18B20_ReadT:读取温度。
  • 单总线

    • OneWire_Init:初始化单总线。
    • OneWire_SendBit:发送一位数据。
    • OneWire_ReceiveBit:接收一位数据。
    • OneWire_SendByte:发送一个字节数据。
    • OneWire_ReceiveByte:接收一个字节数据。
  • 时间设置

    • TimeSet:用于时间设置功能。
    • TimeShow:用于时间显示功能。
  • 秒表

    • StopwatchControl:用于秒表控制。
    • ShowStopwatch:用于显示秒表示数。
  • 蜂鸣器

    • Timer0_Routine:定时器中断服务程序,控制蜂鸣器鸣叫和秒表示数更新。

注意事项

  • 请确保所有硬件连接正确无误。
  • 在实际使用中,可能需要根据具体的单片机型号和开发环境进行适当的调整。
  • 温度传感器DS18B20的读取可能需要根据实际温度范围和精度进行优化。

编译与烧录

使用Keil uVision或其他兼容的51单片机开发环境进行编译,将生成的HEX文件烧录到单片机中进行测试。

完整程序

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
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629

#include <REGX52.H>
#include "intrins.h"


//1602引脚配置
#define LCD_RS P2_6
#define LCD_RW P2_5
#define LCD_EN P2_7
#define LCD_DataPort P0
//1302引脚配置
#define DS1302_SCLK P3_6
#define DS1302_IO P3_4
#define DS1302_CE P3_5
//18B20引脚配置
#define OneWire_DQ P3_7
//1302寄存器写入地址/指令定义
#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
//独立按键函数声明
unsigned char Key();
//延时函数声明
void Delay(unsigned int xms);
//T0定时器初始化函数声明
void Timer0Init(void);
//闹钟功能函数声明
void CheckAlarm();
//1302函数声明
void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command,Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_SetTime(void);
void DS1302_ReadTime(void);
//18B20函数声明
void DS18B20_ConvertT(void);
float DS18B20_ReadT(void);
void DS18B20_Init(void);
//单总线函数声明
unsigned char OneWire_Init(void);
void OneWire_SendBit(unsigned char Bit);
unsigned char OneWire_ReceiveBit(void);
void OneWire_SendByte(unsigned char Byte);
unsigned char OneWire_ReceiveByte(void);
//DS18B20指令
#define DS18B20_SKIP_ROM 0xCC
#define DS18B20_CONVERT_T 0x44
#define DS18B20_READ_SCRATCHPAD 0xBE
//时间数组,索引0~6分别为年、月、日、时、分、秒、星期,设置为有符号的便于<0的判断
char DS1302_Time[]={25,01,01,11,31,55,3};
//闹钟时间设置
char AlarmTime[] = {25,01,01,11,31,59,3}; //年、月、日、 时、分、秒
//标志全局变量
unsigned char KeyNum,MODE,TimeSetSelect,TimeSetFlashFlag,AlarmFlag,BuzzerState,BuzzerCount,StopwatchMode,StopwatchState;
unsigned int StopwatchTime = 0;
float T;//温度
#define Buzzer P1_5
//星期计算函数声明
unsigned char CalculateWeekday(int year, int month, int day);
//1602函数声明
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
int LCD_Pow(int X,int Y);
//时间函数声明
void TimeSet(char* TimeArray,unsigned char* SelectPtr);//时间设置功能
void TimeShow(void);//时间显示功能
//秒表功能函数声明
void ShowStopwatch();// 显示秒表计时值
void StopwatchControl();//秒表按键功能
//温度显示函数声明
void Show_Temperature();



void main()
{
LCD_Init();
DS1302_Init();
DS18B20_ConvertT();
DS18B20_Init();
Timer0Init();
LCD_ShowString(1,1," - - ");//静态字符初始化显示
LCD_ShowString(2,1," : : ");
DS1302_Time[6] = CalculateWeekday(DS1302_Time[0], DS1302_Time[1], DS1302_Time[2]);
DS1302_SetTime();

while(1)
{
KeyNum=Key();//读取键码
if(KeyNum==1)//按键1按下
{
if(MODE==0){MODE=1;TimeSetSelect=0;}//功能切换
else if(MODE==1){MODE=0;DS1302_SetTime();}
else if(MODE==3){MODE=0;}
}
if(KeyNum==5){
if(MODE==0){
MODE=2;
LCD_Init(); // 切换到秒表模式时初始化LCD
LCD_ShowString(1,1,"Stopwatch");
StopwatchTime = 0; // 重置秒表时间
StopwatchState = 0; // 重置秒表状态
}
else if(MODE==2){
MODE=3;
LCD_Init();
LCD_ShowString(1,1," - - ");
LCD_ShowString(2,1," : : ");
}
else if(MODE == 3)
{
MODE=0;
LCD_Init();
LCD_ShowString(1,1," - - ");
LCD_ShowString(2,1," : : ");
}

}
switch(MODE)//根据不同的功能执行不同的函数
{
case 0:TimeShow();CheckAlarm();Show_Temperature();break;
case 1:TimeSet(DS1302_Time,&TimeSetSelect);break;
case 2:StopwatchControl();break;
case 3:TimeSet(AlarmTime,&TimeSetSelect);LCD_ShowString(2, 10, "W:");LCD_ShowString(1, 10, "SETTING");break;
}
if (BuzzerState) {
BuzzerCount++;
if (BuzzerCount >= 50) { // 蜂鸣器鸣叫 5 秒(100ms * 10)
BuzzerState = 0; // 关闭蜂鸣器
BuzzerCount = 0;
Buzzer = 0;
}
Buzzer = !Buzzer;
Delay(5);
Buzzer = !Buzzer;
Delay(5);
Buzzer = !Buzzer;
Delay(5);// 蜂鸣器状态取反
} else {
Buzzer = 0; // 关闭蜂鸣器
}
}
}

void Show_Temperature(){
DS18B20_ConvertT(); //转换温度
T=DS18B20_ReadT(); //读取温度
//Delay(500);
if(T<0) //如果温度小于0
{
LCD_ShowChar(1,10,'-'); //显示负号
T=-T; //将温度变为正数
}
else //如果温度大于等于0
{
LCD_ShowChar(1,10,'+'); //显示正号
}
LCD_ShowNum(1,11,(unsigned int)T,2); //显示温度整数部分
LCD_ShowChar(1,13,'.'); //显示小数点
LCD_ShowNum(1,14,(unsigned int)(T*100)%100,2);//显示温度小数部分
}
//秒表按键功能
void StopwatchControl() {
// 按键2:开始/暂停秒表
if (KeyNum == 6) {
StopwatchState = !StopwatchState;
}
// 按键3:清零秒表
if (KeyNum == 7) {
StopwatchTime = 0;
StopwatchState = 0;
}
// 显示秒表计时值
ShowStopwatch();
}
// 显示秒表计时值
void ShowStopwatch() {
unsigned int seconds = StopwatchTime / 1000; // 计算秒
unsigned int milliseconds = StopwatchTime % 1000; // 计算毫秒

LCD_ShowNum(2, 1, seconds / 60, 2); // 显示分钟
LCD_ShowChar(2, 3, ':'); // 显示冒号
LCD_ShowNum(2, 4, seconds % 60, 2); // 显示秒
LCD_ShowChar(2, 6, '.'); // 显示小数点
LCD_ShowNum(2, 7, milliseconds / 10, 2); // 显示毫秒(取前两位)
}
void TimeShow(void)//时间显示功能
{
DS1302_ReadTime();//读取时间
LCD_ShowNum(1,1,DS1302_Time[0],2);//显示年
LCD_ShowNum(1,4,DS1302_Time[1],2);//显示月
LCD_ShowNum(1,7,DS1302_Time[2],2);//显示日
LCD_ShowNum(2,1,DS1302_Time[3],2);//显示时
LCD_ShowNum(2,4,DS1302_Time[4],2);//显示分
LCD_ShowNum(2,7,DS1302_Time[5],2);//显示秒
LCD_ShowString(2, 10, "W:"); // 显示星期
LCD_ShowNum(2, 12, DS1302_Time[6], 1); // 显示星期值
}

void TimeSet(char* TimeArray,unsigned char* SelectPtr)//时间设置功能
{
if(KeyNum==2)//按键2按下
{
(*SelectPtr)++;//设置选择位加1
*SelectPtr%=7;//越界清零
}
if(KeyNum==3)//按键3按下
{
TimeArray[*SelectPtr]++;//时间设置位数值加1

if(TimeArray[0]>99){TimeArray[0]=0;}//年越界判断
if(TimeArray[1]>12){TimeArray[1]=1;}//月越界判断

if( TimeArray[1]==1 || TimeArray[1]==3 || TimeArray[1]==5 || TimeArray[1]==7 ||
TimeArray[1]==8 || TimeArray[1]==10 || TimeArray[1]==12)//日越界判断
{
if(TimeArray[2]>31){TimeArray[2]=1;}//大月
}
else if(TimeArray[1]==4 || TimeArray[1]==6 || TimeArray[1]==9 || TimeArray[1]==11)
{
if(TimeArray[2]>30){TimeArray[2]=1;}//小月
}
else if(TimeArray[1]==2)
{
if(TimeArray[0]%4==0)
{
if(TimeArray[2]>29){TimeArray[2]=1;}//闰年2月
}
else
{
if(TimeArray[2]>28){TimeArray[2]=1;}//平年2月
}
}
TimeArray[6] = CalculateWeekday(TimeArray[0], TimeArray[1], TimeArray[2]);//更新星期
if(TimeArray[3]>23){TimeArray[3]=0;}//时越界判断
if(TimeArray[4]>59){TimeArray[4]=0;}//分越界判断
if(TimeArray[5]>59){TimeArray[5]=0;}//秒越界判断
if(TimeArray[6]>6){TimeArray[6]=0;}//星期越界判断

}
if(KeyNum==4)//按键4按下
{
TimeArray[*SelectPtr]--;//时间设置位数值减1
if(TimeArray[0]<0){TimeArray[0]=99;}//年越界判断
if(TimeArray[1]<1){TimeArray[1]=12;}//月越界判断
if( TimeArray[1]==1 || TimeArray[1]==3 || TimeArray[1]==5 || TimeArray[1]==7 ||
TimeArray[1]==8 || TimeArray[1]==10 || TimeArray[1]==12)//日越界判断
{
if(TimeArray[2]<1){TimeArray[2]=31;}//大月
if(TimeArray[2]>31){TimeArray[2]=1;}
}
else if(TimeArray[1]==4 || TimeArray[1]==6 || TimeArray[1]==9 || TimeArray[1]==11)
{
if(TimeArray[2]<1){TimeArray[2]=30;}//小月
if(TimeArray[2]>30){TimeArray[2]=1;}
}
else if(TimeArray[1]==2)
{
if(TimeArray[0]%4==0)
{
if(TimeArray[2]<1){TimeArray[2]=29;}//闰年2月
if(TimeArray[2]>29){TimeArray[2]=1;}
}
else
{
if(TimeArray[2]<1){TimeArray[2]=28;}//平年2月
if(TimeArray[2]>28){TimeArray[2]=1;}
}
}
if(TimeArray[3]<0){TimeArray[3]=23;}//时越界判断
if(TimeArray[4]<0){TimeArray[4]=59;}//分越界判断
if(TimeArray[5]<0){TimeArray[5]=59;}//秒越界判断
if(TimeArray[6]<0){TimeArray[6]=6;}//星期越界判断
TimeArray[6] = CalculateWeekday(TimeArray[0], TimeArray[1], TimeArray[2]);
}
//更新显示,根据TimeSetSelect和TimeSetFlashFlag判断可完成闪烁功能
if(*SelectPtr==0 && TimeSetFlashFlag==1){LCD_ShowString(1,1," ");}
else {LCD_ShowNum(1,1,TimeArray[0],2);}
if(*SelectPtr==1 && TimeSetFlashFlag==1){LCD_ShowString(1,4," ");}
else {LCD_ShowNum(1,4,TimeArray[1],2);}
if(*SelectPtr==2 && TimeSetFlashFlag==1){LCD_ShowString(1,7," ");}
else {LCD_ShowNum(1,7,TimeArray[2],2);}
if(*SelectPtr==3 && TimeSetFlashFlag==1){LCD_ShowString(2,1," ");}
else {LCD_ShowNum(2,1,TimeArray[3],2);}
if(*SelectPtr==4 && TimeSetFlashFlag==1){LCD_ShowString(2,4," ");}
else {LCD_ShowNum(2,4,TimeArray[4],2);}
if(*SelectPtr==5 && TimeSetFlashFlag==1){LCD_ShowString(2,7," ");}
else {LCD_ShowNum(2,7,TimeArray[5],2);}
if(*SelectPtr==6 && TimeSetFlashFlag==1){LCD_ShowString(2,12," ");}
else {LCD_ShowNum(2,12,TimeArray[6],1);}
}

void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
static unsigned char station_toggle;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=100)//每100ms进入一次
{
T0Count=0;
station_toggle++;
if (station_toggle>=4)
{
station_toggle = 0;
TimeSetFlashFlag=!TimeSetFlashFlag;//闪烁标志位取反
}
if (StopwatchState) {
StopwatchTime += 100; // 增加 100ms
}
}
}
//LCD1602写命令
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0;
LCD_RW=0;
LCD_DataPort=Command;
LCD_EN=1;
Delay(1);
LCD_EN=0;
Delay(1);
}
//LCD1602写数据
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_EN=1;
Delay(1);
LCD_EN=0;
Delay(1);
}
//LCD1602设置光标位置
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line==1)
{
LCD_WriteCommand(0x80|(Column-1));
}
else if(Line==2)
{
LCD_WriteCommand(0x80|(Column-1+0x40));
}
}
//LCD1602初始化函数
void LCD_Init()
{
LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
LCD_WriteCommand(0x01);//光标复位,清屏
}
//在LCD1602指定位置上显示一个字符
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
LCD_SetCursor(Line,Column);
LCD_WriteData(Char);
}
//在LCD1602指定位置开始显示所给字符串
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
// 在LCD1602指定位置开始显示所给数字
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
}
}
//LCD1602乘方运算
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
//独立按键函数实现
unsigned char Key()
{
unsigned char KeyNumber=0;
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=1;}
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=2;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
if(P1_0==0){Delay(20);while(P1_0==0);Delay(20);KeyNumber=5;}
if(P1_1==0){Delay(20);while(P1_1==0);Delay(20);KeyNumber=6;}
if(P1_2==0){Delay(20);while(P1_2==0);Delay(20);KeyNumber=7;}
if(P1_3==0){Delay(20);while(P1_3==0);Delay(20);KeyNumber=8;}
return KeyNumber;
}
//延时函数实现
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
//T0定时器初始化函数实现
void Timer0Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=0;
}
//DS1302初始化
void DS1302_Init(void)
{
DS1302_CE=0;
DS1302_SCLK=0;
}
//DS1302写一个字节
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;
DS1302_SCLK=0;
}
for(i=0;i<8;i++)
{
DS1302_IO=Data&(0x01<<i);
DS1302_SCLK=1;
DS1302_SCLK=0;
}
DS1302_CE=0;
}
//DS1302读一个字节
unsigned char DS1302_ReadByte(unsigned char Command)
{
unsigned char i,Data=0x00;
Command|=0x01; //将指令转换为读指令
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;
}
//DS1302设置时间
void DS1302_SetTime(void)
{
DS1302_WriteByte(DS1302_WP,0x00);
DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);//十进制转BCD码后写入
DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
DS1302_WriteByte(DS1302_WP,0x80);
}
//DS1302读取时间
void DS1302_ReadTime(void)
{
unsigned char Temp;
Temp=DS1302_ReadByte(DS1302_YEAR);
DS1302_Time[0]=Temp/16*10+Temp%16;//BCD码转十进制后读取
Temp=DS1302_ReadByte(DS1302_MONTH);
DS1302_Time[1]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_DATE);
DS1302_Time[2]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_HOUR);
DS1302_Time[3]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_MINUTE);
DS1302_Time[4]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_SECOND);
DS1302_Time[5]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_DAY);
DS1302_Time[6]=Temp/16*10+Temp%16;
}
//闹钟功能函数实现
void CheckAlarm() {
if (DS1302_Time[0] == AlarmTime[0] &&
DS1302_Time[1] == AlarmTime[1] &&
DS1302_Time[2] == AlarmTime[2] &&
DS1302_Time[3] == AlarmTime[3] &&
DS1302_Time[4] == AlarmTime[4] &&
DS1302_Time[5] == AlarmTime[5] &&
DS1302_Time[6] == AlarmTime[6]) {
AlarmFlag = 1; // 触发闹钟
BuzzerState = 1;
}else {
AlarmFlag = 0; // 关闭闹钟
}
}
//18B20函数实现
void DS18B20_Init(void){
DS18B20_ConvertT(); //上电先转换一次温度,防止第一次读数据错误
Delay(1000); //等待转换完成
}
//转换温度
void DS18B20_ConvertT(void)
{
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_CONVERT_T);
}
//读取温度
float DS18B20_ReadT(void)
{
unsigned char TLSB,TMSB;
int Temp;
float T;
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
TLSB=OneWire_ReceiveByte();
TMSB=OneWire_ReceiveByte();
Temp=(TMSB<<8)|TLSB;
T=Temp/16.0;
return T;
}
//单总线函数实现
unsigned char OneWire_Init(void)
{
unsigned char i;
unsigned char AckBit;
OneWire_DQ=1;
OneWire_DQ=0;
i = 247;while (--i); //Delay 500us
OneWire_DQ=1;
i = 32;while (--i); //Delay 70us
AckBit=OneWire_DQ;
i = 247;while (--i); //Delay 500us
return AckBit;
}
//单总线发送一位
void OneWire_SendBit(unsigned char Bit)
{
unsigned char i;
OneWire_DQ=0;
i = 4;while (--i); //Delay 10us
OneWire_DQ=Bit;
i = 24;while (--i); //Delay 50us
OneWire_DQ=1;
}
//单总线接收一位
unsigned char OneWire_ReceiveBit(void)
{
unsigned char i;
unsigned char Bit;
OneWire_DQ=0;
i = 2;while (--i); //Delay 5us
OneWire_DQ=1;
i = 2;while (--i); //Delay 5us
Bit=OneWire_DQ;
i = 24;while (--i); //Delay 50us
return Bit;
}
//单总线发送一个字节
void OneWire_SendByte(unsigned char Byte)
{
unsigned char i;
for(i=0;i<8;i++)
{
OneWire_SendBit(Byte&(0x01<<i));
}
}
//单总线接收一个字节
unsigned char OneWire_ReceiveByte(void)
{
unsigned char i;
unsigned char Byte=0x00;
for(i=0;i<8;i++)
{
if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
}
return Byte;
}
//星期计算函数实现
unsigned char CalculateWeekday(int year, int month, int day) {
unsigned char weekday;
if (month < 3) {
month += 12;
year--;
}
weekday = (day + 2 * month + 3 * (month + 1) / 5 + year + year / 4 - year / 100 + year / 400) % 7;
return (weekday + 1);
}

  • 标题: 多功能数字钟
  • 作者: lczhuigz
  • 创建于 : 2025-08-24 20:12:50
  • 更新于 : 2025-09-05 14:35:28
  • 链接: https://www.lczhuigz.top/2025/08/24/multifunctional-digital-clock/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论