一、设计题目说明
题目九:出租车计价器设计(平台实现)★★
完成简易出租车计价器设计,选做停车等待计价功能。
基本功能:
1)起步8元/3公里,此后2元/公里;
2)里程指示信号为每前进50米一个高电平脉冲,上升沿有效;显示行驶公里数,精确到0.1公里。
4)前进里程开始之前显示价钱,精确到0.1元;
5)用两个按键分别表示开始行程和结束行程。
选做功能:
1)增加一个停车等待/恢复行程按钮,用2个数码管显示等待时间,精确到0.1分钟。
2)等候费1元/分钟,计价精度为0.1元。
二、设计目的与要求
1.学会在QuartusⅡ环境中运用VHDL语言设计方法构建具有一定逻辑功能的模块,并能运用图形设计方法完成顶层原理图的设计。
2.掌握出租车自动计费器的主要功能与在电路板中的实现。
3.运用QuartusⅡ软件中的仿真功能对所设计的出租车自动计费器的各个模块及顶层电路的功能进行仿真分析。
三、总体设计
3.1 基本原理(EDA设计流程、开发环境和硬件资源介绍)
EDA设计流程:
1.设计输入
本次大作业使用文本输入方式,采用VHDL语言编写各个模块:分频模块、控制模块、计量模块、计费模块、译码动态扫描显示模块。 然后每个模块生成原件加入元件库,醉胡将电路的设计以原理图的方式输入。这种输入方式直观,便于电路的观察及修改。
2.设计处理
设计处理是EDA设计流程中重要的设计环节,主要对设计输入的文件进行逻辑化简,综合优化,最后产生编程文件。此阶段主要包括设计编译与检查、逻辑分割、逻辑优化、布局布线等过程。 设计编译与检查是对输入文件进行语法检查,编译之后确实出现不少语法错误。
3.设计验证
设计验证即时序仿真和功能仿真。
器件编程,板载测试
器件编程是指将设计处理中产生的编程数据下载到具体的可编程器件中。如果之前的步骤都满足设计的要求,就可以将适配器产生的配置或下载文件通过CPLD/FPGA编程器或下载电缆载入目标芯片CPLD或FPGA中。 本次使用芯片为:FPGA10K20TC144-4
开发环境:Quartus II 9.0 sp2 Web Edition
3.2 总体结构分析与设计
根据层次化设计理论,该设计问题自顶向下可分为分频模块、控制模块、计量模块、计费模块、译码动态扫描显示模块。
四、实现与仿真(实现步骤、VHDL代码含注释、原理图、仿真、板载测试)
4.1分频器模块
本模块中,clk_3和clk_2 是控制模块的中的clk_in1和clk_in2,二选一之后是clk_out应用于计费,所以clk_3是表示行驶计费中的0.1元;clk_2代表等待计费中的0.1元;clk_1适用于计算等待时间和公里数的;
代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity fenpin is
port(clk :in std_logic; --系统时钟
clk_3: buffer std_logic; –
clk_2: buffer std_logic; –
clk_1: buffer std_logic); –
end fenpin;
architecture rtl of fenpin is
signal q_15:integer range 0 to 4;
signal q_1:integer range 0 to 1;
begin
process(clk)
begin
clk_2<=clk;
if (clk’event and clk=‘1’ )
then
–if q_15=2 then q_15<=0;
clk_3<=not clk_3;
–else q_15<= q_15+1;
–end if;
clk_1<=not clk_1;
end if;
end process;
end rtl;
原理图:
仿真:
4.2 计费模块
当计费信号 Start 一直处于高电平即计费状态时,本模块根据控制模块迭择出的信号从而对不同单价的时段进行计费。即行程在3km内起步价8元:3km外以每0.1公里按0.1元计费,等待时间每0.1分钟0.2元计费。c0、 cl 、c2分别表示费用的显示.处于计费状态时,随着clk2的高电平的到来,计费起步价为8元。c0满9向 cl 进位, cl 满9向2产生进位,依次逐级进位,从而完成计费功能。
代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity jifei is
port(clk2:in std_logic; --计费驱动信号
start: in std_logic; --计费开始信号
c0,c1,c2: buffer std_logic_vector(3 downto 0));–
end jifei;
architecture rt4 of jifei is
begin
process(clk2,start)
begin
if start=‘0’
then
c2<= “0000”;----0.1
c1<=“1000”;--------1-----8----coci.c2
c0<=“0000”; ------10
elsif clk2'event and clk2='1' then
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;
end if;
end process;
end rt4;
原理图:
仿真:
3.3 计量模块
Start 置1程序始终处于计费状态,当 fin 脉冲到来时进入计程状态,且k0每次满9就向k1进位,超过3km时en0就变为高电平:同理,当 stop 由0置为1时开始由计程进入等待状态, fin 脉冲归为0里程计数停止, enl 变为高电平,等待时间开始计时,m0每次满9就向 ml 进位。
代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity jiliang is
port( start: in std_logic; --计费开始信号
fin: in std_logic;
stop: in std_logic; --行驶中,中途等待信号
clk1:in std_logic;
en1,en0: buffer std_logic; --计费单价使能信号
k1,k0,k00: buffer std_logic_vector(3 downto 0);
m1,m0: buffer std_logic_vector(3 downto 0)); --等待时间计数
end jiliang;
architecture tr2 of jiliang is
begin
process(clk1)
begin
if clk1’event and clk1=‘1’ then
if start=‘0’ then
en1<=‘0’;
en0<=‘0’;
m1<=“0000”;
m0<=“0000”;
k1<=“0000”;
k0<=“0000”;
k00<=“0000”;
elsif stop=‘1’ then --计时开始信号
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 stop='1' then en0<='0';
en1<='1';
end if;
elsif fin='1' then
--里程计数开始
if k00="1001" then k00<="0000";
if k0="1001" then k0<="0000";
if k1="1001" then k1<= "0000"; --计程范围 0.0-99.9
else k1<=k1+1;
end if;
else k0<=k0+1;
end if;
else k00<=k00+1;
end if;
if stop='0' then en1<='0';
if k1&k0>"0000010" then en0<='1'; --若行驶里程大于3km则en0置1
else en0<='0';
end if;
end if;
end if;
end if;
if stop='0' and fin='0' then
en0<='0';
en1<='0';
end if;
end process;
end tr2;
原理图:
仿真:
4.4控制模块
本模块主要是通过计量模块产生的两个不同的输入使能信号en0、 enl ,对两个分频模块输出的脉冲进行选择输出的过程;本模块实现了双脉冲的二选一:最终目的为了计费模块中对行驶过程中不同的模式进行计价.
代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity kongzhi is
port(en0,en1:in std_logic;
–使能选择信号
clk_in1:in std_logic;
–20分频输入信号
clk_in2:in std_logic;
–15分频输入信号
clk_out:out std_logic);
–输出信号
end kongzhi;
architecture rt3 of kongzhi is
begin
process(en0,en1)
begin
if en0=‘1’ then --实现二选一功能
clk_out<= clk_in2;
elsif en1=‘1’ then
clk_out<=clk_in1;
else clk_out<= null;
end if;
end process;
end rt3;
原理图:
仿真:
4.5译码显示模块
片选信号有8个,低电平有效,8个数码区的片选全部赋值为0了,这样8个数码管就全部有效,同时显示(片选的意思是选择哪一个数码管有效);
段选就是显示什么形状如下图:
代码:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity dis is
port(clk:in std_logic; --动态显示刷新速度时钟
q0:in std_logic_vector(3 downto 0); --c2
q1:in std_logic_vector(3 downto 0); --c1
q2:in std_logic_vector(3 downto 0); --c0
q3:in std_logic_vector(3 downto 0); --k1
q4:in std_logic_vector(3 downto 0); --k0
q5:in std_logic_vector(3 downto 0); --k00
q6:in std_logic_vector(3 downto 0); --m1
q7:in std_logic_vector(3 downto 0); --m0
qudong1:out std_logic_vector(7 downto 0); --驱动信号输出
------0~7分别为abcdefgp
contrl:buffer std_logic_vector(2 downto 0)); --数码管位选输出,000最低位数码管有效,111最高位数码管有效
end dis;
architecture behavior of dis is
signal disp:std_logic_vector(3 downto 0);
signal temp:std_logic_vector(2 downto 0);
begin
process(clk)
begin
if clk’event and clk=‘1’ then
temp<=temp+1;
end if;
contrl<=temp;
end process;
process(contrl) --位选信号产生进程
begin
case contrl is
when"000"=>disp<=q0;
when"001"=>disp<=q1;
when"010"=>disp<=q2;
when"011"=>disp<=q3;
when"100"=>disp<=q4;
when"101"=>disp<=q5;
when"110"=>disp<=q6;
when"111"=>disp<=q7;
when others=>disp<=“0000”;
end case;
end process;
---
process(disp) --译码进
begin
case disp is
when"0000"=>qudong1<="00111111";
when"0001"=>qudong1<="00000110";
when"0010"=>qudong1<="01011011";
when"0011"=>qudong1<="01001111";
when"0100"=>qudong1<="01100110";
when"0101"=>qudong1<="01101101";
when"0110"=>qudong1<="01111101";
when"0111"=>qudong1<="00000111";
when"1000"=>qudong1<="01111111";
when"1001"=>qudong1<="01101111";
when others=>qudong1<="00000000";
end case;
end process;
end behavior;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity over is
port(
con :in std_logic_vector(2 downto 0);
outsel: out std_logic_vector(7 downto 0)
);
end over;
architecture behavior of over is
begin
process(con) --译码进
begin
case con is
when"111"=>outsel<="11111110";
when"110"=>outsel<="11111101";
when"101"=>outsel<="11111011";
when"100"=>outsel<="11110111";
when"011"=>outsel<="11101111";
when"010"=>outsel<="11011111";
when"001"=>outsel<="10111111";
when"000"=>outsel<="01111111";
when others=>outsel<="11111111";
end case;
end process;
end behavior;
原理图:
仿真:
4.6没有显示模块时做的测试
原理图:
仿真:
4.7总原理图
仿真:
引脚分配
五、设计结论与分析
系统测试结论:
实现了功能。
性能特点(优点、不足):
优点:完成了基本功能和补充内容中的功能。
不足:没有小数点;
可扩展性分析 :
夜晚和白天计费不同;
节假日增加服务费;
阶梯价格更加详细;
车速不固定,加一个车速模拟模块。
六、小结与心得体会
要养成看API或者说明文档的习惯:在最后调试的时候数码管显示一直有问题,在同学的帮助下发现是0/1表示的问题;
动态显示就是数码管不断变化,当变化速度超过人眼的识别范围,看起来就像数码管一直显示。需要一个八位段选信号和一个八位片选信号。然后这个信号对应比较麻烦。
板载实验中,数码管数字跳的太快或者太慢的问题,在数码管后边有频率说明,但是没有直观感受,切换引脚多试几次就明白了;
连接引脚的时候没有pinplanner,解决:View—>All Pins list,就是没有location之类的配置引脚信息,这个时候我们就可以鼠标放在下面那栏中单击右键,然后选择customize columns就会进入到下面这种选项,把想要的添加进去,然后点击OK即可,这样这个配置引脚的窗口就正常化了。
分频模块花费了不少时间,关于计算的问题总是错,系统时钟一个脉冲代表50m和一秒钟,按照题目的要求1元/分钟,起步价之后2元/公里
设计的核心内容就是QuartusⅡ环境中,利用VHDL语言设计出基于CPLD的出租车自动计费器。整个设计过程中首先对数字电路这门课程有了更深的了解, 将以前所学的理论知识运用到实际的电路设计当中去;
设计的验证重要但费时。每个模块都要去仿真一次,所以每个模块都创建工程去看仿真的结果正不正确,对设计的各个模块以及顶层电路进行的功能仿真及分析,这个方式更加有效。
最后测试的时候分频的问题
process(clk)–时钟频率为100Hz
If clk’event and clk=‘1’ then
count:=count+1;
If count=100 then
Second<=second+1;
count:=0;
END IF;
end if;
这样second就是一秒一秒的增加的