第一篇:出租车智能计价器的设计与实现探讨论文
0 引言
出租车作为城市交通中独特的交通工具,在城市交通运营中具有不可替代的重要作用。出租车司机最关心计价器的营运数据管理是否方便,而乘客往往最在意出租车计价计费是否合理。为了减少出租车司机和乘客间不必要的误会,设计既能准确计价又能方便使用的计价器显得非常重要。
科技在不断发展,社会在快速进步,出租车计价系统也需不断地得到优化。文中以嵌入式单片机AT89C51为主控MCU,设计多功能出租车智能计价器。此计价器能够按实际情况综合计价,并将乘车用时、行驶里程和乘车费用等重要信息显示出来,具有功能更齐全、系统更稳定、使用更方便等优势。出租车智能计价系统总体设计
利用AT89C51作为单片机核心器件设计的智能计价系统,使用方便、灵敏性好,其强大的控制处理功能和可扩展功能为设计电路提供了很好的选择。利用其I/O端口及其控制的多功能特点,采用按键控制进行分屏显示,实现基本乘车计价和信息显示功能。
在系统硬件设计中,以AT89C51单片机为控制中心,外接A44E霍尔传感器信号采集模块、时钟模块、按键模块、显示模块以及掉电保护存储模块。其中,选用A44E霍尔传感器信号采集模块可将磁感应转换为脉冲信号,从而计测出行车里程;时钟模块采用DS1302芯片,设置标准时钟;掉电存储模块采用AT24C02芯片,以确保掉电时数据自动保存在存储单元;当系统重新上电时,能自动读取数据;按键模块采用四个按键控制,可实现分屏显示功能;显示模块采用8位LED数码管进行显示。系统软件设计
2.1 系统主程序
在主程序模块中,不仅需要完成参量和接口的初始化设计、出租车起步价和单价的设置以及中断、计算等操作,还应设置启动/清除标志、里程以及价格寄存器,并对其进行初始化。最后,为实现寄存器中内容的完整性及精确性,主程序应能分别完成启动、清除、计程及计费等操作。
当出租车起步运行时,计价器同时启动开始计价,根据里程寄存器中的存储数据进行运算并判别行驶路程是否超过起步价的里程。若已超过起步价里程,则根据里程值、单价数和起步价等来综合计算当前的乘车费用;当处于等待时段时,若无脉冲输入,不产生中断,一旦等待时间超过预设时间则会把等待超标费用另加到乘车总费用中,并显示相关信息。
2.2 系统模块程序
系统模块程序主要包括五个服务程序:显示子程序、里程计数中断、定时中断、中途等待中断和按键服务程序。各服务程序介绍如下:
(1)显示子程序。由于采取的是分屏数据显示方式,因此需要用到4 款显示子程序:时、分、秒的显示,金额单价的显示,路程单价的显示以及标准时间的显示。
(2)里程计数中断。霍耳传感器每输出一个低电平信号便中断一次,当里程计数器计满1000个里程脉冲时,便将当前计数送至里程计数中断服务程序,并将当前行车里程及相关数据传至行车里程与乘车费用寄存器中。
(3)定时中断。在定时中断服务程序中,设置一次中断时间为50ms,20 次中断时间为1s,计满1s后将数据送到相应显示单元实时显示。
(4)中途等待中断。在计数状态下霍耳开关无信号输出时,片内定时器启动。等待计时每达到5分钟,就会在当前金额基础上自动加上中途等待费用。等待结束后计价系统自动转换到正常计价程序。
(5)按键服务程序。按键服务采取查询模式,设置在主程序中。当无按键按下时,单片机循环运行主程序;按键被按下,则转向运行相应子程序,并进行其他操作处理。系统仿真与功能实现
3.1 仿真软件Proteus简介
Proteus仿真软件是英国Labcenter Electronics公司设计开发的EDA工具,它不但拥有其它工具软件的仿真功能,而且可仿真微处理器和相关外围设备。Proteus软件功能强大:拥有Proteus电子设计工具,就等同搭建了一个电子设计和分析平台。利用功能强大的Proteus仿真软件,我们可以实现对电路的仿真,以确定方案是否可行,并且可使设计过程流畅。
3.2 电路功能仿真
首先通过Proteus平台搭建电路,然后在KEIL中编写相应代码,并将生成的HEX文件在Proteus平台单片机模型中加载,便可看到仿真效果。系统实验及结果分析
按原理图进行焊接,确保接线无误后。对实物进行调试与实验。实验结果表明,利用AT89C51主控,霍尔传感器进行采集,AT24C02进行掉电存储保护,配以程序,就能较好地实现出租车智能计价功能。结论
文中设计的出租车智能计价系统能够实时存储相关数据,并通过8位LED数码管分屏显示存储数据,实现基本的计价功能。本系统对乘车中可能出现的情况考虑较全面,能根据白天、夜晚、中途等待等不同情况来调节单价,从而达到出租车智能计价的目的。当然,要达到大规模的实际应用要求,还需不断改进和完善系统综合性能指标,以达到实际应用要求。
第二篇:出租车计价器设计范文
平顶山工业职业技术学院
目录
目录......................................................................................................................................................1 前言......................................................................................................................................................2 第一章 系统工作原理........................................................................................................................2 1.1 功能说明..............................................................................................................................2 1.2 基本原理..............................................................................................................................2 第二章 硬件设计...............................................................................................................................3 2.1 单片机最小系统单元..........................................................................................................3 2.2 A44E霍尔传感器检测单元................................................................................................4 2.3 AT24C01存储单元..............................................................................................................6 2.4 键盘调整单元......................................................................................................................7 2.5 显示单元..............................................................................................................................8 第三章 软件设计...............................................................................................................................8 3.1 系统主程序..........................................................................................................................8 3.2 中断程序..............................................................................................................................9 3.2.1 里程计数中断程序...................................................................................................9 3.2.2 中途等待中断程序.................................................................................................10 3.3 计算程序............................................................................................................................10 3.4 显示程序............................................................................................................................10 3.5 键盘程序............................................................................................................................10 第四章 总结.....................................................................................................................................11 参考文献............................................................................................................................................12
平顶山工业职业技术学院
算出行驶公里数,再根据从EEPROM中读取的价格等相关数据进行金额的计算,计算好的金额、里程和单价都实时地显示在数码管上。独立键盘可以调节价格等相关数据,按下相应的按钮,产生信号交由单片机处理并实时显示出来,调节好的数据存储到EEPROM中,掉电后可以使调好的数据不丢失,下次得电后直接从EEPROM读到单片机,系统结构图如图1。
图1 系统结构图
第二章 硬件设计
2.1 单片机最小系统单元
主控机系统采用了Atmel 公司生产的 AT89S52单片机,它含有256 字节数据存储器,内置8K 的电可擦除FLASH ROM,可重复编程,大小满足主控机软件系统设计,所以不必再扩展程序存储器。复位电路和晶振电路是AT89S52 工作所需
平顶山工业职业技术学院 的最简外围电路。单片机最小系统电路图如图2所示。
图2 单片机最小系统图
AT89S52 的复位端是一个史密特触发输入,高电平有效。RST端若由低电平上升到高电平并持续2个周期,系统将实现一次复位操作。在复位电路中,按一下复位开关就使在RST端出现一段时间的高电平,外接11.0592M 晶振和两个30pF 电容组成系统的内部时钟电路。
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霍尔传感器原理如图3所示。
平顶山工业职业技术学院
图3 A44E霍尔传感器原理
里程计算是通过安装在车轮上的霍尔传感器检测到的脉冲信号,送到单片机产生中断,单片机再根据程序设定,计算出里程。其原理如图4所示。
图4 传感器测距示意图
本系统选择了将A44E的脉冲输出口接到P3.3口外部中断1作为信号的输入端(这样可以减少程序设计的麻烦),车轮每转一圈(设车轮的周长是1米),霍尔开关就检测并输出信号,引起单片机的中断,对脉冲计数,当计数达到1000次时,即1公里,单片机就控制将金额自动增加,如图5。
图5 A44E霍尔元件接线图
平顶山工业职业技术学院
2.3 AT24C01存储单元
存储单元的作用是在电源断开的时候,存储当前设定的单价信息。AT24C01 是Ateml公司的1KB的电可擦除存储芯片,采用两线串行的总线和单片机通讯,电压最低可以到2.5V,额定电流为1mA,静态电流10uA(5.5V),芯片内的资料可以在断电的情况下保存40年以上,而且采用8 脚的DIP 封装,使用方便。AT24C02芯片引脚配置如图6所示。
存储单元电路连接如图7所示。
图 7 存储单元电路原理图
图中R4、R5 是上拉电阻,其作用是减少AT24C01 的静态功耗。由于AT24C01的数据线和地址线是复用的,采用串口的方式传送数据,所以只用两根线SCL(时钟脉冲)和SDA(数据/地址)与单片机P2.2和P2.3口连接,进行传送数据。
平顶山工业职业技术学院
每当设定一次单价,系统就自动调用存储程序,将单价信息保存在芯片内;当系统重新上电的时候,自动调用读存储器程序,将存储器内的单价等信息,读到缓存单元中,供主程序使用。
2.4 键盘调整单元
当单价等信息需要进行修改时,就要用到键盘进行修改。由于调节信息不多,故采用4个独立键盘即可,分别实现清零、切换、增大、减小和功能等作用。电路原理如图8所示。
图8 键盘调整单元接线图
S1:接P1.0口,对上一次的计费进行清零,为下次载客准备
S2:接P1.1口,实现白天和夜晚单价的切换;当功能键S4按下时,S2可对数据进行增大。
S3:接P1.2口,当功能键S4按下时,S3可对数据进行减小。
S4:接P1.3口,按1次,进入调整白天单价;按2次,进入调整夜晚单价;按3次,进入调整等待单价;按4次,进入调整起步价;按5次,返回。
平顶山工业职业技术学院
2.5 显示单元
显示单元由7个8段共阳数码管组成,采用动态扫描进行显示。前三个数码管分别接P3.0、P3.1和P3.2,用于显示总金额;中间两个分别接P3.4和P3.5,用于显示里程;后边两个分别接P3.6和P3.7,用于显示单价。电路如图9所示。
图9 数码管显示图
第三章 软件设计
3.1 系统主程序
在主程序模块中,需要完成对各参量和接口的初始化、出租车起价和单价的初始化以及中断、计算、循环等工作。另外,在主程序模块中还需要设置启动/清除标志寄存器、里程寄存器和价格寄存器,并对它们进行初始化。然后,主程序将根据各标志寄存器的内容,分别完成启动、清除、计程和计价等不同的操作。当汽车运行起来时,就启动计价,根据里程寄存器中的内容计算和判断行驶里程是否已超过起步价公里数。若已超过,则根据里程值、每公里的单价数和起步价数来计算出当前的总金额,并将结果存于总金额寄存器中;中途等待时,无脉冲输入,不产生中断,当时间超过等待设定值时,开始进行计时,并把等待价格加到总金额里,然后将总金额、里程和单价送数码管显示出来。程序流程如图10所示。
平顶山工业职业技术学院
图10 主程序流程图
图11 计算程序流程图
3.2 中断程序
3.2.1 里程计数中断程序
每当霍尔传感器输出一个低电平信号就使单片机中断一次,当里程计数器对里程脉冲计满1000次时,进入里程计数中断服务程序中,里程变量加一。主函数中总金额也相应地变化。
101112-
第三篇:出租车计价器
基于单片机的出租车计价器设计
摘要
出租车计价器的数字系统的设计正是基于一些专用的芯片,才发挥其有效特性,从而实现出租车的计价功能。此数字系统主要分为三个单元,即里程计数及显示单元、价格计数及显示单元、脉冲产生。本设计是一个基于单片机AT89C51的出租车自动计费设计,附有复位电路,时钟电路等。关键词:出租车计费器;单片机;控制
Abstract Taximeter design digital system is based on some special chip, to play their effective characteristics, thus realizing the taxi valuation function.This system is mainly divided into there modules, namely the mileage counting and display unit, and display unit price counting, pulsing.The design is based on a single chip AT89C51taxis design, a reset circuit, clock circuit.Keywords:taximeter,a single-chip microcomputer,control
1引言
1.1 设计目的
近几年来,出租汽车行业在各地得以蓬勃发展,但采用模拟电路和数字电路设计的计价器整体电路的规模较大,用到的器件多,造成故障率高,难调试。而采用单片机进行的设计,相对来说功能强大,用较少的硬件和适当的软件相互配合可以很容易地实现设计要求,且灵活性强。
1.2 功能要求
(1)用前4位数码管实时显示里程数,单位为千米,最后一位为小数位;用后4位数码管时时显示金额数,单位为元,最后一位为小数位。
(2)规定出租车里程小于2千米收费5元,超过2千米收费为8*(way-20)/5。
1.3 设计方法
本设计采用AT89C51单片机为主控器,并用频率信号发生器模拟车速,利用AT89C51的定时器工作在方式1下定时实现对出租车的计价设计,输出采用共阴极的集成8位7段数码显示管。设计方案及原理
2.1 设计方案
采用AT89C51单片机为主控器,并用频率信号发生器模拟车速,利用AT89C51的定时器/定时器T1工作在方式1下定时实现对出租车的计价设计,输出采用共阴极的集成8位7段数码显示管。本电路设计的计价器不但能实现基本的计价,而且
单片机原理及系统课程设计报告
还能根据里程来调节单价。
2.2 设计原理
出租车计价是根据车所行驶的路程以及乘客乘车的里程综合决定的。出租车行驶总路程可以通过车轮的周长乘车轮旋转圈数得到。即可计算得到车轮旋转几周出租车能行驶一公里的路程。通过计数接收到的脉冲个数,计算出当前所行驶的路程。同时,通过数码管显示当前的行驶里程和需支付的车费。出租车计价器用于记录里程、起步公里数与价格的关系。模拟出租车计价器能根据总里程数、起步公里数的情况作出相应报价等。这个系统以AT89C51单片机为主控器,单片机的计数器/定时器T1工作在方式1下来对外部脉冲计数,最后通过集成的8位7段LED数码管显示里程数和价钱。总体模块框图如图1所示。
总金额显示单价显示AT89C51脉冲产生动态扫描数码管显示
图1 总体框图 硬件设计
对于AT89C51的计数器/定时器T1,通过对寄存器TCON的设置,即使它的M1M0=01,计数器/定时器T1工作在方式1下,构成16位计数器/定时器。此时TH0、TL0都是8位加法计数器。此设计中,T1为计数工作方式,计数范围为1~2^16=1~65536(个外部脉冲)。当计数溢出时则置位并申请中断,进入中断服务 执行中断程序。
通过74HC138接P20、P21、P22输出来对8位7段的智能扫描LED进行段选,并且通过P1口对LED进行位选,最后将结果显示在LED上。硬件设计图如图2所示。
74HC138是三八译码器,在工作之前,使74HC138的使能端有效,再使74HC138的A、B、C接P20、P21、P22的输出达到对LED位选线的控制,使相应的位显示相应的结果。硬件总设计图如图2所示。
第四篇:出租车计价器调试报告
出租车计价器调试报告
本设计可分为单片机主控模块、键盘、显示器、温度检测、状态指示、时钟日历、语音收录播报、分频器电路、脉冲信号发生器等9部分。仔细分析系统的工作原理,分别按照模块在系统中的作用,对各个模块分别单独调试,最后形成该系统的用户程序,实现功能要求。
一、接通电源
调试要求:1.首先仔细检查该系统板的电源和地是否有短路问题,在未接入电源轻快下,使用万用表检验电源和地检查是否短路,如果没有短路,再仔细核查电源极性后予以通电,观察电源指示灯D1是否点亮。如果电源指示的灯不亮应立即关闭电源,并用手触摸各个芯片,检查是否用某芯片发热。如果没有发热的器件,很可能是电源指示二极管极性安装错误,或者是该发光二极管的串联电阻阻值偏大。
2.黑板上调试要求:(1)焊接好电路板加电前,用万用表测量板上Vcc 和
GND之间的电阻,应大于1KΩ
(2)加电后测量电路板上各电压,应大于4.2V 调试结果:1.经万用表检验,电路板无短路问题。
2.通电后,D1指示灯点亮。
3.测量Vcc 与 地之间的电阻,1.14KΩ > 1KΩ
4.测量Vcc与 地之间的电压:4.28V > 4.20V
二、测试状态指示
本系统中状态指示二极管共有3个,它们分别是D1、D2、D3。D1是指示电源的,可以在电源接通时直接看到,D2用于指示语音芯片的工作状态,留作语音模块调试时观察。D3是可以由单片机的引脚控制的。
编写测试D3的程序: #include
sbit a_c=P1^0;extern serial_initial();
main(){ serial_initial();a_c=0;while(1);}
测试结果: 1.2.三、脉冲信号发生器测试
测试要求:该模块由5G555芯片构成一个多谐振荡器,使用示波器观察该芯片的第3引脚的波形,并调节电位器W1,观察输出波形及频率变化。
测试结果:
调整W1前,f=147.1Hz
调整W1后,f=130.5Hz
四、分频电路测试
测试要求:该模块由一个4位二进制计数器74HC161和一个多路选择器74HC153构成。调试时可以利用由5G555芯片构成一个多谐振荡器的输出,或信号发生器作为计数器74HC161的计数输入信号。值得注意的是控制多路选择器74HC153的S0、S1与单片机调试时所使用的引脚复用,要采取特殊措施才能正确试验检测。
测试结果:利用函数信号发生器生成一个方波,周期/频率如图:
其在输出端输出的波形为:
f1=3.881kHz
f2 =1.235kHz 分频功能无误。
五、键盘测试
测试要求:本系统相对比较简单,仅有5个按键,其中4个为系统功能键,它们分别是S1、S2、S3、S4,另一个是系统复位按键S6。对于系统复位按键S6可以在上电之后,使用万用表予以检查,按下该按键,单片机的第9脚应该为高电平,释放后应该为点电平。
对于系统功能键,编写如下程序予以测试检查:
#include
#define BIT_LED XBYTE[0x0a000] void display();sbit k1=P1^0;sbit k2=P1^1;sbit k3=P1^2;sbit k4=P1^3;unsigned char a;unsigned
char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x67,0x40,0x00,0x63,0x39,};void delay(unsigned int i);main(){ while(1){ if(k1==0)a=0x06;if(k2==0)a=0x5b;if(k3==0)a=0x4f;if(k4==0)a=0x66;display();} } 测试结果:对于复位键S6,按下前应为低电平,按下后应为高电平
按下前
按下后
对于S1—S4,按下前为高电平,按下后为低电平。其测试结果均符合预期。
六、动态数码管测试
测试要求:本系统中的数码管的原理采用的是动态扫描方式,即某一时刻只用一个数码管在显示,利用人的视觉暂留特性,让数码管高速轮流显示,达到完整显示的目的。
编写如下程序进行测试: #include
#define BIT_LED XBYTE[0x0a000] void displayhello();sbit k1=P1^0;sbit k2=P1^1;sbit k3=P1^2;sbit k4=P1^3;unsigned char a;unsigned char table[]={0x06,0x06,0x3f,0x3e,0x79,0x6e,0x3f,0x3e,0x7f,0x67,0x40,0x00,0x63,0x39,};void delayms(unsigned int i);main(){ while(1){ displayhello();} }
void displayhello(){
unsigned char BIT=1;
unsigned int i;
BIT_LED=1;
for(i=0;i<=7;i++)
{
SEGMENT=table[i];
BIT_LED=BIT;
BIT=BIT<<1;
delayms(1);
}
} void delayms(unsigned int i){ unsigned int n;while(i--){
for(n=0;n<125;n++);
} }
测试结果:显示“I love you”
由于是动态显示,所以按下复位键后,只有一个数码管点亮
七、温度传感器测试
测试要求:本系统使用的是一款单线温度传感器(DS18B20),可将温度穿换成12的数字量,以表示温度。
编写如下程序予以测试检查: #include
//段码寄存器地址 #define BIT_LED XBYTE[0x0a000]
//位码寄存器地址 #define fosc 11.0592
unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x67,0x40,0x00,0x63,0x39,};//分别显示0 1 2 3 4 5 6 7 8 9-o C
unsigned char table1[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};//分别显示0.1.2.3.4.5.6.7.8.9.unsigned char table2[]={0x76,0x79,0x38,0x38,0x3f};sbit k1=P1^0;sbit k2=P1^1;sbit k3=P1^2;unsigned char data display_buffer[13];unsigned char bdata data_ds1302;
unsigned char disbuf[]={0,0,0,0};sbit k4=P1^3;
sbit TMDAT=P3^4;
//温度入口
void dmsec(unsigned int count);void tmreset(void);
//ds18b20 reset void tmstart(void);
// void tmrtemp(void);void Disbuf(unsigned int temper);void displaytemper();void delay(unsigned int);main(){ display_buffer[0]=0x01;
display_buffer[1]=0x00;
display_buffer[2]=0x00;display_buffer[3]=0x08;
display_buffer[4]=0x05;
display_buffer[5]=0x00;display_buffer[6]=0x01;
display_buffer[7]=0x04;
display_buffer[8]=0x00;display_buffer[9]=0x05;
display_buffer[10]=0x00;
display_buffer[11]=0x01;
display_buffer[12]=0x04;while(1){ tmstart();
tmrtemp();
displaytemper();} }
void tmreset(void){
unsigned int i;
TMDAT = 0;
i = 103;while(i>0)i--;
TMDAT = 1;
i = 4;while(i>0)i--;}
void tmpre(void){
unsigned int i;
while(TMDAT);
while(~TMDAT);
i = 4;while(i>0)i--;}
bit tmrbit(void){
// ds1820
// Reset TX
unsigned int i;
bit dat;
TMDAT = 0;i++;
TMDAT = 1;i++;i++;
dat = TMDAT;
i = 8;while(i>0)i--;
return(dat);}
unsigned char tmrbyte(void){
unsigned char i,j,dat;
dat = 0;
for(i=1;i<=8;i++){
j = tmrbit();
dat =(j << 7)|(dat >> 1);
}
return(dat);}
void tmwbyte(unsigned char dat){
unsigned int i;
unsigned char j;
bit testb;
for(j=1;j<=8;j++){
testb = dat & 0x01;
dat = dat >> 1;
if(testb){
TMDAT = 0;
i++;i++;
TMDAT = 1;
i = 8;while(i>0)i--;
}
else {
TMDAT = 0;
i = 8;while(i>0)i--;
TMDAT = 1;
i++;i++;
}
} }
void tmstart(void){
tmreset();
tmpre();
// ds1820
displaytemper();//delay(100);
tmwbyte(0xcc);
tmwbyte(0x44);
}
void tmrtemp(void){
unsigned char a,xiao,b,y1,y2,y3;
tmreset();
tmpre();
delay(1);
tmwbyte(0xcc);
tmwbyte(0xbe);
a = tmrbyte();
b = tmrbyte();
xiao=a&0x0f;//小数部分
y1=a>>4;
y2=b<<4;
y3=y1|y2;if((b&0x0f8)==0x0f8)
{y3=~y3+1;
disbuf[0]=10;//显示符号
disbuf[1]=y3/10;
disbuf[2]=y3%10;
disbuf[3]=xiao*10*0.0625;} else
disbuf[0]=11;//不显示
disbuf[1]=y3/10;
disbuf[2]=y3%10;
disbuf[3]=xiao*10*0.0625;}
void displaytemper()
//温度显示函数
{ unsigned int i;unsigned char e=0x01;//<<1;for(i=1;i<6;i++)
{ switch(i)
{
case 1:{SEGMENT=table[disbuf[1]];BIT_LED=e;break;}
case 2:{SEGMENT=table1[disbuf[2]];BIT_LED=e;break;}
case 3:{SEGMENT=table[disbuf[3]];BIT_LED=e;break;}
case 4:{SEGMENT=table[12];BIT_LED=e;break;}
case 5:{SEGMENT=table[13];BIT_LED=e;break;}
}
e=e<<1;
delay(80);
}
BIT_LED=0;
}
void delay(unsigned int i)
//delay函数 {
while(i--);}
测试结果:
经传感器及数码管延时,温度重新显示
八、时钟日历测试
测试要求:本系统使用了时钟日历专用芯片,该芯片是以串行方式实现控制和数据传输的。
编写如下程序进行测试: #include
//段码寄存器地址 #define BIT_LED XBYTE[0x0a000]
//位码寄存器地址 #define fosc 11.0592
unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x67,0x40,0x00,0x63,0x39,};unsigned char table1[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};unsigned char table2[]={0x76,0x79,0x38,0x38,0x3f};sbit k1=P1^0;sbit k2=P1^1;sbit k3=P1^2;sbit k4=P1^3;//利用开关量实现切换
//频率变量及子函数预定义 void displayfreq();void read_freq();unsigned char tcount=0,timecount=0;unsigned long freq=0.0;bit freqflag=0;unsigned char fr[6];unsigned int i=0,x=0;
//日期变量及子函数预定义 sbit SCL_ds1302=P2^0;sbit IO_ds1302=P2^1;sbit RST_ds1302=P2^2;
unsigned char data display_buffer[13];unsigned char bdata data_ds1302;
//传输符
unsigned char disbuf[]={0,0,0,0};void open_write_bit();void initial_ds1302();unsigned char read_ds1302(char command);void close_write_bit();void read_time();void set_time();void delay(unsigned int i);void delayms(unsigned int i);void displaytime();void displaydate();main(){ initial_ds1302();
//上电走时
read_time();
//读取当前时间,放到数组中
display_buffer[0]=0x01;
display_buffer[1]=0x05;
display_buffer[2]=0x01;display_buffer[3]=0x07;
display_buffer[4]=0x04;
display_buffer[5]=0x00;display_buffer[6]=0x01;
display_buffer[7]=0x06;
display_buffer[8]=0x00;display_buffer[9]=0x05;
display_buffer[10]=0x00;
display_buffer[11]=0x01;
display_buffer[12]=0x04;
set_time();
//设置时间
while(1){
if(k1==0)
{
while(1){
read_time();
displaytime();
if(k2==0)break;
}
}
read_time();
displaydate();} }
void close_write_bit()//close write { unsigned int i;
SCL_ds1302=0;
_nop_();
RST_ds1302=1;_nop_();_nop_();data_ds1302=0x8e;
for(i=1;i<=8;i++){
SCL_ds1302=0;
IO_ds1302=(data_ds1302&0x01);
_nop_();
SCL_ds1302=1;
data_ds1302=data_ds1302>>1;} data_ds1302=0x80;
IO_ds1302=0;for(i=1;i<=8;i++){
SCL_ds1302=0;
IO_ds1302=(data_ds1302&0x01);
_nop_();
SCL_ds1302=1;
data_ds1302=data_ds1302>>1;} }
void open_write_bit()//open write { unsigned int i;SCL_ds1302=0;_nop_();
//打开写保护//关闭写保护
RST_ds1302=1;_nop_();_nop_();data_ds1302=0x8e;for(i=1;i<=8;i++){
SCL_ds1302=0;
IO_ds1302=data_ds1302&0x01;
_nop_();SCL_ds1302=1;
data_ds1302=data_ds1302>>1;} data_ds1302=0x00;
//0x00,书上为0x80 IO_ds1302=0;for(i=1;i<=8;i++){
SCL_ds1302=0;
IO_ds1302=data_ds1302&0x01;
_nop_();SCL_ds1302=1;
data_ds1302=data_ds1302>>1;} }
void initial_ds1302()
//初始化函数 { unsigned int i;SCL_ds1302=0;_nop_();RST_ds1302=1;_nop_();_nop_();data_ds1302=0x8e;
for(i=1;i<=8;i++){
SCL_ds1302=0;
IO_ds1302=data_ds1302&0x01;
_nop_();SCL_ds1302=1;
data_ds1302=data_ds1302>>1;} IO_ds1302=0;data_ds1302=0x00;
for(i=1;i<=8;i++){
SCL_ds1302=0;
IO_ds1302=data_ds1302&0x01;
_nop_();SCL_ds1302=1;
data_ds1302=data_ds1302>>1;} RST_ds1302=0;SCL_ds1302=0;_nop_();RST_ds1302=1;_nop_();_nop_();data_ds1302=0x90;
for(i=1;i<=8;i++){ SCL_ds1302=0;IO_ds1302=data_ds1302&0x01;_nop_();SCL_ds1302=1;data_ds1302=data_ds1302>>1;}
data_ds1302=0x0a4;
for(i=1;i<=8;i++){ SCL_ds1302=0;IO_ds1302=data_ds1302&0x01;_nop_();SCL_ds1302=1;data_ds1302=data_ds1302>>1;} RST_ds1302=0;_nop_();SCL_ds1302=0;_nop_();RST_ds1302=1;
data_ds1302=0x8e;
for(i=1;i<=8;i++){ SCL_ds1302=0;IO_ds1302=data_ds1302&0x01;_nop_();SCL_ds1302=1;data_ds1302=data_ds1302>>1;}
data_ds1302=0x80;
for(i=1;i<=8;i++){ SCL_ds1302=0;IO_ds1302=data_ds1302&0x01;_nop_();SCL_ds1302=1;data_ds1302=data_ds1302>>1;} RST_ds1302=0;_nop_();SCL_ds1302=0;}
unsigned char read_ds1302(char command)
//read函数 { unsigned int i;data_ds1302=command;SCL_ds1302=0;_nop_();RST_ds1302=1;for(i=1;i<=8;i++){
SCL_ds1302=0;IO_ds1302=data_ds1302&0x01;_nop_();SCL_ds1302=1;data_ds1302=data_ds1302>>1;}
SCL_ds1302=1;for(i=1;i<=8;i++){
SCL_ds1302=0;
if(IO_ds1302)data_ds1302=(data_ds1302>>1)|0x80;
//送入到data_ds1302中,准备送出
else data_ds1302>>=1;SCL_ds1302=1;} RST_ds1302=0;_nop_();SCL_ds1302=0;return(data_ds1302);}
void write_ds1302(unsigned char address,unsigned char numb){
unsigned int i;
SCL_ds1302=0;
RST_ds1302=0;
RST_ds1302=1;
data_ds1302=address;for(i=1;i<=8;i++){
SCL_ds1302=0;
IO_ds1302=data_ds1302&0x01;
//送入写地址
_nop_();SCL_ds1302=1;
data_ds1302=data_ds1302>>1;} data_ds1302=numb;for(i=1;i<=8;i++){
SCL_ds1302=0;
IO_ds1302=data_ds1302&0x01;
_nop_();SCL_ds1302=1;
data_ds1302=data_ds1302>>1;} } void read_time(){ unsigned char second,minte,hour,d,date,month,year,zhou;second=0x81;
//读秒
d=read_ds1302(second);display_buffer[5]=d&0x0f;display_buffer[4]=d>>4;minte=0x83;
//读分
d=read_ds1302(minte);display_buffer[3]=d&0x0f;display_buffer[2]=d>>4;hour=0x85;
//读时
d=read_ds1302(hour);display_buffer[1]=d&0x0f;display_buffer[0]=d>>4;year=0x8d;
//读年
d=read_ds1302(year);display_buffer[7]=d&0x0f;display_buffer[6]=d>>4;month=0x89;
//读月
d=read_ds1302(month);display_buffer[9]=d&0x0f;display_buffer[8]=d>>4;
//送入写的内容
zhou=0x8b;
//读周d=read_ds1302(zhou);display_buffer[12]=d;date=0x87;
//读日期
d=read_ds1302(date);display_buffer[11]=d&0x0f;display_buffer[10]=d>>4;}
void set_time(){ unsigned char data temp;unsigned char data hour_address=0x84,minte_address=0x82,second_address=0x80,date_address=0x86,month_address=0x88,zhou_address=0x8a,year_address=0x8c;//各个时间量的地址
open_write_bit();
temp=(display_buffer[0]<<4)|display_buffer[1];write_ds1302(hour_address,temp);
//写小时
temp=(display_buffer[2]<<4)|display_buffer[3];write_ds1302(minte_address,temp);
//写分钟
temp=(display_buffer[4]<<4)|display_buffer[5];write_ds1302(second_address,temp);
//写秒
temp=(display_buffer[6]<<4)|display_buffer[7];write_ds1302(year_address,temp);
//写年
temp=(display_buffer[8]<<4)|display_buffer[9];write_ds1302(month_address,temp);
//写月
temp=display_buffer[12];write_ds1302(zhou_address,temp);
//写周temp=(display_buffer[10]<<4)|display_buffer[11];write_ds1302(date_address,temp);
//写日期
close_write_bit();
}
void delay(unsigned int i)
//delay函数 {
while(i--);}
void delayms(unsigned int i){ unsigned int n;while(i--){
for(n=0;n<125;n++);
} }
void displaytime(){ unsigned char e=0x01;unsigned int i;BIT_LED=0;
for(i=0;i<=5;i++){
if(i==5||i%2==0||i==11)
SEGMENT=table[display_buffer[i]];
else
SEGMENT=table1[display_buffer[i]];
BIT_LED=e;
e<<=1;
delayms(1);
}
}
void displaydate(){ unsigned char e=0x01;unsigned int i;BIT_LED=0;
for(i=6;i<=13;i++){
if(i==7||i==9)
SEGMENT=table1[display_buffer[i]];
else if(i==12)
SEGMENT=table[10];
else if(i==13)
SEGMENT=table[display_buffer[i-1]];
else
SEGMENT=table[display_buffer[i]];
BIT_LED=e;
e<<=1;delayms(1);
}
}
测试结果:
S1,S2实现年月日周与时分秒的切换
九、语音收录播报测试:
测试要求:本系统中使用的是语音专用芯片IDS1760芯片,该芯片是以串行方式实现控制和数据传输的。
编写如下程序进行测试: #include
unsigned char bdata SR0_L;unsigned char bdata SR0_H;unsigned char bdata SR1;unsigned char APCL=0,APCH=0;unsigned char PlayAddL=0,PlayAddH=0;unsigned char RecAddL=0,RecAddH=0;
sbit CMD=SR0_L^0;sbit FULL=SR0_L^1;sbit PU=SR0_L^2;sbit EOM=SR0_L^3;sbit INTT=SR0_L^4;sbit RDY=SR1^0;sbit ERASE=SR1^1;sbit PLAY=SR1^2;sbit REC=SR1^3;
unsigned char ISD_SendData(unsigned char dat);void ISD_PU(void);void ISD_Rd_Status(void);void ISD_WR_APC2(unsigned char apcdatl,apcdath);void ISD_SET_PLAY(unsigned char Saddl,Saddh,Eaddl,Eaddh);void ISD_SET_Rec(unsigned char Saddl,Saddh,Eaddl,Eaddh);void ISD_SET_Erase(unsigned char Saddl,Saddh,Eaddl,Eaddh);
sbit SS=P1^4;sbit SCK=P1^7;sbit MOSI=P1^5;sbit MISO=P1^6;
void Cpu_Init(void);void ISD_Init(void);void delay(unsigned int t);
void main(){ Cpu_Init();ISD_Init();
while(1){ ISD_SET_Erase(0,0,9,0);ISD_SET_Rec(0,0,9,0);ISD_SET_PLAY(0,0,9,0);} }
void Cpu_init(void){ P0=P1=P2=P3=0xff;TMOD=0x01;EA=0;} void ISD_Init(void){ uchar i=2;SS=1;SCK=1;MOSI=0;do { ISD_PU();//上电 delay(50);ISD_Rd_Status();//读取状态
}while(CMD||(!PU));
//if(CMD_Err==1||(PU!+1))则再次发送上电指令 ISD_WR_APC2(0x40,0x04);//将0x0440写入APC寄存器
do { ISD_Rd_Status();}while(RDY==0);do { delay(300);delay(300);i--;}while(i>0);}
//向cpu读回或发送数据
unsigned char ISD_SendData(unsigned char dat){ unsigned char i,j,BUF_ISD=dat;SCK=1;SS=0;for(j=4;j>0;j--){;}
for(i=0;i<8;i++){ SCK=0;for(j=2;j>0;j--){;} if(BUF_ISD&0x01)
{MOSI=1;} else
{MOSI=0;} BUF_ISD>>=1;if(MISO)
{BUF_ISD|=0x80;} SCK=1;for(j=6;j>0;j--){;} } MOSI=0;return(BUF_ISD);} void ISD_PU(void){
ISD_SendData(0x01);
ISD_SendData(0x00);
SS=1;} void ISD_Rd_Status(void){ unsigned char i;ISD_SendData(0x05);ISD_SendData(0x00);ISD_SendData(0x00);SS=1;for(i=2;i>0;i--){;} SR0_L=ISD_SendData(0x05);SR0_H=ISD_SendData(0x00);SR1=ISD_SendData(0x00);SS=1;}
void ISD_WR_APC2(unsigned char apcdatl,apcdath){ ISD_SendData(0x65);ISD_SendData(apcdatl);ISD_SendData(apcdath);SS=1;}
void ISD_SET_PLAY(unsigned char Saddl,Saddh,Eaddl,Eaddh){ ISD_SendData(0x80);ISD_SendData(0x00);ISD_SendData(Saddl);ISD_SendData(Saddh);ISD_SendData(Eaddl);ISD_SendData(Eaddh);ISD_SendData(0x00);SS=1;}
void ISD_SET_Rec(unsigned char Saddl,Saddh,Eaddl,Eaddh){
ISD_SendData(0x81);ISD_SendData(0x00);ISD_SendData(Saddl);ISD_SendData(Saddh);ISD_SendData(Eaddl);ISD_SendData(Eaddh);ISD_SendData(0x00);SS=1;}
void ISD_SET_Erase(unsigned char Saddl,Saddh,Eaddl,Eaddh){ ISD_SendData(0x82);ISD_SendData(0x00);ISD_SendData(Saddl);ISD_SendData(Saddh);ISD_SendData(Eaddl);ISD_SendData(Eaddh);ISD_SendData(0x00);SS=1;} void delay(unsigned int t){ for(;t>0;t--){ TH0=0xfc;TL0=0x18;TR0=1;while(TF0!=1){;} TF0=0;TR0=0;} }
测试结果:需要在程序中设置断点,完成录音,放音再录音放音的循环操作。
测试功能正常。
十、单片机模块调试
测试要求:该模块的调试很复杂,牵扯面也很多。其实通过前面各个模块的调试,已经大部分得到了间接地验证。例如在“动态数码管测试”和“串行通讯测试”中就是用到了定时器。
如有必要可以再编写一些测试程序。例如检测单片机的某一口线的功能是否正常、测试某段程序运行时间,等等。
测试结论:因单片机大部分功能在前调试方案中大部分已使用过,此处不再进行其余调试。
第五篇:单片机出租车计价器源程序
出租车计价器设计与制作
设计并制作一台出租车计价器。调试时采用10Hz方波信号模拟,每个方波代表10m。基本要求:
(1)不同情况具有不同的收费标准
白天 1元/公里 晚上 2元/ 公里 途中等待(30s)1元/30s
(2)数据输出(6位LED数码管显示)
单价输出2位 路途输出2位 总金额输出2位
(3)按键(3个)
启动计价开关 数据复位(清零)白天/晚上转换
3.4.1模块1:系统设计
(1)分析任务要求,写出系统整体设计思路
通过分析,需要实现四个主要的功能模块,分别为脉冲计数模块、定时器计时模块、按键的处理以及
数码管动态扫描等功能。
定时器计时模块主要完成途中等待(即没有脉冲来时)30秒的计时。在启动键按下后,定时器就不停的计时,只要有脉冲来就将计时的值清除为零。如果没有脉冲来,当计时超过30秒时,相应的总金额要
按照收费标准计价。
中断的管理:尽管中断有嵌套以及优先级的功能,但是由于定时器已经使用一个了中断资源,脉冲检测不宜再采用中断方式,而是采用查询方式。由于需要不停的要清除30秒的计时,因此,脉冲的计数不
采用定时器的计数方式。
启动键触发定时器开始工作,而定时器的运行可以作为脉冲计数的标志,只要定时器计时在运行,每来一个中断都应该计数。
主程序完成键盘的扫描和按键的处理,查询脉冲产生的中断,并完成脉冲的计数。每个脉冲代表10米,则当计数到100时表示1千米的距离,相应的总金额要按照收费标准计价
(2)选择单片机型号和所需外围器件型号,设计单片机硬件电路原理图
采用MCS51系列单片机At89S51作为主控制器,外围电路器件包括数码管驱动、独立式键盘、复位电
路等。硬件电路原理图如图3-9所示。
图3-11 出租车计价器的硬件电路原理图
数码管驱动采用2个四联共阴极数码管显示,由于单片机驱动能力有限,采用74HC244作为数码管的驱动。在74HC244的7段码输出线上串联100欧姆电阻起限流作用。
独立式按键使用上提拉电路连接,在没有键按下时,输出高电平。P0口用于输出7段LED共阴极显示代码,P2口用于输出低电平有效的位选码。0~9的7段LED共阴极显示代码:3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH。
(3)分析软件任务要求,写出程序设计思路,分配单片机内部资源,画出程序流程图
软件的任务要求包括定时器的设置、按键的扫描、按键的功能处理、脉冲的计数、路途等待超30秒的计
时以及总金额的计算等。
程序设计的思路:使用中断方式对定时器的溢出进行计数实现30秒的计时。主程序采用查询外部中断标志实现脉冲的计数,由于每个脉冲代表10m,因此,当脉冲计数超过100时,计价器按照收费标准计价。主程序在初始化变量和定时器参数设置之后,进入一个循环结构,循环扫描键盘、查询脉冲的中断、数码管的动态扫描等功能,当脉冲的中断标志被查询到,若路途等待时间未超30秒时,要及时将路途等待时间的值清除为零。主程序的流程图如图3-12所示。
图3-12 出租车计价器的主程序流程图
中断服务程序主要实现计时功能,当启动键按下之后,定时器开始工作,用一个变量对定时器溢出中断的次数进行计数,达到计时功能,该变量在每次脉冲到来时被清零(在主程序中清零),当脉冲长时间没有来,则当该变量计数超过30秒时,总金额按照途中等待计费标准进行计价。中断程序的流程图如图
3-13所示。
图3-13 出租车计价器的中断服务程序流程图
(4)设计系统软件调试方案、硬件调试方案及软硬件联合调试方案
软件调试方案:伟福软件中,在“文件新建文件”中,新建C语言源程序文件,编写相应的程序。在“文件新建项目”的菜单中,新建项目并将C语言源程序文件包括在项目文件中。
在 “项目编译”菜单中将C源文件编译,检查语法错误及逻辑错误。在编译成功后,产生以 “*.hex”和“*.bin” 后缀的目标文件。
硬件调试方案:在设计平台中,将单片机的P1.0-P1.2分别与3个独立式键盘通过插线连接起来,将P3.2与脉冲信号源连接起来。
在伟福中将程序文件编译成目标文件后,将下载线安装在实验平台上,运行“MCU下载程序”,选择相应的flash 数据文件,点击“编程”按钮,将程序文件下载到单片机的Flash中。
然后,上电重新启动单片机,检查所编写的程序是否达到题目的要求,是否全面完整地完成试题的内容。3.4.2 程序设计
/*晶振:11.0592M T1-250微秒溢出中断一次;P3.2(int0)-中断100次,查询IE0置位,P1^0为启动键;P1^1为清除键;P1^2为白天/晚上的切换键 变量的定义: key_val: 返回按键的值 255-无键
T1_cnt: 定时器溢出数计数
cnt_30: 30秒钟的计时
cnt_distance: 计算路程
cnt_cost: 总金额
state_val: 状态:0-白天 1 夜晚
cost_val[3]: 收费标准:白天单价cost_val[0]=1元/公里;晚上单价cost_val[1]=2元/公里; 等待单价cost_val[2]=1元/30s
led_seg_code:数码管7段码 */ //-------------------#include “reg51.h” unsigned char data cnt_30,cnt_distance,cnt_cost;unsigned int data T1_cnt,D_cnt;unsigned char data key_val,key_val_old;unsigned char data state_val;char code cost_val[3]={1,2,1};char code led_seg_code[10]={0x3f,0x06,0x05b,0x04f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//led_seg_code[0-9]代表0-9 //-------延时-----------------void delay(unsigned int i)//延时 { while(--i);} //-------初始化变量------------------void init_variant()//初始化一些变量的内容 {unsigned char i;cnt_30=0;//30秒的计时 D_cnt=0;//脉冲的个数 cnt_distance=0;//距离的计数
cnt_cost=0;//保存总价格 } //-------扫描键盘-----------------unsigned char scan_key(){ unsigned char i,k;i=P1;if(i==0xff){ k=255;} //无键按下
else //有键按下
{ delay(10);//延时去抖动
if(i!=P1){k=255;} else { switch(i){ case 0xfe: k=0;break;//P1.0按下,启动键
case 0xfd: k=1;break;//P1.1按下,清除键
case 0xfb: k=2;break;//P1.2按下,切换键
} } } return k;} //-------数码管动态扫描-------------void led_show(){unsigned char i,k;
//-----显示单价----k=cost_val[state_val];i=k%10;//暂存个位 P0=led_seg_code[i];P2=0xbf;delay(10);i=k%100/10;P0=led_seg_code[i];P2=0x7f;delay(10);//-----显示距离------k=cnt_distance;i=k%10;//暂存个位 P0=led_seg_code[i];P2=0xf7;delay(10);i=k%100/10;P0=led_seg_code[i];P2=0xef;delay(10);//-----显示总价格-----------k=cnt_cost;i=k%10;//暂存个位 P0=led_seg_code[i];P2=0xfe;delay(10);i=k%100/10;P0=led_seg_code[i];P2=0xfd;delay(10);} //-------计时----------------void timer1()interrupt 3 //T1中断 { T1_cnt++;if(T1_cnt>3999)//如果计数>3999, 计时1s { T1_cnt=0;if(cnt_30<30)//没有超过30秒,继续计时
{cnt_30++;} else //超过30秒,途中等待计价
{cnt_30=0;cnt_cost=cnt_cost+cost_val[2];} } } //---------主程序----------------
main(){//初始化各变量 T1_cnt=0;state_val=0;key_val_old=255;init_variant();//初始化51的寄存器
TMOD=0x20;//用T1计时 8位自动装载定时模式,不用T0 TH1=0x19;//250微秒溢出一次;250=(256-x)*12/11.0592-> x= 230.4 TL1=0x19;EA=1;//开中断 ET1=1;
TR1=0;//定时器T0 TCON=0x01;//Int0中断取边沿触发模式 while(1){ key_val=scan_key();// 255;// if(key_val!=key_val_old){ key_val_old=key_val;if(key_val!=255){ switch(key_val){ case 0: //启动键
TR1=1;//启动计时,TR1=1为启动了的标志
break;case 1: //清除键
init_variant();//清除变量
TR1=0;//关闭定时器
break;case 2: //白天/黑夜的切换
if(state_val==0){state_val=1;} else {state_val=0;} break;} } } if(IE0==1&& TR1==1)//每来1个脉冲,中断一次
{ IE0=0;cnt_30=0;//30秒的计时清零
if(D_cnt<100)
{D_cnt++;} else //计数100次,每次10米,表示一公里
{D_cnt=0;cnt_distance=cnt_distance+1;
cnt_cost=cnt_cost+cost_val[state_val];} } led_show();} } //-----出租车计价器程序结束------------