显示时间,每次数码管显示年或月或日或时或分或秒。(月和日中间加小数点,时和分也是,注意闰年闰月),在程序中能进行时间的初始化,使用按键(中断)能进行年月日时分秒的交替显示,使用按键(不需要用中断)进行时间的调节,调节过程中调节的数码管闪烁
时间: 2023-09-18 20:12:11 浏览: 143
显示“HELLO”或“PASS”-c51单片机关键内容分讲经典之数码管
这是一道较为复杂的题目,需要使用到定时器、中断、按键输入、数码管显示等多种知识。下面给出一个基本的实现思路:
1. 定义数码管显示的函数,可以使用共阴数码管,通过对应的端口输出高低电平控制数码管显示。
2. 定义定时器中断函数,每秒钟触发一次,更新时间,并调用数码管显示函数。
3. 定义按键中断函数,检测到按键按下后,根据当前显示的内容进行时间调整或者切换显示内容。
4. 在主函数中初始化定时器和按键中断,进入循环等待中断触发。
下面是一份基于51单片机的C语言代码,仅供参考:
```c
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
// 数码管共阴接口
sbit D1 = P2^0; // 第一位数码管
sbit D2 = P2^1; // 第二位数码管
sbit D3 = P2^2; // 第三位数码管
sbit D4 = P2^3; // 第四位数码管
// 按键输入接口
sbit KEY1 = P3^0; // 调节时间按键
sbit KEY2 = P3^1; // 切换显示按键
// 定义时间结构体
typedef struct {
uchar year; // 年(后两位)
uchar month; // 月
uchar day; // 日
uchar hour; // 时
uchar minute; // 分
uchar second; // 秒
} Time;
// 定义全局变量
Time curTime = {21, 1, 1, 0, 0, 0}; // 当前时间
uchar curDisplay = 0; // 当前显示内容(0:年,1:月,2:日,3:时,4:分,5:秒)
uchar isAdjusting = 0; // 是否正在调节时间
uchar adjustDigit = 0; // 正在调节的数字位(0:年个位,1:年十位,2:月个位,3:月十位...)
// 数码管显示函数
void displayTime(Time t) {
uchar digit1 = t.year % 10;
uchar digit2 = t.year / 10;
uchar digit3 = t.month % 10;
uchar digit4 = t.month / 10;
uchar digit5 = t.day % 10;
uchar digit6 = t.day / 10;
uchar digit7 = t.hour % 10;
uchar digit8 = t.hour / 10;
uchar digit9 = t.minute % 10;
uchar digit10 = t.minute / 10;
uchar digit11 = t.second % 10;
uchar digit12 = t.second / 10;
switch (curDisplay) {
case 0:
D1 = 1; D2 = 1; D3 = 0; D4 = 0; // 显示年个位
P0 = digit1;
break;
case 1:
D1 = 1; D2 = 1; D3 = 0; D4 = 0; // 显示年十位
P0 = digit2;
break;
case 2:
D1 = 1; D2 = 0; D3 = 1; D4 = 0; // 显示月个位
P0 = digit3;
break;
case 3:
D1 = 1; D2 = 0; D3 = 1; D4 = 0; // 显示月十位
P0 = digit4;
break;
case 4:
D1 = 0; D2 = 1; D3 = 1; D4 = 0; // 显示日个位
P0 = digit5;
break;
case 5:
D1 = 0; D2 = 1; D3 = 1; D4 = 0; // 显示日十位
P0 = digit6;
break;
case 6:
D1 = 0; D2 = 1; D3 = 0; D4 = 1; // 显示时个位
P0 = digit7;
break;
case 7:
D1 = 0; D2 = 1; D3 = 0; D4 = 1; // 显示时十位
P0 = digit8;
break;
case 8:
D1 = 0; D2 = 0; D3 = 1; D4 = 1; // 显示分个位
P0 = digit9;
break;
case 9:
D1 = 0; D2 = 0; D3 = 1; D4 = 1; // 显示分十位
P0 = digit10;
break;
case 10:
D1 = 0; D2 = 0; D3 = 0; D4 = 1; // 显示秒个位
P0 = digit11;
break;
case 11:
D1 = 0; D2 = 0; D3 = 0; D4 = 1; // 显示秒十位
P0 = digit12;
break;
}
}
// 定时器中断函数
void timer0_isr() interrupt 1 {
TH0 = 0xFC; // 重新设置定时器初值
TL0 = 0x67;
curTime.second++; // 更新时间
if (curTime.second == 60) {
curTime.second = 0;
curTime.minute++;
if (curTime.minute == 60) {
curTime.minute = 0;
curTime.hour++;
if (curTime.hour == 24) {
curTime.hour = 0;
curTime.day++;
switch (curTime.month) { // 根据月份判断是否需要更新天数
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
if (curTime.day > 31) {
curTime.day = 1;
curTime.month++;
}
break;
case 4: case 6: case 9: case 11:
if (curTime.day > 30) {
curTime.day = 1;
curTime.month++;
}
break;
case 2:
if ((curTime.year % 4 == 0 && curTime.year % 100 != 0) || curTime.year % 400 == 0) { // 闰年
if (curTime.day > 29) {
curTime.day = 1;
curTime.month++;
}
} else { // 平年
if (curTime.day > 28) {
curTime.day = 1;
curTime.month++;
}
}
break;
}
if (curTime.month > 12) { // 更新月份,注意从12月到1月的跨年
curTime.month = 1;
curTime.year++;
}
}
}
}
displayTime(curTime); // 显示时间
}
// 按键中断函数
void key_isr() {
if (KEY1 == 0) { // 调节时间按键
isAdjusting = 1;
switch (curDisplay) { // 根据当前显示内容确定正在调节的数字位
case 0:
adjustDigit = 0;
break;
case 1:
adjustDigit = 1;
break;
case 2:
adjustDigit = 2;
break;
case 3:
adjustDigit = 3;
break;
case 4:
adjustDigit = 4;
break;
case 5:
adjustDigit = 5;
break;
}
while (KEY1 == 0) { // 等待按键松开
P0 = 0; // 数码管闪烁
}
P0 = 0xFF; // 关闭数码管显示
}
if (KEY2 == 0) { // 切换显示按键
curDisplay++;
if (curDisplay > 5) {
curDisplay = 0;
}
while (KEY2 == 0) { // 等待按键松开
displayTime(curTime); // 数码管持续显示当前内容
}
}
}
void main() {
TMOD = 0x01; // 设置定时器0为模式1
TH0 = 0xFC; // 设置初值,每隔1ms产生一次中断
TL0 = 0x67;
ET0 = 1; // 允许定时器0中断
EA = 1; // 允许总中断
TR0 = 1; // 启动定时器0
EX0 = 1; // 允许外部中断0(按键中断)
IT0 = 1; // 设置外部中断0为下降沿触发
while (1) {
if (isAdjusting) { // 正在调节时间
// 根据adjustDigit显示当前数字
uchar digit = 0;
switch (adjustDigit) {
case 0:
digit = curTime.year % 10;
break;
case 1:
digit = curTime.year / 10;
break;
case 2:
digit = curTime.month % 10;
break;
case 3:
digit = curTime.month / 10;
break;
case 4:
digit = curTime.day % 10;
break;
case 5:
digit = curTime.day / 10;
break;
}
displayTime(curTime); // 先显示当前时间
D1 = 0; D2 = 0; D3 = 0; D4 = 1; // 数码管闪烁
P0 = digit;
while (isAdjusting) { // 等待调节完成
// 根据adjustDigit更新当前数字
switch (adjustDigit) {
case 0:
curTime.year = curTime.year / 10 * 10 + digit;
break;
case 1:
curTime.year = curTime.year % 10 + digit * 10;
break;
case 2:
curTime.month = curTime.month / 10 * 10 + digit;
break;
case 3:
curTime.month = curTime.month % 10 + digit * 10;
break;
case 4:
curTime.day = curTime.day / 10 * 10 + digit;
break;
case 5:
curTime.day = curTime.day % 10 + digit * 10;
break;
}
delay(100); // 延时一段时间,避免误触发
digit = digit + 1;
if (digit == 10) {
digit = 0;
}
P0 = digit; // 更新数码管显示
}
} else {
displayTime(curTime); // 正常显示时间
}
}
}
// 延时函数
void delay(uint i) {
uint j, k;
for (j = i; j > 0; j--) {
for (k = 110; k > 0; k--);
}
}
```
需要注意的几个点:
1. 定时器中断函数中需要根据当前时间更新天数、月份和年份,以处理闰年闰月等特殊情况。
2. 按键中断函数中需要判断当前正在调节哪一位数字,以便在调节过程中正确更新时间。
3. 调节时间过程中需要让数码管闪烁,以提示用户正在进行调节。可以使用一个计时器或者延时函数来实现。
4. 在调节完成后需要及时更新当前时间,并关闭数码管显示,以便正常显示时间。
阅读全文