📄 mod1.c
字号:
#include <reg51.h>
#include <absacc.h>
#include <string.h>
#include <intrins.h>
#include <ctype.h>
#include <stdlib.h>
#define Uchar unsigned char
#define Uint unsigned int
#define Ulong unsigned long
/* 定义8155的I/O端口地址 */
#define P8155CW 0x7f00 /* 8155命令口地址 */
#define P8155IA 0x7f01 /* 8155的PA口地址 */
#define P8155IB 0x7f02 /* 8155的PB口地址 */
#define P8155IC 0x7f03 /* 8155的PC口地址 */
/* 定义定时器T0的时间常数值和方式控制字 */
#define V_TH0 0x9e /* 时间常数高8位 */
#define V_TL0 0x75 /* 时间常数低8位 */
#define V_TMOD 0x01 /* 定时器T0方式控制字 */
/* 定义LED显示字符段码 */
static struct {
Uchar ascii;
Uchar stroke;
} code led_strokes[27] =\
{{'0',0x3f}, {'1',0x06}, {'2',0x5b}, {'3',0x4f}, {'4',0x66},\
{'5',0x6d}, {'6',0x7d}, {'7',0x07}, {'8',0x7f}, {'9',0x6f},\
{'A',0x77}, {'B',0x7c}, {'C',0x39}, {'D',0x5e}, {'E',0x79},\
{'F',0x71}, {'H',0x76}, {'O',0x5c}, {'P',0x73}, {'U',0x3e},\
{'R',0x50}, {'Y',0x6e}, {'.',0x80}, {'-',0x40}, {'=',0x48},\
{0x00,0x00}, {0xff,0xff}};
/* 定义非闰年每月的天数 */
Uchar code days_month[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
struct TIME { /* 定义时间结构 */
Uchar sec;
Uchar min;
Uchar hour;
};
struct DATE { /* 定义日期结构 */
Uchar year;
Uchar month;
Uchar day;
};
struct TIME time;
struct DATE date;
/* 定义一组全局变量和函数原型 */
Uchar bdata flag;
sbit time_init=flag^0;
sbit auto_flush=flag^1;
sbit message_flag=flag^2;
Uint message_time;
Uchar led_buf[8];
extern void delay(Uint);
void led_buf_auto_flush(void) reentrant;
bit leap_year(void) reentrant;
void init_sys(void);
void monitor(void);
void set_led_buf(Uchar,Uchar,Uchar);
Uchar get_strokes(Uchar);
void put_on_leds(void);
void put_off_leds(void);
bit kb_hit(void);
Uchar get_ch(void);
Uchar * get_str(Uchar *, Uint);
void ask_date(void);
bit set_date_time(void);
void error_message(void);
/**************************************************************************
* 函数原型: main();
* 功 能: 调用init_sys()函数对系统进行初始化, 调用monitor()函数对
* 用户输入的键盘命令进行解释。
/*************************************************************************/
main() {
init_sys();
monitor();
}
/**************************************************************************
* 函数原型: void init_sys(void);
* 功 能: 对系统进行初始化并接受用户的的初始化日期时间设置
**************************************************************************/
void init_sys(void) {
/* 8155初始化 */
XBYTE[P8155CW]=0x03; XBYTE[P8155IA]=0xff; XBYTE[P8155IB]=0xff;
/* 定时器T0初始化 */
TMOD=V_TMOD; TH0=V_TH0; TL0=V_TL0;
TR0=1; ET0=1; EA=1;
/* 标志变量初始化 */
time_init=0; auto_flush=0; message_flag=0; message_time=0;
/* 显示8个"-"直到用户按下"0"键并成功设置初始化日期时间为止 */
set_led_buf('-',0,8); /* 用"-"填充显示缓冲区 */
while(1) {
put_on_leds(); /* 显示缓冲区当前的内容 */
if(!get_ch()) continue; /* 如果用户按下的不是"0"键 */
if(! set_date_time()) /* 如果日期时间初始化不成功 */
set_led_buf('-',0,8);
else
break;
}
}
/**************************************************************************
* 函数原型: void monitor(void);
* 功 能: 用当前的时、分、秒值自动刷新LED显示, 并对用户按键进行解释。
* "0"键表示校正日期和时间, 如果校时成功则动态显示时间, 否则
* 显示出错信息"ERROR"。"1"键表示查询并显示当前日期。在显示出
* 错信息"ERROR"期间, 按任意键可清除显示, 否则10秒后自动恢复
* 动态时间显示。
**************************************************************************/
void monitor(void) {
Uchar command;
while(1) {
put_on_leds(); /* 显示缓冲区当前内容 */
if(message_time==0) { /* 如果日期或出错信息显示时间为0秒 */
message_flag=0; /* 清除错误信息显示标志 */
auto_flush=1; /* 设置用当前时间自动刷新缓冲区标志*/
}
if((command=get_ch())) { /* 如果有键按下 */
message_flag=0; /* 清除错误信息显示标志 */
message_time=0; /* 设置错误信息显示时间为0秒 */
}
switch(command) { /* 对键盘命令进行解释 */
case'0':if(!set_date_time()) /* 如果校时不成功 */
error_message(); /* 显示错误信息"ERROR" */
break;
case'1':ask_date(); /* 查询当前日期 */
break;
default : break;
}
}
}
/**************************************************************************
* 函数原型: void timer0(void);
* 功 能: 定时器T0中断服务函数。每次执行时先重装时间常数, 然后检查日
* 期和时间是否已经初始化, 如果未初始化则立即返回, 否则每中断
* 20次(即一秒钟)根据信息显示标志的设置来决定是否将日期或错误
* 信息显示时间减1, 然后自动修改日期和时间结构。如果缓冲区自动
* 刷新标志为1, 则用当前时间刷新显示缓冲区。
**************************************************************************/
void timer0(void) interrupt 1 using 2 {
static Uchar click=0; /* 中断次数计数器变量 */
/* 重装定时器T0时间常数 */
TH0=V_TH0; TL0=V_TL0;
if(!time_init) return; /* 如果日期时间未初始化, 返回 */
++click;
if(click>=20) { /* 间隔1秒钟(20*50ms=1s) */
click=0;
/* 根据消息显示标志决定是否将消息显示时间减少1秒 */
if(message_flag && message_time) --message_time;
/* 计算并修改时间和日期 */
if(++time.sec>=60) {
time.sec=0;
if(++time.min>=60) {
time.min=0;
if(++time.hour>=24) {
time.hour=0;
if(++date.day>days_month[date.month]) {
if(date.month==2 && leap_year());
else date.day=1;
if(++date.month>12) {
date.month=1;
++date.year;
}
}
}
}
}
/* 如果已设置缓冲区自动刷新标志, 则用当前时间刷新显示缓冲区 */
if(auto_flush) led_buf_auto_flush();
}
}
/**************************************************************************
* 函数原型: void led_buf_auto_flush(void) ;
* 功 能: 用当前时间的时、分、秒值填充显示缓冲区。
**************************************************************************/
void led_buf_auto_flush(void) reentrant {
led_buf[0]=time.sec%10+0x30;
led_buf[1]=time.sec/10+0x30;
led_buf[2]='-';
led_buf[3]=time.min%10+0x30;
led_buf[4]=time.min/10+0x30;
led_buf[5]='-';
led_buf[6]=time.hour%10+0x30;
led_buf[7]=time.hour/10+0x30;
}
/**************************************************************************
* 函数原型: bit leap_year(void);
* 功 能: 判断某年是否为闰年, 若是闰年则返回1, 否则返回0。
**************************************************************************/
bit leap_year(void) reentrant {
if(date.year%4==0 && date.year%100 != 0) return((bit)1);
if(date.year%400==0) return((bit)1);
return((bit)0);
}
/**************************************************************************
* 函数原型: void set_led_buf(Uchar c, Uchar pos, Uchar cnt);
* 功 能: 从显示缓冲区的pos位置开始, 用字符c填充cnt个字节。
**************************************************************************/
void set_led_buf(Uchar c,Uchar pos, Uchar cnt) {
Uchar ledbuf_pos;
auto_flush=0; /* 在填充期间关闭LED显示器 */
for(ledbuf_pos=pos; cnt>0; cnt--) {
led_buf[ledbuf_pos]=((islower(c)) ? (toupper(c)) : (c));
ledbuf_pos++;
if(ledbuf_pos>=8) ledbuf_pos=0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -