[FPGA 学习记录] 简单组合逻辑——多路选择器

简单组合逻辑——多路选择器

封面来源:Multiplexer


在本小节中,我们将使用 Verilog 语言描述一个具有多路选择器功能的电路,目的是学会使用 Verilog 语言实现简单的组合逻辑
本小节的主要内容分为两个部分:一个部分是理论学习,在这一部分我们会对本小节涉及到的理论知识做一个讲解;另一个部分是实战演练,我们将设计一个多路选择器,加深对理论知识的理解
接下来是理论部分的学习。

1 理论学习

1.1 组合逻辑

首先我们先对组合逻辑的相关知识做一下讲解。
数字电路根据逻辑功能的不同的特点,可以分为两大类:一类就是组合逻辑,另一类就是我们后面将会讲到的时序逻辑。组合逻辑是 Verilog HDL 设计中的一个重要的组成部分。从电路本质上讲,组合逻辑电路的特点就是:输出信号只是当前输入信号的函数,与其他时刻的输入状态无关,无存储电路,也没有反馈电路。怎么理解呢?
就是说组合逻辑电路,它的输出信号的电平变化仅仅与输入信号的电平变化有关,不涉及信号跳变沿的处理,这就是组合逻辑。

1.2 多路选择器

了解完组合逻辑的概念之后,我们来学习一下多路选择器。
多路选择器也叫数据选择器,它在多路数据传输过程中,能够根据需求将其中任意一路选出来的电路,叫做数据选择器。也可以称它为多路选择器或者多路开关。

我们举个例子,比如说,图 1.2.1 是一个多路选择器。多路选择器会有很多的输入信号(in1、in2、……、n),我们可以使用一些选择条件(sel)来对这些信号进行选择,可以从中选择出任意一条电路作为输出,这就是多路选择器的功能。

image-20231010082804485

图 1.2.1 多路选择器

2 多路选择器的实战演练

那么以上就是理论部分的学习,接下来开始实战的演练。

2.1 实验目标

在实战演练部分,我们将会设计并实现一个二选一多路选择器。它有两个输入信号,我们使用选择信号 sel 对俩信号进行选择,选择任一信号作为输出。

当控制选择信号 sel 为高电平时,输出信号 1,当选通控制信号 sel 为低电平时,输出信号 2。

如图 2.1 所示

image-20231010085136175

图 2.1 二选一多路选择器

2.2 硬件资源

那么具体怎么在开发板上实现呢?
我们可以使用按键和 LED 灯。我们可以使用我们的 KEY1 作为信号 1 的输入,KEY2 作为信号 2 的输入,使用 KEY3 作为 sel 选通信号;然后使用 D6 LED 灯作为输出。如图 2.2 所示

image-20231010085919933

图 2.2 开发板上实现二选一多路选择器

在上一小节中我们也提到了:当按键未按下时,输出电平为高电平;按下时,输出电平为低电平;LED 灯输入低电平时被点亮,输入高电平时熄灭。

2.3 程序设计

接下来就正式开始实验工程的设计。

首先我们新建一个文件夹,命名为 mux2_1,用来存放我们的实验工程,在里面新建 4 个子文件夹。打开 doc 文件夹,新建一个 Visio 文件,用来绘制模块框图和波形图。文件结构如下

├─mux2_1
│  ├─doc
│  │  └─mux2_1.vsdx
│  ├─quartus_prj
│  ├─rtl
│  └─sim
2.3.1 模块框图

双击打开 Visio 文件,进行模块框图的绘制。我们将输入信号 1 命名为 in_1,我们将输入信号 2 命名为 in_2,将选择信号命名为 sel,将输出信号命名为 out,这样,二选一多路选择器的模块框图就画完了。如图 2.3.1 所示

image-20231010093018278

图 2.3.1 二选一多路选择器模块框图
2.3.2 波形绘制

接下来进行波形图的绘制。
首先是波形信号的命名,我们可以直接选用模块框图的命名。输入信号我们填充为绿色,表示输入信号;输出信号命名为 out,输出信号我们填充红色来表示。如图 2.3.2.1 所示

image-20231010093757799

图 2.3.2.1 波形信号的命名

因为二选一多路选择器,它是使用选择信号对输入信号进行一个选择,所以说输入信号、输出信号它的波形变化是随机的,所以说我们对输入信号和输出信号它们的波形进行随机的绘制。

先来对 in_1 输入信号的波形进行随机的绘制,我们随机绘制的 in_1 的输入信号的波形如图 2.3.2.2 所示

image-20231010094233981

图 2.3.2.2 输入信号 in_1 的波形

那么下面开始 in_2 输入信号波形的随机绘制。如图 2.3.2.3 所示

image-20231010094810560

图 2.3.2.3 输入信号 in_2 的波形

输入信号 in_1 和 in_2 的电平变化是随机的,大家可以按照自己的想法来进行绘制。

输入、输出信号绘制完成之后,对我们的选择信号进行一下随机的绘制。如图 2.3.2.4 所示

image-20231010095250187

图 2.3.2.4 选通信号 sel 的波形

好了,两路输入信号和一路选择信号他们的波形绘制完成了

输出信号的电平变化是根据选择信号的高低电平变化,对输入的信号进行一个选择性的输出。为了方便输出信号的绘制,我们添加几条参考线。因为输出信号的波形变化,它的参照是选择信号的高低电平变化,所以说,参考线我们加在 sel 信号的上升沿和下降沿。如图 2.3.2.5 所示

image-20231010095955393

图 2.3.2.5 参考线

好了,参考线已经添加完成,下面就是输出信号的绘制。
我们前面已经讲过了:当我们的选择信号为低电平时,我们进行输入信号 2 的输出;选择信号为高电平时,进行输入信号 1 的输出。如图 2.3.2.6 所示

image-20231010101009957

图 2.3.2.6 输出信号 out 的波形

那么到这里,输出信号的波形就绘制完成,整体的波形图也绘制完成了。

2.4 代码编写

那么下面就可以开始代码的编写,找到文件存放位置,找到我们的 rtl 文件夹,新建一个 .v 文件,命名为 mux2_1 就是我们的模块名称(后缀名一定要改成.v,因为 .v 才是 Verilog 文件的格式 )。文件结构如下

├─mux2_1
│  ├─doc
│  │      mux2_1.vsdx
│  ├─quartus_prj
│  ├─rtl
│  │      mux2_1.v
│  │
│  └─sim

那么接下来就可以进行代码的编写

实现二选一多路选择器的功能的 Verilog 代码它的形式有很多,我们这里主要列举以下三种实现的方法

1. always 语句与 if-else 相结合的方式
2. always 与 case 语句相结合的
3. 使用 assign 语句对我们的组合逻辑进行一个赋值

这三种方法对应的核心语法是不相同的,后面我们会经常遇到这三种语法。 第一种方法,我们使用 always 进行组合逻辑的编写,同时使用 if-else 条件分支语句,进行这个多路选择器的实现。**模块的名称与我们的文件名称,尽量保持一致**

notepad_MlBr1Gr6rm

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

2.5 代码编译

接下来就新建我们的工程,对我们的代码进行编译,查找我们的语法错误

我们回到桌面,双击开发软件快捷方式打开我们的开发软件。开发软件打开,我们可以通过启动界面的快捷方式来进行实验工程的创建。第一个导向界面,点击 下一步,文件存放位置的选择框我们选择 quartus_prj 文件夹,点击 选择文件夹。工程的命名我们命名为 mux2_1,然后点击 下一步。.v 文件我们暂时不添加,点击 下一步。FPGA 芯片系列的选择,我们使用的是 Cyclone IV 系列,封装方式的选择我们选择的是 FBGA,然后引脚数是 256 个引脚,速度等级选择的是第 8 等级。那么经过筛选,就筛选出了四个满足条件的 FPGA 芯片,我们的型号是第二个:EP4CE10F17C8 选中它,点击 下一步。EDA 仿真工具的设置,我们可以直接选择我们的 ModelSim 作为仿真软件,语言就是 Verilog HDL,在这里如果进行了设置,那么后期就不需要再进行设置了,当然了,你也可以跳过,在后面进行设置。设置完成之后,点击 下一步,就是我们的工程设置信息,确定没有错误,点击 Finish,那么实验工程就已经设置完了

B1Yxw5MJ5X

点击我们的 Files,点击 Files,点击(鼠标)右键添加我们的 .v 文件,那么这些内容,在上一讲已经讲过了,大家应该是轻车熟路。点击这个位置,选择我们的 .v 文件,找到 rtl 文件夹,选择 .v 文件。然后选择 添加、应用、OK。点击这个位置进行代码的编译,然后查找我们的语法错误。编译完成有 8 个警告,没有严重警告和错误,就可以先不关心,我们点击 OK

quartus_t1dglgGe9V

2.6 逻辑仿真

那么编译完成之后要进行仿真,仿真就要进行仿真文件的编写。找到我们的 sim 文件夹,然后新建一个 .v 文件,命名为 tb_mux2_1,它表示的是对我们的 mux2_1 模块进行仿真,后缀名改成 .v,回车 是

explorer_DjLYGWYQnx

双击打开仿真文件,开始仿真文件的编写

notepadL7e2hQzRB1

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。回到我们的实验工程

quartus_n2CmAlWinS

进行仿真的设置,选择 Assignmengts 选项卡,选择我们的 设置,找到我们的 Simulation(仿真)。我们之前在新建工程的时候,对仿真软件这儿已经进行了设置,所以说这儿不需要再进行更改。我们直接选择这个位置编译 test bench,选择 Test Benches… 新建
,然后输入我们的 tb 名称,就是 tb_mux2_1,这俩个名称默认是一致的,我们不需要进行修改。然后是时间停止参数的设置,设置为 1 us,在这个位置添加仿真文件,然后点击 添加,然后 OK、OK、应用、OK,我们可以点击这个位置与 Modelsim 进行联合仿真

quartus_0NPvG1ExeF

我们打开波形窗口,点击 全局视图,添加我们的参考线,然后进行放大,在选通信号这个上升沿之前它是保持低电平,sel 低电平时输出信号应该与输入信号 2 保持一致,这儿是正确的

vish_KVpaK14ynz

在这个上升沿到这个下降沿,选通信号保持高电平。所以说,输出信号应该与输入信号 1 保持一致,它俩的电平是相同的。选通信号到下一个上升沿,这一段时间一直是低电平,那么输出信号应该与输入信号 2 保持一致,这也是一致的,而且仿真波形与我们绘制的波形图是一致的

vish_GX4NyniHsU

那么波形变化是一致的,我们来查看一下数据打印窗口

image-20231010150712963

在打印信息显示界面,我们可以看到,打印的内容与我们监测函数里边编写的内容是一致的。我们随便挑选一组数据:当选通信号为高电平时,输出信号为高电平,与我们的输入信号 1 电平是一样的;那么当选通信号为 0 时,输出信号为 0,与我们选通信号 2 是保持一致的,那么仿真验证通过了。

2.7 管脚绑定

下面就可以进行管脚的绑定。打开我们的工程文件,选择 Pin Planner 这个位置,在下面这个界面进行管脚的绑定。输入信号 1 我们使用按键 KEY1 来进行输入,按键 KEY1 与 FPGA 的物理连接是 M2 引脚,我们输入 M2,点击回车;in_2 是 M1,输入完成,点击回车;那么输出是 L7,就是我们的 LED 灯,点击回车;那么选通信号是 E15,选择回车。引脚绑定完成之后,我们关闭

quartus_0MjOreu0DO

2.8 全编译

回到我们的实验工程,进行一次全编译

quartus_3epHIkYhk8

那么编译完成,有 7 个警告,不需要关心,点击 OK。

2.9 上板验证

那么接下来就是上板验证

我们下图所示,连接我们的下载器和我们的电源,下载器的另一端连接我们的电脑

上板验证前的硬件连线

回到我们的实验工程,点击 Programmer 这个位置,打开下载界面。点击 添加文件,找到我们的 SOF 文件,点击 打开,点击 开始,进行程序的下载

quartus_hq42Wv2XmL

程序下载完成,我们打开摄像头

二选一多路选择器 上板验证

输入信号 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 赋值给输出信号

我们常用的三种组合逻辑的赋值方式,已经讲解完了,那么实战演练的全部内容,也已经讲解完毕。

在本讲视频当中,我们主要学习了,我们三种常用的组合逻辑的赋值方式。

参考资料:

06-第六讲-简单组合逻辑—多路选择器(一)

07-第六讲-简单组合逻辑—多路选择器(二)

4. 简单组合逻辑—–多路选择器

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值