课程设计出租车计价器Word文档格式.docx
《课程设计出租车计价器Word文档格式.docx》由会员分享,可在线阅读,更多相关《课程设计出租车计价器Word文档格式.docx(39页珍藏版)》请在冰豆网上搜索。
基本要求:
(1)能显示里程,单位为公里,最后一位为小数位。
(2)能显示金额数,单位为元,最后一位为小数位。
(3)可设定单程价格和往返价格,单程价格为2元/公里,往返价格为1.5元/公里。
(4)车速<
5公里/小时的时间累积为总等待时间,每5分钟等待时间相当于里程数增加1公里。
(5)起步公里数为3公里,价格为5元,若实际距离大于3公里,按规则3计算价格。
(6)按暂停键,计价器可暂停计价,按查询键,可显示总等待时间。
2系统总体方案及硬件设计
2.1系统总体方案
模拟计数器系统主要由五大模块组成:
霍尔传感器、AT89S52单片机、独立键盘、EEPROMAT24C01和显示数码管。
霍尔传感器安装在车轮的旁侧,主要检测汽车行进的公里数,并产生一系列相应的脉冲输出,脉冲送到单片机进行处理,单片机根据程序设定通过计算脉冲数换算出行驶公里数,再根据从EEPROM中读取的价格等相关数据进行金额的计算,计算好的金额、里程都实时地显示在数码管上。
独立键盘可以调节价格等相关数据,按下相应的按钮,产生信号交由单片机处理并实时显示出来。
总体方案结构图如下:
图2.1系统总体结构框图
2.2单片机最小系统单元
这次设计用到了AT89S52单片机(如图2.2),AT89S52系列单片机是由Atmel公司生产,而这家公司得到了Intel公司MCS51系列单片机内核生产授权,所以,它与MCS51系列单片机指令兼容,同时它的内部包含有用作程序存储器的4KB的基于FLASH技术的只读存储器。
采用这款芯片及克服了采用8031需要添加外部外部程序存储器导致电路复杂的缺点,又克服了采用8751导致电路制作成本高的缺点。
AT89S52单片机芯片具有以下特性:
1)指令集合芯片引脚与Intel公司的8051兼容;
2)4KB片内在系统可编程FLASH程序存储器;
3)时钟频率为0~33MHZ;
4)128字节片内随机读写存储器(RAM);
5)6个中断源,2级优先级;
6)2个16位定时/记数器;
7)全双工串行通信接口;
8)监视定时器;
9)两个数据指针。
2.2.1时钟电路模块
为达到振荡周期是12MHZ的要求,这里要采用12MHZ的晶振,另外有两个22P的独石电容,两晶振引脚分别连到XTAL1和XTAL2振荡脉冲输入引脚。
具体如图所示:
图2.2时钟电路模块
2.2.2复位电路模块
单片机系统的复位电路在这里采用的是上电+按钮复位电路形式,其中电阻R采用200Ω的阻值,电容采用电容值为10μ的电解电容。
具体连接电路如图示5:
图2.3复位电路模块
2.3霍尔传感器检测单元
属于开关型的霍尔器件,其工作电压范围比较宽(4.5~18V),其输出的信号符合TTL电平标准,可以直接接到单片机的IO端口上,而且其最高检测频率可达到1MHZ。
集成霍耳开关由稳压器A、霍耳电势发生器(即硅霍耳片)B、差分放大器C、施密特触发器D和OC门输出E五个基本部分组成。
在输入端输入电压Vcc,经稳压器稳压后加在霍尔电势发生器的两端,根据霍尔效应原理,当霍尔片处在磁场中时,在垂直于磁场的方向通以电流,则与这二者相垂直的方向上将会产生霍尔电势差VH输出,该VH信号经放大器放大后送至施密特触发器整形,使其成为方波输送到OC门输出。
当施加的磁场达到工作点(即Bop)时,触发器输出高电压(相对于地电位),使三极管导通,此时OC门输出端输出低电压,三极管截止,使OC门输出高电压,这种状态为关。
这样两次电压变换,使霍尔开关完成了一次开关动作。
霍尔传感器原理如图5所示。
图2.4传感器测距示意图
里程计算是通过安装在车轮上的霍尔传感器检测到的脉冲信号,送到单片机产生中断,单片机再根据程序设定,计算出里程。
其原理如图2.4所示。
本系统选择了将霍尔传感器的脉冲输出口接到P3.3口外部中断1作为信号的输入端(这样可以减少程序设计的麻烦),车轮每转一圈(设车轮的周长是5米),霍尔开关就检测并输出信号,引起单片机的中断,对脉冲计数,当计数达到200次时,即1公里,单片机就控制将金额自动增加,如图2.5(霍尔传感器)。
图2.5霍尔传感器
2.4AT24C01存储单元
存储单元的作用是在电源断开的时候,存储当前设定的单价信息。
AT24C01是Ateml公司的1KB的电可擦除存储芯片,采用两线串行的总线和单片机通讯,电压最低可以到2.5V,额定电流为1mA,静态电流10uA(5.5V),芯片内的资料可以在断电的情况下保存40年以上,而且采用8脚的DIP封装,使用方便。
A0,A1,A2——地址输入引脚,走位硬件寻址的依据,同种芯片可同时连接8片(2^3);
Vcc,Gnd——电源,接地引脚,1.8-5.5v
Wp——写保护,当Wp接地时,允许对器件的正常读写操作;
当Wp接高电平时,写保护,只能进行读操作。
SDA——串行地址/数据输入/输出端口,双向传输,漏极开路,需外接上拉电阻到Vcc(典型阻值为10k)。
SCL——串行时钟输入,高低电平不同状态与SDA配合,执行不同的命令。
AT24C02芯片引脚配置如图所示。
图2.6AT24C01
图中R13、R14是上拉电阻,其作用是减少AT24C01的静态功耗。
由于AT24C01的数据线和地址线是复用的,采用串口的方式传送数据,所以只用两根线SCL(时钟脉冲)和SDA(数据/地址)与单片机P1.6和P1.7口连接,进行传送数据。
每当设定一次单价,系统就自动调用存储程序,将单价信息保存在芯片内;
当系统重新上电的时候,自动调用读存储器程序,将存储器内的单价等信息,读到缓存单元中,供主程序使用.
图2.7AT24C02原理图
2.5键盘调整单元
当单价等信息需要进行修改时,就要用到键盘进行修改。
由于调节信息不多,故采用4个独立键盘即可,分别实现清零、切换、增大、减小和功能等作用。
电路原理如图所示。
图2.8键盘调整模块
S1:
接P1.1口,对上一次的计费进行清零/暂停,为下次载客准备
S2:
接P1.2口,实现白天和夜晚单价的切换;
当功能键S4按下时,S2可对数据进行增大。
S3:
接P1.3口,当功能键S4按下时,S3可对数据进行减小。
S4:
接P1.4口,按1次,进入调整单程单价;
按2次,进入调整返程单价;
;
按3次,进入调整起步价;
按4次,返回。
S5:
接P1.5口,对等待时间进行查询
2.6数据显示模块
显示单元由7个8段共阴数码管组成,采用动态扫描进行显示。
前四个数码管分别接P2.0、P2.1和P2.2、P2.3,用于显示总金额;
后面分别接P2.4、P2.5、P2.6和P2.7,用于显示里程;
图2.9数据显示模块
3软件设计
3.1系统主程序
在主程序模块中,需要完成对各参量和接口的初始化、出租车起步价和单价的初始化以及中断、计算、循环等工作。
另外,在主程序模块中还需要设置启动/清除标志寄存器、里程寄存器和价格寄存器,并对它们进行初始化。
然后,主程序将根据各标志寄存器的内容,分别完成启动、清除、计程和计价等不同的操作。
3.1主程序流程图
当汽车运行起来时,就启动计价,根据里程寄存器中的内容计算和判断行驶里程是否已超过起步价公里数。
若已超过,则根据里程值、每公里的单价数和起步价数来计算出当前的总金额,并将结果存于总金额寄存器中;
中途等待时,脉冲输入小于设定值时,当时间超过等待设定值时,开始进行计时,并把等待价格加到总金额里,然后将总金额、里程送数码管显示出来。
程序流程如图所示。
3.2中断程序
3.2.1里程计数中断程序
每当霍尔传感器输出一个低电平信号就使单片机中断一次,当里程计数器对里程脉冲计满1000次时,进入里程计数中断服务程序中,里程变量加一。
主函数中总金额也相应地变化。
3.2.2中途等待中断程序
在中途等待中断程序中,每1ms产生一次中断,将当前里程值送入某个缓存变量,每5分钟将缓存变量中的值和当前里程值比较,当汽车车速小于5公里/小时,将存储器里面的值与实时测量的值比较,当行进的里程小于1/12公里每分钟时,则进入等待计时,每5分钟记一次价格。
3.3计算程序
计算程序根据里程数分别进入不同的计算公式。
如果里程大于3公里,则执行公式:
总金额=起步价+(里程-3)*单价+等待时间*等待单价;
否则,执行公式:
总金额=起步价+等待时间*等待单价。
程序流程图如图所示。
3.3计算程序流程图
3.4显示程序
显示程序利用定时器每1ms产生一次中断,相应变量置位,点亮一个数码管,显示一位数据,利用主函数内的循环,实现动态扫描显示,同时根据数码管余辉和人眼暂留现象,即可实现显示。
3.5键盘程序
键盘采用查询的方式,放在主程序中,当没有按键按下的时候,单片机循环主程序,一旦右按键按下,便转向相应的子程序处理,处理结束再返回。
流程图如图
3.4键盘程序流程图
4Proteus软件仿真
图4.1初始化(数码管上:
总金额-元下:
里程-公里)
图4.2单程单位价格(数码管上:
标识符下:
单程单价-元)
图4.3单程计价费用(数码管上:
图4.4返程单位价格(数码管上:
返程单价-元)
图4.5返程计价费用(数码管上:
图4.6起步价格(数码管上:
起步单价-元)
图4.7小于三公里计价费用(数码管上:
图4.8等待时间查询(数码管上:
等待时间-分钟)
5总结
经过这些天有关于出租车计价器的课程设计,使我对单片机的应用有了更深的了解。
在课程设计的过程中,还是碰到了许多的问题。
比如,对于数码管动态扫描显示和键盘的延时防抖的综合编程不能较好地解决;
对于代码的前后顺序及调用掌握得还不够好;
对于一些相关的应用软件没能熟练掌握。
通过这几天晚上的苦想和反复调试,以及参考网上的程序,最终还是把问题解决了。
通过这次课程设计,我最大的收获就是自己的动手能力和独立解决问题的能力得到了很大的提高,也充分体会到了自己设计东西的乐趣、学会查阅资料和对别人的东西融会变通的重要性,也明白了很多知识光靠趴在书本上学是学不到其中的精髓的,必须亲自去试着实践,亲自去经历才能对它们真正的掌握,凡事都要自己去动下手,去实践一下,遇到困难,永远不要沮丧气馁。
在动手的过程中,不仅能增强实践能力,而且在理论上可以有更深的认识;
这次设计给了我极大的鼓舞和信心,相信在以后的学习中可以通过不断的摸索和实践来提高其他方面的知识。
参考文献
[1]段晨东.单片机实用技术教程.清华大学出版社,2008
[2]王晓明.单片机接口技术.北京航空航天大学出版社,2007
[3]王晓敏.传感器检测技术及应用.北京大学出版社,2010
[4]吴红星.电机驱动与控制专用集成电路及应用.中国电力出版社,2006
[5]Schulz,Joerg.Accelerationtransducerforpositioningdrivesinprecisionengineering.engineeringvillage,1999
[6]TransducerforMeasurementofMotion.SpeedandAcceleration,Duc,M.;
Peters,M.;
Yvroud,E..engineeringvillage,1975
附录1源程序
#include<
reg52.h>
#include<
intrins.h>
#defineucharunsignedchar
#defineuintunsignedint
#definedelayNOP();
{_nop_();
_nop_();
};
ucharcodetable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
//共阴数码管段选
sbitexter=P3^3;
//外部中断
sbitkey0=P1^1;
//清零
sbitkey1=P1^2;
//切换/+
sbitkey2=P1^3;
//-
sbitkey3=P1^4;
//功能键
sbitkey4=P1^5;
//查询键
sbitP20=P2^0;
//数码管各位控制
sbitP21=P2^1;
sbitP22=P2^2;
sbitP23=P2^3;
sbitP24=P2^4;
sbitP25=P2^5;
sbitP26=P2^6;
sbitP27=P2^7;
sbitP34=P3^4;
//单程
sbitP35=P3^5;
//返程
sbitP36=P3^6;
//空车
sbitSDA=P1^6;
sbitSCL=P1^7;
//IIC引脚
uintinter,aa,bb,temp,temp1,flag,flag1;
ucharzongjine,licheng,dengdai,licheng1;
uintkey3num,qiehuantemp,delaytemp;
uchardanjia1,danjia2,danjia3,danjia4,danjia,qibu;
voiddelay(uintx)//延时时基为1ms
{
inti,j;
for(i=x;
i>
0;
i--)
for(j=110;
j>
j--);
}
voidstart()//IIC开始位
SDA=1;
SCL=1;
delayNOP();
SDA=0;
SCL=0;
voidstop()//IIC停止位
voidrespons()//IIC应答位
uchari;
SCL=1;
while((SDA==1)&
&
(i<
250))
i++;
SCL=0;
ucharread_byte()//从EEPROM读到MCU
uchari,j;
for(i=0;
i<
8;
i++)
{
j<
<
=1;
j|=SDA;
}
return(j);
voidwrite_byte(uchardate)//从MCU写到EEPROM
uchari,temp;
temp=date;
temp=temp<
1;
SDA=CY;
SDA=1;
voidwrite_data(ucharaddr,uchardate)//在指定地址addr处写入数据date
start();
write_byte(0xa0);
respons();
write_byte(addr);
write_byte(date);
stop();
ucharread_data(ucharaddr)//在指定地址addr读取数据
uchardate;
write_byte(0xa1);
date=read_byte();
returndate;
voiddisplay(uintzongjine0,uintlicheng0)//数码管显示方式0
uintjbai,jshi,jge,jxiaoshu,lbai,lshi,lge,lxiaoshu;
uintnumwei,numshu;
//数码管位置分配
jbai=zongjine0/1000;
jshi=zongjine0%1000/100;
jge=zongjine0%100/10;
jxiaoshu=zongjine0%10;
jbai=licheng0/1000;
lshi=licheng0%1000/100;
lge=licheng0%100/10;
lxiaoshu=licheng0%10;
//数码管动态显示
if(aa)
aa=0;
numshu++;
if(numshu==8)
numshu=0;
P0=0xff;
P2=0xff;
switch(numwei)
case0:
P20=0;
P0=table[jbai];
break;
case1:
P21=0;
P0=table[jshi];
case2:
P22=0;
P0=table[jge]|0x80;
case3:
P23=0;
P0=table[jxiaoshu];
case4:
P24=0;
P0=table[lbai];
case5:
P25=0;
P0=table[lshi];
case6:
P26=0;
P0=table[lge]|0x80;
case7:
P27=0;
P0=table[lxiaoshu];
//动态扫描位选控制
numwei++;
if(numwei==8)
numwei=0;
voiddisplay1(uintzongjine1,uintlicheng1)//数码管显示方式1
uintjbai1,jshi1,jge1,jxiaoshu1,lbai1,lshi1,lge1,lxiaoshu1;
jbai1=zongjine1/1000;
jshi1=zongjine1%1000/100;
jge1=zongjine1%100/10;
jxiaoshu1=zongjine1%10;
jbai1=licheng1/1000;
lshi1=licheng1%1000/100;
lge1=licheng1%100/10;
lxiaoshu1=licheng1%10;
//数码管动态显示
P0=table[jbai1];
P0=table[jshi1];
P0=table[jge1];
P0=table[jxiaoshu1];
P0=table[lbai1];
P0=table[lshi1];
P0=table[lge1]|0x80;
P0=table[lxiaoshu1];
voiddisplay2(uintzongjine2,uintlicheng2)//数码管显示方式2
uintjbai2,jshi2,jge2,jxiaoshu2,lbai2,lshi2,lge2,lxiaoshu2;
/