1. 程式人生 > >基於51微控制器的電子秒錶設計

基於51微控制器的電子秒錶設計

設計要求:

最多可記錄十組資料

可刪除其中多組資料

可上下查閱所記錄的資料

資料通過lcd1602顯示

計時精度到0.01s

由於並沒有使用24c02,導致程式去資料較大,模擬可能不行。實際驗證通過

程式介面如圖:


模擬介面如圖:


如果編譯出錯,將keil按如圖引數設定:


以下為程式程式碼:

包括兩個檔案,主程式裡面是:

#include<1602.h>
#include<reg52.h>




#ifndef uchar
#define uchar unsigned char
#endif


#ifndef uint 
#define uint unsigned int
#endif


/*按鍵定義*/
/*開始鍵,計數鍵,停止計數鍵或者清零鍵,上下查閱鍵,刪除資料鍵*/


sbit key_start=P1^0;
sbit key_count=P1^1;
sbit key_stop=P1^2;
sbit key_up=P1^3;
sbit key_down=P1^4;




/*變數定義*/
int count=0;//計數器


uint i,j,state,k=0,countnum,m,delete;


/*設定標誌位*/


char flag;
char maxflag;
char clearflag;
char turnflag; //
char upflag;  //為1時可以繼續上翻
char minflag=0; //為0時可以繼續下翻
char downflag; 


/*定義陣列 */
 unsigned char str[] = "time:";
 unsigned char str2[]= "num:";
 unsigned char str3[]="...press start..";
 unsigned char str4[]="....counting....";
 unsigned char str5[]=".. press count..";
 unsigned char str6[]="press up or down";
 unsigned char str7[]="..overcounting..";




 int number[10]=0;
 int num2[5]=0;


void keyscan();
void init();




void main()
{
   
    InitLcd1602();
    init();
/*以下為除錯程式段*/
   LcdShowStr(0,0,str3);
  //  LcdShowStr(0,1,str2);
//  LcdWriteCom(0x91);
//  LcdWriteData('0'+1);
//  LcdWriteCom(0x90);
//   LcdWriteData('0'+1);
/*以上為除錯程式段*/




    while(1)
{//LcdShowStr(0,1,str4);//測試
    keyscan();
Lcd1602_Delay1ms(50);
}


}
void init()
{
IT0=0;
EX0=0;
TMOD=0x01;
TH0=(65536-10000)/256; 
TL0=(65536-10000)%256;
EA=0; //開總中斷


//key_count=0;
//key_stop=0;
//key_up=0;
//key_down=0;
//key_delete=0;


flag=0; //標誌位為0時代表未計時狀態,為1時代表為計時狀態
i=0;
maxflag=0;//定時標誌位,為1時代表定時已滿
clearflag=0;//清除標誌位
turnflag=0;//為1時可以上下翻頁顯示
downflag=0;
upflag=1;
}
void keyscan()
{
if((key_start==0)&&(flag==0)) //防抖處理
{
Lcd1602_Delay1ms(10);//防抖處理
if((key_start==0)&&(flag==0))//防抖處理
{
while((!(key_start==0)&&(flag==0)));//防抖處理
InitLcd1602();
EA=1;//檢測到開始按鍵按下後,啟動定時器
ET0=1; //計時器0開啟
 TR0=1; //計時器開啟
flag=1;//設定標誌位為計時狀態
LcdShowStr(0,0,str4);
LcdShowStr(0,1,str5);
}
}
if((key_count==0)&&(flag==1)&&(maxflag==0))
{
       Lcd1602_Delay1ms(50);
if((key_count==0)&&(flag==1)&&(maxflag==0))
{

while(!((key_count==0)&&(flag==1)&&(maxflag==0)));

    InitLcd1602();
LcdShowStr(0,0,str);
    LcdShowStr(0,1,str2);
number[i]=count;
LcdWriteCom(0xC7);
        LcdWriteData('0'+i+1); 
LcdWriteCom(0xC6);
        LcdWriteData('0');
if(i==9)
{
LcdWriteCom(0xC7);
LcdWriteData('0'); 
LcdWriteCom(0xC6);
LcdWriteData('0'+1);
}




num2[0]=number[i]/10000;
num2[1]=number[i]/1000%10;
num2[2]=number[i]/100%10;
num2[3]=number[i]/10%10;
num2[4]=number[i]%10;

LcdWriteCom(0x86);
    LcdWriteData('0'+num2[0]);


LcdWriteCom(0x87);
    LcdWriteData('0'+num2[1]);


LcdWriteCom(0x88);
    LcdWriteData('0'+num2[2]);


LcdWriteCom(0x89);
    LcdWriteData('.');


 LcdWriteCom(0x8A);
    LcdWriteData('0'+num2[3]);


LcdWriteCom(0x8B);
    LcdWriteData('0'+num2[4]);


LcdWriteCom(0x8D);
    LcdWriteData('S');


i++;
state=i;


if(i==10)
{
maxflag=1;

}
}
}


if(key_stop==0)
{
Lcd1602_Delay1ms(50);

 if(key_stop==0)
{
while(!(key_stop==0));
if(clearflag==0)
{
TR0=0;  //關定時器,查閱時定時就停止
EX0=1;  //開外部中斷,保證只有在上下翻閱時才能觸發外部中斷
count=0;//計數清零
clearflag=1;//清除標誌位開啟,也就是說再按一下這個按鍵所有制清零
turnflag=1;
minflag=0;

}
else if(clearflag==1)//此塊執行清除任務
{

InitLcd1602();
number[10]=0;
clearflag=0;
LcdShowStr(0,0,str3);
turnflag=0;
maxflag=0;
flag=0;
i=0;//將陣列計數給清零
}
}
}





if(key_up==0)
{
Lcd1602_Delay1ms(50);
     if(key_up==0)
{
while(!(key_up==0));
if(upflag==0)
{
InitLcd1602();
LcdShowStr(0,0,str);
LcdShowStr(0,1,str2);
 minflag=0;//只要上翻過後都可以下翻
 state++;
if(state==10)
{
LcdWriteCom(0xC7);
LcdWriteData('0'); 
LcdWriteCom(0xC6);
LcdWriteData('0'+1);
}
else
{
LcdWriteCom(0xC7);
LcdWriteData('0'+state); 
LcdWriteCom(0xC6);
LcdWriteData('0');
}
m=state-1;
delete=m;
 
 /*顯示時間*/
num2[0]=number[m]/10000;
num2[1]=number[m]/1000%10;
num2[2]=number[m]/100%10;
num2[3]=number[m]/10%10;
num2[4]=number[m]%10;

LcdWriteCom(0x86);
LcdWriteData('0'+num2[0]);

LcdWriteCom(0x87);
LcdWriteData('0'+num2[1]);

LcdWriteCom(0x88);
LcdWriteData('0'+num2[2]);

LcdWriteCom(0x89);
LcdWriteData('.');

LcdWriteCom(0x8A);
LcdWriteData('0'+num2[3]);

LcdWriteCom(0x8B);
LcdWriteData('0'+num2[4]);

LcdWriteCom(0x8D);
LcdWriteData('S');
if(state==10)
{
upflag=1;
}
}
 
 
}

}


if(key_down==0)
{
 Lcd1602_Delay1ms(50);
 if(key_down==0)
{
while(!(key_down==0));
if((turnflag==1)&&(minflag==0))
{
InitLcd1602();
LcdShowStr(0,0,str);
LcdShowStr(0,1,str2);
/*顯示組號*/
state--;
LcdWriteCom(0xC7);
LcdWriteData('0'+state); 
LcdWriteCom(0xC6);
LcdWriteData('0');
k=state-1;
delete=k;


/*顯示時間*/
num2[0]=number[k]/10000;
num2[1]=number[k]/1000%10;
num2[2]=number[k]/100%10;
num2[3]=number[k]/10%10;
num2[4]=number[k]%10;

LcdWriteCom(0x86);
LcdWriteData('0'+num2[0]);

LcdWriteCom(0x87);
LcdWriteData('0'+num2[1]);

LcdWriteCom(0x88);
LcdWriteData('0'+num2[2]);

LcdWriteCom(0x89);
LcdWriteData('.');

LcdWriteCom(0x8A);
LcdWriteData('0'+num2[3]);

LcdWriteCom(0x8B);
LcdWriteData('0'+num2[4]);

LcdWriteCom(0x8D);
LcdWriteData('S');

if(state==1)
{
minflag=1;

}
upflag=0;

}
}
 }




}


void timer0() interrupt 1
{
TH0=(65536-10000)/256; 
TL0=(65536-10000)%256;
count++;
if(count==6000)
{
count=0; 
ET0=0; //計時器0關閉
TR0=0; //計時器關閉
turnflag=1;
EX0=1;
InitLcd1602();
LcdShowStr(0,0,str6);
LcdShowStr(0,1,str7);
}
}


void  counter0(void) interrupt 0  using 1
{
  number[delete]=0;
LcdWriteCom(0x86);
LcdWriteData('0');

LcdWriteCom(0x87);
LcdWriteData('0');

LcdWriteCom(0x88);
LcdWriteData('0');


LcdWriteCom(0x89);
LcdWriteData('.');


LcdWriteCom(0x8A);
LcdWriteData('0');


LcdWriteCom(0x8B);
LcdWriteData('0');


LcdWriteCom(0x8D);
LcdWriteData('S');

}

然後是lcd的驅動程式:



#include<1602.h>








void Read_Busy()           //忙檢測函式,判斷bit7是0,允許執行;1禁止
{
    unsigned char sta;      //
    LCD1602_DB = 0xff;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do
    {
        LCD1602_EN = 1;
        sta = LCD1602_DB;
        LCD1602_EN = 0;    //使能,用完就拉低,釋放匯流排
    }while(sta & 0x80);
}


void Lcd1602_Write_Cmd(unsigned char cmd)     //寫命令
{
    Read_Busy();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
    LCD1602_EN = 1;
    LCD1602_EN = 0;    
}


void Lcd1602_Write_Data(unsigned char dat)   //寫資料
{
      Read_Busy();
      LCD1602_RS = 1;
      LCD1602_RW = 0;
      LCD1602_DB = dat;
      LCD1602_EN = 1;
      LCD1602_EN = 0;
}


void LcdSetCursor(unsigned char x,unsigned char y)  //座標顯示
{
    unsigned char addr;
    if(y == 0)
        addr = 0x00 + x;
    else
        addr = 0x40 + x;
    
    Lcd1602_Write_Cmd(addr|0x80);
}




void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str)     //顯示字串
{
    LcdSetCursor(x,y);      //當前字元的座標
    while(*str != '\0')
    {
        Lcd1602_Write_Data(*str++);
    }
}


void InitLcd1602()              //1602初始化
{
    Lcd1602_Write_Cmd(0x38);    //開啟,5*8,8位資料
    Lcd1602_Write_Cmd(0x0c);
    Lcd1602_Write_Cmd(0x06);
    Lcd1602_Write_Cmd(0x01);    //清屏   
}


  
 void Lcd1602_Delay1ms(uint c)   //誤差 0us
{
    uchar a,b;
for (; c>0; c--)
{
for (b=199;b>0;b--)
{
 for(a=1;a>0;a--);
}      
}
   
}
/*******************************************************************************
* 函 數 名         : LcdWriteCom
* 函式功能  : 向LCD寫入一個位元組的命令
* 輸    入         : com
* 輸    出         : 無
*******************************************************************************/
#ifndef LCD1602_4PINS//當沒有定義這個LCD1602_4PINS時
void LcdWriteCom(uchar com) //寫入命令
{
LCD1602_EN = 0;     //使能
LCD1602_RS = 0;  //選擇傳送命令
LCD1602_RW = 0;  //選擇寫入

LCD1602_DB = com;     //放入命令
Lcd1602_Delay1ms(1);//等待資料穩定


LCD1602_EN = 1;         //寫入時序
Lcd1602_Delay1ms(5); //保持時間
LCD1602_EN = 0;
}
#else 
void LcdWriteCom(uchar com) //寫入命令
{
LCD1602_EN = 0;//使能清零
LCD1602_RS = 0;//選擇寫入命令
LCD1602_RW = 0;//選擇寫入


LCD1602_DB = com;//由於4位的接線是接到P0口的高四位,所以傳送高四位不用改
Lcd1602_Delay1ms(1);


LCD1602_EN = 1;//寫入時序
Lcd1602_Delay1ms(5);
LCD1602_EN = 0;


//Lcd1602_Delay1ms(1);
LCD1602_DB = com << 4; //傳送低四位
Lcd1602_Delay1ms(1);


LCD1602_EN = 1;//寫入時序
Lcd1602_Delay1ms(5);
LCD1602_EN = 0;
}
#endif


/*******************************************************************************
* 函 數 名         : LcdWriteData
* 函式功能  : 向LCD寫入一個位元組的資料
* 輸    入         : dat
* 輸    出         : 無
*******************************************************************************/  
#ifndef LCD1602_4PINS  
void LcdWriteData(uchar dat)//寫入資料
{
LCD1602_EN = 0;//使能清零
LCD1602_RS = 1;//選擇輸入資料
LCD1602_RW = 0;//選擇寫入


LCD1602_DB = dat; //寫入資料
Lcd1602_Delay1ms(1);


LCD1602_EN = 1;   //寫入時序
Lcd1602_Delay1ms(5);   //保持時間
LCD1602_EN = 0;
}
#else
void LcdWriteData(uchar dat)//寫入資料
{
LCD1602_EN = 0; //使能清零
LCD1602_RS = 1; //選擇寫入資料
LCD1602_RW = 0; //選擇寫入


LCD1602_DB = dat;//由於4位的接線是接到P0口的高四位,所以傳送高四位不用改
Lcd1602_Delay1ms(1);


LCD1602_EN = 1; //寫入時序
Lcd1602_Delay1ms(5);
LCD1602_EN = 0;


LCD1602_DB = dat << 4; //寫入低四位
Lcd1602_Delay1ms(1);


LCD1602_EN = 1; //寫入時序
Lcd1602_Delay1ms(5);
LCD1602_EN = 0;
}
#endif

還有一個1602.h檔案:

#include<reg52.h>


#ifndef uchar
#define uchar unsigned char
#endif


#ifndef uint 
#define uint unsigned int
#endif


#define LCD1602_DB  P0    




sbit LCD1602_RS = P2^6;
sbit LCD1602_RW = P2^5;
sbit LCD1602_EN = P2^7;




void InitLcd1602();//初始化lcd1602


void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str);//寫入一個字串


void LcdWriteData(uchar dat1);//寫入一個單個字
void LcdWriteCom(uchar com);//寫入地址
void Lcd1602_Delay1ms(uint c);
void InitLcd1602();

實際效果如圖: