概述
单片机采用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系统原理图

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

5.预备知识
1、51单片机原理与接口技术;
2、详细了解DS1302、LCD1602、DS18B20、L298或ULN2003D数据手册,特别是单片机与DS18B20单总线接口通信时序以及异步电机的工作原理。
6.结语
运用at89c51及各模块实现电子钟功能