基于单片机的出租车计价器方案设计书.docx
《基于单片机的出租车计价器方案设计书.docx》由会员分享,可在线阅读,更多相关《基于单片机的出租车计价器方案设计书.docx(25页珍藏版)》请在冰豆网上搜索。
基于单片机的出租车计价器方案设计书
4.2.1里程计数中断程序..........................................10
4.2.2中途等待终端程序...........................................10
出租车计价器
摘要:
本设计是以STC89C51单片机为核心器件,附加A44E霍尔传感器测距,实现对出租车的计价统计。
采用AT24C02实现在系统掉电时保存单价和系统时间等信息,输出采用7位8段数码显示管。
用该电路设计的计价器不但能实现基本的计价,而且还能根据白天、黑夜、中途等待来调节单价,同时在不计价的时候还能作为时钟为司机提供方便。
关键词:
STC89C51。
霍尔传感器。
出租车计价器。
数码显示管
Abstract:
ThisdesignisbasedonSTC89C51microcontrollerasthecoredevice,additionalA44Ehallsensors,realizetothetaxirangingvaluationstatistics.AT24C02realizethepowerlostinthesystempreservedwhenunitpriceandthesystemtime,theinformationsuchastheoutputforseven8digitalXianShiGuan.Withthecircuitdesignofthemetercannotonlyrealizethebasicvaluation,andstillcanaccordingtothedayandthenight,halfwaytoadjusttheunitprice,whilewaitinginthevaluationisalsocanbeusedastheclockforthedriverwithease.
Keywords:
STC89C51。
Hallsensors。
Themetertaxi。
1、任务及要求
(1)模拟一个检测车轮转动里程的计价系统;
(2)计程计价显示功能:
当启动键被按下时,系统开始计程,同时显示出起价和每公里单价;在行使过程中,实时显示已行走的里程数和当前累计价格;当清除键被按下时,计程计价器清零。
(3)显示采用7位静态方式,其中价格4位,公里数3位。
(4)具有时钟功能,可以通过开关切换显示时间和计价。
2、设计方案介绍
2.1基本工作原理
计数器系统主要由五部分组成:
A44E霍尔传感器、STC89C51单片机、独立键盘、EEPROMAT24C02A和显示数码管。
霍尔传感器安装在车轮上,主要检测汽车行进的公里数,并产生一系列相应的脉冲输出,脉冲送到单片机进行处理,单片机根据程序设定通过计算脉冲数换算出行驶公里数,再根据从EEPROM中读取的价格等相关数据进行金额的计算,计算好的金额、里程和单价都实时地显示在数码管上。
独立键盘可以调节价格等相关数据,按下相应的按钮,产生信号交由单片机处理并实时显示出来,调节好的数据存储到EEPROM中,掉电后可以使调好的数据不丢失,下次得电后直接从EEPROM读到单片机,系统结构图如图2.1。
2.2系统整体框图
图2.1系统整体框图
3、硬件电路设计
3.1单片机最小系统
89C51是片内有ROM/EPROM的单片机,因此,这种芯片构成的最小系统简单﹑可靠。
用89C51单片机构成最小应用系统时,只要将单片机接上时钟电路和复位电路即可,如图3.1单片机最小系统所示。
由于集成度的限制,最小应用系统只能用作一些小型的控制单元。
其应用特点:
(1)有可供用户使用的大量I/O口线。
(2)内部存储器容量有限。
(3)应用系统开发具有特殊性。
图3.1单片机最小系统
STC89C51的复位端是一个史密特触发输入,高电平有效。
RST端若由低电平上升到高电平并持续2个周期,系统将实现一次复位操作。
在复位电路中,按一下复位开关就使在RST端出现一段时间的高电平,外接11.0592M晶振和两个30pF电容组成系统的内部时钟电路。
3.2A44E霍尔传感器检测单元
A44E属于开关型的霍尔器件,其工作电压范围比较宽(4.5~18V),其输出的信号符合TTL电平标准,可以直接接到单片机的IO端口上,而且其最高检测频率可达到1MHZ。
A44E集成霍耳开关由稳压器A、霍耳电势发生器(即硅霍耳片)B、差分放大器C、施密特触发器D和OC门输出E五个基本部分组成。
在输入端输入电压Vcc,经稳压器稳压后加在霍尔电势发生器的两端,根据霍尔效应原理,当霍尔片处在磁场中时,在垂直于磁场的方向通以电流,则与这二者相垂直的方向上将会产生霍尔电势差VH输出,该VH信号经放大器放大后送至施密特触发器整形,使其成为方波输送到OC门输出。
当施加的磁场达到工作点(即Bop)时,触发器输出高电压(相对于地电位),使三极管导通,此时OC门输出端输出低电压,三极管截止,使OC门输出高电压,这种状态为关。
这样两次电压变换,使霍尔开关完成了一次开关动作。
A44E霍尔传感器原理如图3.2所示。
图3.2A44E霍尔传感器原理
里程计算是通过安装在车轮上的霍尔传感器检测到的脉冲信号,送到单片机产生中断,单片机再根据程序设定,计算出里程。
其原理如图3.3所示。
图3.3A44E传感器测距示意图
本系统选择了将A44E的脉冲输出口接到P3.3口外部中断1作为信号的输入端(这样可以减少程序设计的麻烦),车轮每转一圈(设车轮的周长是1M),霍尔开关就检测并输出信号,引起单片机的中断,对脉冲计数,当计数达到1000次时,即1公里,单片机就控制将金额自动增加,如图3.4所示。
图3.4霍尔元件接线图
3.3存储单元
存储单元的作用是在电源断开的时候,存储当前设定的单价信息。
AT24C02A是Ateml公司的1KB的电可擦除存储芯片,采用两线串行的总线和单片机通讯,电压最低可以到2.5V,额定电流为1mA,静态电流10uA(5.5V),芯片内的资料可以在断电的情况下保存40年以上,而且采用8脚的DIP封装,使用方便。
AT24C02芯片引脚配置如图3.5所示。
图3.5AT24C02A引脚图
具体电路图3.6所示:
图3.6存储单元电路原理图
图中R2、R3是上拉电阻,其作用是减少AT24C02A的静态功耗。
由于AT24C02A的数据线和地址线是复用的,采用串口的方式传送数据,所以只用两根线SCL(时钟脉冲)和SDA(数据/地址)与单片机P2.3和P2.2口连接,进行传送数据。
每当设定一次单价,系统就自动调用存储程序,将单价信息保存在芯片内;当系统重新上电的时候,自动调用读存储器程序,将存储器内的单价等信息,读到缓存单元中,供主程序使用。
3.4键盘调整单元
当单价等信息需要进行修改时,就要用到键盘进行修改。
由于调节信息不多,故采用4个独立键盘即可,分别实现清零、切换、增大、减小和功能等作用。
电路原理如图3.7所示。
S1:
接P1.0口,对上一次的计费进行清零,为下次载客准备
S2:
接P1.1口,实现白天和夜晚单价的切换;当功能键S4按下时,S2可对数据进行增大。
S3:
接P1.2口,当功能键S4按下时,S3可对数据进行减小。
S4:
接P1.3口,按1次,进入调整白天单价;按2次,进入调整夜晚单价;按3次,进入调整等待单价;按4次,进入调整起步价;按5次,返回。
图3.7键盘单元电路
3.5显示单元
显示单元由7个8段共阳数码管组成,采用动态扫描进行显示。
前三个数码管分别接P3.0、P3.1和P3.2,用于显示总金额;中间两个分别接P3.4和P3.5,用于显示里程;后边两个分别接P3.6和P3.7,用于显示单价。
电路如图3.8所示。
图3.8显示单元电路
4、软件设计
4.1系统主程序
在主程序模块中,需要完成对各参量和接口的初始化、出租车起价和单价的初始化以及中断、计算、循环等工作。
另外,在主程序模块中还需要设置启动/清除标志寄存器、里程寄存器和价格寄存器,并对它们进行初始化。
然后,主程序将根据各标志寄存器的内容,分别完成启动、清除、计程和计价等不同的操作。
当汽车运行起来时,就启动计价,根据里程寄存器中的内容计算和判断行驶里程是否已超过起步价公里数。
若已超过,则根据里程值、每公里的单价数和起步价数来计算出当前的总金额,并将结果存于总金额寄存器中;中途等待时,无脉冲输入,不产生中断,当时间超过等待设定值时,开始进行计时,并把等待价格加到总金额里,然后将总金额、里程和单价送数码管显示出来。
程序流程如图4.1所示。
图4.1主程序流程图图4.2计算程序流程图
4.2中断程序
4.2.1里程记数中断程序
每当霍尔传感器输出一个低电平信号就使单片机中断一次,当里程计数器对里程脉冲计满1000次时,进入里程计数中断服务程序中,里程变量加一。
主函数中总金额也相应地变化。
4.2.2中途等待中断程序
在中途等待中断程序中,每1ms产生一次中断,将当前里程值送入某个缓存变量,每5分钟将缓存变量中的值和当前里程值比较,当汽车停止,霍尔传感器5分钟没有输出信号,当前里程值和缓存变量内的值相同,则进入等待计时,每5分钟记一次价格。
4.3计算程序
计算程序根据里程数分别进入不同的计算公式。
如果里程大于3公里,则执行公式:
总金额=起步价+(里程-3)*单价+等待时间*等待单价;否则,执行公式:
总金额=起步价+等待时间*等待单价。
程序流程图如图4.2所示。
4.4显示程序
显示程序利用定时器每1ms产生一次中断,相应变量置位,点亮一个数码管,显示一位数据,利用主函数内的循环,实现动态扫描显示,同时根据数码管余辉和人眼暂留现象,即可实现显示。
4.5键盘程序
键盘采用查询的方式,放在主程序中,当没有按键按下的时候,单片机循环主程序,一旦右按键按下,便转向相应的子程序处理,处理结束再返回。
流程图如图4.3。
图4.3键盘程序流程图
5、设计总结
经过这些天有关于出租车计价器的课程设计,使我对单片机的应用有了更深的了解。
在课程设计的过程中,还是碰到了许多的问题。
比如,对于数码管动态扫描显示和键盘的延时防抖的综合编程不能较好地解决;对于代码的前后顺序及调用掌握得还不够好;对于一些相关的应用软件没能熟练掌握。
通过这几天晚上的苦想和反复调试,以及参考网上的程序,最终还是把问题解决了。
通过这次课程设计,我最大的收获就是自己的动手能力和独立解决问题的能力得到了很大的提高,也充分体会到了自己设计东西的乐趣、学会查阅资料和对别人的东西融会变通的重要性,也明白了很多知识光靠趴在书本上学是学不到其中的精髓的,必须亲自去试着实践,亲自去经历才能对它们真正的掌握,凡事都要自己去动下手,去实践一下,遇到困难,永远不要沮丧气馁。
在动手的过程中,不仅能增强实践能力,而且在理论上可以有更深的认识;这次设计给了我极大的鼓舞和信心,相信在以后的学习中可以通过不断的摸索和实践来提高其他方面的知识。
6、参考资料
(1)李光飞单片机课程设计实例指导[M]北京 北京航空航天大学出版社;
(2)马淑华,王凤文,张美金编著.单片机原理与接口技术(第二版).北京:
北京邮电大学出版社,2007;
(3)谭浩强著.C程序设计(第三版).北京:
清华大学出版社,2005;
(4)靳达编单片机应用系统开发实例导航[M]北京人民邮电出版社;
7、附件
7.1电路图
7.2元件清单
元件名称
封装
数量
编号(值)
电阻
AXIAL0.3
1
R1(10K)
电阻
AXIAL0.3
2
R2,R3(5.1K)
电阻
AXIAL0.3
7
R4~R10(1K)
电容
RAD0.1
2
C2,C3(30Pf)
电解电容
RB.2/.4
1
C1(10uF/16V)
三极管
TO92A
7
Q1~Q7(PNP)
STC89C51单片机
DIP40
1
U1
AT24C02A
DIP8
1
U2
开关
SW-PB
5
S1~S5
晶振
XTAL1
1
Y1(11.0592MHz)
LED数码管
7
DS1~DS7
A44E霍尔元件
1
J1
7.3源程序清单
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
#definedelayNOP()。
{_nop_()。
_nop_()。
_nop_()。
_nop_()。
_nop_()。
}。
ucharcodetable[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}。
sbitexter=P3^3。
//外部中断
sbitkey0=P1^0。
//清零
sbitkey1=P1^1。
//切换/+
sbitkey2=P1^2。
//-
sbitkey3=P1^3。
//功能键
sbitp30=P3^0。
//数码管各位控制
sbitp31=P3^1。
sbitp32=P3^2。
sbitp34=P3^4。
sbitp35=P3^5。
sbitp36=P3^6。
sbitp37=P3^7。
sbitSDA=P2^2。
//IIC引脚
sbitSCL=P2^3。
uintinter,aa,bb,temp,temp1。
uintzongjine,licheng,dengdai。
uintkey3num,qiehuantemp,delaytemp。
uchardanjia1,danjia2,danjia3,danjia,qibu。
voiddelay(uintx)//延时时基为1ms
{
inti,j。
for(i=x。
i>0。
i--)
for(j=340。
j>0。
j--)。
}
voidstart()//IIC开始位
{
SDA=1。
SCL=1。
delayNOP()。
SDA=0。
delayNOP()。
SCL=0。
}
voidstop()//IIC停止位
{
SDA=0。
delayNOP()。
SCL=1。
delayNOP()。
SDA=1。
}
voidrespons()//IIC应答位
{
uchari。
SCL=1。
delayNOP()。
while((SDA==1)&&(i<250))
i++。
SCL=0。
delayNOP()。
}
ucharread_byte()//从EEPROM读到MCU
{
uchari,j。
for(i=0。
i<8。
i++)
{
SCL=1。
j<<=1。
j|=SDA。
SCL=0。
}
return(j)。
}
voidwrite_byte(uchardate)//从MCU写到EEPROM
{
uchari,temp。
temp=date。
for(i=0。
i<8。
i++)
{
temp=temp<<1。
SCL=0。
delayNOP()。
SDA=CY。
delayNOP()。
SCL=1。
delayNOP()。
}
SCL=0。
delayNOP()。
SDA=1。
delayNOP()。
}
voidwrite_data(ucharaddr,uchardate)//在指定地址addr处写入数据date
{
start()。
write_byte(0xa0)。
respons()。
write_byte(addr)。
respons()。
write_byte(date)。
respons()。
stop()。
}
ucharread_data(ucharaddr)//在指定地址addr读取数据
{
uchardate。
start()。
write_byte(0xa0)。
respons()。
write_byte(addr)。
respons()。
start()。
write_byte(0xa1)。
respons()。
date=read_byte()。
stop()。
returndate。
}
voiddisplay(uintzongjine0,uintlicheng0,uintdanjia0)//数码管显示
{
uintjbai,jshi,jge,lshi,lge,dshi,dge。
uintnumwei,numshu。
//数码管位置分配
jbai=zongjine0/100。
jshi=zongjine0%100/10。
jge=zongjine0%100%10。
lshi=licheng0/10。
lge=licheng0%10。
dshi=danjia0/10。
dge=danjia0%10。
//数码管动态显示
if(aa)
{
aa=0。
numshu++。
if(numshu==7)
numshu=0。
P3=0xff。
switch(numwei)
{
case0:
p30=0。
P0=table[jbai]。
break。
case1:
p31=0。
P0=table[jshi]&0x7f。
break。
case2:
p32=0。
P0=table[jge]。
break。
case3:
p34=0。
P0=table[lshi]。
break。
case4:
p35=0。
P0=table[lge]。
break。
case5:
p36=0。
P0=table[dshi]&0x7f。
break。
case6:
p37=0。
P0=table[dge]。
break。
}
numwei++。
if(numwei==7)
numwei=0。
}
}
voidkeyscan()//键盘扫描
{
if(key3==0)//功能键调节
{
delay(5)。
if(key3==0)
{
key3num=1。
while(!
key3)。
delay(5)。
while(!
key3)。
while(key3num)
{
if(key3num==1)//调白天单价
{
if(key1==0)
{
delay(5)。
if(key1==0)
{
danjia1++。
if(danjia1==100)
danjia1=0。
while(!
key1)。
delay(5)。
while(!
key1)。
}
}
if(key2==0)
{
delay(5)。
if(key2==0)
{
danjia1--。
if(danjia1==-1)
danjia1=99。
while(!
key2)。
delay(5)。
while(!
key2)。
}
}
display(1,0,danjia1)。
}
if(key3num==2)
//调夜晚单价
{
write_data(1,danjia1)。
if(key1==0)
{
delay(5)。
if(key1==0)
{
danjia2++。
if(danjia2==100)
danjia2=0。
while(!
key1)。
delay(5)。
while(!
key1)。
}
}
if(key2==0)
{
delay(5)。
if(key2==0)
{
danjia2--。
if(danjia2==-1)
danjia2=99。
while(!
key2)。
delay(5)。
while(!
key2)。
}
}
display(2,0,danjia2)。
}
if(key3num==3)//调等待单价
{
write_data(2,danjia2)。
if(key1==0)
{
delay(5)。
if(key1==0)
{
danjia3++。
if(danjia3==100)
danjia3=0。
while(!
key1)。
delay(5)。
while(!
key1)。
}
}
if(key2==0)
{
delay(5)。
if(key2==0)
{
danjia3--。
if(danjia3==-1)
danjia3=99。
while(!
key2)。
delay(5)。
while(!
key2)。
}
}
display(3,0,danjia3)。
}
if(key3num==4)//调起步价
{
write_data(3,danjia3)。
if(key1==0)
{
delay(5)。
if(key1==0)
{
qibu++。
if(qibu==100)qibu=0。
while(!
key1)。
delay(5)。
while(!
key1)。
}
}
if(key2==0)
{
delay(5)。
if(key2==0)
{
qibu--。
if(qibu==-1)
qibu=99。
while(!
key2)。
delay(5)。
while(!
key2)。
}
}
display(4,0,qibu)。
}
if(key3num==5)//退出功能键
{
write_data(4,qibu)。
key3num=0。
}
if(key3==0)
{
delay(5)。
if(key3==0)
{
key3num++。
while(!
key3)。
delay(5)。
while(!
key3)。
}
}
}
}
}
}
voidinit()
{
SDA=1。
SCL=1。
zongjine=0。
licheng=0。
dengdai=0。
danjia1=read_data
(1)。
danjia2=read_data
(2)。
danjia3=read_data(3)。
qibu=read_data(4)。
aa=0。
//数码管动态扫描的定