1、译码器简介
译码器是一种组合逻辑电路,用于将输入的二进制信号转换为特定的输出信号。它接收 n 个输入信号,并生成 2^n 个输出信号,其中只有一个输出在特定输入组合下为高电平(逻辑 1),其余输出为低电平(逻辑 0)。译码器广泛应用于地址解码、数据选择和指令译码等领域,是数字电路中的基本组件。
在数字电路中,译码器(如 N 线-2N 线 BCD 译码器)可以担任多输入多输出逻辑门的角色,能将已编码的输入转换成已编码的输出,这里输入和输出的编码是不同的。输入使能信号必须接在译码器上使其正常工作,否则输出将会是一个无效的码字。译码在多路复用、 七段数码管和内存地址译码等应用中是必要的
三八译码器也就是三线八线译码器,它是指三位二进制数字,其会组成 000 到 111 共八个不同的数字,因此一共会有 八 种状态,所以称为 三八 译码器。
2、实战任务
设计并进行仿真验证 三八 译码器。
3、系统框图
根据功能分析,该模块的输入为 A B C 三个信号,输出为 X 是一个 8bit 信号代表输出的 八 种状态系统框图如图下所示:
4、真值表
根据三八译码器功能描述,其真值表,如下表所示:
输入 A | 输入 B | 输入 C | 输出 X |
0 | 0 | 0 | 0000_0001 |
0 | 0 | 1 | 0000_0010 |
0 | 1 | 0 | 0000_0100 |
0 | 1 | 1 | 0000_1000 |
1 | 0 | 0 | 0001_0000 |
1 | 0 | 1 | 0010_0000 |
1 | 1 | 0 | 0100_0000 |
1 | 1 | 1 | 1000_0000 |
5、波形图
通过对真值表进行分析,我们可以绘制三八译码器的输入与输出波形。其波形如下图所示:
6、程序编写
实现三八译码器功能的 Verilog 代码形式也有很多种,这里选择 case 方式来实现:
module decoder_3_8 (
input A, // 输入 A
input B, // 输入 B
input C, // 输入 C
output reg [7:0] X // 8位输出
);
always @(*) begin
case ({A, B, C}) // 拼接输入信号
3'b000: X = 8'b00000001; // 输出 x0
3'b001: X = 8'b00000010; // 输出 x1
3'b010: X = 8'b00000100; // 输出 x2
3'b011: X = 8'b00001000; // 输出 x3
3'b100: X = 8'b00010000; // 输出 x4
3'b101: X = 8'b00100000; // 输出 x5
3'b110: X = 8'b01000000; // 输出 x6
3'b111: X = 8'b10000000; // 输出 x7
default : X = 8'b0000_0001; // 默认情况,输出 x0
endcase
end
endmodule
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
程序注释:
第 2 - 5 行:根据三八译码器的功能定义了,三个输入信号,分别为 A B C ,输出信号为 X 是一个 8bit 的信号,代表译码器的八种状态。
第 9 - 21 行:在使用 case 语句列举输入与输出的 8 种译码关系时,虽然第 19 行的 default 可以省略,但为了代码规范和良好习惯,建议包含 default,可以指定某种情况。
第 10 行:位拼接,是使用花括号 {} 来实现,将三个一位信号,拼接成一个 3bit 信号来使用。
7、仿真编写
`timescale 1ns / 1ns // 定义时间单位和精度为 1 纳秒
module decoder_3_8_mod();
// 输入和输出信号定义
reg A; // 输入 A
reg B; // 输入 B
reg C; // 输入 C
wire X; // 输出 X
initial begin // 初始块开始
A = 1'b0; // 设置输入 A 为 0
B = 1'b0; // 设置输入 B 为 0
C = 1'b0; // 设置输入 C 为 0
#200; // 延迟 200 纳秒
A = 1'b0; // 设置输入 A 为 0
B = 1'b0; // 设置输入 B 为 0
C = 1'b1; // 设置输入 C 为 1
#200; // 延迟 200 纳秒
A = 1'b0; // 设置输入 A 为 0
B = 1'b1; // 设置输入 B 为 1
C = 1'b0; // 设置输入 C 为 0
#200; // 延迟 200 纳秒
A = 1'b0; // 设置输入 A 为 0
B = 1'b1; // 设置输入 B 为 1
C = 1'b1; // 设置输入 C 为 1
#200; // 延迟 200 纳秒
A = 1'b1; // 设置输入 A 为 1
B = 1'b0; // 设置输入 B 为 0
C = 1'b0; // 设置输入 C 为 0
#200; // 延迟 200 纳秒
A = 1'b1; // 设置输入 A 为 1
B = 1'b0; // 设置输入 B 为 0
C = 1'b1; // 设置输入 C 为 1
#200; // 延迟 200 纳秒
A = 1'b1; // 设置输入 A 为 1
B = 1'b1; // 设置输入 B 为 1
C = 1'b0; // 设置输入 C 为 0
#200; // 延迟 200 纳秒
A = 1'b1; // 设置输入 A 为 1
B = 1'b1; // 设置输入 B 为 1
C = 1'b1; // 设置输入 C 为 1
#1000; // 延迟 1000 纳秒
$stop; // 停止仿真
end
// 例化 3-to-8 译码器
decoder_3_8 u_decoder_3_8(
.A(A), // 将输入 A 连接到译码器
.B(B), // 将输入 B 连接到译码器
.C(C), // 将输入 C 连接到译码器
.X(X) // 将输出 X 连接到译码器输出
);
endmodule // 模块结束
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
程序注释:
第 1 行 :时间尺度预编译指令 时间单位/时间精度,第一个 1ns 是时间单位,第二个 1ns 是时间精度。
第 3 行:定义了仿真模块名称。
第 12 ~ 55 行:使用 initial 语句块进行输入信号的初始化,根据真值表依次将输入的状态都列举出来。从而能够观察程序是否与我们所列真值表相同。
第 58 ~ 63 行:对我们的 decoder_3_8.v 文件的输出输入信号进行一个绑定。
8、项目工程
开始使用 Gowin 创建项目工程了,芯片选型如下所示:
接着在 Gowin 的 Design 窗口空白地方右键点击选择 New Files... 添加文件。如下图所示:
分别创建所需的文件 decoder_3_8.v 和 decoder_3_8_mod.v,如下图所示:
添加完对应程序后,然后开始仿真,新建工程将 Project_Name 和 Default Library Name 都改成 decoder_3_8 名称,如下图所示:
分别添加我们仿真所需的文件 decoder_3_8.v 和 decoder_3_8_mod.v,如下图所示:
接下来选择 Compile->Compile All ,编译没有问题后,在 Add Simulation Configuration 配置好对应的文件,如下图所示:
仿真结果如下:
由上面的仿真图,可以看出与我们的真值表所列出的来结果是一致的,证明我们的程序没有问题。
9、RTL 原理图
接下来开始 Synthesize 编译判断 decoder_3_8.v 文件是否有语法错误,执行 Synthesize 编译,接下来的就该绑定引脚,由于我们 逻辑派 板载按键只有两个所以本章只讲仿真和查看 RTL 电路图。
接下来在过程管理窗口 Process > Place & Route > Run,来对代码布局布线进行综合,再点击 tools -> Shematic Viewer -> RTL Design Viewer 然后查看 RTL 电路图,如下图所示:
然后查看 RTL 电路图,在软件里 三八译码器 是怎样的,如下图所示: