用at89c51单片机实现“万年钟”
1)基本功能
使用字符型 LCD 显示器显示当前时间。
显示格式为“年-月-日”
时时:分分:秒秒
用 4 个功能键操作来设置当前时间, 4 个功能键接在 P1.0~P1.3 引脚上
2)扩展功能
显示星期
备注:
功能键 1-K4 功能如下。
K1-进入设置年,月,日,星期,小时,分钟,秒。
K2-设置所选位的加 1
K3-设置所选位减1
K4-确认完成设置。
#include <reg51.h>
// 定义 LCD1602 的引脚连接
#define LCD_RS P0_0
#define LCD_RW P0_1
#define LCD_EN P0_2
#define LCD_DATA P2
// 定义功能键连接的引脚
#define FUNC_KEY_1 P1_0
#define FUNC_KEY_2 P1_1
#define FUNC_KEY_3 P1_2
#define FUNC_KEY_4 P1_3
// 定义初始时间
unsigned char year = 20; // 年份,例如 2020 年
unsigned char month = 6; // 月份
unsigned char day = 5; // 日期
unsigned char hour = 12; // 小时
unsigned char minute = 0; // 分钟
unsigned char second = 0; // 秒钟
// 定义星期数组
unsigned char weekday[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
unsigned char currentWeekday = 0; // 当前星期几的索引
// 延时函数
void delay(unsigned int ms) {
unsigned int i, j;
for (i = 0; i < ms; i++)
for (j = 0; j < 125; j++);
}
// 向 LCD 发送命令
void lcdCommand(unsigned char cmd) {
LCD_RS = 0;
LCD_RW = 0;
LCD_DATA = cmd;
LCD_EN = 1;
delay(5);
LCD_EN = 0;
}
// 向 LCD 发送数据
void lcdData(unsigned char dat) {
LCD_RS = 1;
LCD_RW = 0;
LCD_DATA = dat;
LCD_EN = 1;
delay(5);
LCD_EN = 0;
}
// 初始化 LCD
void lcdInit() {
lcdCommand(0x38); // 设置显示模式为 8 位数据接口
lcdCommand(0x0C); // 显示开,光标关闭
lcdCommand(0x06); // 光标移动设置:右移
lcdCommand(0x01); // 清屏
delay(10);
}
// 在 LCD 上显示时间和日期
void lcdDisplayDateTime() {
lcdCommand(0x80); // 设置光标位置为第一行第一列
lcdData('2'); // 显示 "20",表示年份
lcdData('0');
lcdData((year / 10) + '0');
lcdData((year % 10) + '0');
lcdData('-');
lcdData((month / 10) + '0');
lcdData((month % 10) + '0');
lcdData('-');
lcdData((day / 10) + '0');
lcdData((day % 10) + '0');
lcdCommand(0xC0); // 设置光标位置为第二行第一列
lcdData((hour / 10) + '0');
lcdData((hour % 10) + '0');
lcdData(':');
lcdData((minute / 10) + '0');
lcdData((minute % 10) + '0');
lcdData(':');
lcdData((second / 10) + '0');
lcdData((second % 10) + '0');
lcdData(' ');
lcdData(' ');
lcdData(' ');
lcdData(weekday[currentWeekday][0]);
lcdData(weekday[currentWeekday][1]);
lcdData(weekday[currentWeekday][2]);
}
// 增加当前时间
void incrementTime() {
second++;
if (second >= 60) {
second = 0;
minute++;
if (minute >= 60) {
minute = 0;
hour++;
if (hour >= 24) {
hour = 0;
day++;
currentWeekday++;
if (currentWeekday >= 7) {
currentWeekday = 0;
month++;
if (month >= 13) {
month = 1;
year++;
}
}
}
}
}
}
// 减少当前时间
void decrementTime() {
if (second > 0) {
second--;
} else {
if (minute > 0) {
minute--;
second = 59;
} else {
if (hour > 0) {
hour--;
minute = 59;
second = 59;
} else {
if (day > 1) {
day--;
currentWeekday--;
if (currentWeekday < 0) {
currentWeekday = 6;
month--;
if (month < 1) {
month = 12;
year--;
}
}
}
}
}
}
}
// 主函数
void main() {
lcdInit(); // 初始化 LCD
while (1) {
lcdDisplayDateTime(); // 显示当前时间和日期
if (FUNC_KEY_1 == 0) {
// 进入设置模式
while (FUNC_KEY_1 == 0) {
// 等待 FUNC_KEY_1 松开
}
// 选择要设置的位
unsigned char settingIndex = 0; // 0 表示年份,1 表示月份,以此类推
while (1) {
lcdCommand(0x8F); // 设置光标位置为第二行最后一列
lcdData('^');
if (FUNC_KEY_4 == 0) {
// 确认设置完成,退出设置模式
while (FUNC_KEY_4 == 0) {
// 等待 FUNC_KEY_4 松开
}
break;
}
if (FUNC_KEY_2 == 0) {
// 增加当前位的值
while (FUNC_KEY_2 == 0) {
// 等待 FUNC_KEY_2 松开
}
switch (settingIndex) {
case 0: // 年份
year++;
if (year >= 100) {
year = 0;
}
break;
case 1: // 月份
month++;
if (month >= 13) {
month = 1;
}
break;
case 2: // 日期
day++;
if (day >= 32) {
day = 1;
}
break;
case 3: // 星期
currentWeekday++;
if (currentWeekday >= 7) {
currentWeekday = 0;
}
break;
case 4: // 小时
hour++;
if (hour >= 24) {
hour = 0;
}
break;
case 5: // 分钟
minute++;
if (minute >= 60) {
minute = 0;
}
break;
case 6: // 秒钟
second++;
if (second >= 60) {
second = 0;
}
break;
}
}
if (FUNC_KEY_3 == 0) {
// 减少当前位的值
while (FUNC_KEY_3 == 0) {
// 等待 FUNC_KEY_3 松开
}
switch (settingIndex) {
case 0: // 年份
year--;
if (year >= 100) {
year = 99;
}
break;
case 1: // 月份
month--;
if (month <= 0) {
month = 12;
}
break;
case 2: // 日期
day--;
if (day <= 0) {
day = 31;
}
break;
case 3: // 星期
currentWeekday--;
if (currentWeekday < 0) {
currentWeekday = 6;
}
break;
case 4: // 小时
hour--;
if (hour >= 24) {
hour = 23;
}
break;
case 5: // 分钟
minute--;
if (minute >= 60) {
minute = 59;
}
break;
case 6: // 秒钟
second--;
if (second >= 60) {
second = 59;
}
break;
}
}
settingIndex++;
if (settingIndex >= 7) {
settingIndex = 0;
}
delay(200); // 延时一段时间,避免按键抖动
}
}
incrementTime(); // 增加当前时间
delay(1000); // 延时 1 秒
}
}