課程設計
用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的定時效果一直達不到理想狀態,希望有大佬能指正,感謝!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/82126.html
標籤:其他
