郝佳齐 江宏球具有语音报价功能的出租车计价器.docx
《郝佳齐 江宏球具有语音报价功能的出租车计价器.docx》由会员分享,可在线阅读,更多相关《郝佳齐 江宏球具有语音报价功能的出租车计价器.docx(53页珍藏版)》请在冰点文库上搜索。
郝佳齐江宏球具有语音报价功能的出租车计价器
具有语音功能的出租车计价器
--电子系统设计答辩
电气110郝佳齐2110401282
江宏球2110401283
一.引言
当今,随着科学技术的发展,计算机技术带来了科研和生产的许多重大的飞跃,特别是单片微型计算机的应用已经渗透到生产和生活中的各个方面,有力的推动了社会的发展。
单片微机以其体积小,集成度高,价格便宜,在数据处理、实时控制等方面有着无与伦比的强大功能。
其性能不断提高,应用范围愈来愈广,在计算机应用领域日益占重要地位。
出租车计价器就是单片微型计算机的一个典型的应用。
基于单片机的出租车计价器可以利用单片机强大的可编程功能,轻松地实现原来模拟电路无法实现或者要通过极为复杂的电路才能实现的功能,同时,各种周边外部电路芯片的飞速发展,也给单片机应用的设计者们提供了很大的方便,使得他们在实现常用的功能时可以直接复用已经成熟的电路,从而极大地提高了设计效率。
二.设计任务及要求
1.目的及任务:
(1)通过查阅相关资料,深入了解出租车计价器的工作原理;
(2)学习有关数字信号处理及采样原理;
(3)复习“MCS-51单片机原理及C语言程序设计”,掌握其接口扩展,如:
显示、键盘等;
(4)设计出租车计价器的原理图,构建硬件平台;
(5)采用汇编或C语言编写应用程序并调试通过;
(6)制作出样机并测试达到功能和技术指标要求;
(7)写出设计报告和答辩PPT。
2.技术要求:
(1)用555振荡器模拟出租车车轮转数传感器,计量出租车所走的公里数。
(2)显示里程、价格和等待红灯或堵车的计时,语音播报价格。
(3)具有等待计时功能。
(4)具有实时年月日显示与切换功能。
3.具体工作任务:
(1)组建基于单片机的出租车计价器的总体结构框图;
(2)根据设计要求,通过理论分析和计算选择电路参数;
(3)根据操作功能要求,确定键盘控制功能;
(4)按设计要求确定显示位数、指示类型和单位;
(5)编写应用程序并调试通过;
(6)对系统进行测试和结果分析;
(7)撰写设计报告和答辩PPT。
三.整体框架
系统的硬件部分以AT89C52单片机为控制核心,通过时钟芯片DS1302,语音芯片ISD1760,七段数码管构成了一个具有语音报价功能,时间日期显示功能的出租车计价器。
整个系统采用8块七段数码管来显示信息,不仅可以显示出租车行驶的公里数与价格,也可以通过按键切换至日期与价格的显示。
系统通过555振荡器模拟出租车车轮转速传感器,计算出租车走过的公里数。
系统的软件设计部分全部采用C语言进行编写,具有良好的可移植性和扩展升级能力
总体方案框图如图
整个出租车计价器除单片机本体外的电路大体分为四块,即:
①通过74LS573和ULN2803A实现数码管动态扫描中位码与段码的传送的数码管动态显示模块;
②实现时钟日期信息的走时、调整和数据传送的DS1302模块;
③通过实现语音报价功能的ISD1760语音芯片及其周边电路的语音模块;
④以及在出租车计价器设计过程中模拟车轮运转脉冲的由555芯片构成的脉冲发生电路模块。
下面,就对这四个部分分别进行简要的介绍。
四.各模块功能介绍
1.数码管动态显示模块
如上图所示即为本设计中实现数码管动态扫描显示的部分电路,其中之上的两个MC74HC02AN分别通过或非经过单片机实现对于两个锁存器74LS573的选择和控制,而ULN2803A则通过提供驱动电流实现对于不同位的显示。
动态接口采用各数码管循环轮流显示的方法,当循环显示频率较高时,利用人眼的暂留特性,看不出闪烁显示现象,这种显示需要一个接口完成字形码的输出(字形选择),另一接口完成各数码管的轮流点亮(数位选择)。
在进行数码显示的时候,要对显示单元开辟8个显示缓冲区,每个显示缓冲区装有显示的不同数据即可。
对于显示的字形码数据我们采用查表方法来完成。
其中,对于数码管显示的段码和位码都必须经过锁存器74LS573实现,其特性有:
三态总线驱动输出;置数全并行存取;缓冲控制输入;使能输入有改善抗扰度的滞后作用。
原理:
74LS573的八个锁存器都是透明的D型锁存器,当使能(G)为高时,Q输出将随数据(D)输入而变。
当使能为低时,输出将锁存在已建立的数据电平上。
输出控制不影响锁存器的内部工作,即老数据可以保持,甚至当输出被关闭时,新的数据也可以置入。
这种电路可以驱动大电容或低阻抗负载,可以直接与系统总线接口并驱动总线,而不需要外接口。
特别适用于缓冲寄存器,I/O通道,双向总线驱动器和工作寄存器。
2.DS1302模块
上图即为DS1302部分电路,DS1302包括时钟/日历寄存器和31字节(8位)的数据暂存寄存器,数据通信仅通过一条串行输入输出口。
实时时钟/日历提供包括秒、分、时、日期、月份和年份信息。
闰年可自行调整,可选择12小时制和24小时制,可以设置AM、PM。
DS1302实时时钟具有能计算2100年之前的秒分时日日期星期月年的能力还有闰年调整的能力;318位暂存数据存储RAM;串行I/O口方式使得管脚数量最少;宽范围工作电压2.05.5V;工作电流2.0V时,小于300nA;读/写时钟或RAM数据时有两种传送方式单字节传送和多字节传送字符组方式;8脚DIP封装或可选的8脚SOIC封装根据表面装配;简单3线接口;与TTL兼容Vcc=5V;可选工业级温度范围-40+85;与DS1202兼容;在DS1202基础上增加的特性;对Vcc1有可选的涓流充电能力;双电源管用于主电源和备份电源供应;备份电源管脚可由电池或大容量电容输入;附加的7字节暂存存储器。
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为时钟输入端。
3.脉冲发生电路模块
本模块的存在仅为调试脉冲计数功能时使用,由555定时器芯片构成,555定时器是美国Signetics公司1972年研制的用于取代机械式定时器的中规模集成电路,因输入端设计有三个5kΩ的电阻而得名。
由555定时器构成的多谐振荡器如图所示,R1,R2和C是外接定时元件,电路中将高电平触发端(6脚)和低电平触发端(2脚)并接后接到R2和C的连接处,将放电端(7脚)接到R1,R2的连接处。
由于接通电源瞬间,电容C来不及充电,电容器两端电压uc为低电平,小于(1/3)Vcc,故高电平触发端与低电平触发端均为低电平,输出uo为高电平,放电管VT截止。
这时,电源经R1,R2对电容C充电,使电压uc按指数规律上升,当uc上升到(2/3)Vcc时,输出uo为低电平,放电管VT导通,把uc从(1/3)Vcc上升到(2/3)Vcc这段时间内电路的状态称为第一暂稳态,其维持时间TPH的长短与电容的充电时间有关。
充电时间常数T充=(R1+R2)C。
由于放电管VT导通,电容C通过电阻R2和放电管放电,电路进人第二暂稳态.其维持时间TPL的长短与电容的放电时间有关,放电时间常数T放=R2*C0随着C的放电,uc下降,当uc下降到(1/3)Vcc时,输出uo。
为高电平,放电管VT截止,Vcc再次对电容c充电,电路又翻转到第一暂稳态。
不难理解,接通电源后,电路就在两个暂稳态之间来回翻转,则输出可得矩形波。
电路一旦起振后,uc电压总是在(1/3~2/3)Vcc之间变化。
4.语音模块
上图即为设计中采用ISD1760芯片实现语音的录放和播报的部分电路,ISD1760系列芯片是Winbond推出的单片机优质语音录放电路,在之前语音系列芯片的基础上,该芯片提供多项新功能,包括内置专利的多信息管理系统,新信息提示,双运作模式(独立&嵌入式),以及可定制的信息操作指示音效。
芯片内部包含有自动增益控制、麦克风前置扩大器、扬声器驱动线路、振荡器与内存等等全方位整合系统功能。
该芯片还具备微控制器所需的控制接口,通过编程能够实现复杂的信息处理功能,如信息的组合、连接,设定固定的信息段和信息管理等。
五.各模块程序设计
1.主程序
主程序的作用在于将程序的各部分连接,并且完成功能的相应初始化,进行扫描键盘待命。
在具体的设计中,只需调用相应的子程序完成初始化,调整好相应的定时器模式、中断的允许和优先级,再在扫描键盘时将相应的功能子程序添加即可。
一共有5个按键S1,S2,S3,S4,S5,其中S1,S2,S3,S4分别与89C52的P1.0,P1.1,P1.2,P1.3连接,起到控制作用,S5与INT0连接,为外部中断。
另外,将语音播报功能嵌入主程序中,并通过jiaoflag判断是否报价。
程序代码如下:
voidmain()
{unsignedchari;
EA=1;
ET1=1;
ET0=1;
EX0=1;
ISD_Init();
initial_ds1302();
initialdata_DS1302();
read_date();
while
(1)
{
if(jiaoflag==1)
{jiaoflag=0;
//intn,m;
//unsignedcharl,h;
n=(cnt_cost%1000-cnt_cost%100)/100;
l=n*10+1;
m=(cnt_cost%100-cnt_cost%10)/10;
h=m*10+1;
ISD_SET_PLAY(141,0,160,0);
ISD_SET_PLAY(l,0,l+9,0);
ISD_SET_PLAY(101,0,110,0);
ISD_SET_PLAY(h,0,h+9,0);
ISD_SET_PLAY(111,0,120,0);
ISD_SET_PLAY(161,0,180,0);
}
if(start_key==0)
{
delay(10000);
if(start_key==0)
{
if(startflag==0)
{
startflag=1;
for(i=2;i<8;i++)
{
read_date();
display_buffer[i]=date_buffer[i-2];
}
ET0=1;
display_buffer[0]=2;
display_buffer[1]=0;
show();
delay(20000000);
ISD_SET_PLAY(121,0,140,0);
}
else
{
startflag=0;
TR0=0;
D_cnt=0;
cnt_distance=0;
cnt_cost=600;
cnt_time=0;
read_date();
for(i=2;i<8;i++)
{display_buffer[i]=date_buffer[i-2];}
display_buffer[0]=2;
display_buffer[1]=0;
//ISD_SET_PLAY(121,0,150,0);
show();
}
}
}
if(startcharge_key==0)
{delay(10000);
if(startcharge_key==0)
{
if(cflag==0)
{
cflag=1;
initial_charge();
showcharge();
}
else
{
cflag=0;
TR1=0;
showcharge();
}
}
}
if(change_key==0)
{delay(10000);
if(change_key==0)
change();
}
if(wait_key==0)
{delay(10000);
if(wait_key==0)
waitcharge();
}
}
}2.数码管动态扫描的显示模块
数码管的动态扫描通过单片机的P0口依次送出需要显示数据的段码和位码,通过或非门MC74HC02AN的控制,依次通过573锁存器送段码和573锁存器接ULN2803A驱动电路驱动所扫描到的数码管来完成显示。
在程序设计当中,通过定时器0来完成扫描之间的延时计时,通过定时器0的中断服务程序调用显示用子程序反复扫描。
相应的子程序unsignedcharget_code(unsignedchari)的作用为查询所显示的字符的段码,运用swich-case结构将所需的段码取出。
程序代码如下:
//动态显示模块
voidtime1_int(void)interrupt1
{
TH0=time1_h;TL0=time1_l;
display();
}
unsignedcharget_code(unsignedchari)
{
unsignedcharp;
switch(i){
case0:
p=0x3F;break;
case1:
p=0x06;break;
case2:
p=0x5B;break;
case3:
p=0x4F;break;
case4:
p=0x66;break;
case5:
p=0x6D;break;
case6:
p=0x7D;break;
case7:
p=0x07;break;
case8:
p=0x7F;break;
case9:
p=0x67;break;
case10:
p=0x77;break;
case11:
p=0x7C;break;
case12:
p=0x39;break;
case13:
p=0x5E;break;
case14:
p=0x79;break;
case15:
p=0x71;break;
case16:
p=0xBF;break;/*0.*/
case17:
p=0x86;break;/*1。
*/
case18:
p=0xDB;break;/*2。
*/
case19:
p=0xCF;break;/*3。
*/
case20:
p=0xE6;break;/*4。
*/
case21:
p=0xED;break;/*5。
*/
case22:
p=0xFD;break;/*6。
*/
case23:
p=0x87;break;/*7。
*/
case24:
p=0xFF;break;/*8。
*/
case25:
p=0xE7;break;/*9。
*/
case26:
p=0x00;break;
default:
break;}
return(p);
}
voiddisplay(void)
{
unsignedchari;
switch(display_bit)
{
case1:
i=0;break;
case2:
i=1;break;
case4:
i=2;break;
case8:
i=3;break;
case16:
i=4;break;
case32:
i=5;break;
case64:
i=6;break;
case128:
i=7;break;
default:
break;}
{
BIT_LED=0;//关闭显示
SEGMENT=get_code(display_buffer[i]);//送段码
BIT_LED=display_bit;//送位码
if(display_bit<0x64){display_bit=display_bit*2;}
elsedisplay_bit=0x01;
}
}
voidshow()
{
BIT_LED=0;
TMOD=0x61;//定时器1计数器方式2(可自动重载),定时器0计时器方式1
time1_times=65536-time1*f/12;//2500us倒计时
time1_h=(time1_times/256);
time1_l=(time1_times%256);
TH0=time1_h;TL0=time1_l;
TR0=1;
display_bit=0x01;
}
3.DS1302日期显示模块
首先定义DS1302_write_byte()和DS1302_read_byte(),用于写入和读取一字节的数据。
DS1302_write(ucharaddress,ucharucdat)的作用是往DS1302写入数据。
具体作用是先确定要写入的地址address,然后将ucdat写入改地址中。
DS1302_read(ucharaddress)用于读取DS1302某地址的数据。
具体作用是先确定要读取的地址address,然后将该地址中的数据读出。
最后要初始化时间了。
定义DS1302_set(uchardate_set[])函数,用date_set的值初始化时间。
而要将时间显示出来,必须一位位的由数码管显示出来。
完成此任务的函数是DS1302_read_date()。
至此,日期显示模块方可以工作。
程序如下:
//DS1302时钟日历芯片部分
voidclose_write_bit()
{
chari;
SCL_DS1302=0;
_nop_();
RST_DS1302=1;
_nop_();_nop_();
data_ds1302=0x8e;
for(i=1;i<=8;i++){
SCL_DS1302=0;IO_DS1302=bit_data0;
_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=bit_data0;
_nop_();SCL_DS1302=1;
data_ds1302=data_ds1302>>1;
}
}
voidopen_write_bit()
{
chari;
SCL_DS1302=0;
_nop_();
RST_DS1302=1;
_nop_();_nop_();
data_ds1302=0x8e;
for(i=1;i<=8;i++){
SCL_DS1302=0;IO_DS1302=bit_data0;
_nop_();SCL_DS1302=1;
data_ds1302=data_ds1302>>1;
}
data_ds1302=0x00;
IO_DS1302=0;
for(i=1;i<=8;i++){
SCL_DS1302=0;IO_DS1302=bit_data0;
_nop_();SCL_DS1302=1;
data_ds1302=data_ds1302>>1;
}
}
voidinitial_ds1302()
{
unsignedchari;
SCL_DS1302=0;
_nop_();
RST_DS1302=1;
_nop_();_nop_();
data_ds1302=0x8e;
for(i=1;i<=8;i++){
SCL_DS1302=0;IO_DS1302=bit_data0;
_nop_();SCL_DS1302=1;
data_ds1302=data_ds1302>>1;
}
data_ds1302=0x00;//80
IO_DS1302=0;
for(i=1;i<=8;i++){
SCL_DS1302=0;IO_DS1302=bit_data0;
_nop_();SCL_DS1302=1;
data_ds1302=data_ds1302>>1;
}
RST_DS1302=0;
_nop_();
SCL_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=bit_data0;
_nop_();SCL_DS1302=1;
data_ds1302=data_ds1302>>1;
}
data_ds1302=0xa4;
for(i=1;i<=8;i++){
SCL_DS1302=0;IO_DS1302=bit_data0;
_nop_();SCL_DS1302=1;
data_ds1302=data_ds1302>>1;
}
RST_DS1302=0;
_nop_();
SCL_DS1302=0;
SCL_DS1302=0;
_nop_();
RST_DS1302=1;
_nop_();_nop_();
data_ds1302=0x8e;//80
for(i=1;i<=8;i++){
SCL_DS1302=0;IO_DS1302=bit_data0;
_nop_();SCL_DS1302=1;
data_ds1302=data_ds1302>>1;
}
data_ds1302=0x80;
for(i=1;i<=8;i++){
SCL_DS1302=0;IO_DS1302=bit_data0;
_nop_();SCL_DS1302=1;
data_ds1302=data_ds1302>>1;
}
RST_DS1302=0;
_nop_();
SCL_DS1302=0;
}
unsignedcharread_ds1302(charcommand)
{
chari;
data_ds1302=(command<<1)|0x81;
SCL_DS1302=