主控制函數(shù)包括初始化各個功能模塊,車程數(shù)據(jù)的保存與恢復(fù),將車程車速實(shí)時顯示。其中初始化包括系統(tǒng)初始化、定時器和外部中斷初始化、LCD初始化。主控制程序工作流程圖如圖4-1。中斷工作可依據(jù)中斷位置分為外部中斷0和定時器中斷0。外部中斷0程序分別對里程計數(shù)和速度計數(shù)。定時器0中斷程序任務(wù)是對計數(shù)器裝入初值;時間每隔1s將速度計數(shù)值進(jìn)行累加并對時間和速度計數(shù)清0。流程如4-2,4-3所示。 
圖4-1 控制函數(shù)流程圖 圖4-2 外部中斷流程圖 圖4-3 定時器中斷流程圖 4.2 系統(tǒng)的初始化系統(tǒng)初始化包含主控制函數(shù)初始化工作、LCD初始化、中斷定時器初始化。主函數(shù)初始化需要定義主函數(shù)中使用的變量。LCD初始化任務(wù)是設(shè)定LCD工作方式,具體流程圖如圖4-4所示。中斷與定時器初始化是調(diào)整中斷與定時器工作方式如圖4-5所示。  圖4-4 LCD初始化流程圖 圖4-5 中斷與定時器初始化流程圖 4.3 車程車速數(shù)據(jù)的實(shí)時顯示4.3.1 車程車速數(shù)據(jù)的獲得與計算公式車輪一周安裝8個擋板,均勻分布在車輪上,車輪在轉(zhuǎn)動過程中,會使紅外線接收管在通斷狀態(tài)進(jìn)行變換。每變換一次紅外線電路輸出端都會進(jìn)行高低電平的轉(zhuǎn)換,形成一次跳變沿。跳變沿可觸發(fā)單片機(jī)外部中斷,執(zhí)行中斷程序時對跳變沿進(jìn)行計數(shù)。為了程序的簡單化(因?yàn)橛糜谒俣扔嫈?shù)的變量要不斷進(jìn)行清零)。可設(shè)置兩個變量分別計數(shù),一個用于計算速度,一個用于計算里程。速度度計數(shù)值設(shè)為speedsum,里程計數(shù)值設(shè)為milesum。設(shè)速度為V單位km/h,車程為S單位為km,車輪周長為L單位為cm,計時時間為T單位為s。 速度的計算公式為: V=L/8*speedsum/T*3600/100000 (km/h) (4-1) 里程計算公式為: S=milesum*L/8/100000 (km) (4-2) 同時要完成液晶上顯示詳細(xì)變量數(shù)據(jù),務(wù)必把變量各位上的數(shù)字分離出來。根據(jù)設(shè)計任務(wù),速度與里程需要精確到小數(shù)點(diǎn)后一位。具體方法如下:將變量乘10賦值給t,按下面公式計算便可得各位上的數(shù)字(其它以此類推) qwei=t/1000000%10; bwei=t/100000%10; swei=t/10000%10; gwei= t/1000%10; hpoint=t/100%10; 4.3.2 設(shè)定字符在液晶上的顯示位置12864液晶可以顯示四行,但行與行間的地址并不是連續(xù)的,所以將設(shè)定顯示位置寫成函數(shù)形式,以方便調(diào)用,防止出錯。液晶顯示設(shè)計流程圖如圖4-6所示。 設(shè)要設(shè)定的行數(shù)為X,X值從0到3。列數(shù)為Y,Y值從0到7。 
圖4-6 字符在液晶顯示位置控制流程圖 4.3.3 車程車速數(shù)據(jù)的顯示數(shù)據(jù)顯示要實(shí)現(xiàn)將速度和里程顯示出來。具體是,第一行居中顯示“天天如意”,第二行依次顯示“速度:  km/h”字符和實(shí)時速度。第三行依次顯示“里程:  km”字符和實(shí)時里程。根據(jù)12864液晶的特性,固定字符顯示在固定位置不需要重復(fù)傳送數(shù)據(jù),對于變量速度和里程需要不停的傳送數(shù)據(jù)。因此可將顯示部分兩部分來寫。一部分顯示固定的字符,另一部分顯示變量。要將變量顯示在液晶上,需要將其各位上的數(shù)分離出來,然后分別顯示。這里如果高位為0時,不能顯示。本設(shè)計需要將速度和里程兩具變量顯示在液晶上,顯示這兩變量原理相同,這里只寫出其中一個的流程圖。流程圖如圖4-7。設(shè)要顯示的位數(shù)為3位,需要更高位顯示功能則以此類推。 
圖4-7 液晶顯示車速數(shù)據(jù)位數(shù)控制流程圖 4.4車程車速數(shù)據(jù)的保存與恢復(fù) 根據(jù)設(shè)計任務(wù)要求,需對里程數(shù)據(jù)完成斷電保護(hù)工作預(yù)防特殊情況下重要數(shù)據(jù)斷電不遺失,上電時能及時恢復(fù)。本系統(tǒng)采用單片機(jī)EEPROM完成數(shù)據(jù)掉電保護(hù)工作。基于程序?qū)?shù)據(jù)備份到單片機(jī)EEPROM內(nèi)存儲,上電時可及時完成恢復(fù)工作。 4.4.1對單片機(jī)EEPROM的基本操作流程圖單片機(jī)EEPROM讀寫刪三個操作。三個操作的工作流程示意圖對應(yīng)如圖4-8~4-10所示。 
圖4-8 讀流程圖 圖4-9 寫流程圖 圖4-10 刪流程圖 4.4.2里程數(shù)據(jù)的保存與恢復(fù)里程speedsum為32位long型數(shù)據(jù),而STC89C52單片機(jī)只能進(jìn)行字節(jié)讀,字節(jié)寫,扇區(qū)擦除。要想保存speedsum信息數(shù)據(jù),移動把speedsum分解成字節(jié)型信息數(shù)據(jù)。設(shè)4個unsigned char型變量a1~a4分別用于保存speedsum低8位,次低8位,次高8位,高8位。在C語言中Long型信息數(shù)據(jù)賦值給char型信息數(shù)據(jù)只把最低8位賦值給char信息數(shù)據(jù)。將speedsum直接賦值給a1,可得低8位,再將speedsum分別移位8位,16位,24位分別賦值給a2~a4,就可成功分speedsum。然后,再分別保存a1~a4,便可間接保存speedsum。 當(dāng)系統(tǒng)上電時恢復(fù)speedsum,取出a1~a4,分別移位相加便可得到speedsum。具體方法如下:取出a1~a4,強(qiáng)制類型轉(zhuǎn)成到long型,再分別按位左移0位,8位,16位,24位,然后再相加賦給speedsum便可恢復(fù)。 具體程序設(shè)計流程圖如4-11和4-12所示: 
圖4-11數(shù)據(jù)恢復(fù)流程圖 圖4-12 信息數(shù)據(jù)保存流程圖
5系統(tǒng)調(diào)試根據(jù)硬件設(shè)計原理圖完成硬件焊制工作并組裝,組裝后利用Keil軟件將寫好的程序存儲到單片機(jī)內(nèi)部。依據(jù)實(shí)際任務(wù)需求,完成車程車速實(shí)時顯示及為驗(yàn)證車輛車速行駛檢測的準(zhǔn)確性;谌缦滦问綑z測車程車速的誤差大小及準(zhǔn)確度。單片機(jī)計算車程速度主要是基于對P3.2端口電平信號跳變沿累計求和計數(shù),基于內(nèi)部時鐘頻率計時累計而獲取。單片機(jī)完成跳變沿計數(shù)具體值可以基于調(diào)整單片機(jī)內(nèi)部相關(guān)程序呈現(xiàn)數(shù)據(jù)于液晶。測試也可基于人工計數(shù),但需保證單片機(jī)計數(shù)具體值與實(shí)際值一直就能達(dá)到車速數(shù)據(jù)測量的準(zhǔn)確性及精度。具體檢測數(shù)據(jù)結(jié)果記錄詳情如表5-1所示。 表5-1 跳變沿計數(shù) 
系統(tǒng)經(jīng)過調(diào)試后的得到液晶顯示圖和實(shí)物結(jié)果圖如5-1和5-2所示 
圖5-1 液晶顯示車速結(jié)果圖 
圖5-2 系統(tǒng)整體實(shí)物結(jié)果圖
6 總結(jié)伴隨目前車輛控制技術(shù)和軌道交通工具的飛速發(fā)展,在全球各國家,不管重要的交通運(yùn)輸業(yè)還是用戶個體,車輛是長距離運(yùn)輸?shù)牟豢扇鄙俚闹匾煌üぞ咧弧.?dāng)面對汽車等駕駛員長時間高速行駛車輛時,容易造成疲勞而造成速度控制不到位的狀況,及在限速路段總頻頻發(fā)生超速現(xiàn)象,對自己和其他人們均都造成重大安全隱患。本文設(shè)計就是基于解決這一問題的分枝做的主要工作成果如下: 系統(tǒng)基于紅外線收發(fā)工作原理完成了信息數(shù)據(jù)采集工作,依據(jù)紅外線接收管判定了是否出現(xiàn)紅外線照射,從而形成通斷電路,進(jìn)而產(chǎn)生了高低電壓數(shù)據(jù)以生成電信號。利用了核心控制模塊基于STC89C52單片進(jìn)行完成信號數(shù)據(jù)處理,將數(shù)據(jù)處理值通過液晶顯示器完成了顯示。說明了系統(tǒng)的整體布局設(shè)計方案和整體規(guī)劃流程,闡述了硬件和軟件設(shè)計核心工作原理,最終對系統(tǒng)整體及實(shí)物進(jìn)行軟硬件功能的調(diào)試和運(yùn)行測試,證實(shí)系統(tǒng)設(shè)計符合實(shí)際標(biāo)準(zhǔn)且可行。
- #include<reg52.h>
- #include<intrins.h>
- #define uchar unsigned char
- #define RdCommand 0x01 //定義ISP的操作命令
- #define PrgCommand 0x02
- #define EraseCommand 0x03
- #define WaitTime 0x01 //定義CPU的等待時間
-
- sfr ISP_DATA=0xe2; //寄存器申明
- sfr ISP_ADDRH=0xe3;
- sfr ISP_ADDRL=0xe4;
- sfr ISP_CMD=0xe5;
- sfr ISP_TRIG=0xe6;
- sfr ISP_CONTR=0xe7;
-
- sbit rs=P2^4;
- sbit rw=P2^5;
- sbit e=P2^6;
- sbit psb=P2^1;
-
- uchar code table1[]={" 天天如意"};
- uchar code table2[]={"速度: km/h"};
- uchar code table3[]={"里程: km"};
- uchar code table4[]={" --石頭"};
-
- /**********************************/
- void delay(int k); //延遲ms
- void writecmd(uchar cmd); //lcd寫命令
- void writedata(uchar dat); //lcd寫數(shù)據(jù)
- void init(); //初始化lcd工作方式
- void setadd(uchar x,uchar y); //設(shè)定lcd顯示地址
- void display(); //lcd顯示
- void ISP_IAP_enable(void); //ISP_EN=1
- void ISP_IAP_disable(void); //ISP_EN=0
- void ISP_TRIGER(void); //激活I(lǐng)SP_CMD
- unsigned char byte_read(unsigned int byte_addr);//讀字節(jié)
- void SectorErase(unsigned int sector_addr);//刪除扇區(qū)
- void byte_write(unsigned int byte_addr, uchar original_data);//寫字節(jié)
-
- /**********************************/
- uchar num,num1;
- long speedsum=0; //外部中斷計數(shù)
- int timnum=0,k,i,able=0; //定時器中斷計數(shù)
- unsigned long milesum=0; //總里程計數(shù),浮點(diǎn)型
- int shifen,baifen,ge,shi,bai,qian,wan,milshifen,milge,milshi;
- int milbai,milqian,milwan,milshiwan; //display中的參數(shù);
- unsigned long t,y,s; //中間數(shù)據(jù),t為每小時走的距離(m) y為計算里程的中間數(shù)字
-
- /**********************************/
- main()
- {
- uchar a1~a4; //分別為milesum的第1,2,3,4個8位
- TMOD=0x01; //定時器0工作方式16位
- TH0=(65536-46080)/256; //高8位初值
- TL0=(65536-46080)%256; //低八位初值 晶振12Mhz時 計滿一次為1us
- EA=1; /*開總中斷*/
- EX0=1; /*開外部中斷0*/
- IT0=1; /*外部中斷0為跳變沿觸發(fā)*/
- TR0=1; //啟動定時器0
- ET0=1; //開外部中斷0
- PT0=1; //定時器0置為高優(yōu)先級
-
- EA=0;
- a1=byte_read(0x2000); //讀資料a1
- a2=byte_read(0x2001); //讀資料a2
- a3=byte_read(0x2200); //讀資料a3
- a4=byte_read(0x2201); //讀資料a4
- EA=1;
- milesum=(unsigned long)(a1+((long)a2<<8)+((long)a3<<16)+((long)a4<<24));
- //恢復(fù)milesum值
- if(milesum>4800000000)
- milesum=0;
- init();
- setadd(1,0);//設(shè)置顯示位置
- i=0;
- while(table1[i]!='\0')
- {
- writedata(table1[i]);
- i++;
- }
- i=0;
- setadd(2,0);//設(shè)置顯示位置
- while(table2[i]!='\0')
- {
- writedata(table2[i]);
- i++;
- }
- i=0;
- setadd(3,0);//設(shè)置顯示位置
- while(table3[i]!='\0')
- {
- writedata(table3[i]);
- i++;
- }
-
- i=0;
- setadd(4,0);//設(shè)置顯示位置
- while(table4[i]!='\0')
- {
- writedata(table4[i]);
- i++;
- }
- while(1)
- {
- a1=milesum&0x000000ff; //將第個八位取出
- a2=milesum>>8; //將第個八位取出
- a3=milesum>>16; //將第個八位取出
- a4=milesum>>24;
- if(num>=20) //將第個八位取出
- {
- num=0;
- SectorErase(0x2000);//擦除扇區(qū)
- byte_write(0x2000,a1);//重新寫入數(shù)據(jù)
- byte_write(0x2001,a2);//重新寫入數(shù)據(jù)
- SectorErase(0x22200);//擦除扇區(qū)
- byte_write(0x2200,a3);//重新寫入數(shù)據(jù)
- byte_write(0x2201,a4);//重新寫入數(shù)據(jù)
- }
- //if(able==1)
- display();
- }
- }
-
- /***************外部中斷程序*******************/
- void exter0() interrupt 0
- {
- speedsum++; //外部中斷
- milesum++; //總里程計
- }
-
- /****************定時器0中斷程序******************/
- void T0_time() interrupt 1
- {
- TR0=0; //關(guān)閉定時器0
- TH0=(65536-46080)/256; //高8位初值
- TL0=(65536-46080)%256; //低八位初值 晶振12Mhz時 計滿一次為50ms
- timnum++;
- num++ ; //計時器計數(shù)
- if(timnum>=20) //如果到1s時
- {
- s=speedsum;
- timnum=0;
- speedsum=0;
- able=1;
- }
- else
- able=0;
-
- TR0=1;//啟動定時器0
- }
-
- /**************顯示速度,里程********************/
- void display()
- {
- //顯示速度
- t=s*2.08*3600/100; //t為每小時走的距離(m) s為每秒外部中斷次數(shù)
- //2.08cm為每兩孔之間的距離 *3600化為每小時;
- // /100距離化為米
- qian=t/1000000%10;
- bai=t/100000%10;
- shi=t/10000%10;
- ge= t/1000%10;
- shifen=t/100%10;
- setadd(2,3); //設(shè)置指針
-
- if(bai==0) //百位為0時不顯示
- writedata(' ');
- else
- writedata(0x30+bai);
- if(bai==0&&shi==0) //百位,十位為0時不顯示十位
- writedata(' ');
- else
- writedata(0x30+shi);//顯示十位
- writedata(0x30+ge); //顯示個位
- writedata('.'); //顯示小數(shù)點(diǎn)
- writedata(0x30+shifen);//顯示十分位
-
- //顯示里程
- y=milesum*2.08/10000;
- //除10*milesum得里程的長度(cm)(2為2cm 除100000化為km
- //乘10是為了下面得十分位 y為long型
- milshifen=y%10;
- milge=y/10%10;
- milshi=y/100%10;
- milbai=y/1000%10;
- milqian=y/10000%10;
- milwan=y/100000%10;
- milshiwan=y/1000000%10;
- setadd(3,3); //設(shè)置指針位置
- if(milwan==0)
- writedata(' ');
- else
- writedata(0x30+milwan);
- if(milwan==0&&milqian==0)
- writedata(' ');
- else
- writedata(0x30+milqian);
- if(milwan==0&&milqian==0&&milbai==0)
- writedata(' ');
- else
- writedata(0x30+milbai);
- if(milwan==0&&milqian==0&&milbai==0&&milshi==0)
- writedata(' ');
- else
- writedata(0x30+milshi);
- writedata(0x30+milge);
- writedata('.');
- writedata(0x30+milshifen)
- }
-
- /***************延遲ms*******************/
- void delay(int k)//
- {
- int d,s;
- for(d=k;d>0;d--)
- {
- for(s=110;s>0;s--);
- }
- }
- /****************寫命令******************/
- void writecmd(uchar cmd)
- {
- e=0;
- rs=0;
- rw=0;
- P0=cmd;
- delay(5);
- e=1;
- delay(5);
- e=0;
- }
- /****************寫數(shù)據(jù)******************/
- void writedata(uchar dat)
- {
- e=0;
- rs=1;
- rw=0;
- P0=dat;
- delay(5);
- e=1;
- delay(5);
- e=0;
- }
- /****************lcd初始化******************/
- void init()
- {psb=1; //設(shè)置并口工作方式
- writecmd(0x30);//8位數(shù)據(jù)模式,基本指令操作
- delay(5);
- writecmd(0x0c);//顯示開,關(guān)光標(biāo)
- delay(5);
- writecmd(0x01);//清顯示屏內(nèi)容
- delay(5);
- }
- /****************設(shè)定要顯示的位置******************/
- // 1234行01234567列
- void setadd(uchar x,uchar y)
- {
- switch(x)
- {
- case 1: writecmd(0x80+y);break;
- case 2: writecmd(0x90+y);break;
- case 3: writecmd(0x88+y);break;
- case 4: writecmd(0x98+y);break;
- default:break;
- }
- }
- /* ================ 打開 ISP,IAP 功能 ================= */
- void ISP_IAP_enable(void)
- {
- EA = 0; /* 關(guān)中斷 */
- ISP_CONTR = WaitTime; /* 寫入硬件延時 */
- ISP_CONTR = 0x80; /* ISPEN=1 */
- }
- /* =============== 關(guān)閉 ISP,IAP 功能 ================== */
- void ISP_IAP_disable(void)
- {
- ISP_CONTR = 0x7f; /* ISPEN = 0 */
- ISP_TRIG = 0x00;
- EA = 1; /* 開中斷 */
- }
- /* ================ 公用的觸發(fā)代碼 ==================== */
- void ISP_TRIGER(void)
- {
- ISP_IAP_enable(); /* 打開 ISP,IAP 功能 */
- ISP_TRIG = 0x46; /* 觸發(fā)ISP_IAP命令字節(jié)1 */
- ISP_TRIG = 0xb9; /* 觸發(fā)ISP_IAP命令字節(jié)2 */
- _nop_();
- }
- /* ==================== 字節(jié)讀 ======================== */
- unsigned char byte_read(unsigned int byte_addr)
- {
- ISP_ADDRH = (unsigned char)(byte_addr >> 8); /* 地址賦值 */
- ISP_ADDRL = (unsigned char)(byte_addr );
- ISP_CMD = I0; /* 清除低3位 */
- ISP_CMD = RdCommand; /* 寫入讀命令 */
- ISP_TRIGER(); /* 觸發(fā)執(zhí)行 */
- ISP_IAP_disable(); /* 關(guān)閉ISP,IAP功能 */
- return (ISP_DATA); /* 返回讀到的數(shù)據(jù) */
- }
-
- /* ================== 扇區(qū)擦除 ======================== */
- void SectorErase(unsigned int sector_addr)
- {
- unsigned int iSectorAddr;
- iSectorAddr = sector_addr /* 取扇區(qū)地址 */
- ISP_ADDRH = (unsigned char)(iSectorAddr >> 8);
- ISP_ADDRL = 0x00;
- ISP_CMD = 0; /* 清空低3位 */
- ISP_CMD = EraseCommand; /* 擦除命令3 */
- ISP_TRIGER(); /* 觸發(fā)執(zhí)行 */
- ISP_IAP_disable(); /* 關(guān)閉ISP,IAP功能 */
- }
- /* ==================== 字節(jié)寫 ======================== */
- void byte_write(unsigned int byte_addr, unsigned char original_data)
- {
- ISP_ADDRH = (unsigned char)(byte_addr >> 8); /* 取地址 */
- ISP_ADDRL = (unsigned char)(byte_addr);
- ISP_CMD = 0; /* 清低3位 */
- ISP_CMD = ISP_CMD | PrgCommand; /* 寫命令2 */
- ISP_DATA = original_data; /* 寫入數(shù)據(jù)準(zhǔn)備 */
- ISP_TRIGER(); /* 觸發(fā)執(zhí)行 */
- ISP_IAP_disable(); /* 關(guān)閉IAP功能 */}</font></font>
復(fù)制代碼
51hei.png (5.15 KB, 下載次數(shù): 22)
下載附件
2020-5-15 17:26 上傳
另外給大家分享2個相關(guān)的程序:
參考資料.7z
(924.28 KB, 下載次數(shù): 12)
2020-5-15 17:25 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
|