//改程序将实现电子时钟的显示
//依靠定时计数器0的中断进行时间参数的确定
#include <reg52.h>
#include <stdio.h>
#include <intrins.h>
#define uchar unsigned char
#define Data P0
//端口的定义
sbit WEI = P2^7;
sbit DUAN = P2^6;
sbit RS = P2^1;
sbit RW = P1^5;
sbit E = P1^6;
sbit BF = P0^7;
uchar code num[] = {"0123456789"};
uchar time; //计时器
//用到函数的声明
void Delay(uchar); //延时函数
void Busy(); //忙时检测函数
void InitLCD(); //液晶屏初始化函数
void InitTimer0(); //定时计数器初始化函数
void Write(uchar, bit); //写指令/数据
void ShowData(uchar, bit, uchar); //显示字符函数
void ShowString(uchar, bit, uchar *); //显示字符串函数
void main()
{
//生命变量时分秒,并给每个变量赋予;一个十位和一个个位
uchar shi, fen, miao, ss, sg, fs, fg, ms, mg;
//开始执行前关闭数码管
Data = 0x0;
WEI = 1;
WEI = 0;
Data = 0xff;
DUAN = 1;
DUAN = 0;
//液晶屏显示信息
InitLCD();
InitTimer0();
ShowString(2, 0, "BeiJing Time");
while(1)
{
if(time == 20) //到了一秒钟
{
time = 0;
miao ++;
if(miao == 60)
{
miao = 0;
fen ++;
if(fen == 60)
{
fen = 0;
shi ++;
if(shi == 24)
shi = 0;
}
}
}
ss = shi / 10;
sg = shi % 10;
fs = fen / 10;
fg = fen % 10;
ms = miao / 10;
mg = miao % 10;
ShowData(4, 1, num[ss]);
ShowData(5, 1, num[sg]);
ShowData(6, 1, 0x3a); //冒号
ShowData(7, 1, num[fs]);
ShowData(8, 1, num[fg]);
ShowData(9, 1, 0x3a); //冒号
ShowData(0x0a, 1, num[ms]);
ShowData(0x0b, 1, num[mg]);
}
}
void Delay(uchar i)
{
uchar j;
for(; i > 0; i --)
for(j = 155; j > 0; j --); //最少延时1ms
}
void Busy()
{
Delay(5); //只有在不忙时才能进行检测
RS = 0; //根据规定,当RS = 0; RW = 1;读取指令
RW = 1;
E = 0; //在读取指令时,E要处于高脉冲,就是将E从0状态跳至1状态
_nop_();
_nop_(); //两个空操作给硬件一定的反应时间
E = 1;
while(BF); //忙时检测
_nop_();
_nop_(); //两个空操作给硬件一定的反应时间
E = 0; //当E从1状态跳至0状态时,开始执行指令
}
void Write(uchar msg, bit flag) //msg是要写入的指令/数据的相对位移,flag的值决定写入的是数据还是指令
{
Busy(); //只有在不忙时才能进行读写操作
RS = flag; //flag的值决定是对数据/指令操作
RW = 0; //RW = 0决定写数据/指令
E = 0; //在读取指令时,E要处于高脉冲,就是将E从0状态跳至1状态
_nop_();
_nop_(); //两个空操作给硬件一定的反应时间
E = 1;
_nop_();
_nop_(); //两个空操作给硬件一定的反应时间
Data = msg; //往数据端口写如数据
_nop_();
_nop_(); //两个空操作给硬件一定的反应时间
E = 0; //当E从1状态跳至0状态时,执行指令
}
void InitLCD()
{
Busy();
Delay(10); //首次操作给硬件较长的延时时间
Write(0x01, 0); //清平指令
Delay(5);
Write(0x06, 0); //【输入方式显示指令】光标从左向右移动,内容不移动
Delay(5);
Write(0x0c, 0); //【显示开关控制指令】显示开,光标不显示,字符不闪烁
Delay(5);
Write(0x38, 0); //【功能设置指令】8位数,双行显示,5*7点阵
Delay(5);
}
void InitTimer0()
{
time = 0;
TMOD = 0x01; //选择定时计数器的中断方式1
EA = 1; //打开总中断
ET0 = 1; //打开定时计数器0的中断
TR0 = 1; //打开定时计数器0开始计时
}
void timer0() interrupt 1
{
//每隔50ms计时一次
TH0 = (65536 - 50000) / 256;
TL0 = (65536 - 50000) % 256;
time ++;
}
void ShowData(uchar addr, bit flag, uchar msg) //addr表示相对位移,flag指定进行操作所在的行,msg表示要显示的信息
{
if(flag == 1) //表示显示在第二行
{
Write((addr | 0xc0), 0);
Write(msg, 1); //写如信息
}
else
{
Write((addr | 0x80), 0);
Write(msg, 1);
}
}
void ShowString(uchar addr, bit flag, uchar *ptr) //addr表示相对位移,flag指定进行操作所在的行,*ptr表示要显示的信息
{
if(flag == 1) //表示显示在第二行
{
while(*ptr)
{
Write((addr | 0xc0), 0);
Write(*ptr, 1);
ptr ++;
addr ++;
}
}
else //在第一行显示信息
{
while(*ptr)
{
Write((addr | 0x80), 0);
Write(*ptr, 1);
ptr ++;
addr ++;
}
}
}