题目九:出租车计价器设计(平台实现)★★
完成简易出租车计价器设计,选做停车等待计价功能。
基本功能:
(1)起步8元/3公里,此后2元/公里;
(2)里程指示信号为每前进50米一个高电平脉冲,上升沿有效;显示行公里数,精确到0.1公里。(模拟时速40KM/h)
(3)前进里程开始之前显示价钱,精确到0.1元;
(4)用两个按键分别表示开始行程和结束行程。
选做功能:
(1)增加一个停车等待/恢复行程按钮,用2个数码管显示等待时间,精确到0.1分钟。
(2)等候费1元/分钟,计价精度为0.1元。
从思维导图看出,本次设计为分为分频、计时(内含有计算)、显示三个部分。分频得到一秒,计时内分为两个部分:等待模块和行驶模块。
最后通过显示模块输出到数码管。
1.实现步骤:分频得到一秒,将一秒的频率作为输入,传入计时模块。在计时模块的行驶模块中:当汽车行驶时,如果km大于3km,那么每9s,km加上0.1km,即小数位加1,价钱加0.2元。
在计时模块的等待模块中:当汽车等待时,每6s即0.1min,等待时间加上0.1min,价钱加上0.1元。
2.VHDL代码
library IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
entity taxi is
port(clk_100:in std_logic;
clk_scan:in std_logic;
start:in std_logic; --开始
stop:in std_logic; --停车与恢复行驶
reset:in std_logic; --重置键
ended:in std_logic; --结束
op,led:out std_logic_vector(7 downto 0));--数码管位选与段选
end taxi;
architecture one of taxi is
signal f_1:std_logic; --1Hz频率
signal q_1:integer range 0 to 99;
signal c2,c1,c0:std_logic_vector(3 downto 0);--费用cost
signal k2,k1,k0:std_logic_vector(3 downto 0);--km
signal m1,m0:std_logic_vector(3 downto 0); --min
signal bit_2:integer range 9 downto 0; --op
signal num:std_logic_vector(3 downto 0); --led
begin
feipin:process(clk_100,start) --分频得1s
begin
if (clk_100'event and clk_100='1') then
if start='0' then q_1<=0;f_1<='0';
else
if q_1=99 then q_1<=0;f_1<='1';
else q_1<=q_1+1;f_1<='0';
end if;
end if;
end if;
end process;
jishi:process(f_1,start) --计时模块
variable x:integer range 9 downto 0:=0;
variable w:integer range 9 downto 0:=0;
begin
if f_1'event and f_1='1' then
if reset='1' then --重置
k2<="0000";k1<="0000";k0<="0000";
m1<="0000";m0<="0000";
c2<="0000";c1<="1000";c0<="0000"; --行驶状态,3km以内8元
elsif (start='1' and stop='0' and ended='0') then --行驶状态
if x=8 then x:=0; --9s行程加0.1km,即0.2元
if k0="1001" then k0<="0000";
if k1="1001" then k1<="0000";
if k2="1001" then k2<="0000";
else k2<=k2+1;
end if;
else k1<=k1+1;
end if;
else k0<=k0+1;
end if;
if (k2&k1&k0>="000000110000") then --大于3km,开始行驶计费
if c0>="1001" then c0<=c0-"1000"; --行驶计费
if c1="1001" then c1<="0000";
if c2="1001" then c2<="0000";
else c2<=c2+1;
end if;
else c1<=c1+1;
end if;
else c0<=c0+2; --9s行程加0.1km,即0.2元
end if;
end if;
else x:=x+1;
end if;
elsif (start='1' and stop='1' and ended='0') then --等待停车状态
if w=5 then w:=0; --计时0.1分钟即6s,即0.1元
if m0="1001" then m0<="0000";
if m1="1001" then m1<="0000";
else m1<=m1+1;
end if;
else m0<=m0+1;
end if;
if c0="1001" then c0<="0000"; --等待计费
if c1="1001" then c1<="0000";
if c2="1001" then c2<="0000";
else c2<=c2+1;
end if;
else c1<=c1+1;
end if;
else c0<=c0+1;
end if;
else w:=w+1;
end if;
end if;
end if;
end process;
xiangshi:process(clk_scan,c0,k0,m0) --显示模块
variable a:integer range 9 downto 0:=0;
begin
if clk_scan'event and clk_scan='1' then
if start='1' then
bit_2<=a;
a:=a+1;
a:=a rem 8;
case bit_2 is
when 0=>num<=k0;op<="11111110";
when 1=>num<=k1;op<="11111101";
when 2=>num<=k2;op<="11111011";
when 3=>num<=c0;op<="11110111";
when 4=>num<=c1;op<="11101111";
when 5=>num<=c2;op<="11011111";
when 6=>num<=m0;op<="10111111";
when 7=>num<=m1;op<="01111111";
when others=>null;
end case;
end if;
end if;
end process;
shumaguan:process(num)
variable y:std_logic_vector(6 downto 0);
begin
case num is
when "0000" =>y:="1111110";
when "0001" =>y:="0110000";
when "0010" =>y:="1101101";
when "0011" =>y:="1111001";
when "0100" =>y:="0110011";
when "0101" =>y:="1011011";
when "0110" =>y:="1011111";
when "0111" =>y:="1110000";
when "1000" =>y:="1111111";
when "1001" =>y:="1111011";
when others =>null;
end case;
if (bit_2=2 or bit_2=5 or bit_2=0) then --添加小数点
led<=y&'1';
else led<=y&'0';
end if;
end process;
end one;
3.仿真:
4.板载测试
上图为:等待3.9min,总费用为23.9元,行驶里程为9.0km.
23.9=3.9*1+8+(9-3)*2,符合题意。
多次测试各种情况也符合题意。
测试成功!
1.系统测试结论: 通过反复地测试工作情况,得出本次实验的设计满足题意,并且只要输入的为标准100Hz的时钟信号,那么就能正确计算出行驶路程、等待时间、总费用,能精确到0.1。
2.性能特点: ①优点:计费、计时、计程很准确,达到40km/h的效果。功能全部实现。
3.可扩展性分析: 可以在加上几个模式:比如把模式分为:白天、黑夜、雨天等,不同的环境下实现计时、计程、计费。
1.设计过程中的困难和解决方法:
问题一:一个信号量只能在一个进程中赋值。解决:想办法在一个进程中赋值。
问题二:需要1500多个单元,但是只有1150个。解决:这个时候是用整形做的,然后把整形换为位矢量,并且优化过程,因为此时有六个进程process.
有的问题解决了,有的没解决,就换了思路。
当然还有一些小问题。
2.经验与收获体会、对EDA的认识
刚开始的时候感觉这一题还挺简单的,因为思路真的是异常清晰(之前习惯软件思维的我,把它当软件看),然后感觉用C语言写,分分钟的事情。一写起来,到处报错,才发现一些语法的细节不是很了解,在不断摸索中,终于对VHDL的越来越熟悉,通过不断地认识,从刚开始的数码管显示的有点乱七八糟,最后终于达到了自己的一点点要求,最后不断完善程序,终于达到了自己的要求。
发现VHDL这种硬件语言真的和之前学过的很不一样,有的时候编译通过,逻辑没问题,但是到了物理层次,还是出了问题。于是,在写VHDL的时候把它看出是一个物理盒子,写代码就是在连线一样,把变量尽量用二进制表示,成功率会提升许多。