多功能计价器设计.docx
《多功能计价器设计.docx》由会员分享,可在线阅读,更多相关《多功能计价器设计.docx(57页珍藏版)》请在冰豆网上搜索。
多功能计价器设计
基于MCS-52单片机的出租车计价器设计
通信工程
通信082
专业:
_________________________
班级:
_________________________
姓 名:
牛生奇200809524
王晓明200809520
吕成龙200809560
指导教师:
2010年10月24日
基于MCS-52单片机的出租车计价器设计
摘要
由于科技的飞速发展,计价器也不断发展,而且更加精确和智能化。
本设计主要基于MCS-51系列89C51单片机出租车计价器的系统设计,把A44E霍尔传感器测速的脉冲信号作为单片机的输入信号,单片机输出的数字量信号控制液晶显示系统。
计价器可根据时间来确定单价和起步价,并用AT24C02来存储数据。
而且在形使过程中时刻显示时间、路程、温度和价格。
本设计主要是用51系列单片机,完成了对计的脉冲信号的转换,并且实现了根据起步价和单价计算收费金额的功能,并且实现了用单片机控制型号为液晶显示器。
本设计充分显示了单片机在显示生产和生活中的应用和优势,也显示了在计量方面的发展,精度不断提高和不断智能化和自动化。
关键词:
89C51单片机A44E霍尔传感器液晶显示系统
时钟芯片ds1302EEPROM24C02温度传感DS18B20
4*4矩阵键盘蜂鸣器
作品实物图:
操作流程:
1.按下计价键(10键),液晶屏显示“欢迎乘车祝你一路顺风”然后就进入计价界面,初始化设的起始价为7元,当行驶的路程小于3公里,一直维持7元,但如果有等待时间,就要算等待价格。
当大于3公里且小于10公里,总金额=起步价+(里程-3)*单价+等待时间。
当大于10公里时,总金额=起步价+(里程-10)*(单价+0.7)+等待时间*等待单价。
2.初始化键就是将程序回到一个最初的时间。
3.调时键用来校准时间,当第一次按下时用数字键调年份,调完后再按一次调时键,就进入调月,其余的时间也是如此。
跳完以后按确定键结束调时。
4.调价键按下调价键进入调价界面,首先调白天单价,跳完以后将价格写入了24c02存储起来,然后再按调价键,进入调夜晚单价,调完后,再按调价键进入调延误单价,调完后同样按调价键,进入调起步单价。
以上都调完以后,按确定键结束调价。
1.系统工作原理
1.1.功能说明
出租车计价器根据乘客乘坐汽车行驶距离和等候时间的多少进行计价,并在行程中同步显示车费值。
从起步价开始,当汽车程行驶未满3公里时,均按起步价计算。
过3公里后,实现每1公里单价收费,中间遇暂停时,计程数不再增加,开始计时收费,测距收费和测时收费的和便构成了一位乘客的车费。
另外还设有温度检测和时钟芯片,可以利用4*4矩阵键盘进行调时。
同时,白天和夜晚价格不同,可以进行自动切换。
白天单价、夜晚单价、等待单价和起步价格都可通过独立键盘进行调节。
(默认起步价为7元/3公里,里程单价白天为1.5元/公里,夜晚为1.8元/公里,等待计时单价为0.5元/5分钟)。
1.2.系统原理
计数器系统主要由七部分组成:
A44E霍尔传感器、AT89S52单片机、独立键盘、EEPROMAT24C01、温度传感器Ds18b20、时钟芯片DS1302和液晶显示。
霍尔传感器安装在车轮上,主要检测汽车行进的公里数,并产生一系列相应的脉冲输出,脉冲送到单片机进行处理,单片机根据程序设定通过计算脉冲数换算出行驶公里数,再根据从EEPROM中读取的价格等相关数据进行金额的计算,计算好的金额、里程和单价都实时地显示在液晶屏上。
独立键盘可以调节价格等相关数据,按下相应的按钮,产生信号交由单片机处理并实时显示出来,调节好的数据存储到EEPROM中,掉电后可以使调好的数据不丢失,下次得电后直接从EEPROM读到单片机,系统结构图如图1。
2.硬件设计
2.1.单片机最小系统
主控机系统采用了STC89C52单片机,它含有256字节数据存储器,内置8K的电可擦除FLASHROM,可重复编程,大小满足主控机软件系统设计,所以不必再扩展程序存储器。
复位电路和晶振电路是STC89C52工作所需的最简外围电路。
STC89C52的复位端是一个史密特触发输入,高电平有效。
RST端若由低电平上升到高电平并持续2个周期,系统将实现一次复位操作。
在复位电路中,按一下复位开关就使在RST端出现一段时间的高电平,外接22M晶振和两个30pF电容组成系统的内部时钟电路。
单片机最小系统电路图如图2所示:
2.2.A44E霍尔传感器检测单元
A44E属于开关型的霍尔器件,其工作电压范围比较宽(4.5~18V),其输出的信号符合TTL电平标准,可以直接接到单片机的IO端口上,而且其最高检测频率可达到1MHZ。
A44E集成霍耳开关由稳压器A、霍耳电势发生器(即硅霍耳片)B、差分放大器C、施密特触发器D和OC门输出E五个基本部分组成。
在输入端输入电压Vcc,经稳压器稳压后加在霍尔电势发生器的两端,根据霍尔效应原理,当霍尔片处在磁场中时,在垂直于磁场的方向通以电流,则与这二者相垂直的方向上将会产生霍尔电势差VH输出,该VH信号经放大器放大后送至施密特触发器整形,使其成为方波输送到OC门输出。
当施加的磁场达到工作点(即Bop)时,触发器输出高电压(相对于地电位),使三极管导通,此时OC门输出端输出低电压,三极管截止,使OC门输出高电压,这种状态为关。
这样两次电压变换,使霍尔开关完成了一次开关动作。
里程计算是通过安装在车轮上的霍尔传感器检测到的脉冲信号,送到单片机产生中断,单片机再根据程序设定,计算出里程。
传感器测距原理示意图:
本系统选择了将A44E的脉冲输出口接到P3.2口外部中断1作为信号的输入端(这样可以减少程序设计的麻烦),车轮每转一圈(设车轮的周长是2米),霍尔开关就检测并输出信号,引起单片机的中断,对脉冲计数,当计数达到500次时,即1公里,单片机就控制将金额自动增加。
A44E霍尔元件接线图:
2.3.AT24C02存储单元
存储单元的作用是在电源断开的时候,存储当前设定的单价信息。
AT24C02是Ateml公司的1KB的电可擦除存储芯片,采用两线串行的总线和单片机通讯,电压最低可以到2.5V,额定电流为1mA,静态电流10uA(5.5V),芯片内的资料可以在断电的情况下保存40年以上,而且采用8脚的DIP封装,使用方便。
AT24C02芯片引脚配置如图所示:
存储单元电路连接如图所示:
图中R4、R5是上拉电阻,其作用是减少AT24C02的静态功耗。
由于AT24C02的数据线和地址线是复用的,采用串口的方式传送数据,所以只用两根线SCL(时钟脉冲)和SDA(数据/地址)与单片机P3.6和P3.7口连接,进行传送数据。
每当设定一次单价,系统就自动调用存储程序,将单价信息保存在芯片内;当系统重新上电的时候,自动调用读存储器程序,将存储器内的单价等信息,读到缓存单元中,供主程序使用。
2.4.键盘调整单元
当单价等信息需要进行修改时,就要用到键盘进行修改。
由于调节信息不多,故采用4*4矩阵键盘,分为数字键和功能键。
电路原理如图所示:
0—9是数字键进行调时和调单价用。
10按键用于:
开始计价。
11按键用于:
初始化系统。
12按键用于:
调时功能键。
13按键用于:
调价功能键。
15按键用于:
设置完以后的确定键。
14还未利用。
具体操作见实物图下的操作流程。
2.5.液晶显示
显示利用12864液晶显示,第一行显示年月日,第二行显示星期、时分秒,第三行显示温度,第四行显示总费用和总路程。
2.6.时钟芯片DS1302单元
DS1302是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。
采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。
DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。
DS1302是DS1202的升级产品,与DS1202兼容,但增加了主电源/后背电源双电源引脚,同时提供了对后背电源进行涓细电流充电的能力。
DS1302的引脚排列,其中Vcc1为后备电源,VCC2为主电源。
在主电源关闭的情况下,也能保持时钟的连续运行。
DS1302由Vcc1或Vcc2两者中的较大者供电。
当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电。
当Vcc2小于Vcc1时,DS1302由Vcc1供电。
X1和X2是振荡源,外接32.768kHz晶振。
RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。
RST输入有两种功能:
首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据的传送手段。
当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。
如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。
上电运行时,在Vcc>2.0V之前,RST必须保持低电平。
只有在SCLK为低电平时,才能将RST置为高电平。
I/O为串行数据输入输出端(双向)。
SCLK为时钟输入端。
下图为DS1302的引脚功能图:
Ds1302连线图:
2.7.温度检测模块DS18B20
1、DS18B20的主要特性
1.1、适应电压范围更宽,电压范围:
3.0~5.5V,在寄生电源方式下可由数据线供电
1.2、独特的单线接口方式,DS18B20在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯
1.3、DS18B20支持多点组网功能,多个DS18B20可以并联在唯一的三线上,实现组网多点测温
1.4、DS18B20在使用中不需要任何外围元件,全部传感元件及转换电路集成在形如一只三极管的集成电路内
1.5、温范围-55℃~+125℃,在-10~+85℃时精度为±0.5℃
1.6、可编程的分辨率为9~12位,对应的可分辨温度分别为0.5℃、0.25℃、0.125℃和0.0625℃,可实现高精度测温
1.7、在9位分辨率时最多在93.75ms内把温度转换为数字,12位分辨率时最多在750ms内把温度值转换为数字,速度更快
1.8、测量结果直接输出数字温度信号,以"一线总线"串行传送给CPU,同时可传送CRC校验码,具有极强的抗干扰纠错能力
1.9、负压特性:
电源极性接反时,芯片不会因发热而烧毁,但不能正常工作。
DS18B20的读写时序和测温原理与DS1820相同,只是得到的温度值的位数因分辨率不同而不同,且温度转换时的延时时间由2s减为750ms。
DS18B20测温原理如图3所示。
图中低温度系数晶振的振荡频率受温度影响很小,用于产生固定频率的脉冲信号送给计数器1。
高温度系数晶振随温度变化其振荡率明显改变,所产生的信号作为计数器2的脉冲输入。
计数器1和温度寄存器被预置在-55℃所对应的一个基数值。
计数器1对低温度系数晶振产生的脉冲信号进行减法计数,当计数器1的预置值减到0时,温度寄存器的值将加1,计数器1的预置将重新被装入,计数器1重新开始对低温度系数晶振产生的脉冲信号进行计数,如此循环直到计数器2计数到0时,停止温度寄存器值的累加,此时温度寄存器中的数值即为所测温度。
图3中的斜率累加器用于补偿和修正测温过程中的非线性,其输出用于修正计数器1的预置值。
Ds18b20连线图:
3.软件设计
3.1.系统主程序
在主程序模块中,需要完成对各参量和接口的初始化、出租车起价和单价的初始化以及中断、计算、循环等工作。
另外,在主程序模块中还需要设置启动/清除标志寄存器、里程寄存器和价格寄存器,并对它们进行初始化。
然后,主程序将根据各标志寄存器的内容,分别完成启动、清除、计程和计价等不同的操作。
当汽车运行起来时,就启动计价,根据里程寄存器中的内容计算和判断行驶里程是否已超过起步价公里数。
若已超过,则根据里程值、每公里的单价数和起步价数来计算出当前的总金额,并将结果存于总金额寄存器中;中途等待时,无脉冲输入,不产生中断,当时间超过等待设定值时,开始进行计时,并把等待价格加到总金额里,然后将总金额、里程和单价送液晶显示出来。
程序流程如图所示:
3.2.中断程序
3.2.1 里程计数中断程序
每当霍尔传感器输出一个低电平信号就使单片机中断一次,当里程计数器对里程脉冲计满500次时,进入里程计数中断服务程序中,里程变量加1。
主函数中总金额也相应地变化。
3.2.2 中途等待中断程序
在中途等待中断程序中,每1ms产生一次中断,将当前里程值送入某个缓存变量,每30秒将缓存变量中的值和当前里程值比较,当汽车停止,霍尔传感器30秒没有输出信号,当前里程值和缓存变量内的值相同,则进入等待计时,每30秒记一次价格。
3.3.计算程序
计算程序根据里程数分别进入不同的计算公式。
如果里程大于3公里,则执行公式:
总金额=起步价+(里程-3)*单价+等待时间*等待单价;如果超过十公里,执行公式:
总金额=起步价+(里程-10)*(单价+0.7)+等待时间*等待单价。
4.系统总程序
#include//52单片机头文件
#include
#defineucharunsignedchar
#defineuintunsignedint
//-----LCD
#defineLCD_DataP0
#defineBusy0x80//用于检测LCD状态字中的Busy标识
sbitLCD_RS=P1^0;//定义引脚
sbitLCD_RW=P1^1;
sbitLCD_E=P1^2;
sbitPSB=P1^3;//PSB脚为12864-12系列的串、并通讯功能切换,我们使用8
位并行接口
//sbitRest=P1^4;
sbitbeep=P3^0;
//-----AT24C02
sbitsda=P3^7;
sbitscl=P3^6;
//-----18b20
sbitIO_18b20=P3^1;//定义温度DS18B20接口
unsignedchara=0,b=0,c=0;
inttemp;
//-----1302
#defineWrite_DisableRW_DS1302(0x8e,0x80)//写保护
#defineWrite_EnableRW_DS1302(0x8e,0x00)//允许写入
sbitDS1302_CLK=P1^5;//实时时钟时钟线引脚
sbitDS1302_IO=P1^6;//实时时钟数据线引脚
sbitDS1302_RST=P1^7;//实时时钟复位线引脚
sbitACC0=ACC^0;//定义累加器A中的各位
sbitACC7=ACC^7;
ucharyy,mo,dd,xq,hh,mm,ss,e;//定义时间映射全局变量
//------键盘
Time[2]={'0','0'};
ucharKeydown_flag=0;
ucharTimeset_flag=0;
ucharKey=0;
ucharp=0;
ucharsel=0;
uchare=0;
uchari;
//-------计费
ucharStartprice,Unitprice,Dayprice,Nightprice,Waitprice,Startprice1,
Unitprice1,Dayprice1,Nightprice1,Waitprice1;
uintJourney,aa,Waittime,Cost,Cost1,Cost2,Cost3;
ucharPriceset_flag=0;
ucharCost_flag=0;
ucharq=0;
ucharx=0;
ucharPrice[8]={'0','0','0','0','0','0','0','0'};
//voidLCM_w_ss(void);
voidLCM_w_mm(void);
voidLCD_WriteString(uchar*str);
voidWaittime1();
//voidLCM_w_hh(void);
//voidLCM_w_dd(void);
//voidLCM_w_mo(void);
//voidLCM_w_yy(void);
//voidLCM_w_xq(void);
//voidDS1302InputByte(unsignedchard);
//unsignedcharDS1302OutputByte(void);
//voidInit_1302(void);
//unsignedcharRead1302(unsignedchar);
//voidSet_time(unsignedcharsel);
//voidWrite1302(unsignedchar,unsignedchar);
voidupdata(void);
codeunsignedchara0[]={"20"};
codeunsignedchara1[]={"年"};
codeunsignedchara2[]={"月"};
codeunsignedchara3[]={"日"};
codeunsignedcharb0[]={":
"};
codeunsignedcharb1[]={"星期"};
codeunsignedcharc0[]={"温度"};
codeunsignedcharc1[]={"℃"};
codeunsignedchard0[]={"总金额:
"};
/********************************************************/
/**/
/*DS18b20温度传感器程序段*/
/**/
/********************************************************/
/***10毫秒延时***/
voiddelay10ms()
{
uchara,b;
for(a=1;a>0;a--)
for(b=110;b>0;b--);
}
/*延时子程序,空5个指令*/
/*voiddelay(void)
{
_nop_();_nop_();_nop_();_nop_();_nop_();
}*/
/***延时子程序***/
voiddelayb(uintcount)
{
uinti;
while(count)
{
i=200;
while(i>0)
i--;
count--;
}
}
/***DS18B20初始化***/
voidInit_18b20(void)
{
uinti;
IO_18b20=0;
i=103;
while(i>0)i--;
IO_18b20=1;
i=4;
while(i>0)i--;
}
/***读一位数据值***/
bittmpreadbit(void)
{
uinti;
bitdat;
IO_18b20=0;i++;//i++,小延时一下
IO_18b20=1;i++;i++;
dat=IO_18b20;
i=8;while(i>0)i--;
return(dat);
}
/***读一个字节数据***/
uchartmpread(void)
{
uchari,j,dat;
dat=0;
for(i=1;i<=8;i++)
{
j=tmpreadbit();
dat=(j<<7)|(dat>>1);//读出的数据最低位在最前面,这样刚好//一个字节在
DAT里
}
return(dat);//将一个字节数据返回
}
/***写一个字节到DS18B20里***/
voidtmpwritebyte(uchardat)
{
uinti;
ucharj;
bittestb;
for(j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if(testb)//写1部分
{
IO_18b20=0;
i++;i++;
IO_18b20=1;
i=8;while(i>0)i--;
}
else
{
IO_18b20=0;//写0部分
i=8;while(i>0)i--;
IO_18b20=1;
i++;i++;
}
}
}
/***获取温度并转化命令***/
voidtmpchange(void)
{
Init_18b20();//初始化DS18B20
delayb
(1);//延时
tmpwritebyte(0xcc);//跳过序列号命令
tmpwritebyte(0x44);//发送温度转换命令
}
/***读取DS18B20中温度寄存器数据***/
uintget_temp()
{
floatftemp;
uchara,b;
tmpchange();
Init_18b20();
delayb
(1);
tmpwritebyte(0xcc);
tmpwritebyte(0xbe);//发送读取数据命令
a=tmpread();//连续读两个字节数据,读低8位
b=tmpread();//读高8位
temp=b;
temp<<=8;//temp高8位和低8位交换,将交换过的值重新赋给temp
。
不懂的看C语言基础书
temp=temp|a;//两字节合成一个字
ftemp=temp*0.0625;//得到真实十进制温度值,因为DS18B20可以精确到0.0625度
//所以读回数据的最低位代表的是0.0625度
temp=ftemp*10+0.5;
//放大十倍,这样做的目的将小数点后第一位也转换为可显示数字,同时进行一个四舍五?
氩僮鳌?
returntemp;//返回温度值
}
/***温度警告函数***/
/*voidtemp_warn()
{
uinti;
P0=0xff;
if(temp>250)//温度大于32度
{
i=5;
beep=1;
led1=~led1;
while(i--)
dis_temp(get_temp());//温度转化过程不能停
}
elseif(temp<190)
{
i=5;
beep=1;