赞
踩
封面来源:Multiplexer
首先我们先对组合逻辑的相关知识做一下讲解。
数字电路根据逻辑功能的不同的特点,可以分为两大类:一类就是组合逻辑,另一类就是我们后面将会讲到的时序逻辑。组合逻辑是 Verilog HDL 设计中的一个重要的组成部分。从电路本质上讲,组合逻辑电路的特点就是:输出信号只是当前输入信号的函数,与其他时刻的输入状态无关,无存储电路,也没有反馈电路。怎么理解呢?
就是说组合逻辑电路,它的输出信号的电平变化仅仅与输入信号的电平变化有关,不涉及信号跳变沿的处理,这就是组合逻辑。
了解完组合逻辑的概念之后,我们来学习一下多路选择器。
多路选择器也叫数据选择器,它在多路数据传输过程中,能够根据需求将其中任意一路选出来的电路,叫做数据选择器。也可以称它为多路选择器或者多路开关。
我们举个例子,比如说,图 1.2.1 是一个多路选择器。多路选择器会有很多的输入信号(in1、in2、……、n),我们可以使用一些选择条件(sel)来对这些信号进行选择,可以从中选择出任意一条电路作为输出,这就是多路选择器的功能。
那么以上就是理论部分的学习,接下来开始实战的演练。
在实战演练部分,我们将会设计并实现一个二选一多路选择器。它有两个输入信号,我们使用选择信号 sel 对俩信号进行选择,选择任一信号作为输出。
那么具体怎么在开发板上实现呢?
我们可以使用按键和 LED 灯。我们可以使用我们的 KEY1 作为信号 1 的输入,KEY2 作为信号 2 的输入,使用 KEY3 作为 sel 选通信号;然后使用 D6 LED 灯作为输出。如图 2.2 所示
在上一小节中我们也提到了:当按键未按下时,输出电平为高电平;按下时,输出电平为低电平;LED 灯输入低电平时被点亮,输入高电平时熄灭。
接下来就正式开始实验工程的设计。
首先我们新建一个文件夹,命名为 mux2_1,用来存放我们的实验工程,在里面新建 4 个子文件夹。打开 doc 文件夹,新建一个 Visio 文件,用来绘制模块框图和波形图。文件结构如下
├─mux2_1
│ ├─doc
│ │ └─mux2_1.vsdx
│ ├─quartus_prj
│ ├─rtl
│ └─sim
双击打开 Visio 文件,进行模块框图的绘制。我们将输入信号 1 命名为 in_1,我们将输入信号 2 命名为 in_2,将选择信号命名为 sel,将输出信号命名为 out,这样,二选一多路选择器的模块框图就画完了。如图 2.3.1 所示
接下来进行波形图的绘制。
首先是波形信号的命名,我们可以直接选用模块框图的命名。输入信号我们填充为绿色,表示输入信号;输出信号命名为 out,输出信号我们填充红色来表示。如图 2.3.2.1 所示
因为二选一多路选择器,它是使用选择信号对输入信号进行一个选择,所以说输入信号、输出信号它的波形变化是随机的,所以说我们对输入信号和输出信号它们的波形进行随机的绘制。
先来对 in_1 输入信号的波形进行随机的绘制,我们随机绘制的 in_1 的输入信号的波形如图 2.3.2.2 所示
那么下面开始 in_2 输入信号波形的随机绘制。如图 2.3.2.3 所示
输入信号 in_1 和 in_2 的电平变化是随机的,大家可以按照自己的想法来进行绘制。
输入、输出信号绘制完成之后,对我们的选择信号进行一下随机的绘制。如图 2.3.2.4 所示
好了,两路输入信号和一路选择信号他们的波形绘制完成了
输出信号的电平变化是根据选择信号的高低电平变化,对输入的信号进行一个选择性的输出。为了方便输出信号的绘制,我们添加几条参考线。因为输出信号的波形变化,它的参照是选择信号的高低电平变化,所以说,参考线我们加在 sel 信号的上升沿和下降沿。如图 2.3.2.5 所示
好了,参考线已经添加完成,下面就是输出信号的绘制。
我们前面已经讲过了:当我们的选择信号为低电平时,我们进行输入信号 2 的输出;选择信号为高电平时,进行输入信号 1 的输出。如图 2.3.2.6 所示
那么到这里,输出信号的波形就绘制完成,整体的波形图也绘制完成了。
那么下面就可以开始代码的编写,找到文件存放位置,找到我们的 rtl 文件夹,新建一个 .v 文件,命名为 mux2_1 就是我们的模块名称(后缀名一定要改成.v,因为 .v 才是 Verilog 文件的格式 )。文件结构如下
├─mux2_1
│ ├─doc
│ │ mux2_1.vsdx
│ ├─quartus_prj
│ ├─rtl
│ │ mux2_1.v
│ │
│ └─sim
那么接下来就可以进行代码的编写
实现二选一多路选择器的功能的 Verilog 代码它的形式有很多,我们这里主要列举以下三种实现的方法
mux2_1.v
module mux2_1 ( input wire [0:0] in_1, //输入信号1 input wire in_2, //输入信号2 input wire sel , //选通信号 output reg out //输出信号 ); //out:输出信号 always @ (*) if (sel == 1'b1) out = in_1; else out = in_2; endmodule
接下来就新建我们的工程,对我们的代码进行编译,查找我们的语法错误
我们回到桌面,双击开发软件快捷方式打开我们的开发软件。开发软件打开,我们可以通过启动界面的快捷方式来进行实验工程的创建。第一个导向界面,点击 下一步,文件存放位置的选择框我们选择 quartus_prj 文件夹,点击 选择文件夹。工程的命名我们命名为 mux2_1,然后点击 下一步。.v 文件我们暂时不添加,点击 下一步。FPGA 芯片系列的选择,我们使用的是 Cyclone IV 系列,封装方式的选择我们选择的是 FBGA,然后引脚数是 256 个引脚,速度等级选择的是第 8 等级。那么经过筛选,就筛选出了四个满足条件的 FPGA 芯片,我们的型号是第二个:EP4CE10F17C8 选中它,点击 下一步。EDA 仿真工具的设置,我们可以直接选择我们的 ModelSim 作为仿真软件,语言就是 Verilog HDL,在这里如果进行了设置,那么后期就不需要再进行设置了,当然了,你也可以跳过,在后面进行设置。设置完成之后,点击 下一步,就是我们的工程设置信息,确定没有错误,点击 Finish,那么实验工程就已经设置完了
点击我们的 Files,点击 Files,点击(鼠标)右键添加我们的 .v 文件,那么这些内容,在上一讲已经讲过了,大家应该是轻车熟路。点击这个位置,选择我们的 .v 文件,找到 rtl 文件夹,选择 .v 文件。然后选择 添加、应用、OK。点击这个位置进行代码的编译,然后查找我们的语法错误。编译完成有 8 个警告,没有严重警告和错误,就可以先不关心,我们点击 OK
那么编译完成之后要进行仿真,仿真就要进行仿真文件的编写。找到我们的 sim 文件夹,然后新建一个 .v 文件,命名为 tb_mux2_1,它表示的是对我们的 mux2_1 模块进行仿真,后缀名改成 .v,回车 是
双击打开仿真文件,开始仿真文件的编写
tb_mux2_1.v
`timescale 1ns/1ns module tb_mux2_1(); reg in_1; reg in_2; reg sel ; wire out; initial begin in_1 <= 1'b0; in_2 <= 1'b0; sel <= 1'b0; end always #10 in_1 <= {$random} % 2; always #10 in_2 <= {$random} % 2; always #10 sel <= {$random} % 2; initial begin $timeformat(-9, 0, "ns", 6); $monitor("@time %t:in_1=%b in_2=%b sel=%b out=%b", $time, in_1, in_2, sel, out); end mux2_1 mux2_1_inst ( .in_1(in_1), //输入信号1 .in_2(in_2), //输入信号2 .sel (sel ), //选通信号 .out (out ) //输出信号 ); endmodule
那么到了这里仿真文件编写完成,我们保存。回到我们的工程文件,然后添加我们的仿真文件。点击 Files 右键 添加文件,这儿已经轻车熟路了,找到我们的仿真文件,然后 添加 应用 OK。回到我们的实验工程
进行仿真的设置,选择 Assignmengts 选项卡,选择我们的 设置,找到我们的 Simulation(仿真)。我们之前在新建工程的时候,对仿真软件这儿已经进行了设置,所以说这儿不需要再进行更改。我们直接选择这个位置编译 test bench,选择 Test Benches… 新建
,然后输入我们的 tb 名称,就是 tb_mux2_1,这俩个名称默认是一致的,我们不需要进行修改。然后是时间停止参数的设置,设置为 1 us,在这个位置添加仿真文件,然后点击 添加,然后 OK、OK、应用、OK,我们可以点击这个位置与 Modelsim 进行联合仿真
我们打开波形窗口,点击 全局视图,添加我们的参考线,然后进行放大,在选通信号这个上升沿之前它是保持低电平,sel 低电平时输出信号应该与输入信号 2 保持一致,这儿是正确的
在这个上升沿到这个下降沿,选通信号保持高电平。所以说,输出信号应该与输入信号 1 保持一致,它俩的电平是相同的。选通信号到下一个上升沿,这一段时间一直是低电平,那么输出信号应该与输入信号 2 保持一致,这也是一致的,而且仿真波形与我们绘制的波形图是一致的
那么波形变化是一致的,我们来查看一下数据打印窗口
在打印信息显示界面,我们可以看到,打印的内容与我们监测函数里边编写的内容是一致的。我们随便挑选一组数据:当选通信号为高电平时,输出信号为高电平,与我们的输入信号 1 电平是一样的;那么当选通信号为 0 时,输出信号为 0,与我们选通信号 2 是保持一致的,那么仿真验证通过了。
下面就可以进行管脚的绑定。打开我们的工程文件,选择 Pin Planner 这个位置,在下面这个界面进行管脚的绑定。输入信号 1 我们使用按键 KEY1 来进行输入,按键 KEY1 与 FPGA 的物理连接是 M2 引脚,我们输入 M2,点击回车;in_2 是 M1,输入完成,点击回车;那么输出是 L7,就是我们的 LED 灯,点击回车;那么选通信号是 E15,选择回车。引脚绑定完成之后,我们关闭
回到我们的实验工程,进行一次全编译
那么编译完成,有 7 个警告,不需要关心,点击 OK。
那么接下来就是上板验证
我们下图所示,连接我们的下载器和我们的电源,下载器的另一端连接我们的电脑
回到我们的实验工程,点击 Programmer 这个位置,打开下载界面。点击 添加文件,找到我们的 SOF 文件,点击 打开,点击 开始,进行程序的下载
程序下载完成,我们打开摄像头
二选一多路选择器 上板验证
输入信号 1 是 KEY1 表示,输入信号 2 是 KEY2 表示,那么选通信号使用了按键 KEY3。按键都没有被按下,所以说都是为高电平,那么目前 LED 灯输入的应该是按键 KEY1 传入的信号
,所以说 LED 灯没有被点亮。我们按下按键 KEY1,输入到 LED 灯的是低电平,所以说被点亮;如果我们按下按键 KEY3,选通信号为低电平,同时按下按键 KEY2,输入到 LED 灯的就是低电平,LED 灯被点亮,那么上板验证验证通过。
那么我们前面已经提到了:我们将使用三种组合逻辑的方式来实现我们的多路选择器。
那么刚刚使用的是:always 语句与 if-else 相结合的这种方式
always @ (*)
if (sel == 1'b1)
out = in_1;
else
out = in_2;
那么第二种方式就是 always 与 case 语句相结合的
always @ (*)
case (sel)
1'b1: out = in_1;
1'b0: out = in_2;
default: out = in_1;
endcase
case 条件分支语句的结构,我们之前已经讲过了,那么这段代码是怎么运行的呢?
首先是对 sel 选通信号进行一个判断,如果它是一个高电平的,就将输入信号 1 赋值给输出信号;如果是低电平就将输入信号 2 赋值给输出信号
这儿添加 default: out = in_1;
语句的目的是表示:如果说所有的情况并没有被完全列举,那么除这两种情况之外的其他情况,都执行这条语句;如果说所有的情况都被列举了,这条语句可以省略
第三种方式是使用 assign 语句对我们的组合逻辑进行一个赋值
assign out = (sel==1'b1)? in_1: in_2;
使用的是条件运算符,我们前面已经讲过了,这条语句是怎么执行的呢?
当我们的选通信号为高电平时,将输入信号 1 赋值给我们的输出信号;如果选通信号不是高电平那么就是低电平,那么就将输入信号 2 赋值给输出信号
我们常用的三种组合逻辑的赋值方式,已经讲解完了,那么实战演练的全部内容,也已经讲解完毕。
在本讲视频当中,我们主要学习了,我们三种常用的组合逻辑的赋值方式。
参考资料:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。