基于单片机的出租车计价系统设计
1 设计目的,要求和设计方法
1.1设计目的
(1)学习基本理论在实践中综合运用的初步经验,掌握电路设计的基本方法、设计步骤,培养综合设计与调适能力,进一步提高综合运用所学知识和设计能力的的目的。
(2)掌握C语言程序设计方法。
(3)培养实践技能,提高分析和解决实际问题的能力,并具备一定程度的设计能力。
1.2基本设计要求
本出租车自动计费,上电后显示最初的起步价,里程计费单价,等待时间计费单价,通过按键可以调节起步价,里程计费单价,等待时间计费单价。同时具有运行,等待,暂停等状态,可以显示暂停的时间。出租车停止后能够显示行驶的总费用。
1.3性能指标
1、费用的计算是按行驶里程收费。设起步价为7.00元。
2、当里程<3km时,按起价计算费用。
3、当里程>3km时,每公里按1.7元计费。
4、等待累计时间>2min时,按1.5元/min计费。
1.4显示功能
1、显示行驶里程:用两位数字显示,显示方式为“XX”,单位为km。计程范围0-99km,精确到1km。
2、显示等候时间:用两位数字显示,显示方式为“XX”,单位为min。计时范围0-59min,精确到1min。
3、显示总费用:用四位数字显示,显示方式为“XXX.X”,单位为元。计价范围0-999.9元,精确到0.1元。
1.3 设计方法
本设计采用AT89C51单片机为主控器,并用开关或者频率信号发生器模拟车速,利用AT89C51的定时器工作在方式1下定时实现对出租车的计时及计价设计,输出采用LCD液晶显示屏显示。
2 设计方案及原理
2.1 设计方案
本设计,利用单片机丰富的端口和控制的灵活性,采用AT89C51单片机为主控器,并用开关或频率信号发生器模拟车速,通过石英振荡器,LCD液晶显示和发光二级管以及单片机内部程序构成完整的出租车计价系统,基本可以实现了按运行状态计价的功能,价格调整功能。
2.2 设计原理
出租车计价是根据车所行驶的路程以及乘客乘车的里程综合决定的。出租车行驶总路程可以通过车轮的周长乘车轮旋转圈数得到。即可计算得到车轮旋转几周出租车能行驶一公里的路程。通过计数接收到的脉冲个数,计算出当前所行驶的路程。同时,通过LCD液晶显示器显示当前的行驶里程、等待时间和需支付的车费。出租车计价器用于记录里程、起步公里数与价格的关系。模拟出租车计价器能根据总里程数、起步公里数的情况作出相应报价等。
3 出租车计价器系统的硬件设计
3.1 出租车硬件框图
图2-1系统的硬件框图
3.2 出租车计价器硬件连接图
AT89C51的最小系统:时钟电路是单片机内部有一个高增益反相放大器,其输入端为芯片引脚XTAL1,其输出端为引脚XTAL2。通过这两个引脚在芯片外并接石英晶体振荡器和两只电容(电容和一般取30pF)。这样就构成一个稳定的自激振荡器。复位操作是按键复位,按键复位具有上电复位功能外,若要复位,只要按图中的RESET键,电源VCC经电阻R1、R2分压,在RESET端产生一个复位高电平。AT89C51的最小系统硬件图如图3.2(a)所示。
图3.2(a) AT89C51的最小系统硬件图
液晶显示和LED灯指示电路:显示电路对于现实电路我们采用液晶显示,液晶又分字符型和点阵型,我们使用的液晶是字符型液晶,并且带字符库的,不需要查找代码,英文字符就可以。运行状态指示电路采用发光二级管对运行方式进行指示,可清楚看到计价器的运行状态。液晶显示和LED灯指示电路如图3.2(b)所示。
图3.2(b) 液晶显示和LED灯指示电路
按键电路:按键电路是通过按键去调节初始选择、调节,模式选择,开始运行,终止等功能。霍尔传感器里程计算是通过安装在车轮旁的霍尔传感器检测到的信号,送到单片机,经处理计算,送给显示单元的。而由于本次实验室的局限不能利用霍尔传感器,所以我们利用按键来代替霍尔传感器,通过按一次键代表汽车行驶了1公里,当在行驶过程中通过按键来选择运行状态。按键电路如图3.2(c)所示。
图3.2(c) 按键电路
4 出租车计价器系统的软件设计
4.1系统流程图
出租车计价器系统流程图如附录1所示。
4.2源程序代码
根据设计的要求,在本系统中主要有主程序和延时程序,主程序中包括中断服务程序和键盘显示子程序、计算子程序等。现在应用更广泛的是单片机C语言,因其简单明了,故此次课程设计采用单片机C语言编程。程序源代码如附录2所示。
4.3程序调试域运行结果
在Keil C51 uvision4中对系统建立项目,选定合适的单片机AT89C51,创建一个计价器的新文件,并将上述的源程序进行编辑和选项操作进行编译,以生成计价器的HEX文件。
5 系统仿真及实际调试
5.1运行图示
仿真开始后,首先按动初始选择按钮, 则可以在运行单价,等待单价,起步价之间切换,每按一次切换一个量,选定后可以按动初始调节按钮进行调节,调节完成后,按下开始运行按钮则开始运行,选择运行模式后开始计费,不同的运行模式会有不同的指示灯亮起,在运行过程中液晶屏会随时显示走过的路程和等待的时间,以及总的费用。仿真图如附录3所示。
5.2仿真问题分析
问题需要改进,例如本设计经过多次的调试与改正,最终达到了设计方案中的结果。在仿真试验中各种设计要求都能够得到验证。但由于设计的原因,本系统仍然总在一些自动化程度不够,运行模式还需要手动选择。
6 总结
出租车计费器系统的设计已经全部完成,能利用AT89C51单片机对出租车启动,停止,暂停等运行状态进行选择和显示,能将单价和费用适时通过LCD显示出来。本款出租车计价器包括单价输出、单价调整、显示当前的总费用等功能。虽然达到了基本的设计目的,但仍然存在一些问题,策划的不够全面,对单片机不够熟悉,系统编写不够简洁完善,使得计价器计费不够细致,不够人性化。
经过这次课程设计让我学会了很多的东西。经过自己努力,基本上完成了设计要求的内容,在系统可行性分析、原理图设计等方面都作了一些实际工作,同时也遇到了一些问题,存在一些不足。学会了怎么去查找些资料,把所找到的东西与自己的问题所结合起来并给予解决。这次设计使我学会把以前学到的理论知识应用于实践,使我认识到理论知识与实践之间有一定的差距,只有通过不断的努力学习和实践才能很好的把理论知识应用到实践当中,也只有通过不断的实践才能加深对理论知识的理解。
参考文献
[1] 王思明,张金敏,张鑫等.单片机原理及应用系统设计.北京:科学出版社,2012
[2] 张金敏,董海棠,高博等.单片机原理与应用系统设计.成都:西南交通大学出版社, 2010
[3] 李华,王思明,张金敏.单片机原理及应用.兰州:兰州大学出版社,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设置函数
void wr_com(ucharcommand); //命令函数
void wr_data(uchardata0); //数据函数
void lcd_clear(); //清屏函数
void lcd_set(); //屏幕设置函数
void busy(); //测忙函数
void display(); //启动前显示函数
voidprintstring(uchar *s);
void display1(); //启动后显示函数
void key1(); //启动前按键
sbit K=P3^0;
sbit K1=P3^1;
sbit K2=P3^5; //开始计价
sbit K3=P3^3; //模式选择(行程/等待)
sbit K4=P3^4; //复位
sbit g=P2^7;
sbit aa=P2^3; //运行
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(); //启动后按键
/*定义液晶显示地址数组*/
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); //延时函数
void clear(); //终止函数
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(); //定时器中断函数
EX0=1;//开外部中断0
IT0=1;//采用跳变沿触发方式
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) //数据
{
busy();
rs=1;
rw=0;
P0=data0;
en=1;
en=0;
}
void busy() //测忙函数
{
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() //初始显示函数
{
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() //运行后显示函数
{
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) //输出显示函数
{
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; //运行
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) //跳出运行
{
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() //初始调节按键
{
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++;
}
|