一.声明
1. 首先该博客由本人的EDA课设报告改写而成,在此发布以供各位参考,目的是为大家提供一些理解和思路,希望大家不要盲目复制粘贴,一定要在自己有一定的理解基础上借鉴本文,才能在本次eda大作业中有所收获。(vhdl代码放在文章最后)
2. 如果遇到USB-Blaster驱动问题记得禁用驱动程序强制签名(一般是临时的,每次重启都需要重新禁用一遍),如果跳出小弹窗提示兼容性问题(无法在此设备上加载驱动程序),就需要打开“Windows安全中心”的控制面板,依次点击“设备安全性”->“内核隔离详细信息”->“内存完整性”,将“内存完整性”的选项关闭,然后重启电脑并重新安装驱动程序。
二.正文
1.题目要求
完成简易出租车计价器设计,选做停车等待计价功能。
基本功能:
1)起步8元/3公里,此后2元/公里;
2)里程指示信号为每前进50米一个高电平脉冲,上升沿有效;显示行驶公里数,精确到0.1公里。
4)前进里程开始之前显示价钱,精确到0.1元;
5)用两个按键分别表示开始行程和结束行程。
选做功能:
增加一个停车等待/恢复行程按钮,用2个数码管显示等待时间,精确到0.1分钟。
等候费1元/分钟,计价精度为0.1元。
2.分析与设计思路
1. 考虑到数码管只有八个,从左往右,这里把前三个数码管设置成价格显示部分,精确到0.1,第四个为最大行程的计数器,第五,六个数码管为行程显示部分,最后两个为等待时间显示
2. 前3公里为8元,意味着价格默认显示为0 8 0,其他数码管显示0,由于行程需要精确到0.1公里,而每50米一个上升沿脉冲,为了方便仿真,这里设置成每两个时钟脉冲,行程的小数部分要加1;等待部分精确到0.1分钟,这里设置成每6个时钟脉冲到来时等待时间的小数部分加1,同时对相应的价格进行计算和累加
3. 由于最大显示9.9公里(相当于10公里),为解决这个超限的问题,我们加了一个数码管记录行驶了多少个最大行程,而实际上在计费的时候,不是把计数部分乘以(行程-3)*2+8就能得到结果,因为当计数的数码管显示大于1时,计费标准依然是按3公里之后算的,所以第二段行程是从3开始累计。如果从行程0开始重新累计,那么前3公里就会停止计费,对一段未结束的行程来说,这是不符合现实情况的,所以将第二段及以上的行程从三公里开始计费,相当于对于同一个行程,除了第一段,其他都是7公里,由于重点是价格显示,我们不想做太大的改动,就让行程的显示不那么直观,否则价格变动不符合实际
4. 按下启动键,行程开始计数,到三公里以后,价格累加;按下停止键就会暂停;按下等待键也会停止行程,等待时间开始累加,价格也会相应增加,恢复行程按下启动键即可,清零键可随时作用,但除了停止状态,其他状态下按清零键依然会计数,所以需要手动停止(结束行程)再清零
5. 当价格显示部分超限就自动回到初始状态,同样要手动停止清零
3.引脚设置
4.开发板测试
验证公式:设n为数码管显示经过最大行程的个数(对应从左往右第四个数码管),m为行程部分显示的数,p为等待时间,则价格w=[(10*n+m-3*n)-3]*2+8+p元
5.总结
1. vhdl语言用起来并不顺手,但逻辑理清后多调试几次很快就能熟悉
2.这道题主要分为运行、等待、停止状态,三者的状态转换需要明确;事实上停止状态stop_state并不需要成为进程的敏感信号,因为在状态转换进程中任意一个状态经判断都是唯一的,即只允许一个状态为“1”,停止按键按下后,其他两个状态就会为“0”,计费和行程自然就停止了;
3.为了方便开发板测试,需要设置合适频率的时钟,不能过快导致捕捉不到变化;也不能太慢增加不必要的时间;
4.在处理进位的时候一定要注意语句的顺序问题,否则数码管会显示混乱
5.动态扫描进程需要用到conv_std_logic_vector函数来对数码管进行选择,要引入use ieee.std_logic_arith.all;
6.给最大行程计数,不至于因为量程不够影响计费,算是一个创新点;
7.代码没有考虑按键消抖问题,因为几乎没有冲突和按键失灵
8.验证价格是否正确,可以采用以下方式:
设n为数码管显示经过最大行程的个数(对应从左往右第四个数码管),m为行程部分显示的数,p为等待时间,则价格w为[(10*n+m-3*n)-3]*2+8+p元
9.通过此次eda大作业,加深了我对软硬结合应用的理解,也让我初步掌握vhdl的基本使用方法,锻炼了我分析问题解决问题的能力.
6.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(start_key:in std_logic;--启动
stop_key:in std_logic;--停止
wait_key:in std_logic;--等待
reset_key:in std_logic;--清零重置
drive_clk:in std_logic;--运行状态时钟
digital_clk:in std_logic;--选择数码管时钟
digital_sel:out std_logic_vector(7 downto 0);--控制八个数码管显示
choose:out std_logic_vector(7 downto 0));--选择第几个数码管
end Taxi;
Architecture situation of Taxi is
--数码管部分
type digital_status is array (0 to 9) of std_logic_vector(7 downto 0);--控制七段数码管的数组,用来控制0-9的数字显示
signal digital_array:digital_status;--不包含小数点
signal digital_array_dot:digital_status;--显示小数点
signal number:integer range 0 to 7:=0;--用于动态扫描数码管的数字显示选择
type sels is array(0 to 7) of std_logic_vector(7 downto 0);--定义选择数码管的数组类型
signal digitals:sels;--定义选择第几个数码管的信号,方便为digital-sel赋值
signal run_state:std_logic:='0';--判断是否处于运行状态的标志
signal wait_state:std_logic:='0';--判断是否处于等待状态的标志
signal stop_state:std_logic:='0';--判断是否处于停止状态的标志
signal state_temp:std_logic:='0';--临时判断标志,备用
--数码管的功能模块
--费用
signal pay0:integer range 0 to 9:=0;
signal pay1:integer range 0 to 9:=0;
signal pay2:integer range 0 to 9:=0;
--记录完成多少个最大行程10公里
signal counter_km:integer range 0 to 9:=0;
--行程
signal pos1:integer range 0 to 9:=0;
signal pos2:integer range 0 to 9:=0;
--等待
signal w1:integer range 0 to 9:=0;
signal w2:integer range 0 to 9:=0;
begin
--选择有小数点的显示
digital_array_dot(9)<="11110111";
digital_array_dot(8)<="11111111";
digital_array_dot(7)<="11100001";
digital_array_dot(6)<="10111111";
digital_array_dot(5)<="10110111";
digital_array_dot(4)<="01100111";
digital_array_dot(3)<="11110011";
digital_array_dot(2)<="11011011";
digital_array_dot(1)<="01100001";
digital_array_dot(0)<="11111101";
--选择无小数点的显示
digital_array(9)<="11110110";
digital_array(8)<="11111110";
digital_array(7)<="11100000";
digital_array(6)<="10111110";
digital_array(5)<="10110110";
digital_array(4)<="01100110";
digital_array(3)<="11110010";
digital_array(2)<="11011010";
digital_array(1)<="01100000";
digital_array(0)<="11111100";
--需要显示的数码管
show:process(digital_clk)
begin
digitals(7)<=digital_array(pay0);
digitals(6)<=digital_array_dot(pay1);
digitals(5)<=digital_array(pay2);
digitals(4)<=digital_array(counter_km);
digitals(3)<=digital_array_dot(pos1);
digitals(2)<=digital_array(pos2);
digitals(1)<=digital_array_dot(w1);
digitals(0)<=digital_array(w2);
end process;
--启动或停止或等待的进程状态判断和转化,1表示处于当前状态
state_reverse:process(start_key,stop_key,wait_state)
begin
--按下等待键
if wait_key='0' then
wait_state<='1';
run_state<='0';
stop_state<='0';
--按下启动键
elsif start_key='0' then
run_state<='1';
stop_state<='0';
wait_state<='0';
--按下停止键
elsif stop_key='0' then
stop_state<='1';
run_state<='0';
wait_state<='0';
end if;
end process;
run:process(drive_clk,run_state,wait_state,stop_state)
variable temp_pay0:integer range 0 to 9:=0;
variable temp_pay1:integer range 0 to 9:=8;
variable temp_pay2:integer range 0 to 9:=0;
variable temp_pos1:integer range 0 to 9:=0;
variable temp_pos2:integer range 0 to 9:=0;
variable temp_w1:integer range 0 to 9:=0;
variable temp_w2:integer range 0 to 9:=0;
variable count_pos:integer range 0 to 2:=0;--判断上升沿的次数,方便公里部分计数,每两个时钟脉冲相当于0.1㎞
variable count_wait:integer range 0 to 6:=0;--给等待时间计数,每六个时钟脉冲上升相当于0.1分钟
variable temp_counter_km:integer range 0 to 9:=0;--记录完成多少个9.9公里
--variable flag_empty:integer range 0 to 1:=0;--清零标志
begin
if rising_edge(drive_clk) then
--处于运行状态
if run_state='1' then
count_pos:=count_pos+1;
if count_pos>=2 then --行驶了0.1公里
temp_pos2:=temp_pos2+1;
if temp_pos1>=3 and temp_pos2>=0 then --三公里外价格才开始累加
temp_pay2:=temp_pay2+2;
if temp_pay2>9 then
temp_pay2:=0;
temp_pay1:=temp_pay1+1;
end if;
--一旦费用超出最大显示限额,全部清理,属于极端情况
if temp_pay1>9 then
temp_pay1:=0;
temp_pay0:=temp_pay0+1;
if temp_pay0>9 then
temp_pay0:=0;
temp_pay1:=8;
temp_pay2:=0;
temp_counter_km:=0;
temp_pos1:=0;
temp_pos2:=0;
temp_w1:=0;
temp_w2:=0;
end if;
end if;
end if;--三公里外的价格计算
if temp_pos2>9 then
temp_pos2:=0;
temp_pos1:=temp_pos1+1;
if temp_pos1>9 then
temp_pos2:=0;
temp_pos1:=3;
temp_counter_km:=temp_counter_km+1;--已完成一个最大行程
end if;
end if;
count_pos:=0;--重新计数
end if;
end if;--运行状态
--处于等待状态
if wait_state='1' then
count_wait:=count_wait+1;
if count_wait>=6 then ----经过0.1分钟
temp_w2:=temp_w2+1;
if temp_w2>9 then
temp_w2:=0;
temp_w1:=temp_w1+1;
if temp_w1>9 then
temp_w1:=0;
temp_w2:=0;
end if;
end if;
--等待时间下价格累加
temp_pay2:=temp_pay2+1;
if temp_pay2>9 then
temp_pay1:=temp_pay1+1;
temp_pay2:=0;
end if;
--一旦费用超出最大显示限额,全部清理,属于极端情况
if temp_pay1>9 then
temp_pay1:=0;
temp_pay0:=temp_pay0+1;
if temp_pay0>9 then
temp_pay0:=0;
temp_pay1:=8;
temp_pay2:=0;
temp_counter_km:=0;
temp_pos1:=0;
temp_pos2:=0;
temp_w1:=0;
temp_w2:=0;
end if;
end if;
count_wait:=0;--重新计数
end if;
end if;--等待状态
if reset_key='0' then --清零重置
temp_pay0:=0;
temp_pay1:=8;
temp_pay2:=0;
temp_counter_km:=0;
temp_pos1:=0;
temp_pos2:=0;
temp_w1:=0;
temp_w2:=0;
end if;
end if;--时钟上升沿
--给信号赋值
pay0<=temp_pay0;
pay1<=temp_pay1;
pay2<=temp_pay2;
counter_km<=temp_counter_km;
pos1<=temp_pos1;
pos2<=temp_pos2;
w1<=temp_w1;
w2<=temp_w2;
end process;
--动态扫描数码管
scan_sel:process(digital_clk)
begin
if rising_edge(digital_clk) then
digital_sel<=digitals(number);
choose<=not(conv_std_logic_vector(2**number,8));
if number=7 then number<=0;
else number<=number+1;
end if;
end if;
end process;
end situation;