出租车计价器设计与制作
???? 设计并制作一台出租车计价器。调试时采用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();
?}
}
//-----出租车计价器程序结束------------
评论