学校布置的数字系统设计大作业,要求完成VHDL核心代码的设计,采用quartus II进行相关仿真并且在开发板上实现。由于本人能力有限,目的就是为了完成所要求的功能,就没有使用元件例化(同时也觉得作业中的要求比较简单),格式比较随便,代码仅供参考
- LED 输出显示资源
一共有24个发光二极管当输出为高电平时,发光二极管导通,产生光源;当输出为低电平时,发光二极管无法导通,灯不亮。
- 输入开关/输出显示复用资源
实验箱上共有 24 个开关与 24 个发光二极管,当需要输入时,开关闭合(对于拨码开关向上),则对应输入值为逻辑“1”且发光二极管亮,若开关断开,则输入值为逻辑“0”,数码管不亮。当作为输出时,输出值为逻辑“1”,则发光二极管亮,当输出值为逻辑“0”时,发光二极管不亮。
设计流程
EDA的设计流程主要包括设计输入、设计处理、设计验证、器件编程和硬件测试等5个步骤。
本次实验中,我采用通过硬件描述语言VHDL进行电路设计的方式;然后进行综合适配,对设计输入的文件进行逻辑化简,优化,对输入文件进行语法检查,最后产生编程文件;
设计验证即时序仿真和功能仿真。通常情况下,先进行功能仿真,验证其实现的功能是否满足原设计的要求。在功能仿真已经完成,确认设计文件表达的功能满足要求后,再进行综合适配和时序仿真。器件编程是指将设计处理中产生的编程数据下载到具体的可编程器件中,也就是所说的板载测试,将下载文件通过FPGA编程器载入目标芯片FPGA中。硬件测试是指将含有载入了设计的FPGA的硬件系统进行统一测试,便于在真实的环境中检验设计效果。
洗衣机控制器总体上分为状态控制模块、指示灯、显像管控制模块。其中的核心模块是定时模块,应通过定时模块来决定洗衣机当前所在的状态和所控制的显像管。
洗衣机总共有6个状态,分别为启动、正转、反转、浸泡、脱水、结束;每个状态对应一个指示灯,当一个状态结束时,另一个状态及其对应的指示灯需要立即衔接上去。
定时模块主要用于确定剩余时间,首先将输入的CLK信号分频为1Hz,控制每个状态的运行过程,将实时时间显示在数码管上。当倒计时结束后发送结束信号,显示特定的信息。
显像管控制模块包括用于显示各过程的二极管,也包括显示时间的显像管。通过高频率地来回控制两个显像管,人用肉眼看上去就不会觉得有闪动,从而实时显示当前时间。
定时模块需用到两个CLK信号,其中一个用于控制倒计时,另一个用于控制时间在显像管上的显示。将用于倒计时的CLK信号设置成1Hz,每过1Hz,总时间减1,当个位数为0时,控制十位数减1,同时将个位的数重新置为9;十位减至0,此时若个位位置为0时,个位的数开始每经过1Hz加1,持续5秒,最后重新置0,整个状态结束。十位和个位的起始数值由用户选择的模式来决定,若是浸泡洗,则分别为6和5;若是快速洗,则分别为6和0;若是脱水模式,则分别置为1和0。
控制两个显像管分别显示十位和个位,需要输入极快的CLK信号,在极短的时间内来回显示两个显像管,从而使人们看上去像同时控制了两个显像管。
本次控制器设置了6个状态,实验要求是将所有状态运行一遍。但观察生活中的洗衣机我们可知道,洗衣机可以选择从任意一个状态开始,所以我添加了浸泡洗,分离出了脱水,该控制器总共有三种模式可选择;每个状态都有一个显像管所对应,包括暂停状态。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity led is
port(clk: in std_logic; --时间控制信号
sjkz: in std_logic; --数码管控制
qidong: in std_logic; --启动信号
zanting:in std_logic; --暂停信号
fenggan:in std_logic; --脱水信号
jingpaoxi:in std_logic; -浸泡洗信号
qidongdeng:out std_logic; --启动指示灯
zhengzhuan:out std_logic; --正转指示灯
fanzhuan:out std_logic; --反转指示灯
jingpao:out std_logic; --浸泡指示灯
tuoshui:out std_logic; --脱水指示灯
jieshudeng:out std_logic; --结束指示灯
zantingdeng:out std_logic; --暂停指示灯
ledag:out std_logic_vector(7 downto 0);
Bt:out std_logic_vector(7 downto 0));
end led;
architecture arc of led is
signal cnt1: integer range 0 to 8 :=6;
signal cnt2: integer range 0 to 9 :=0;
signal jsjs: integer range 0 to 5 :=0; --结束倒计时控制信号
signal guan:integer range 0 to 1;
signal cntx:integer range 0 to 1; --两个数码管控制信号
signal jieshu:std_logic :='0';
begin
--控制特定的数码管
P1:process(cnt1,cnt2)
begin
case cntx IS
when 0=> BT<="11111101";guan<=0; --显示十位的数码管
when 1=> BT<="11111110";guan<=1; --显示个位的数码管
when others=>NULL;
End case;
end process p1;
--两个数码管来回显示控制
p2:process(sjkz)
begin
if sjkz='1' then
cntx<=1;
else cntx<=0;
end if;
end process p2;
--倒计时进程控制
P3:process(clk)
begin
qidongdeng<='0';
if fenggan='1' and jingpaoxi='0' and qidong='0' then
cnt1<=1;
elsif jingpaoxi='1' and fenggan='0' and qidong='0' then
cnt2<=5;
else
if qidong='1' then
qidongdeng<='1';
if clk'event and clk='1' then --每隔1Hz进行一次减1操作
if zanting='0' then
zantingdeng<='0';
if jieshu='0' then
if cnt2=0 and cnt1 /=0 then
cnt1<=cnt1-1;
cnt2<=9;
elsif cnt2=0 and cnt1=0 then
cnt1<=0;
cnt2<=0;
else cnt1<=cnt1;
cnt2<=cnt2-1;
end if;
if cnt1=5 or cnt1=4 then
if cnt2=9 or cnt2=7 or cnt2=5 or cnt2=3 or cnt2=1 then
zhengzhuan<='1';
else zhengzhuan<='0';
end if;
end if;
if cnt1=3 or cnt1=2 then
if cnt2=9 or cnt2=7 or cnt2=5 or cnt2=3 or cnt2=1 then
fanzhuan<='1';
else fanzhuan<='0';
end if;
end if;
if cnt1=1 then
if cnt2=9 or cnt2=7 or cnt2=5 or cnt2=3 or cnt2=1 then
jingpao<='1';
else jingpao<='0';
end if;
end if;
if cnt1=0 then
if cnt2=9 or cnt2=7 or cnt2=5 or cnt2=3 or cnt2=1 then
tuoshui<='1';
else tuoshui<='0';
end if;
if cnt2=0 then
jieshudeng<='1';
jieshu<='1';
end if;
end if;
else cnt1<=0;
cnt2<=0;
if jsjs=5 then
jieshudeng<='0';
cnt1<=8;
cnt2<=0;
else
jsjs<=jsjs+1;
cnt2<=jsjs+1;
jieshudeng<='1';
end if;
end if;
else cnt1<=cnt1;
cnt2<=cnt2;
zantingdeng<='1';
end if;
end if;
end if;
end if;
end process P3;
--显像管显示资源控制
P4:process(guan,cnt1,cnt2)
begin
if guan=1 then
case cnt2 is --控制个位的数码管显示数字信息
when 0 => ledag <="11111100";
when 1 => ledag <="01100000";
when 2 => ledag <="11011010";
when 3 => ledag <="11110010";
when 4 => ledag <="01100110";
when 5 => ledag <="10110110";
when 6 => ledag <="10111110";
when 7 => ledag <="11100000";
when 8 => ledag <="11111110";
when 9 => ledag <="11110110";
when others => null;
end case;
else
case cnt1 is --控制十位的数码管显示数字信息
when 0 => ledag <="11111100";
when 1 => ledag <="01100000";
when 2 => ledag <="11011010";
when 3 => ledag <="11110010";
when 4 => ledag <="01100110";
when 5 => ledag <="10110110";
when 6 => ledag <="10111110";
when 7 => ledag <="11100000";
when 8 => ledag <="00000001";
when others => null;
end case;
end if;
end process P4;
end arc;
注意!一定要根据自己使用的开发板上的引脚来设置,下面我只能提供我所使用的开发板的引脚分布,设置不一定要一模一样,具体情况具体布局
输入信号主要分三大类型,第一类是左上角蓝色部分的通用时钟信号,用于发送固定时钟频率的波动信号,这里选择一个合适的频率来回切换当前一瞬间所控制的数码管,再选择一个合适的频率用来控制倒计时速度
第二类就是红色部分中的电平信号,将开关向上拨动表示该引脚输出高电平,向下
表示低电平
第三类就是黑色部分的脉冲信号,按一次表示输出一个高脉冲,不像电平信号会一直维持当前状态,所以可以用于电话按键等方面
开发板应该都具备这些基本输入信号类型,建议看看开发板相应的说明书
运行结束:
5秒倒计时结束后,结束指示灯长亮,显像管显示规定数值。
本实验中系统设计已达成目的,完成了所要求的各功能,但还有一些地方可以进行优化,比如在程序中加入一部分对波形图显示进行优化的代码,使显像管对应的二进制表示改变成人们更习惯的十进制。
这次大作业,我收获最大的就是EDA操作的流程,VHDL语言的使用以及进程之间的通信都有了更深刻的认识,在实际操作中遇到了很多人都会遇到的问题,这些问题不会在书中讲述,只有靠平时的经验积累,才能为以后工作少走弯路。使用硬件描述语言需要我们学会从硬件的角度出发,理解信号传递之间的逻辑,在使代码精简的同时,确保系统运行的稳定性和正确性。