|
基于單片機(jī)的出租車計價系統(tǒng)設(shè)計
1 設(shè)計目的,要求和設(shè)計方法
1.1設(shè)計目的
(1)學(xué)習(xí)基本理論在實踐中綜合運(yùn)用的初步經(jīng)驗,掌握電路設(shè)計的基本方法、設(shè)計步驟,培養(yǎng)綜合設(shè)計與調(diào)適能力,進(jìn)一步提高綜合運(yùn)用所學(xué)知識和設(shè)計能力的的目的。
(2)掌握C語言程序設(shè)計方法。
(3)培養(yǎng)實踐技能,提高分析和解決實際問題的能力,并具備一定程度的設(shè)計能力。
1.2基本設(shè)計要求
本出租車自動計費(fèi),上電后顯示最初的起步價,里程計費(fèi)單價,等待時間計費(fèi)單價,通過按鍵可以調(diào)節(jié)起步價,里程計費(fèi)單價,等待時間計費(fèi)單價。同時具有運(yùn)行,等待,暫停等狀態(tài),可以顯示暫停的時間。出租車停止后能夠顯示行駛的總費(fèi)用。
1.3性能指標(biāo)
1、費(fèi)用的計算是按行駛里程收費(fèi)。設(shè)起步價為7.00元。
2、當(dāng)里程<3km時,按起價計算費(fèi)用。
3、當(dāng)里程>3km時,每公里按1.7元計費(fèi)。
4、等待累計時間>2min時,按1.5元/min計費(fèi)。
1.4顯示功能
1、顯示行駛里程:用兩位數(shù)字顯示,顯示方式為“XX”,單位為km。計程范圍0-99km,精確到1km。
2、顯示等候時間:用兩位數(shù)字顯示,顯示方式為“XX”,單位為min。計時范圍0-59min,精確到1min。
3、顯示總費(fèi)用:用四位數(shù)字顯示,顯示方式為“XXX.X”,單位為元。計價范圍0-999.9元,精確到0.1元。
1.3 設(shè)計方法
本設(shè)計采用AT89C51單片機(jī)為主控器,并用開關(guān)或者頻率信號發(fā)生器模擬車速,利用AT89C51的定時器工作在方式1下定時實現(xiàn)對出租車的計時及計價設(shè)計,輸出采用LCD液晶顯示屏顯示。
2 設(shè)計方案及原理
2.1 設(shè)計方案
本設(shè)計,利用單片機(jī)豐富的端口和控制的靈活性,采用AT89C51單片機(jī)為主控器,并用開關(guān)或頻率信號發(fā)生器模擬車速,通過石英振蕩器,LCD液晶顯示和發(fā)光二級管以及單片機(jī)內(nèi)部程序構(gòu)成完整的出租車計價系統(tǒng),基本可以實現(xiàn)了按運(yùn)行狀態(tài)計價的功能,價格調(diào)整功能。
2.2 設(shè)計原理
出租車計價是根據(jù)車所行駛的路程以及乘客乘車的里程綜合決定的。出租車行駛總路程可以通過車輪的周長乘車輪旋轉(zhuǎn)圈數(shù)得到。即可計算得到車輪旋轉(zhuǎn)幾周出租車能行駛一公里的路程。通過計數(shù)接收到的脈沖個數(shù),計算出當(dāng)前所行駛的路程。同時,通過LCD液晶顯示器顯示當(dāng)前的行駛里程、等待時間和需支付的車費(fèi)。出租車計價器用于記錄里程、起步公里數(shù)與價格的關(guān)系。模擬出租車計價器能根據(jù)總里程數(shù)、起步公里數(shù)的情況作出相應(yīng)報價等。
3 出租車計價器系統(tǒng)的硬件設(shè)計
3.1 出租車硬件框圖
圖2-1系統(tǒng)的硬件框圖
3.2 出租車計價器硬件連接圖
AT89C51的最小系統(tǒng):時鐘電路是單片機(jī)內(nèi)部有一個高增益反相放大器,其輸入端為芯片引腳XTAL1,其輸出端為引腳XTAL2。通過這兩個引腳在芯片外并接石英晶體振蕩器和兩只電容(電容和一般取30pF)。這樣就構(gòu)成一個穩(wěn)定的自激振蕩器。復(fù)位操作是按鍵復(fù)位,按鍵復(fù)位具有上電復(fù)位功能外,若要復(fù)位,只要按圖中的RESET鍵,電源VCC經(jīng)電阻R1、R2分壓,在RESET端產(chǎn)生一個復(fù)位高電平。AT89C51的最小系統(tǒng)硬件圖如圖3.2(a)所示。
圖3.2(a) AT89C51的最小系統(tǒng)硬件圖
液晶顯示和LED燈指示電路:顯示電路對于現(xiàn)實電路我們采用液晶顯示,液晶又分字符型和點陣型,我們使用的液晶是字符型液晶,并且?guī)ё址麕斓,不需要查找代碼,英文字符就可以。運(yùn)行狀態(tài)指示電路采用發(fā)光二級管對運(yùn)行方式進(jìn)行指示,可清楚看到計價器的運(yùn)行狀態(tài)。液晶顯示和LED燈指示電路如圖3.2(b)所示。
圖3.2(b) 液晶顯示和LED燈指示電路
按鍵電路:按鍵電路是通過按鍵去調(diào)節(jié)初始選擇、調(diào)節(jié),模式選擇,開始運(yùn)行,終止等功能。霍爾傳感器里程計算是通過安裝在車輪旁的霍爾傳感器檢測到的信號,送到單片機(jī),經(jīng)處理計算,送給顯示單元的。而由于本次實驗室的局限不能利用霍爾傳感器,所以我們利用按鍵來代替霍爾傳感器,通過按一次鍵代表汽車行駛了1公里,當(dāng)在行駛過程中通過按鍵來選擇運(yùn)行狀態(tài)。按鍵電路如圖3.2(c)所示。
圖3.2(c) 按鍵電路
4 出租車計價器系統(tǒng)的軟件設(shè)計
4.1系統(tǒng)流程圖
出租車計價器系統(tǒng)流程圖如附錄1所示。
4.2源程序代碼
根據(jù)設(shè)計的要求,在本系統(tǒng)中主要有主程序和延時程序,主程序中包括中斷服務(wù)程序和鍵盤顯示子程序、計算子程序等,F(xiàn)在應(yīng)用更廣泛的是單片機(jī)C語言,因其簡單明了,故此次課程設(shè)計采用單片機(jī)C語言編程。程序源代碼如附錄2所示。
4.3程序調(diào)試域運(yùn)行結(jié)果
在Keil C51 uvision4中對系統(tǒng)建立項目,選定合適的單片機(jī)AT89C51,創(chuàng)建一個計價器的新文件,并將上述的源程序進(jìn)行編輯和選項操作進(jìn)行編譯,以生成計價器的HEX文件。
5 系統(tǒng)仿真及實際調(diào)試
5.1運(yùn)行圖示
仿真開始后,首先按動初始選擇按鈕, 則可以在運(yùn)行單價,等待單價,起步價之間切換,每按一次切換一個量,選定后可以按動初始調(diào)節(jié)按鈕進(jìn)行調(diào)節(jié),調(diào)節(jié)完成后,按下開始運(yùn)行按鈕則開始運(yùn)行,選擇運(yùn)行模式后開始計費(fèi),不同的運(yùn)行模式會有不同的指示燈亮起,在運(yùn)行過程中液晶屏?xí)S時顯示走過的路程和等待的時間,以及總的費(fèi)用。仿真圖如附錄3所示。
5.2仿真問題分析
問題需要改進(jìn),例如本設(shè)計經(jīng)過多次的調(diào)試與改正,最終達(dá)到了設(shè)計方案中的結(jié)果。在仿真試驗中各種設(shè)計要求都能夠得到驗證。但由于設(shè)計的原因,本系統(tǒng)仍然總在一些自動化程度不夠,運(yùn)行模式還需要手動選擇。
6 總結(jié)
出租車計費(fèi)器系統(tǒng)的設(shè)計已經(jīng)全部完成,能利用AT89C51單片機(jī)對出租車啟動,停止,暫停等運(yùn)行狀態(tài)進(jìn)行選擇和顯示,能將單價和費(fèi)用適時通過LCD顯示出來。本款出租車計價器包括單價輸出、單價調(diào)整、顯示當(dāng)前的總費(fèi)用等功能。雖然達(dá)到了基本的設(shè)計目的,但仍然存在一些問題,策劃的不夠全面,對單片機(jī)不夠熟悉,系統(tǒng)編寫不夠簡潔完善,使得計價器計費(fèi)不夠細(xì)致,不夠人性化。
經(jīng)過這次課程設(shè)計讓我學(xué)會了很多的東西。經(jīng)過自己努力,基本上完成了設(shè)計要求的內(nèi)容,在系統(tǒng)可行性分析、原理圖設(shè)計等方面都作了一些實際工作,同時也遇到了一些問題,存在一些不足。學(xué)會了怎么去查找些資料,把所找到的東西與自己的問題所結(jié)合起來并給予解決。這次設(shè)計使我學(xué)會把以前學(xué)到的理論知識應(yīng)用于實踐,使我認(rèn)識到理論知識與實踐之間有一定的差距,只有通過不斷的努力學(xué)習(xí)和實踐才能很好的把理論知識應(yīng)用到實踐當(dāng)中,也只有通過不斷的實踐才能加深對理論知識的理解。
參考文獻(xiàn)
[1] 王思明,張金敏,張鑫等.單片機(jī)原理及應(yīng)用系統(tǒng)設(shè)計.北京:科學(xué)出版社,2012
[2] 張金敏,董海棠,高博等.單片機(jī)原理與應(yīng)用系統(tǒng)設(shè)計.成都:西南交通大學(xué)出版社, 2010
[3] 李華,王思明,張金敏.單片機(jī)原理及應(yīng)用.蘭州:蘭州大學(xué)出版社,2001
附錄1
附錄2
#include<reg52.h>
#define ucharunsigned char
#define uintunsigned int
/*定義1602讀寫使能端口*/
sbit rw=P2^1;
sbit rs=P2^0;
sbit en=P2^2;
sbit b=P0^7;
sbit gl=P1^0;
void lcd_init(); //lcd設(shè)置函數(shù)
void wr_com(ucharcommand); //命令函數(shù)
void wr_data(uchardata0); //數(shù)據(jù)函數(shù)
void lcd_clear(); //清屏函數(shù)
void lcd_set(); //屏幕設(shè)置函數(shù)
void busy(); //測忙函數(shù)
void display(); //啟動前顯示函數(shù)
voidprintstring(uchar *s);
void display1(); //啟動后顯示函數(shù)
void key1(); //啟動前按鍵
sbit K=P3^0;
sbit K1=P3^1;
sbit K2=P3^5; //開始計價
sbit K3=P3^3; //模式選擇(行程/等待)
sbit K4=P3^4; //復(fù)位
sbit g=P2^7;
sbit aa=P2^3; //運(yùn)行
sbit bb=P2^4; //等待
sbit cc=P2^5; //暫停
//sbitled_run=P3^0;
//sbit led_await=P3^1;
//sbitled_stop=P3^2;
bit f_start;
bit jump_in;
bit jump_out;
void key(); //啟動后按鍵
/*定義液晶顯示地址數(shù)組*/
uchar codetable[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x70};
uchardispbuf[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uchar dispbuf1[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uchar v,v1;
uchar i,m=0;
void init();
void chuli();
void chuli1();
void delay(uchart); //延時函數(shù)
void clear(); //終止函數(shù)
void set(uchar x);
void set1(uchary);
uchar command;
ucharcount,count1;
ucharsecond,minite,second1,minite1;
unsigned inttt,tt1;
unsigned charvalue1=70,value2=17,value3=15; //value1=起步價,value2=超出每公里價格,value3=等待價格
unsigned intmoney;
void main()
{
// Init_Timer1(); //定時器中斷函數(shù)
EX0=1;//開外部中斷0
IT0=1;//采用跳變沿觸發(fā)方式
init();
lcd_init();
while(1)
{
key1();
chuli();
display();
if(jump_in==1)
{
jump_in=0;
lcd_init();
while(1)
{
key();
chuli1();
display1();
if(jump_out==1)
{
lcd_init();
jump_out=0;
clear();
break;
}
}
}
}
}
void clear(){
TR0=0;
TR1=0;
money=0;
second=0;
second1=0;
minite=0;
minite1=0;
value1=70;
value2=17;
value3=15;
// led_run=1;
//led_await=1;
// led_stop=1;
v=0;
v1=0;
for(i=0;i<15;i++)
{
dispbuf=0;
dispbuf1=0;
}
m=0;
}
void init() //中斷定時
{
TMOD=0x11;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
ET0=1;
ET1=1;
EA=1;
TR0=0;
TR1=0;
}
void t0_(void)interrupt 1 using 0 //中斷1模式0 用來計時 秒、分
{
count++;
if(count==20)
{
count=0;
second++;
if(second==60)
{
second=0;
minite++;
if(minite==99)
{
minite=0;
}
}
}
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
dispbuf1[0]=m/10;
dispbuf1[1]=m%10;
dispbuf1[2]=second/10;
dispbuf1[3]=second%10;
}
void t1_(void)interrupt 3 using 3 //中斷3模式3用來計時 秒、分
{
count1++;
if(count1==20)
{
count1=0;
second1++;
if(second1==60)
{
second1=0;
minite1++;
if(minite1==99)
{
minite1=0;
}
}
}
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
dispbuf1[4]=minite1/10;
dispbuf1[5]=minite1%10;
dispbuf1[6]=second1/10;
dispbuf1[7]=second1%10;
}
void lcd_init()
{
wr_com(0x3c);
wr_com(0x06);
wr_com(0x0c);
wr_com(0x01);
}
void wr_com(ucharcommand) //命令
{
busy();
rs=0;
rw=0;
P0=command;
en=1;
en=0;
}
void wr_data(uchardata0) //數(shù)據(jù)
{
busy();
rs=1;
rw=0;
P0=data0;
en=1;
en=0;
}
void busy() //測忙函數(shù)
{
while(1)
{
en=0;
rs=0;
rw=1;
P0=0xff;
en=1;
if(b!=1)break;
}
en=0;
}
void chuli() //分離出百位十位個位
{
dispbuf[0]=value1/100%10;
dispbuf[1]=value1/10%10;
dispbuf[2]=value1%10;
dispbuf[3]=value2/100%10;
dispbuf[4]=value2/10%10;
dispbuf[5]=value2%10;
dispbuf[6]=value3/100%10;
dispbuf[7]=value3/10%10;
dispbuf[8]=value3%10;
}
void display() //初始顯示函數(shù)
{
set(0);
printstring("step :");
wr_data(table[dispbuf[0]]);
wr_data(table[dispbuf[1]]);
printstring(".");
wr_data(table[dispbuf[2]]);
set(16);
printstring("mileage :");
wr_data(table[dispbuf[3]]);
wr_data(table[dispbuf[4]]);
printstring(".");
wr_data(table[dispbuf[5]]);
set1(0);
printstring("await :");
wr_data(table[dispbuf[6]]);
wr_data(table[dispbuf[7]]);
printstring(".");
wr_data(table[dispbuf[8]]);
set1(16);
printstring("run : ");
wr_data(table[dispbuf1[0]]);
wr_data(table[dispbuf1[1]]);
printstring(":");
wr_data(table[dispbuf1[2]]);
wr_data(table[dispbuf1[3]]);
}
void chuli1()
{
if(f_start==1)
{
tt=minite*60+second;
tt1=minite1;
if(m<=3)
{money=value1+value3*tt1;}
if(m>3)
{money=value1+value2*(m-3)+value3*tt1;}
}
else if(f_start==0)
{
money=0;
}
dispbuf1[8]=money/100%10;
dispbuf1[9]=money/10%10;
dispbuf1[10]=money%10;
}
void display1() //運(yùn)行后顯示函數(shù)
{
set(0);
printstring("run: ");
//wr_data(table[m]);
wr_data(table[dispbuf1[0]]);
wr_data(table[dispbuf1[1]]);
//printstring(":");
//wr_data(table[dispbuf1[2]]);
//wr_data(table[dispbuf1[3]]);
set(14);
printstring("await:");
wr_data(table[dispbuf1[4]]);
wr_data(table[dispbuf1[5]]);
printstring(":");
wr_data(table[dispbuf1[6]]);
wr_data(table[dispbuf1[7]]);
set1(0);
printstring("sum is: ");
wr_data(table[dispbuf1[8]]);
wr_data(table[dispbuf1[9]]);
printstring(".");
wr_data(table[dispbuf1[10]]);
}
voidprintstring(uchar *s) //輸出顯示函數(shù)
{
while(*s)
wr_data(*s++);
}
void key() //啟動按鍵
{
if(K3==0)
{
delay(50); //延時消抖動
if(K3==0)
{
while(K3==0);
v1++;
if(v1==4) v1=1;
}
}
switch(v1)
{
case1:f_start=1;TR0=1;TR1=0;/*led_run=0;led_await=1;led_stop=1*/;aa=0;bb=1;cc=1;break; //運(yùn)行
case2:TR0=0;TR1=1;/*led_run=1;led_await=0;led_stop=1*/;aa=1;bb=0;cc=1;break; //等待
case3:TR0=0;TR1=0;/*led_run=1;led_await=1;led_stop=0*/;aa=1;bb=1;cc=0;break; //暫停
}
if(K4==0) //跳出運(yùn)行
{
delay(50);
if(K4==0)
{
while(K4==0);
jump_out=1;
}
}
}
void delay(uchart)
{
while(--t);
}
void set(uchar x)
{
command=0x80+x;
wr_com(command);
}
void set1(uchar y)
{
command=0xc0+y;
wr_com(command);
}
void key1() //初始調(diào)節(jié)按鍵
{
if(K==0)
{
delay(100);
if(K==0)
{
while(K==0);
v++;
if(v==4) v=0;
}
}
switch(v)
{
case 0:break;
case1:if(K1==0){while(K1==0);value1=value1+10;}break;
case 2:if(K1==0){while(K1==0);value2=value2+5;}break;
case 3:if(K1==0){while(K1==0);value3=value3+5;}break; }
if(K2==0)
{
delay(50);
if(K2==0)
{
while(K2==0);
jump_in=1;
}
}
}
void mode( )interrupt 0 //外部中斷0控制選位
{
m++;
}
|
|