课程设计
用89C51的P1口(位控)和一片8155的PA口(段控)作输出口控制六数码管显示(二个数码管显示“时”、二个数码管显示“分”、二个数码管显示“秒”),8155的PB口作输入口控制按键输入,做一台电子钟。
要求:8155的PA口地址:EF01H
用一个按键控制作时钟调整状态输入(按下一次进入时钟调整状态下的“时”调整,再按下一次进入“分”调整,再按下一次进入“秒”调整,再按下一次退出时钟调整状态),一个按键用于调整时钟(在时钟调整状态下有效)。在时钟调整状态下,正在调整的“时”或“分”或“秒”要进行闪烁显示指示。
电子时钟主要功能
1、显示时间,并准确计时;
2、可以进入调整状态,对时分秒进行调整加一操作;
3、对应调整状态的数码管闪烁显示;
4、附加功能:万年历(闰年判断)。
电子元件的选择
8位共阴极数码管,89C51芯片,8155芯片,RESPACK-8(排阻,网络电阻器),电阻,反相器,按钮,电容
proteus仿真图
可以标注引脚连接简化接线方式,本图并未使用简化接线方式。
下面展示一些代码,条理与逻辑思路比较清晰,简化了注释
#include<reg51.h>
#include<absacc.h>
#define uchar unsigned char
#define uint unsigned int
#define COM8155 XBYTE[0xef00]
#define PA8155 XBYTE[0xef01]
#define PB8155 XBYTE[0xef02]
uchar a[12]={
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x00};
uchar xs[8]={
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar b[8]={
0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
uint pn[12]={
31,28,31,30,31,30,31,31,30,31,30,31};
uint rn[12]={
31,29,31,30,31,30,31,31,30,31,30,31};
uchar SS=50,MM=59,HH=23,count,flash,count1;
uint Day=27,Month=2,Year=2000,*p;
bit flag=0;
void Delay(uint t) //延迟函数
{
while(t)
{
t--;
}
}
void Dispaly1(uchar SS,uchar MM,uchar HH) //时分秒显示函数
{
uint i;
xs[0]=SS%10;
xs[1]=SS/10;
xs[2]=10;
xs[3]=MM%10;
xs[4]=MM/10;
xs[5]=10;
xs[6]=HH%10;
xs[7]=HH/10;
if(flag==1)
{
if(flash==0)
xs[0]=xs[1]=11;
else if(flash==1)
xs[3]=xs[4]=11;
else if(flash==2)
xs[6]=xs[7]=11;
}
for(i=0;i<8;i++)
{
P1=b[7-i];
PA8155=a[xs[i]];
Delay(5);
P1=0xff;
Delay(5);
P1=0xff;
}
}
void Dispaly2(uint Day,uint Month,uint Year) //年月日显示函数
{
uint i;
xs[0]=Day%10;
xs[1]=Day/10;
xs[2]=Month%10;
xs[3]=Month/10;
xs[4]=Year%10;
xs[5]=(Year%100)/10;
xs[6]=(Year%1000)/100;
xs[7]=Year/1000;
if(flag==1)
{
if(flash==0)
xs[0]=xs[1]=11;
else if(flash==1)
xs[2]=xs[3]=11;
else if(flash==2)
xs[4]=xs[5]=xs[6]=xs[7]=11;
}
for(i=0;i<8;i++)
{
P1=b[7-i];
PA8155=a[xs[i]];
Delay(5);
P1=0xff;
}
}
void Keyscan1() //时钟调位和数值加一功能
{
static uchar j = 0;
if(PB8155==0X01) //进入调整状态
{
Delay(10000); //消抖
if(PB8155==0X01)
{
TR0=0; //关闭定时器0
TR1=1; //打开定时器1
while(PB8155==0X01)
{
}
j++; //进行状态调整按键次数计数
}
}
if(j==1) //调整秒状态
{
flash=0;
if(PB8155==0X02)
{
Delay(10);
if(PB8155==0X02)
{
while(PB8155==0X02)
{
}
SS++;
if(SS==60)
SS=0;
}
}
}
if(j==2) //调整分状态
{
flash=1;
if(PB8155==0X02)
{
Delay(10);
if(PB8155==0X02)
{
while(PB8155==0X02)
{
}
MM++;
if(MM==60)
MM=0;
}
}
}
if(j==3) //调整时状态
{
flash=2;
if(PB8155==0X02)
{
Delay(10);
if(PB8155==0X02)
{
while(PB8155==0X02)
{
}
HH++;
if(HH==24)
HH=0;
}
}
}
if(j==4) //退出调整状态
{
TR0=1; //打开定时器0
TR1=0;
j=0; //计数清零
}
}
void Keyscan2() //日期调位和数值加一功能
{
static uchar m = 0;
if(((Year%4==0)&&(Year%100!=0))||(Year%400==0)) //闰年判断
p=rn;
else
p=pn;
if(PB8155==0X01) //进入调整状态
{
Delay(10000); //消抖
if(PB8155==0X01)
{
TR0=0; //关闭定时器0
TR1=1; //打开定时器1
while(PB8155==0X01)
{
}
m++; //进行状态调整按键次数计数
}
}
if(m==1) //调整日状态
{
flash=0;
if(PB8155==0X02)
{
Delay(10);
if(PB8155==0X02)
{
while(PB8155==0X02)
{
}
Day++;
if(Day==p[Month-1]+1)
Day=1;
}
}
}
if(m==2) //调整月状态
{
flash=1;
if(PB8155==0X02)
{
Delay(10);
if(PB8155==0X02)
{
while(PB8155==0X02)
{
}
Month++;
if(Month==13)
Month=1;
}
}
}
if(m==3) //调整年状态
{
flash=2;
if(PB8155==0X02)
{
Delay(10);
if(PB8155==0X02)
{
while(PB8155==0X02)
{
}
Year++;
if(Year>9999)
Year=0;
}
}
}
if(m==4) //退出调整状态
{
TR0=1; //打开定时器0
TR1=0;
m=0; //计数清零
}
}
void main() //主函数
{
TMOD=0x01; //定时器以方式一工作
TH0=(65536-10000)/256;
TL0=(65536-10000)%256; //10ms计时
ET0=1; //允许定时器0中断
TR0=1; //打开定时器0
TMOD=0x01; //定时器以方式一工作
TH1=(65536-10000)/256;
TL1=(65536-10000)%256; //10ms计时
EA=1;
ET1=1; //允许定时器1中断
TR1=0; //关闭定时器1
COM8155=0x01;
while(1)
{
static uchar h=0;
if(PB8155==0X04) //时钟和日期切换
{
Delay(100);
if(PB8155==0X04)
while(PB8155==0X04);
h++;
}
if(h%2==0) //如果按键偶数次则显示时钟
{
Dispaly1(SS,MM,HH);
Keyscan1();
}
if(h%2==1) //如果按键偶数次则显示日期
{
Dispaly2(Day,Month,Year);
Keyscan2();
}
}
}
void time0_int(void) interrupt 1 //计时中断函数
{
TH0=(65536-10000)/256;
TL0=(65536-10000)%256;
count++;
if(((Year%4==0)&&(Year%100!=0))||(Year%400==0)) //闰年判断
p=rn;
else
p=pn;
if(count==100) //10ms
{
count=0;
SS++;
if(SS==60)
{
SS=0;
MM++;
}
if(MM==60)
{
MM=0;
HH++;
}
if(HH==24)
{
HH=0;
Day++;
}
if(Day==p[Month-1]+1)
{
Day=1;
Month++;
}
if(Month==13)
{
Month=1;
Year++;
}
}
}
void time1_int(void) interrupt 3 //闪烁中断函数
{
TH1=(65536-10000)/256;
TL1=(65536-10000)%256;
count1++;
if(count1%50==0) //500ms计时
flag=~flag;
}
效果图
日期显示效果,2000年为闰年2月有29天,达到预期效果
时间显示无任何问题
本次还有一问题没有解决,定时器1的定时效果一直达不到理想状态,希望有大佬能指正。感谢!