基于单片机出租车计价器课题的设计c语言编写.docx
《基于单片机出租车计价器课题的设计c语言编写.docx》由会员分享,可在线阅读,更多相关《基于单片机出租车计价器课题的设计c语言编写.docx(30页珍藏版)》请在冰豆网上搜索。
基于单片机出租车计价器课题的设计c语言编写
单片机系统课程设计报告
完成日期:
2010年12月28日
系:
电子信息工程系
专业:
通信工程
班级:
071班
设计题目:
出租车计价器
学生姓名:
谢明七王勉
指导教师:
董玉华、许爽
一、设计任务和性能指标
1.1设计任务
出租车计价器是乘客与司机双方的交易准则,它是出租车行业发展的重要标志,是出租车中最重要的工具。
它关系着交易双方的利益。
具有良好性能的计价器无论是对广大出租车司机朋友还是乘客来说都是很必要的。
出租车计价器的主要功能是计价显示、时钟显示、根据白天、黑夜、途中等待来调节营运参数、计量数据查询等。
要求用Protel画出系统的电路原理图(要求以最少组件,实现系统设计所要求的功能),印刷电路板(要求布局合理,线路清晰),绘出程序流程图,并给出程序清单(要求思路清晰,尽量简洁,主程序和子程序分开,使程序有较强的可读性)。
1.2性能指标
1.不同情况具有不同收费标准:
白天、晚上、途中等待(>10min开始收费);
2.数据输出:
单价输出、路程输出、总金额输出;
3.按键:
启动计时开关、数据显示切换、白天/晚上切换、复位;
能手动进行修改单价,但单价设定需密码进入。
二、设计方案
2.1任务分析
出租车计价器基本功能部分是根据里程数来完成总金额的输出。
实现方法有两种。
方案一:
采用数字电路控制。
其原理方框图如图2.1所示。
采用传感器件,输出脉冲信号,经过放大整形作为移位寄存器的脉冲,实现计价,但是考虑到这种电路过于简单,性能不够稳定,而且不能调节单价,也不能根据天气调节计费标准,电路不够实用。
图2.1数字电路实现框图
方案二:
采用单片机控制。
利用单片机丰富的IO端口,及其控制的灵活性,实现基本的里程计价功能和价格调节、时钟显示功能。
本方案有较大的活动空间,不但能实现所要求的功能而且能在很大的程度上扩展功能,而且还可以方便的对系统进行升级,所以我们采用后一种方案。
2.2系统设计
图2.1电路系统构成框图
主控芯片使用51系列AT89C52单片机,采用高性能的静态80C51设计,由先进工艺制造,并带有非易失性Flash程序存储器。
它是一种高性能、低功耗的8位COMS微处理芯片,市场应用最多。
时钟芯片使用美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟芯片DS1302。
采用DS1302作为主要计时芯片、可以做到计时准确。
更重要的是,DS1302可以在很小的电流的后备电源(2.5~5.5V电源,在2.5V时耗电小于300nA)下继续计时,并可编程选择多种充电电流对后备电源进行慢速充电,可以保证后备电源基本不耗电。
采用串行数据传输,与单片机硬件连接简单,如果使用时钟芯片DS12887,将采用并行数据传输,占用更多的硬件资源。
因此为节省单片机端口,时钟芯片采用DS1302。
它们可以检测磁场及其变化,可在各种与磁场有关的场合中使用。
霍尔器件以霍尔效应为其工作基础。
霍尔器件具有许多优点,它们的结构牢固,体积小,重量轻,寿命长,安装方便,功耗小,频率高(可达1MHZ),耐振动,不怕灰尘、油污、水汽及盐雾等的污染或腐蚀。
活儿现行器件的精度高、线性度好;霍尔开关器件无触点、无磨损、输出波形清晰、无抖动、无回跳、无知重复精度高(可达Im级)。
采用了各种步长和保护措施的霍尔器件的工作温度范围宽,可达-55摄氏度~150摄氏度。
数据显示模块采用的是LED数码管显示,LCD虽然也能实现显示功能,但在距屏幕1米之外就无法看清数据,不能满足要求,而且在白天其对比度也不能满足要求,因此建议采用LED数码管显示。
数码管总共用了12个,其中第一行显示小时和分钟,第二行第一个显示单价,后面3个显示里程数,最后一行显示总价。
按键控制模块使用了3个脉冲开关,其中一个开关负责换位,另一个负责改数,第三个按键负责切换至等待时间。
三系统硬件设计
3.1电源电路
因为出租车上的电压时12V,而芯片所需供电电压是5V,所以选择LM7805的经典电路电源电路完成12V转5V的目的。
电源电路图如下图3.1所示:
图3.1电源电路图
3.2单片机的最小系统
单片机最小系统采用的是STC89C54芯片,STC89C54是一种低功耗、高新能CMOS8为微控制器,具有8K在系统可编程Flash存储器。
使用Atmel公司高密度非易失性存储器技术制造,与工业80C51铲平指令和引脚完全兼容。
偏上FLASH允许程序存储器在系统可编程,亦适于常规编程器。
在单芯片上,拥有平桥的8为CPU何在系统可编程Flash,使得STC89C54为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。
STC89C54具有以下标准功能:
8K字节Flash,256字节RAM,32位I/O口线,看门狗定时器,2个数据指针,三个16为定时器/计数器,一个6向量2级终端结构,全双工串行口,片内晶振及时钟电路。
另外,AT89S52可降至0HZ静态逻辑操作,支持2中软件可选择节点模式。
空闲模式下,CPU停止工作,允许RAM、定时器/计数器、串口、终端继续工作。
掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。
单片机最小系统电路图如下图3.2所示:
图3.2单片机最小系统电路图
3.3DS1302时钟电路
若采用单片机计时,一方面需要采用计数器,占用阴间资源,另一方面需要设置终端、查询等,同样耗费单片机的资源,并且使用单片机的时钟误差比较大,当长时间使用后会,会出现很大错误,而在系统中采用DS1302则能很好的解决这个问题。
DS1302时钟电路图如图3.3所示:
图3.3DS1302时钟电路图
3.4显示电路的设计
在显示模块需要对时间、单价、总价、路程、等待时间进行显示,采用的是LED数码管,数码管总共用了12个,其中第一行显示小时和分钟,第二行第一个显示单价,后面3个显示里程数,最后一行显示总价。
显示电路图(一个数码管)如下图3.4所示:
图3.4显示电路图
3.5按键控制的设计
按键的设置是为了能够手动更改时间和单价,还有就是手动切换到等待时间的地方,按键采用的是脉冲按键。
按键设置电路图如图3.5所示:
图3.5按键控制电路图
3.6掉电保护
掉电存储单元的作用是在电源断开的时候,存储当前设定的单价信息。
掉电保护的芯片较多,如AT24C02是ATMEL公司的2KB字节的电可擦除存储芯片,采用两线串行的总线和单片机通讯,电压最低可以到2.5V,额定电流为1mA,静态电流10Ua(5.5V),芯片内的资料可以在断电的情况下保存40年以上,而且采用8脚的DIP封装,使用方便。
掉电保护电路图如下图3.6所示:
图3.6掉电保护电路图
3.7复位电路
复位功能采用的是MAX813L芯片。
MAX813L是具有监控电路的微处理芯片,它具有4个功能:
1具有独立的看门狗计时器,如果看门狗输入在1.6秒内无变化,就会产生看门狗输出;2掉电或电源电压低于1.25V时,产生掉电输出;3上电时能自动产生200ms宽的复位脉冲;4具有人工复位功能,当人工复位端输入低电平时,产生复位信号输出。
复位电路如图3.7所示:
图3.7复位电路图
四、系统软件设计
4.1主程序设计
程序的难度主要就是在数码管的显示和外部脉冲的采集部分,分别采用74LS273芯片对数码管进行段选,使数码管显示对应的数,另外使用74LS154对数码管进行位选,选择哪个数码管亮,采用的是动态显示。
还有外部脉冲的收集,需要对里程数进行显示,所以必须要先进行脉冲的采集。
程序流程图如图4.1所示:
图4.1程序流程图
4.2子程序设计
4.2.1DS1302子程序
4.2.1DS1302子程序流程图
显示单价、总价、路程、时间等数据,循环扫描进行显示。
(如果在一分钟内没有脉冲,开启终端,显示秒分子程序。
DS1302子程序流程图如4.2.1所示:
图4.2.1DS1302子程序流程图
4.2.2显示子程序
voidsett()//显示等待时间及单价、总价、路程子程序
{TAB[0]=Read1302(0x83)/10;
TAB[1]=Read1302(0x83)%10;
TAB[7]=Read1302(0x81)/10;
TAB[6]=Read1302(0x81)%10;TAB[8]=3;
TAB[2]=Coo/100;TAB[3]=Coo/10%10;
TAB[4]=Coo%10;
if(TAB[4]<=3&&TAB[2]==0&&TAB[3]==0)
{TAB[11]=8;}
else{
TAB[11]=(8+(Coo-3)*TAB[8])%10;}
TAB[5]=TAB[2]*TAB[8]/10;
TAB[9]=Coo/100*TAB[8]+Coo%100*TAB[8]/100;
TAB[10]=(Coo/10*TAB[8]+Coo%10*TAB[8]/10)%10;}
voidmmm()//显示时间子程序
{TAB[0]=Read1302(0x85)/10;
TAB[1]=Read1302(0x85)%10;
TAB[7]=Read1302(0x83)/10;
TAB[6]=Read1302(0x83)%10;TAB[8]=3;}
TAB[11]=(8+(Coo-3)*TAB[8])%10;}
TAB[5]=TAB[2]*TAB[8]/10;
TAB[9]=Coo/100*TAB[8]+Coo%100*TAB[8]/100;
TAB[10]=(Coo/10*TAB[8]+Coo%10*TAB[8]/10)%10;}
voidmm()//非计价时的显示时间
{
TAB[0]=Read1302(0x85)/10;
TAB[1]=Read1302(0x85)%10;
TAB[7]=Read1302(0x83)/10;
TAB[6]=Read1302(0x83)%10;TAB[8]=3;
TAB[2]=Coo/100;TAB[3]=Coo/10%10;
TAB[4]=Coo%10;
if(TAB[4]<=3&&TAB[2]==0&&TAB[3]==0)
{TAB[11]=8;}
else{
TAB[11]=(8+(Coo-3)*TAB[8])%10;}
TAB[5]=TAB[2]*TAB[8]/10;
TAB[9]=Coo/100*TAB[8]+Coo%100*TAB[8]/100;
TAB[10]=(Coo/10*TAB[8]+Coo%10*TAB[8]/10)%10;}
4.2.2显示子程序流程图
显示子程序流程图如图4.2.2所示:
图4.2.2显示子程序流程图
4.3修改时间子程序
修改TAB数组里的前5位数据,分别为小时、分钟、单价.
五、调试及性能分析
5.1 调试步骤
5.1.1硬件调试
错误1:
LM7805封装时2脚和3脚弄混
解决办法:
1、将LM78052脚和3脚手工矫正
2、利用飞线重新手工焊接
错误2:
进行原理图设计时,电源网络标号不一致(74LS14、74HC154电源网络标号与其他的不一致)
解决办法:
利用飞线,将错误的网络标号和正确的网络标号进行手工焊接。
错误3:
1K*9排阻焊反
解决办法:
手工拔出,重新焊接
错误四:
在焊接时,由于焊接时间过长,造成三极管烧坏
解决办法:
手工拔出重新焊接
错误5:
有些器件焊接次数过于频繁,造成印刷板上焊盘和导线脱落
解决办法:
利用飞线将对应的网络标号进行连接
5.1.2软件调试:
在软件编程时,应充分利用原理图,不然会在编程时导致硬件与软件不能对应起来,使程序无法实现功能,还有在编程时子程序的名称应与其功能对应,否则会使别人在读程序的时候不能及时理解程序含义,而且在软件调试时逻辑一定要清晰,不然在找错时会浪费很多时间,
5.2性能分析
通过软件调试后,最终能实现实时时钟显示、里程数的显示、单价的显示、总价的显示、时间的调整、等待时间的显示。
时间显示模块使用的是时钟芯片DS1302,它精确度高,功能强大,使用它能降低单片机的负荷,减小误差。
里程数收集模块由于条件限制,所以我们使用一个外部脉冲信号作为里程数的收集,用一个脉冲表示一公里,最大的里程数可达256公里。
电源模块部分由于经验问题,没有在PCB板上加上串口和USB口,使得电源不稳,只能用导线在外部加一个5V电压,而且由于7805的封装引脚分配有错误,导致在最初调试的时候芯片烧坏,所以最终放弃7805的电压转换,而直接使用+5V电压。
显示模块使用LED数码管,通过软件调试,12个数码管能显示时间、总路程、单价、总价及等待时间的自动切换。
六、心得体会
由于初次进行硬件电路设计,出现了很多简单又致命的错误(见硬件调试)。
5个错误在一块线路密集并且已经焊好器件的电路板上无疑是大海捞针。
像器件焊反之类的错误还比较好排除。
而器件损坏和网络标号不一致这样的错误就很让人头疼。
仅仅只是网络标号不一致这个错误就让我们整整测试了一天才发现。
所以下次设计硬件电路的时候一定要找几个人仔细检查电路图,不能再轻易犯这样的错误。
像印刷板上导线断裂这样的错误也比较难找。
而这种错误往往是焊接时温度过高或者是焊接过于频繁造成的,所以以后焊接的时候一定不会再犯这样的错误了。
而且由于当初设计USB口和串行口,为软件调试造成了很大的麻烦(每天不停地拔单片机)。
再做学生实验的时候不能太过于追求趋近于真实产品。
过于追求真实会让你的实验过程变得极其困难。
真的是后悔不已。
当初想利用以前做的单片机最小系统开发板上的串行口进行程序下载,但是到真正实行的时候在发现并不是那么回事。
由于对单片机的要求达不到,虽然理论上天衣无缝,但实际上根本不可能实现。
虽然出租车上提供的电源是12V,即便在实验板上设计了电源电路也应该再加上一个USB口提供5V电源。
因为除了在实验室其他地方是并不太容易找到12V电源。
由于对USB口的省略,对软件调试工作造成了很大的麻烦。
七、参考文献
[1]徐维祥、刘旭敏.单片微型机原理及应用.大连:
大连理工大学出版社,1996
[2]戴胜华,蒋大明 单片机原理与应用 北京:
清华大学出版社 2005
[3]李刚 新概念单片机教程 天津:
天津大学出版社 2004
[4]王宗和 单片机实验与综合训练 北京 高等教育出版社2000
八、附录
附录1、程序清单
#include"reg51.h"
#include"intrins.h"
#defineucharunsignedchar
uchartmp;
uchardet;
ucharCoo;
intm;
intf;
ucharcodeDispTab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xc0};//字形码
ucharTAB[24];
sbitP00=P0^0;
sbitP01=P0^1;
sbitP02=P0^2;
sbitP03=P0^3;
sbitP04=P0^4;
sbitP05=P0^5;
sbitP10=P1^0;
sbitP27=P2^7;
sbitP14=P1^4;
sbitSCLK=P1^3;/*DS1302的SCLK脚脉冲*/
sbitDIO=P1^2;/*DS1302的IO脚数据*/
sbitCE=P1^1;/*DS1302的RST脚片选*/
sbitP15=P1^5;
sbitP23=P2^3;
sbitP21=P2^1;
sbitP16=P1^6;
sbitP35=P3^5;
sbitP22=P2^2;
sbitP17=P1^7;
sbitP20=P2^0;
sbitP26=P2^6;
sbitP24=P2^4;
sbitACC7=ACC^7;
sbitACC0=ACC^0;
voidtime()interrupt1//等待计时中断
{inti,j;TH0=0x15;
TL0=0xa0;i++;
if(i==100){i=0;j++;};
if(j==10){j=0;f=Coo;}}
voidmDelay(unsignedintDelay)//延时子程序
{unsignedintI;
for(;Delay>0;Delay--)
{for(I=0;I<124;I++)
{;}
}}
voidWrite1302(unsignedcharaddr,dat)//DS1302写程序
{
unsignedchari,temp;
CE=0;//CE引脚为低,数据传送中止
SCLK=0;//清零时钟总线
CE=1;//CE引脚为高,逻辑控制有效
//发送地址
for(i=8;i>0;i--)//循环8次移位
{
temp=addr;
DIO=(bit)(temp&0x01);//每次传输低字节
addr>>=1;
SCLK=0;//右移一位
SCLK=1;
}
//发送数据
for(i=8;i>0;i--)
{
temp=dat;
DIO=(bit)(temp&0x01);
dat>>=1;
SCLK=0;
SCLK=1;
}
CE=0;
}
unsignedcharRead1302(unsignedcharaddr)//数据读取子程序
{
unsignedchari,temp,dat1,dat2;
CE=0;
SCLK=0;
CE=1;
//发送地址
for(i=8;i>0;i--)//循环8次移位
{
temp=addr;
DIO=(bit)(temp&0x01);//每次传输低字节
addr>>=1;
SCLK=0;
SCLK=1;//右移一位
}
//读取数据
for(i=8;i>0;i--)
{
ACC7=DIO;
ACC>>=1;
SCLK=1;
SCLK=0;
}
CE=0;
dat1=ACC;
dat2=dat1/16;//数据进制转换
dat1=dat1%16;//十六进制转十进制
dat1=dat1+dat2*10;
return(ACC);
}
voidInitial()//初始化DS1302
{
Write1302(0x8E,0x00);//禁止写保护
Write1302(0x80,0x00);//秒位初始化
Write1302(0x82,0x20);//分钟初始化
Write1302(0x84,0x10);
Write1302(0x86,0x23);
Write1302(0x88,0x05);
Write1302(0x8c,0x10);//小时初始化
Write1302(0x8E,0x80);//允许写保护
}
voidset()//修改时间
{
Write1302(0x8E,0x00);//禁止写保护
Write1302(0x82,TAB[7]*16+TAB[6]);//分钟初始化
Write1302(0x84,TAB[0]*16+TAB[1]);
Write1302(0x8E,0x80);}
voidss()//显示子程序
{inti;uchar*p;p=TAB;
for(i=0;i<1;i++){
det=*p;
tmp=DispTab[det];
P0=tmp;P20=0;P20=1;
P14=0;P15=0;P16=0;P17=0;p++;
det=*p;
tmp=DispTab[det];
P0=tmp;
P20=0;P20=1;P14=1;P15=0;P16=0;P17=0;p++;
det=*p;
tmp=DispTab[det];
P0=tmp;P20=0;P20=1;P14=0;P15=1;P16=0;P17=0;p++;
det=*p;
tmp=DispTab[det];
P0=tmp;P20=0;P20=1;P14=1;P15=1;P16=0;P17=0;p++;
det=*p;
tmp=DispTab[det];
P0=tmp;
P20=0;P20=1;P14=0;P15=0;P16=1;P17=0;p++;
det=*p;
tmp=DispTab[det];
P0=tmp;P20=0;P20=1;P14=1;P15=0;P16=1;P17=0;p++;
det=*p;
tmp=DispTab[det];
P0=tmp;P20=0;P20=1;P14=0;P15=1;P16=1;P17=0;p++;
det=*p;
tmp=DispTab[det];
P0=tmp;P20=0;P20=1;P14=1;P15=1;P16=1;P17=0;p++;
det=*p;
tmp=DispTab[det];
P0=tmp;P20=0;P20=1;P14=0;P15=0;P16=0;P17=1;p++;
det=*p;
tmp=DispTab[det];
P0=tmp;P20=0;P20=1;P14=1;P15=0;P16=0;P17=1;p++;
det=*p;
tmp=DispTab[det];
P0=tmp;P20=0;P20=1;P14=0;P15=1;P16=0;P17=1;p++;
det=*p;
tmp=DispTab[det];
P0=tmp;P20=0;P20=1;P14=1;P15=1;P16=0;P17=1;p++;
det=*p;
tmp=DispTab[det];
P0=tmp;P20=0;P20=1;P14=0;P15=0;P16=1;P17=1;p++;
}}
voidsett()//显示等待时间及单价、总价、路程子程序
{TAB[0]=Read1302(0x83)/10;
TAB[1]=Read1302(0x83)%10;
TAB[7]=Read1302(0x81)/10;
TAB[6]=Read1302(0x81)%10;TAB[8]=3;
TAB[2]=Coo/100;TAB[3]=Coo/10%10;
TAB[4]=Coo%10;
if(TAB[4]<=3&&TAB[2]==0&&TAB[3]==0)
{TAB[11]=8;}
else{
TAB[11]=(8+(Coo-3)*TAB[8])%10;}
TAB[5]=TAB[2]*TAB[8]/10;
TAB[9]=Coo/100*TAB[8]+Coo%100*TAB[8]/100;
TAB[10]=(Coo/10*TAB[8]+Coo%10*TAB[8]/10)%10;}
voidmmm()//显示时间子程序
{TAB[0]=Re