概述

单片机采用AT89S52,显示采用液晶LCD1602,温度测量采用DS18B20,步进电机驱动采用芯片L298或ULN2003D,时间走时可采用单片机定时器或时钟芯片DS1302实现。系统要求实现以下功能

1.实验内容

1.1基本功能

1)需要在LCD上显示以下参数信息:日期、时间;
2)实现日期和时间可用键盘进行设置调整;
3)日期能区分闰年与非闰年,月份与天数的关系;
4)具有闹钟功能,开启闹钟时LCD上应有标志;
5)具有秒表功能,时间范围为0~60s,要求精确到0.1s;
6)具有定时功能,定时时间范围为0~24小时;
7)能够根据功能设置显示的模式:①显示时间和日期;②显示定时时间;③显示秒表时间;④显示所有信息(包括日期、时间、闹钟、定时和秒表)。

1.2扩展功能

1)利用DS18B20测量并显示室内的温度;
2)利用步进电机模拟风扇转动,利用按键可控制开启和关闭风扇工作,并通过定时器控制风扇工作的时间,时间到,风扇自动停止工作。

1.3系统原理图

2026-07-04T02:02:29.png

2.实验步骤

1、根据设计内容与要求,查找相关芯片与模块DS1302、LCD1602、DS18B20、L298或ULN2003D数据手册,弄清个模块硬件接口原理。
2、根据设计内容与要求,弄清系统及各个模块的工作流程,完成系统的硬件设计,采用Proteus完成系统硬件原理图的绘制,并采用C语言完成相应的软件设计,包括系统主程序、显示子程序、键盘设置子程序、时间调整子程序等等。
3、完成系统的在线仿真与实物调试,并使得系统在脱机情况下,能稳定可靠的工作。

3.keil程序

code

\`#include <reg51.h>

include "lcd.h"

include "temp.h"

include "ds1302.h"

sbit K0=P2^0; //下一页
sbit K1=P2^1; //选择/秒表启动暂停/定时器启动暂停
sbit K2=P2^2; //加
sbit K3=P2^3; //减
sbit K4=P2^4;

sbit BEEP=P1^4; //蜂鸣器

sbit INA=P1^0;
sbit INB=P1^1;
sbit INC=P1^2;
sbit IND=P1^3;

// 风扇控制状态变量
bit fanState = 0; // 风扇状态:0=关闭,1=开启
unsigned int fanTimer = 0; // 风扇工作定时器(单位:秒)
bit fanTimerRunning = 0; // 风扇定时器运行标志
bit fanTimerComplete = 0; // 风扇定时器完成标志
bit fanDirection = 1; // 风扇方向:1=顺时针,0=逆时针
unsigned char stepIndex = 0;// 当前步进索引

extern uchar b[],c[16];
extern uchar num[];
unsigned char year;
unsigned char month;
unsigned char day;
unsigned char hour;
unsigned char minute;
unsigned char second;
unsigned int millisecond = 0; // 毫秒计数

// 闹钟时间设置
unsigned char alarmHour = 13;
unsigned char alarmMinute = 0;
bit alarmTriggered = 0; // 闹钟触发标志
unsigned char IsAlarmRun = 0;

// 秒表功能
unsigned char stopwatchSec = 0; // 秒表-秒
unsigned char stopwatchDec = 0; // 秒表-0.1秒
bit stopwatchRunning = 0; // 秒表运行标志
bit stopwatchComplete = 0; // 秒表完成标志
bit stopwatchUpdateFlag = 0; // 秒表更新标志

// 定时器功能
unsigned char timerHour = 0; // 定时器-小时
unsigned char timerMinute = 0; // 定时器-分钟
unsigned char timerSecond = 0; // 定时器-秒
bit timerRunning = 0; // 定时器运行标志
bit timerComplete = 0; // 定时器完成标志
bit timerUpdateFlag = 0; // 定时器更新标志

// 使用内部RAM字节变量的位作为标志
unsigned char flags = 0;

define STOPWATCH_INIT_FLAG 0 // 秒表初始化标志

define TIMER_INIT_FLAG 1 // 定时器初始化标志

bit tempUpdateFlag = 0; // 温度更新标志
unsigned char tempDisplayBuffer[16]; // 温度显示缓冲区

// 原有函数声明...
void DisplayTemperature(); // 新增温度显示函数声明

unsigned char paper=0,mode=0;//0日期,时间,1调日期,2调时间,3设闹钟,4秒表,5定时,6温度

// 日期修改位置
unsigned char dateModifyPos = 0;
// 时间修改位置
unsigned char timeModifyPos = 0;
// 闹钟修改位置
unsigned char alarmModifyPos = 0;

// 闪烁计数器
unsigned char Count = 0;
// 闪烁标志
unsigned char blinkFlag = 0;
// 时间更新标志
bit timeUpdateFlag = 0;
// 闹钟闪烁标志
bit alarmBlinkFlag = 0;

// 延时函数(ms)
void Delay_ms(unsigned int ms) {

unsigned int i, j;
for(i = ms; i > 0; i--)
    for(j = 110; j > 0; j--);

}

// 蜂鸣器响函数
void Beep(unsigned int time) {

unsigned int i;
for(i = 0; i < time; i++) {
    BEEP = ~BEEP;
    Delay_ms(1);
}

}

// 显示日期时间函数
void DisplayDateTime(unsigned char year, unsigned char month, unsigned char day,

                unsigned char hour, unsigned char minute, unsigned char second) {
// 显示日期 (格式: YY-MM-DD)
LCD_SetCursor(1, 1);  
LCD_ShowNum(1, 1, year, 2);
LCD_ShowString(1, 3, "-");
LCD_ShowNum(1, 4, month, 2);
LCD_ShowString(1, 6, "-");
LCD_ShowNum(1, 7, day, 2);

// 显示时间 (格式: HH:MM:SS)
LCD_SetCursor(2, 1);  
LCD_ShowNum(2, 1, hour, 2);
LCD_ShowString(2, 3, ":");
LCD_ShowNum(2, 4, minute, 2);
LCD_ShowString(2, 6, ":");
LCD_ShowNum(2, 7, second, 2);

// 闹钟开启标志显示(LCD1602 列15是第16位)
if(IsAlarmRun == 1) {
    LCD_ShowString(1, 15, "*"); // 修正:列15(原16超出范围)
} else {
    LCD_ShowString(1, 15, " "); // 清除旧标志
}

}

// 显示日期函数
void DisplayDate() {

// 清屏

Delay_ms(2);

// 显示提示
LCD_ShowString(1, 1, "DateSet:");

// 显示日期 (格式: YY-MM-DD)
LCD_SetCursor(2, 1);

// 根据闪烁标志和修改位置决定显示内容
if(mode == 1 && dateModifyPos == 0 && blinkFlag ) {
    LCD_ShowString(2, 1, "__");
        
} else {
    LCD_ShowNum(2, 1, year, 2);
}

LCD_ShowString(2, 3, "-");

if(mode == 1 && dateModifyPos == 1 && blinkFlag ) {
    LCD_ShowString(2, 4, "__");
} else {
    LCD_ShowNum(2, 4, month, 2);
}

LCD_ShowString(2, 6, "-");

if(mode == 1 && dateModifyPos == 2 && blinkFlag ) {
    LCD_ShowString(2, 7, "__");
} else {
    LCD_ShowNum(2, 7, day, 2);
}
    LCD_ShowNum(2,10,blinkFlag,2);

}

// 显示时间函数
void DisplayTime() {

// 清屏
Delay_ms(2);

// 显示提示
LCD_ShowString(1, 1, "TimeSet:");

// 显示时间 (格式: HH:MM:SS)
LCD_SetCursor(2, 1);

// 根据闪烁标志和修改位置决定显示内容
if(mode == 1 && timeModifyPos == 0 && blinkFlag ) {
    LCD_ShowString(2, 1, "__");
} else {
    LCD_ShowNum(2, 1, hour, 2);
}

LCD_ShowString(2, 3, ":");

if(mode == 1 && timeModifyPos == 1 && blinkFlag ) {
    LCD_ShowString(2, 4, "__");
} else {
    LCD_ShowNum(2, 4, minute, 2);
}

LCD_ShowString(2, 6, ":");

if(mode == 1 && timeModifyPos == 2 && blinkFlag) {
    LCD_ShowString(2, 7, "__");
} else {
    LCD_ShowNum(2, 7, second, 2);
}

}

// 显示闹钟设置函数
void DisplayAlarm() {

// 清屏
Delay_ms(2);

// 显示提示 + 闹钟开启标志
LCD_ShowString(1, 1, "ALARM");
if(IsAlarmRun == 1) {
    LCD_ShowString(1, 15, "*"); // 列15,统一位置
} else {
    LCD_ShowString(1, 15, " ");
}

// 显示闹钟时间 (格式: HH:MM)
LCD_SetCursor(2, 1);

// 根据闪烁标志和修改位置决定显示内容
if(mode == 1 && alarmModifyPos == 0 && blinkFlag ) {
    LCD_ShowString(2, 1, "__");
} else {
    LCD_ShowNum(2, 1, alarmHour, 2);
}

LCD_ShowString(2, 3, ":");

if(mode == 1 && alarmModifyPos == 1 && blinkFlag ) {
    LCD_ShowString(2, 4, "__");
} else {
    LCD_ShowNum(2, 4, alarmMinute, 2);
}

// 显示秒(不可修改)
LCD_ShowString(2, 6, ":00");

// 显示闹钟触发状态
if(alarmTriggered) {
    LCD_ShowString(1, 10, "TRIG");
}

}

// 显示秒表函数
void DisplayStopwatch() {

// 使用字节变量的位作为标志
if(!(flags & (1 << STOPWATCH_INIT_FLAG)) || !stopwatchRunning) {
    LcdWriteCom(0x01);
    Delay_ms(2);
    flags |= (1 << STOPWATCH_INIT_FLAG);  // 设置初始化标志
    
    // 显示提示
    LCD_ShowString(1, 1, "STOPWATCH");
}

// 显示秒表状态
LCD_SetCursor(1, 11);
if(stopwatchComplete) {
    LCD_ShowString(1, 11, "DONE");
} else {
    LCD_ShowString(1, 11, stopwatchRunning ? "RUN " : "STOP");
}

// 显示秒表时间 (格式: SS.D)
LCD_SetCursor(2, 1);
LCD_ShowNum(2, 1, stopwatchSec, 2);
LCD_ShowString(2, 3, ".");
LCD_ShowNum(2, 4, stopwatchDec, 1);

}

// 显示定时器函数
void DisplayTimer() {

// 使用字节变量的位作为标志
if(!(flags & (1 << TIMER_INIT_FLAG)) || !timerRunning) {
    LcdWriteCom(0x01);
    Delay_ms(2);
    flags |= (1 << TIMER_INIT_FLAG);  // 设置初始化标志
    
    // 显示提示
    LCD_ShowString(1, 1, "TIMER");
}

// 显示定时器状态
LCD_SetCursor(1, 10);
if(timerComplete) {
    LCD_ShowString(1, 10, "DONE");
} else {
    LCD_ShowString(1, 10, timerRunning ? "RUN" : "SET");
}

// 显示定时器时间 (格式: HH:MM:SS)
LCD_SetCursor(2, 1);
LCD_ShowNum(2, 1, timerHour, 2);
LCD_ShowString(2, 3, ":");
LCD_ShowNum(2, 4, timerMinute, 2);
LCD_ShowString(2, 6, ":");
LCD_ShowNum(2, 7, timerSecond, 2);

}
// 显示温度函数
void DisplayTemperature() {

// 清屏 
unsigned char i;

Delay_ms(2);

// 显示提示
LCD_ShowString(1, 1, "TEMPERATURE");


Datapros(Ds18b20ReadTemp());

// 只更新第二行的温度数据,不重绘第一行
LcdWriteCom(0x80+0x44);  //从第二行第四位开始写

// 使用更高效的方式写入温度数据
for(i = 0; i < 8; i++) {
    LcdWriteData(b[i]);
}

// 显示温度单位
LCD_SetCursor(2, 14);

}
// 显示所有信息函数
// 显示所有信息(适配 LCD1602 两行显示)
// 显示所有信息(最终优化版,闹钟恢复冒号,定时器仅显示小时)
// 显示所有信息(最终版,按指定格式显示)
void DisplayAllInfo() {

// 清屏

Delay_ms(2);

// 第一行:月-日 时:分:秒 (MM-DD HH:MM:SS)
LCD_SetCursor(1, 1);  
LCD_ShowNum(1, 1, month, 2);    
LCD_ShowString(1, 3, "-");      
LCD_ShowNum(1, 4, day, 2);      
LCD_ShowString(1, 6, " ");      
LCD_ShowNum(1, 7, hour, 2);     
LCD_ShowString(1, 9, ":");      
LCD_ShowNum(1, 10, minute, 2);  
LCD_ShowString(1, 12, ":");     
LCD_ShowNum(1, 13, second, 2);  

// 闹钟开启标志(列15,统一位置)
if(IsAlarmRun == 1) {
    LCD_ShowString(1, 15, "*"); // 修正:列15
} else {
    LCD_ShowString(1, 15, " ");
}

// 第二行:AHH:MM SSS THH
LCD_SetCursor(2, 1);  
LCD_ShowString(2, 1, "A");      // 闹钟标识
LCD_ShowNum(2, 2, alarmHour, 2);
LCD_ShowString(2, 4, ":");      // 分隔符
LCD_ShowNum(2, 5, alarmMinute, 2);
LCD_ShowString(2, 7, " ");      // 空格分隔

LCD_ShowString(2, 8, "S");      // 秒表标识
LCD_ShowNum(2, 9, stopwatchSec, 2);  // 3位秒数
LCD_ShowString(2, 12, " ");     // 空格分隔

LCD_ShowString(2, 13, "T");     // 定时器标识
LCD_ShowNum(2, 14, timerHour, 2);  // 小时

}

void stepmotor_send_pulse(unsigned char step, bit dir)
{

unsigned char temp;
if(dir==0) temp=7-step;    //如果为逆时针旋转,调换节拍信号
else temp=step;
switch(temp)    //8个节拍控制:A->AB->B->BC->C->CD->D->DA
{
    case 0: INA=0;INB=0;INC=0;IND=1;break;
    case 1: INA=0;INB=0;INC=1;IND=1;break;
    case 2: INA=0;INB=0;INC=1;IND=0;break;
    case 3: INA=0;INB=1;INC=1;IND=0;break;
                
    case 4: INA=0;INB=1;INC=0;IND=0;break;
    case 5: INA=1;INB=1;INC=0;IND=0;break;
    case 6: INA=1;INB=0;INC=0;IND=0;break;
    case 7: INA=1;INB=0;INC=0;IND=1;break;
    default:INA=0;INB=0;INC=0;IND=0;break;//停止相序    
}

}

// 风扇控制页面显示函数
void DisplayFanControl() {

Delay_ms(2);

// 第一行:风扇状态和方向
LCD_ShowString(1, 1, "FAN: ");
if(fanState) {
    LCD_ShowString(1, 6, "ON   ");

} else {
    LCD_ShowString(1, 6, "OFF  ");
}

// 第二行:定时时间
LCD_ShowString(2, 1, "TIME:");
    LCD_ShowNum(2, 7, (int)(fanTimer / 60), 2);  // 分钟
LCD_ShowString(2, 9, ":");
LCD_ShowNum(2, 10, (int)(fanTimer % 60), 2); // 秒

}

// 按键扫描函数
void KeyScan() {

if(K0 == 0) {
    Delay_ms(20); 
    if(K0 == 0) {
        // 切换页面时重置模式
        mode = 0;
        
        paper++;
        if(paper==9) paper=0;
        
        // 重置相应初始化标志
        if(paper == 4) {
            flags &= ~(1 << STOPWATCH_INIT_FLAG);  // 清除秒表标志
        } else if(paper == 5) {
            flags &= ~(1 << TIMER_INIT_FLAG);       // 清除定时器标志
        }
        
        // 根据当前页面更新显示
        if(paper == 1) {
                        LcdWriteCom(0x01);
            DisplayDate();
        } else if(paper == 2) {
                        LcdWriteCom(0x01);
            DisplayTime();
        } else if(paper == 3) {
                        LcdWriteCom(0x01);
            DisplayAlarm();
        } else if(paper == 4) {
                        LcdWriteCom(0x01);
            DisplayStopwatch();
        } else if(paper == 5) {
                        LcdWriteCom(0x01);
            DisplayTimer();
        }else if(paper == 6) {
                        LcdWriteCom(0x01);
            DisplayTemperature();
        }else if(paper == 0) {
                        LcdWriteCom(0x01);
        } else if(paper == 7) {  
                            LcdWriteCom(0x01);
        DisplayAllInfo();
    }else if(paper == 8) {  
                            LcdWriteCom(0x01);
        DisplayFanControl();
    }
        
        while(K0 == 0);
        Delay_ms(20);
    }
}
    
    if(paper == 8) {  // 风扇控制页面按键处理
    // K4键:控制风扇开启/关闭
    if(K4 == 0) {
        Delay_ms(20);
        if(K4 == 0) {
            if(!fanState) {
                // 开启风扇,使用上次设置的参数
                fanTimerRunning = 1;
                fanState = 1;
            } else {
                // 关闭风扇
                fanState = 0;
                fanTimerRunning = 0;
            }
            DisplayFanControl();  // 更新显示
            while(K4 == 0);
            Delay_ms(20);
        }
    }
    
    // K2键:增加定时时间
    if(K2 == 0) {
        Delay_ms(20);
        if(K2 == 0) {
            if(!fanState) {  // 仅在风扇关闭时可设置时间
                fanTimer += 1;  // 每次增加1分钟
                if(fanTimer > 3600) fanTimer = 3600;  // 最大1小时
                DisplayFanControl();
            }
            while(K2 == 0);
            Delay_ms(20);
        }
    }
    
    // K3键:减少定时时间
    if(K3 == 0) {
        Delay_ms(20);
        if(K3 == 0) {
            if(!fanState && fanTimer >= 1) {  // 仅在风扇关闭时可减少时间
                fanTimer -= 1;
                if(fanTimer < 1) fanTimer = 1;  // 最小1分钟
                DisplayFanControl();
            }
            while(K3 == 0);
            Delay_ms(20);
        }
    }
    
    // K1键:切换方向
    if(K1 == 0) {
        Delay_ms(20);
        if(K1 == 0) {
            fanDirection = !fanDirection;
            DisplayFanControl();
            while(K1 == 0);
            Delay_ms(20);
        }
    }
}

// 检测K1按下(切换修改位置/秒表启动暂停/定时器启动暂停)
if(K1 == 0) {
    Delay_ms(20);  
    if(K1 == 0) {
        if(paper == 1 || paper == 2 || paper == 3) {
            mode = 1;
            
            // 根据当前页面切换不同的修改位置
            if(paper == 1) {
                dateModifyPos++;
                if(dateModifyPos > 2) dateModifyPos = 0;
            } else if(paper == 2) {
                timeModifyPos++;
                if(timeModifyPos > 2) timeModifyPos = 0;
            } else if(paper == 3) {
                alarmModifyPos++;
                if(alarmModifyPos > 1) alarmModifyPos = 0;
            }
        } else if(paper == 4) {
            // 秒表模式下,K1作为启动/暂停键
            if(!stopwatchComplete) {
                stopwatchRunning = !stopwatchRunning;
                if(!stopwatchRunning) {
                    // 暂停时重新初始化显示
                    flags &= ~(1 << STOPWATCH_INIT_FLAG);
                }
            } else {
                // 秒表完成后按K1重置
                stopwatchSec = 0;
                stopwatchDec = 0;
                stopwatchComplete = 0;
                flags &= ~(1 << STOPWATCH_INIT_FLAG);
            }
        } else if(paper == 5) {
            // 定时器模式下,K1作为启动/暂停键
            if(!timerComplete) {
                timerRunning = !timerRunning;
                if(!timerRunning) {
                    // 暂停时重新初始化显示
                    flags &= ~(1 << TIMER_INIT_FLAG);
                }
            } else {
                // 定时器完成后按K1重置
                timerHour = 0;
                timerMinute = 0;
                timerSecond = 0;
                timerComplete = 0;
                flags &= ~(1 << TIMER_INIT_FLAG);
            }
        }
        
        while(K1 == 0);
        Delay_ms(20);
        
        // 根据当前页面更新显示
        if(paper == 1) {
            DisplayDate();
        } else if(paper == 2) {
            DisplayTime();
        } else if(paper == 3) {
            DisplayAlarm();
        } else if(paper == 4) {
            DisplayStopwatch();
        } else if(paper == 5) {
            DisplayTimer();
        }
    }
}

// 检测K2按下(增加数据)
if(K2 == 0) {
    Delay_ms(20);  
    if(K2 == 0) {
        if((paper == 1 && mode == 1) || (paper == 2 && mode == 1) || (paper == 3 && mode == 1)) {
            // 日期增加逻辑
            if(paper == 1) {
                switch(dateModifyPos) {
                    case 0:  // 修改年
                                                    year=DS1302_Time[0];
                                                    DS1302_Time[0]=year+1;
                                                    year=DS1302_Time[0];
                                                    DS1302_SetTime();
                
                        break;
                    case 1:  // 修改月
                        month=DS1302_Time[1];
                                                    DS1302_Time[1]=month+1;
                                                    month=DS1302_Time[1];
                                                    DS1302_SetTime();

                        break;
                    case 2:  // 修改日
                        day=DS1302_Time[2];
                                                    DS1302_Time[2]=day+1;
                                                    day=DS1302_Time[2];
                                                    DS1302_SetTime();

;

                }
            } 
            // 时间增加逻辑
            else if(paper == 2) {
                switch(timeModifyPos) {
                    case 0:  // 修改时
                        hour=DS1302_Time[3];
                                                    DS1302_Time[3]=hour+1;
                                                    hour=DS1302_Time[3];
                                                    
                        break;
                    case 1:  // 修改分
                        minute=DS1302_Time[4];
                                                    DS1302_Time[4]=minute+1;
                                                    minute=DS1302_Time[4];
                        break;
                    case 2:  // 修改秒
                        second=DS1302_Time[5];
                                                    DS1302_Time[5]=second+1;
                                                    second=DS1302_Time[5];
                        break;
                }
                                    DS1302_SetTime();
            }
            // 闹钟增加逻辑
            else if(paper == 3) {
                switch(alarmModifyPos) {
                    case 0:  // 修改时
                        alarmHour++;
                        if(alarmHour > 23) alarmHour = 0;
                        break;
                    case 1:  // 修改分
                        alarmMinute++;
                        if(alarmMinute > 59) alarmMinute = 0;
                        break;
                }
            }
        } else if(paper == 4) {
            //秒表
                                    stopwatchSec = 0;
                stopwatchDec = 0;
                stopwatchComplete = 0;
                        
                        
        }else if(paper == 5 && !timerRunning) {
            // 定时器模式下,增加时间
            if(timerHour < 24) {
                timerMinute++;
                if(timerMinute  == 60) {
                    timerMinute = 0;
                    timerSecond = 0;
                                            timerHour++;
                }
            } else {
                timerHour = 0;
                timerMinute = 0;
                timerSecond = 0;
            }
            DisplayTimer();
        }
        
        while(K2 == 0);
        Delay_ms(20);
        
        // 根据当前页面更新显示
        if(paper == 1) {
            DisplayDate();
        } else if(paper == 2) {
            DisplayTime();
        } else if(paper == 3) {
            DisplayAlarm();
        }
    }
}

        // 检测K3按下(减少数据)
        if(K3 == 0) {
                Delay_ms(20);  
                if(K3 == 0) {
                        if((paper == 1 && mode == 1) || (paper == 2 && mode == 1) || (paper == 3 && mode == 1)) {
                                // 日期减少逻辑
                             if(paper == 1) {  // 日期减少
        switch(dateModifyPos) {
                case 0:  // 修改年
                        year = DS1302_Time[0];
                        DS1302_Time[0] = year - 1;
                        year = DS1302_Time[0];

                        break;
                        
                case 1:  // 修改月
                        month = DS1302_Time[1];
                        DS1302_Time[1] = month - 1;
                        month = DS1302_Time[1];

                        break;
                        
                case 2:  // 修改日
                        day = DS1302_Time[2];
                        DS1302_Time[2] = day - 1;
                        day = DS1302_Time[2];
                        
                        break;
        }
        DS1302_SetTime();
} 
// 时间减少逻辑
else if(paper == 2) {
        switch(timeModifyPos) {
                case 0:  // 修改时
                        hour = DS1302_Time[3];
                        DS1302_Time[3] = hour - 1;
                        hour = DS1302_Time[3];
                    
                        break;
                        
                case 1:  // 修改分
                        minute = DS1302_Time[4];
                        DS1302_Time[4] = minute - 1;
                        minute = DS1302_Time[4];
                
                        break;
                        
                case 2:  // 修改秒
                        second = DS1302_Time[5];
                        DS1302_Time[5] = second - 1;
                        second = DS1302_Time[5];
                    
                        break;
        }
        DS1302_SetTime();
}
            // 闹钟减少逻辑
            else if(paper == 3) {
                switch(alarmModifyPos) {
                    case 0:  // 修改时
                        if(alarmHour == 0) alarmHour = 23;
                        else alarmHour--;
                        break;
                    case 1:  // 修改分
                        if(alarmMinute == 0) alarmMinute = 59;
                        else alarmMinute--;
                        break;
                }
            }
        } else if(paper == 5 && !timerRunning) {
            // 定时器模式下,减少时间
            if(timerHour > 0 || timerMinute > 0 || timerSecond > 0) {
                    
                                            if(timerMinute >= 0) {
                                            if(timerMinute-- == 0) {
                                            timerHour--;
                                            
                }
                }
            } else {
                timerHour = 23;
                timerMinute = 59;
                timerSecond = 59;
            }
            DisplayTimer();
        }
        
        while(K3 == 0);
        Delay_ms(20);
        
        // 根据当前页面更新显示
        if(paper == 1) {
            DisplayDate();
        } else if(paper == 2) {
            DisplayTime();
        } else if(paper == 3) {
            DisplayAlarm();
        }
    }
}
if(K4 == 0) {
        Delay_ms(20); 
        if(K4 == 0) {
            
                // 1. 闹钟设置页(paper=3):切换 IsAlarmRun
                if(paper == 3|| alarmTriggered == 1) {
                        IsAlarmRun = !IsAlarmRun;
                        if(alarmTriggered==1)alarmTriggered=0;
                } 
                while(K4 == 0);
                Delay_ms(20);
        }
}
  

}

void Timer1_Init(){

    TMOD |= 0x10;  // 设置定时器1为模式1

ET1 = 1; // 使能定时器1中断
EA = 1; // 开总中断
TR1 = 1; // 启动定时器1

}

void Timer0_Init() {

TMOD |= 0x01;    // 设置定时器0为模式1
TH0 = 0xFC;     // 定时初值,约1ms
TL0 = 0x66;
ET0 = 1;        // 使能定时器0中断
EA = 1;         // 开总中断
TR0 = 1;        // 启动定时器0

}

void main() {

LcdInit();      
Timer0_Init();  
    DS1302_Init();
DisplayDateTime(year, month, day, hour, minute, second);
  DS1302_SetTime();
Timer1_Init();

while(1) {
    KeyScan();
            DS1302_ReadTime();
    year = DS1302_Time[0];
            month = DS1302_Time[1];
            day = DS1302_Time[2];
            hour = DS1302_Time[3];
            minute = DS1302_Time[4];
            second = DS1302_Time[5];
    // 闹钟触发处理
        
                if(alarmTriggered) {
        Beep(50);  // 短脉冲,避免阻塞主循环
        Delay_ms(50);
    } else {
        BEEP = 1;  // 关闭蜂鸣器
    } 
    
    // 时间显示更新
    if(paper == 0) {
            DisplayDateTime(year, month, day, hour, minute, second);
    } else if(paper == 1) {
                        DisplayDate();
        // 日期设置页面逻辑在DisplayDate()和定时器中断中处理
    } else if(paper == 2) {
                DisplayTime();
        // 时间设置页面逻辑在DisplayTime()和定时器中断中处理
    } else if(paper == 3) {
        // 闹钟设置页面逻辑在DisplayAlarm()和定时器中断中处理
                DisplayAlarm();
    } else if(paper == 4) {
        // 秒表页面逻辑
        if(stopwatchUpdateFlag) {
            DisplayStopwatch();
            stopwatchUpdateFlag = 0;
        }
    } else if(paper == 5) {
        // 定时器页面逻辑
        if(timerUpdateFlag) {
            DisplayTimer();
            timerUpdateFlag = 0;
        }
    }else if(paper == 6) {
                
            DisplayTemperature();
        
    } else if(paper == 7) {  
    DisplayAllInfo();
}else if(paper == 8) {  
    DisplayFanControl();
            
}
    
    Delay_ms(10);  
}

}

// 定时器0中断服务函数 - 处理主要功能
void Timer0_ISR() interrupt 1 {

static unsigned int motorStepCounter = 0;
TH0 = 0xFC;    
TL0 = 0x66;
millisecond++;

// 优先处理时间和闹钟功能
if(IsAlarmRun && hour == alarmHour && minute == alarmMinute ) {
    alarmTriggered = 1;
}

// 次优先处理秒表和定时器
if(stopwatchRunning && !stopwatchComplete) {
    if(millisecond % 100 == 0) {
        stopwatchDec++;
        if(stopwatchDec >= 10) {
            stopwatchDec = 0;
            stopwatchSec++;
            if(stopwatchSec >= 60) {
                stopwatchSec = 60;
                stopwatchDec = 0;
                stopwatchRunning = 0;
                alarmTriggered = 1;
                stopwatchComplete=1;
            }
        }
        stopwatchUpdateFlag = 1;
    }
}

// 定时器中断处理中分钟递减
if(timerRunning && !timerComplete) {
    if(millisecond >= 1000) {
        millisecond = 0;  // 重置毫秒计数
        
        if(timerHour > 0 || timerMinute > 0 || timerSecond > 0) {
            if(timerSecond > 0) {
                timerSecond--;
            } else if(timerMinute > 0) {
                timerMinute--;  // 秒为0时减少分钟
                timerSecond = 59;
            } else if(timerHour > 0) {
                timerHour--;
                timerMinute = 59;
                timerSecond = 59;
            }
            timerUpdateFlag = 1;
        } else {
            timerRunning = 0;
            alarmTriggered = 1;
            timerUpdateFlag = 1;
            timerComplete = 1;
        }
    }
}

// 最后处理电机控制,减少对其他功能的影响
if(fanTimerRunning && fanTimer >=0) {
    if(millisecond >= 10) {  // 减少步进间隔,提高电机控制精度
        millisecond = 0;
        motorStepCounter++;
        
        if(fanState) {
            stepmotor_send_pulse(stepIndex, fanDirection);
            stepIndex = (stepIndex + 1) % 8;
        } else {
            INA=0;INB=0;INC=0;IND=0;  // 关闭所有线圈
        }
    }
    if(motorStepCounter >= 100) {  // 调整计数阈值,确保1秒递减1次
        fanTimer--;
        motorStepCounter = 0;
        
        // 当定时器减到0时,关闭风扇
        if(fanTimer == 0) {
            alarmTriggered = 1;
            fanState = 0;
            fanTimerRunning = 0;
            INA=0;INB=0;INC=0;IND=0;  // 关闭所有线圈
        }
    }
}

}

// 定时器1中断服务函数 - 专门处理LED闪烁
void Timer1_ISR() interrupt 3 {

static unsigned int blinkCounter = 0;
TH1 = 0xFC;    // 1ms定时
TL1 = 0x66;

blinkCounter++;
if(blinkCounter >= 10) {  // 100ms间隔
    blinkCounter = 0;
    blinkFlag = !blinkFlag;
}

} `

4.proteus仿真

4.1原理接线图

此处内容需要评论回复后(审核通过)方可阅读。

4.2成果展示

2026-07-04T02:31:05.png

5.预备知识

1、51单片机原理与接口技术;
2、详细了解DS1302、LCD1602、DS18B20、L298或ULN2003D数据手册,特别是单片机与DS18B20单总线接口通信时序以及异步电机的工作原理。

6.结语

运用at89c51及各模块实现电子钟功能

喜欢我的文章吗?别忘了点赞或赞赏,让我知道创作的路上有你陪伴。