基於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();
實際效果如圖: