本文为明德扬原创及录用文章,转载请注明出处!
1.1 总体设计
1.1.1 概述
学习了明德扬至简设计法和明德扬设计规范,本人设计了一个基于FPGA的出租车计费系统。该系统由一个按键表示出租车上是否有乘客,再通过检测出租车的档位和轮胎的转速来获得乘客所需支付的总费用。在本案例的设计过程中,包含了按键定义和消抖、计数器、数码管显示等技术。经过逐步改进、调试等一系列操作之后,完成了此设计,下面将完整的设计记录与大家分享。
本工程使用VIVADO进行仿真,未进行上板。
1.1.2 设计目标
此设计可以完成出租车计费的功能。在按键按下后(乘客上车),开始按如下规则计费:
起步价5元,超过3KM以每公里2元计费,如果遇到红绿灯、堵车等需要停车等待时,则以每20分钟1元计费。
再按一下按键(乘客下车)则计费结束,算出乘客所需支付的总费用,并在数码管上显示。
1.1.3 系统结构框图
系统结构框图如下所示:
1.1.4 模块功能
key模块实现功能
由于按键信号是异步信号,所以对该将信号打两拍处理,将异步信号同步化;
实现10ms按键消抖功能,并输出按键信号key_flag,每按一次按键,key_flag取反
其中key_flag=1表示有乘客,key_flag=0表示没有乘客。
speed模块实现功能
通过按键信号key_flag有效,对轮胎转速进行每秒取样,进而获得乘客行驶总的路程和判断按时计费的使能信号en_0是否有效。
fare模块实现功能
通过speed模块的总路程和按时计费有效使能信号来获得乘客所需支付的总费用,再取得总费用的个位、十位和百位数值并输出。
show模块实现功能
采用动态扫描3个数码管的方式显示fare模块中获得的三个数值即为乘客所需支付的总费用。
1.1.5 顶层信号
1.1.6 顶层代码
1.2 key模块设计
1.2.1 接口信号
1.2.2 设计思路
此模块通过一个按键来表示车上是否有乘客,复位时输出信号key_flag为0,当乘客上车时,司机按一下按键,key_flag由0变,1,表明乘客已上车,系统开始计费。到达目的地时,司机再按一下按键,key_flag由1变0,表明到达目的地乘客下车,系统结束计费。
硬件电路
独立式按键工作原理如上图所示,4条输入线接到FPGA的IO口上,当按键K1按下时,VCC通过电阻R1再通过按键K1最终进入GND形成一条通路,这条线路的全部电压都加在R1上,则引脚P14是低电平。当松开按键后,线路断开,就不会有电流通过,P14和VCC就应该是等电位,为高电平。我们可以通过P14这个IO口的高低电平状态来判断是否有按键按下。其它按键原理与K1一致,当然本实验只需要一个按键即可,任选一个按键都可以。
从图中可以看出,如果我们按下按键,那么按键就会接通并连接到低电平GND,如果我们没有按下,那么按键就会断开并接到VCC,因此按键为低电平有效。通常的按键所用开关为机械弹性开关,当机械触点断开或者闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而机械式按键在闭合及断开的瞬间均伴随有一连串的抖动,如果不进行处理,会使系统识别到抖动信号而进行不必要的反应,导致模块功能不正常,为了避免这种现象的产生,需要进行按键消抖的操作。
按键消抖
按键消抖主要分为硬件消抖和软件消抖。两个“与非”门构成一个RS触发器为常用的硬件消抖。软件方法消抖,即检测出键闭合后执行一个延时程序,抖动时间的长短由按键的机械特性决定,一般为5ms~20ms,让前沿抖动消失后再一次检测键的状态,如果仍保持闭合状态电平,则确认按下按键操作有效。当检测到按键释放后,也要给5ms~20ms的延时,待后沿抖动消失后才能转入该键的处理程序。经过按键消抖的行人优先按键,判断按键有效后,按键信号传递给控制系统,控制系统再进入相应的处理程序。如还不明白之处,见实验的PDF。
图5.1.2按键消抖示意图
1.2.3 参考代码
使用明德扬的计数器模板,可以很快速很熟练地写出按键消抖模块。
每10ms扫描一次按键输入key_in,可以达到消抖的目的,再用寄存器缓存一下,按键为低电平有效;但本实验是需要按键按下松开这样一次完整的按按键操作后输出key_flag才发生变化,所以检测当检测到按键有上升沿变化时,代表该按键被按下松开,按键输出key_flag才发生变化。
本模块设计了一个状态机,用于按键的检测。该状态机共包括4个状态。
其各个状态的含义如下。
空闲状态(IDLE):表示按键没有被按下,检测到低电平进入下一状态。
延时确认状态(S1):开始10ms延时计数,若计数完成且依然为低电平则进入下一状态,若计数期间按键出现高电平说明为抖动回到初始状态。
检测释放状态(S2):表示按键按下未松开,检测到高电平进入下一状态。
延时确认状态(S3):开始10ms延时计数,若计数完成且依然为高电平视为有效松手行为进入初始状态再检测下一次按键按下,若计数期间按键出现低电平说明为抖动回到S2状态。
代码如下:
1.3 speed模块设计
1.3.1 接口信号
1.3.2 设计思路
消抖后的按键信号输入到本模块中,同样使用明德扬至简设计法和计数器模板,可以快速写出计算总路程和获得按时计费信号en_0有效的代码。当key_flag为1有效且转速rev>=3r/s时,计数器开始计数,每计一秒钟对转速信号rev取样,获得每秒行驶路程并累加,当key_flag为0时,计数停止,累加也停止,此时获得的累加值即为总路程。当key_flag为1有效且rev<3r/s时,en_0拉高为1,表示此时需要按时计费。
1.3.3 参考代码
1.4 fare模块设计
1.4.1 接口信号
1.4.2 设计思路
从speed模块中得到乘客乘坐总路程distance和按时计费使能信号en_0,然后以5元起步价,超过3KM以每满1公里2元的计费方式计算出按路程计费的总费用,再通过en_0按20分钟1元的计费方式计算出按时间计费的总费用,再求和获得总费用,最后得到总费用得个位、十位、百位,分别是x_g、x_s、x_b。
1.4.3 参考代码
1.5 show模块设计
1.5.1 接口信号
1.5.2 设计思路
由于在fare模块中已经获得总费用的个位、十位和百位的值,所以在本模块只需要控制3个数码管对其数值进行显示即可。
本模块在设计过程中采用动态扫描3个数码管的方式进行显示,并且直接使用明德杨提供的数码管显示规范代码。动态扫描方式相比于使用3个独立的数码管显示会节约资源,硬件电路更简单,且数码管越多优势越明显。
1.5.3 参考代码
1.6 效果和总结
仿真验证特殊说明:
由于本系统涉及1秒、20分钟等时间节点,时间很长,所以在仿真时有一定的困难,为此我将系统中的时间节点全部乘上10^(-5),让所有状态提前到达,方便我们仿真验证。
由于乘上了10^(-5),所以原消抖10ms在仿真中为100ns;
系统中原1s取样转速rev在仿真中为10us;
原按时计费20分钟/元在仿真中为12ms/元;
测试文件和理论计算
在测试文件中转速rev>=3r/s的时间是50000000ns;
总路程distance=15/3*50000000/10000=25km;
由于在测试文件中按键消抖有一段时间且这一段时间在rev>=3r/s的时间内,所以系统实际对速度采样的次数会少一次,所以最终的总路程会少5m;
所以,按路程计费的总费用taxi_fare_1=5+(25 - 3)*2 – 0.005*2=48.99(元);
去除小数部分taxi_fare_1=48(元);
在测试文件中转速rev<3r/s的时间是24000000ns;
按时间计费的总费用taxi_fare_2=24000000/12000000=2(元);
所以总车费taxi_fare_1=taxi_fare_1+taxi_fare_2=50(元);
仿真验证结果
由仿真结果可以看到seg_sel=110第1位数码管显示时segment=11000000、seg_sel=101第2位数码管显示时segment=10010010、seg_sel=011第3位数码管显示时segment=11000000,在数码管上分别对应数值为0、5、0,表示为50元。
仿真结果和理论结构都是50元,符合我们的预期,验证成功。
在这个设计中,使用明德杨的至简设计法,让我的思路非常清晰,逻辑非常严谨,虽然没有做到一遍成功,但在调试过程中我都比较快速的找到问题,并快速解决。对于学习FPGA的同学,我非常推荐使用明德杨至简设计法和明德杨模块进行学习和设计。
感兴趣的朋友也可以访问明德扬论坛(http://www.fpgabbs.cn/)进行FPGA相关工程设计学习,也欢迎大家在评论与我们进行讨论!
温馨提示:明德扬2023推出了全新课程——逻辑设计基本功修炼课,降低学习FPGA门槛的同时,增加了学习的趣味性,并组织了考试赢积分活动
http://www.mdy-edu.com/ffkc/415.html
(点击→了解课程详情☝)感兴趣请联系易老师:13112063618(微信同步)