日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

C51单片机实现数字秒表计时(分段计时,LCD1602显示,总计时),误差精度在1s之内

發布時間:2023/12/1 综合教程 43 生活家
生活随笔 收集整理的這篇文章主要介紹了 C51单片机实现数字秒表计时(分段计时,LCD1602显示,总计时),误差精度在1s之内 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、設計題目:數字秒表設計

二、課程設計內容及要求

????????基本要求:

????????1.按鍵2個,一個用于計時開始/停止,一個用于數字清零

????????2.數碼管顯示,數碼管初始顯示00-00-00(分-秒-毫秒)

????????3.基本功能,按計時開始/停止鍵,數碼管從當前計時數字累加,精度為10ms,計時10分鐘誤差補超過2秒,再按計時開始/停止鍵,數碼管停止計時,按數字清零鍵,數碼管恢復初始顯示,重? 新計時

????????擴展功能:

????????1.顯示更換為1602液晶屏顯示

????????2.實現分段計時和總計時兩個模式

此次設計實現了基本功能和拓展功能。

三、明確用戶需求,根據設計需求繪制原理圖(K4鍵可刪掉):

原理圖

四、代碼解析

第一步:根據原理圖定義引腳信息,及相關控制位、標志位、以及需要用到的延時函數

//定義引腳
sbit LCD_RS = P1^0;   
sbit LCD_RW = P1^1;
sbit LCD_E = P2^5;sbit K1 = P3^6;    //定時開始、暫停鍵
sbit K2 = P3^7;    //定時清零鍵
sbit K3 = P3^4;    //顯示分段計時鍵
uint keyCount = 0;    //按鍵次數標志
uint flag1 = 0;       //計時時的時間是否顯示
uint time[] = {0x00,0x00,0x00,0x00,0x00,0x00};    //用來存放計時所產生的時間
uint temp[] = {0x00,0x00,0x00,0x00,0x00,0x00};    //用于計算、并time數組時間的時、分、秒
uchar msg[] = {"     round"};    //提示界面
uchar wname[] = {"welcome"};     //友好界面uchar all_time[4][6];            //存放分段計時所產生的時間uint flag = -1;        //作為向all_time數組保存時間的數組下標
//延時函數delay_nops()
void delay_nops(){_nop_();_nop_();_nop_();_nop_();
}
//延時函數Delay(uint num)
void Delay(uint num)
{while( --num );
}
//延時函數delay1(int ms)
void delay1(int ms)
{unsigned char n;while(ms--){for(n = 0; n<250; n++){_nop_();_nop_();_nop_();_nop_();}}
}

第二步:LCD1602顯示部分

//在對LCD1602進行寫操作(包括寫命令和寫數據)的時候(讀操作不需要),需要檢查“忙”標志位,不“忙”即可寫入
int LCD_BUSY(){bit isBusy;LCD_RS = 0;    //設置RS為命令寄存器LCD_RW = 1;    //設置RW為讀操作,讀busy位LCD_E = 1;     //設置E(使能端)為1,進行讀操作delay_nops();    //延時isBusy = (bit)(P0&0X80);    //根據原理圖引腳信息及LCD1602文檔,busy位對應P1^7口,從P1^7讀出端口的狀態LCD_E = 0;     //恢復使能標志return  isBusy;    //返回busy位狀態信息
}
//LCD1602 寫命令操作
void LCD_WCMD(uchar cmd){while(LCD_BUSY());    //對LCD1602進行寫操作前,要檢查“忙”標志位,不“忙”即可繼續寫操作LCD_RS = 0;           //設置RS為命令寄存器LCD_RW = 0;           //設置RW為寫操作LCD_E = 0;            //設置使能E為低電平,后續給予高電平,即形成一個正脈沖,完成寫操作_nop_();              //延時一個空操作時間,保證引腳初始狀態正確賦值_nop_();              //延時一個空操作時間,保證引腳初始狀態正確賦值P0 = cmd;             //向P0口寫入命令,16進制delay_nops();         //延時若干個空操作LCD_E = 1;            //給予E高電平,形成正脈沖,完成寫操作delay_nops();         //延時若干個空操作,保證命令正確寫入   LCD_E = 0;            //恢復使能E為低電平Delay(10);            //延時
}
//LCD1602 寫數據操作,與LCD1602寫命令操作類似,但又有不同之處,不同之處在下面代碼中標出
void LCD_WDATA(uchar dat){while(LCD_BUSY());    LCD_RS = 1;    //將RS設置為數據寄存器LCD_RW = 0;LCD_E = 0;P0 = dat;      //向P0口寫入數據delay_nops();LCD_E = 1;delay_nops();LCD_E = 0;Delay(5);
}
//設置LCD1602 的顯示位置,以標準 0x80+RAM 地址方式寫入命令,具體LCD1602RAM地址映射圖如下
void LCD_POS(uchar pos){LCD_WCMD(pos | 0x80);    //根據下面RAM地址映射圖,舉例,例如:LCD_WCMD(0x00 | 0x80);即顯示在LCD1602的第一行,從第一個單元開始顯示、LCD_WCMD(0x40 | 0x80);即顯示在LCD1602的第二行,從第一個單元開始顯示
}

????????LCD1602 RAM地址映射圖:

?

//配置完LCD1602引腳和端口信息,以及LCD1602相關函數后,根據LCD1602使用手冊進行LCD1602的初始化
void LCD_INIT(){LCD_RW = 0;         //設置LCD1602中RS為命令寄存器delay1(15);         //延時LCD_WCMD(0x01);     //寫入命令,清屏,清除LCD的顯示內容LCD_WCMD(0x38);     //16*2顯示,5*7點陣,8位數據delay1(5);          //延時,保證正確寫入,下方延時函數功能皆是如此LCD_WCMD(0x38);     //重復寫入,保證正確寫入delay1(5);LCD_WCMD(0x38);    delay1(5);LCD_WCMD(0x38);delay1(5);LCD_WCMD(0x0c);     //開顯示,不顯示光標     delay1(5);LCD_WCMD(0x01);     //清除LCD的顯示內容delay1(5);
}
//LCD1602 顯示部分
void display(){uchar i;for(i = 0;i<6;i++){temp[i] = time[i] + 0x30;    //這里是把time數組(定時器T0計時產生的時間),進行賦值給temp數組,便于后期進行時、分、秒拆分顯示}LCD_POS(0x45);    //設置LCD1602上顯示為第二行第6個單元開始,具體請看上面提到的RAM地址映射圖LCD_WDATA(temp[5]);    //顯示定時器T0產生的 分(十位)LCD_WDATA(temp[4]);    //顯示定時器T0產生的 分(個位)LCD_WDATA(0x3a);       //顯示“:”LCD_WDATA(temp[3]);    //顯示定時器T0產生的 秒(十位)LCD_WDATA(temp[2]);    //顯示定時器T0產生的 秒(個位)LCD_WDATA(0x3a);       //顯示“:”LCD_WDATA(temp[1]);    //顯示定時器T0產生的 0.1sLCD_WDATA(temp[0]);    //顯示定時器T0產生的 0.01s}

第三步:主函數部分

int main(){uchar i;TMOD = 0X01;    //選擇T0工作方式1TH0 = 0XDC;    //10ms觸發一次中斷TL0 = 0X00;    //10ms觸發一次中斷EA = 1;        //開啟中斷總開關ET0 = 1;        //開啟定時中斷T0LCD_INIT();    //LCD1602初始化LCD_POS(0X00);    //設置LCD1602 顯示位置為第一行第一個單元for(i = 0;i<7;i++){LCD_WDATA(wname[i]);    //友好界面}delay1(100);while(1){if(K1 == 0){    //判斷按鍵K1是否按下,按下則進行計時,或者暫停(根據keyCount判斷)keyCount++;    delay1(100);switch(keyCount){case 1:TR0 = 1;    //打開定時器T0,開始LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X31);    //顯示這是第幾輪計時break;case 2:TR0 = 0;    //關閉定時器T0,暫停flag++;saveTime();    //在暫停的時候進行時間保存,即達到分段計時的效果break;case 3:TR0 = 1;    //打開定時器T0,開始LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X32);break;case 4:TR0 = 0;    //關閉定時器T0,暫停flag++; saveTime();break;case 5:TR0 = 1;    //打開定時器T0,開始LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X33);break;case 6:TR0 = 0;    //關閉定時器T0,暫停flag++;saveTime();break;case 7:TR0 = 1;LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X34);break;case 8:TR0 = 0;flag++;saveTime();break;default:TR0 = 0;flag = -1;    break;}delay1(10);}if(K2==0){    //定時時間清零鍵TR0=0;keyCount = 0;flag=3;delay1(10);flag=3;delay1(10);flag=3;delay1(10);for(i=0;i<6;i++){    //對在中斷處理函數中保存在time中的時間進行清零time[i] = 0;}}if(K3==0){    //顯示分段計時,所存儲的時間段TR0 = 0;flag1 = 1;display1(flag);    //顯示分段時間段flag1 = 0;    //顯示完自動隱式退出delay1(10);     }  if(flag1==0){      // 當flag1==0,即自動退出“顯示分段計時”后,顯示計時頁面display();    //顯示計時頁面} }
}

????????定時中斷處理函數:

//定時器T0的中斷處理函數,time數組用來保存定時器T0計時所產生的時間void timer0() interrupt 1{TH0 = 0XDC;    //重新裝入初值TL0 = 0X00;time[0]++;   //保存0.01sif(time[0]==10){  time[1]++;  //保存0.1stime[0] = 0;}if(time[1]==10){  time[2]++;   //保存1stime[1] = 0;}if(time[2]==10){  time[3]++;  //保存10stime[2] = 0;}if(time[3]==6){   time[4]++;  //保存1mintime[3] = 0;}if(time[4]==10){  time[5]++;   //保存10mintime[4] = 0;}if(time[5]==6){time[5] = 0;}
}

? ? ? LCD1602 顯示時間函數(循環顯示):

//LCD1602 顯示函數 時分秒函數
void display1(uint m){uchar i;uint t = 0x31;for(i = 0;i<=m;i++){LCD_WCMD(0X01);LCD_POS(0X00);LCD_WDATA(0X3C);LCD_WDATA(t++);LCD_WDATA(0X3E);LCD_POS(0x45);LCD_WDATA(all_time[i][5] + 0x30);LCD_WDATA(all_time[i][4] + 0x30);LCD_WDATA(0x3a);LCD_WDATA(all_time[i][3] + 0x30);LCD_WDATA(all_time[i][2] + 0x30);LCD_WDATA(0x3a);LCD_WDATA(all_time[i][1] + 0x30);LCD_WDATA(all_time[i][0] + 0x30);delay1(500);}}

? ? ? 在main函數中調用的保存分段時間函數:

//保存時間段
void saveTime(){uchar j = 0;if(flag != -1){for(j = 0;j<6;j++){all_time[flag][j] = time[j];    //保存每次暫停所產生的時間段,即分段計時功能}}
}

? ? ? ? 在main函數中調用的顯示分段時間的函數:

//顯示分段計時存儲的時間信息,類似前面的display()函數
void display1(uint m){uchar i;uint t = 0x31;for(i = 0;i<=m;i++){LCD_WCMD(0X01);    LCD_POS(0X00);LCD_WDATA(0X3C);LCD_WDATA(t++);LCD_WDATA(0X3E);LCD_POS(0x45);LCD_WDATA(all_time[i][5] + 0x30);    //這里加上0x30是根據單片機系統自帶字符庫編碼方式LCD_WDATA(all_time[i][4] + 0x30);LCD_WDATA(0x3a);LCD_WDATA(all_time[i][3] + 0x30);LCD_WDATA(all_time[i][2] + 0x30);LCD_WDATA(0x3a);LCD_WDATA(all_time[i][1] + 0x30);LCD_WDATA(all_time[i][0] + 0x30);delay1(500);}}

第四步:實物連接

?

完整代碼:

#include<reg51.h>
#include<intrins.h>#define uchar unsigned char
#define uint  unsigned intsbit LCD_RS = P1^0;
sbit LCD_RW = P1^1;
sbit LCD_E = P2^5;sbit K1 = P3^6;
sbit K2 = P3^7;
sbit K3 = P3^4;
uint keyCount = 0;
uint flag1 = 0;
uint time[] = {0x00,0x00,0x00,0x00,0x00,0x00};
uint temp[] = {0x00,0x00,0x00,0x00,0x00,0x00};
uchar msg[] = {"     "};
uchar wname[] = {"welcome"};uchar all_time[4][6];uint flag = -1;
void delay_nops(){_nop_();_nop_();_nop_();_nop_();
}
void Delay(uint num)
{while( --num );
}
void delay1(int ms)
{unsigned char n;while(ms--){for(n = 0; n<250; n++){_nop_();_nop_();_nop_();_nop_();}}
}
int LCD_BUSY(){bit isBusy;LCD_RS = 0;LCD_RW = 1;LCD_E = 1;delay_nops();isBusy = (bit)(P0&0X80);LCD_E = 0;return  isBusy;
}
void LCD_WCMD(uchar cmd){while(LCD_BUSY());LCD_RS = 0;LCD_RW = 0;LCD_E = 0;_nop_();_nop_();P0 = cmd;delay_nops();LCD_E = 1;delay_nops();LCD_E = 0;Delay(10);
}
void LCD_WDATA(uchar dat){while(LCD_BUSY());LCD_RS = 1;LCD_RW = 0;LCD_E = 0;P0 = dat;delay_nops();LCD_E = 1;delay_nops();LCD_E = 0;Delay(5);
}void LCD_INIT(){LCD_RW = 0;delay1(15); LCD_WCMD(0x01);LCD_WCMD(0x38);delay1(5);LCD_WCMD(0x38);delay1(5);LCD_WCMD(0x38);delay1(5);LCD_WCMD(0x38);delay1(5);LCD_WCMD(0x0c);delay1(5);LCD_WCMD(0x01);delay1(5);
}
void LCD_POS(uchar pos){LCD_WCMD(pos | 0x80);
}
void display(){uchar i;for(i = 0;i<6;i++){temp[i] = time[i] + 0x30;}LCD_POS(0x45);LCD_WDATA(temp[5]);LCD_WDATA(temp[4]);LCD_WDATA(0x3a);LCD_WDATA(temp[3]);LCD_WDATA(temp[2]);LCD_WDATA(0x3a);LCD_WDATA(temp[1]);LCD_WDATA(temp[0]);}
void saveTime(){uchar j = 0;if(flag != -1){for(j = 0;j<6;j++){all_time[flag][j] = time[j];}}
}
void display1(uint m){uchar i;uint t = 0x31;for(i = 0;i<=m;i++){LCD_WCMD(0X01);LCD_POS(0X00);LCD_WDATA(0X3C);LCD_WDATA(t++);LCD_WDATA(0X3E);LCD_POS(0x45);LCD_WDATA(all_time[i][5] + 0x30);LCD_WDATA(all_time[i][4] + 0x30);LCD_WDATA(0x3a);LCD_WDATA(all_time[i][3] + 0x30);LCD_WDATA(all_time[i][2] + 0x30);LCD_WDATA(0x3a);LCD_WDATA(all_time[i][1] + 0x30);LCD_WDATA(all_time[i][0] + 0x30);delay1(500);}}
int main(){uchar i;TMOD = 0X01;TH0 = 0XDC;TL0 = 0X00;EA = 1;ET0 = 1;LCD_INIT();LCD_POS(0X00);P3 = 0XC0 | P3;LCD_POS(0X00);for(i = 0;i<7;i++){LCD_WDATA(wname[i]);}delay1(100);while(1){if(K1 == 0){keyCount++;delay1(100);switch(keyCount){case 1:TR0 = 1;LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X31);break;case 2:TR0 = 0;flag++;saveTime();break;case 3:TR0 = 1;LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X32);break;case 4:TR0 = 0;flag++; saveTime();break;case 5:TR0 = 1;LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X33);break;case 6:TR0 = 0;flag++;saveTime();break;case 7:TR0 = 1;LCD_POS(0x00);for(i = 0;i<10;i++){LCD_WDATA(msg[i]);}LCD_WDATA(0X34);break;case 8:TR0 = 0;flag++;saveTime();break;default:TR0 = 0;flag = -1;break;}delay1(10);}if(K2==0){TR0=0;keyCount = 0;flag=3;delay1(10);flag=3;delay1(10);flag=3;delay1(10);for(i=0;i<6;i++){time[i] = 0;}}if(K3==0){TR0 = 0;flag1 = 1;display1(flag);flag1 = 0;delay1(10);     }  if(flag1==0){display();} }
}
void timer0() interrupt 1{TH0 = 0XDC;TL0 = 0X00;time[0]++;   //0.01sif(time[0]==10){  time[1]++;  //0.1stime[0] = 0;}if(time[1]==10){  time[2]++;   //1stime[1] = 0;}if(time[2]==10){  time[3]++;  //10stime[2] = 0;}if(time[3]==6){   time[4]++;  //1mintime[3] = 0;}if(time[4]==10){  time[5]++;   //10mintime[4] = 0;}if(time[5]==6){time[5] = 0;}
}

總結

以上是生活随笔為你收集整理的C51单片机实现数字秒表计时(分段计时,LCD1602显示,总计时),误差精度在1s之内的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。