数逻实验7 多路选择器设计及应用
某不烦
2021年02月03日 18:16
收录于文集
共13篇

写在前面

        实验 7 是基于多路选择器设计了一个计分板,通过 4 个阵列按钮输入改变对应 4 位数码管的值并显示。实验 7 结合了输入、输出,掌握以后其实就可以开始着手准备大程。与组合电路不同,大程的难点在于有意义的状态机设计,需要考虑时序电路中的延时对输出造成的影响。如本次实验中设计的计分板稍作修改就可以用作游戏积分的显示模块。

cut-off

实验七 多路选择器设计及应用

1. 实验目的和要求

  • 掌握数据选择器的工作原理和逻辑功能

  • 掌握数据选择器的使用方法

  • 掌握 4 位数码管扫描显示方法

  • 4 位数码管显示应用—记分板设计

2. 实验内容和原理

2.1 实验内容

  • 任务1:数据选择器设计

  • 任务2:记分板设计

2.2 实验原理

2.2.1 Mux4to1: 4选1多路选择器

  • 根据事件简化真值表

图表1 4选1多路选择器真值表

  • 输出是控制信号全部最小项与或结构控制结构不变,每路输入向量化

图表2 4选1多路选择器逻辑电路图

        扩展至16选4如下图所示:

图表3 16选4多路选择器逻辑电路图

        生成元件后如下图所示:

图表4 4选1多路选择器逻辑符号

2.2.2 动态扫描显示

动态扫描显示方案

  • 扫描信号来自计数器:时序转化为组合电路

  • 由板载时钟 clk (100MHz)作为计数器时钟,分频后的高两位信号(clk_div[18:17])作为扫描控制信号,输入2-4译码器控制哪个数码管显示(位选择),同时输入4选1多路复用器选择需要显示哪个数据(段码选择)

  • 计数器的分频系数要适当,几ms切换一次,眼睛舒适即可

图表5 动态扫描示意图

  • 动态扫描同步输出模块的电路图如下:

图表6 动态扫描同步输出模块逻辑电路图

图表7 动态扫描同步输出模块逻辑电路图

图表8 动态扫描同步输出模块逻辑电路图

2.2.3 辅助模块:时钟计数分频器

32位时钟计数分频器

  • 可输出 2~232 分频信号,可用于一般非同步类时钟信号

  • 延时较高,要求不高的时钟也可以用

  • 本实验中用 clkdiv(18:17) 作为扫描控制信号,控制 4 位数码管的动态扫描具体实现代码如下所示:

代码块
Rust
自动换行
复制代码
module clkdiv(
	input clk,
	input rst,
    output reg [31:0] clkdiv
);

// clock diveder - 时钟分频器
    always @ (posedge clk or posedge rst) begin
        if (rst) clkdiv <= 0;
        else clkdiv <= clkdiv + 1'b1;
    end

endmodule
复制成功

        根据原理,设计通用计数分频模块clkdiv,并将其输出的clkdiv(18:17)作为数据选择器的位选信号;clkdiv(17)作为消抖模块的时钟信号。

图表9 时钟分频模块

2.2.4 设计按键数据输入模块

按键去抖动处理

  • 抖动原因:按键按下或放开时,存在机械震动

  • 抖动时间一般在10~20 ms

  • 按键去抖动方法:延时,以避开机械抖动具体实现代码如下所示:

创建数字模块

代码块
Rust
自动换行
复制代码
module CreateNumber(
	input wire clk,
	input wire [3:0] btn,
	output reg [15:0] num
    );
	 wire [3:0] A,B,C,D;
	 wire [3:0] temp_btn;
	
	initial num <= 16'b 0001001000110100;
	
	assign A = num[3:0] + 1'b1;
	assign B = num[7:4] + 1'b1;
	assign C = num[11:8] + 1'b1;
	assign D = num[15:12] + 1'b1;
	
	pbdebounce p0(.clk(clk),.button(btn[0]),.pbreg(temp_btn[0]));
	pbdebounce p1(.clk(clk),.button(btn[1]),.pbreg(temp_btn[1]));
	pbdebounce p2(.clk(clk),.button(btn[2]),.pbreg(temp_btn[2]));
	pbdebounce p3(.clk(clk),.button(btn[3]),.pbreg(temp_btn[3]));
	
	always@(posedge temp_btn[0]) num[ 3: 0] <= A;
	always@(posedge temp_btn[1]) num[ 7: 4] <= B;
	always@(posedge temp_btn[2]) num[11: 8] <= C;
	always@(posedge temp_btn[3]) num[15:12] <= D;
	
endmodule
复制成功

防抖动模块

代码块
Rust
自动换行
复制代码
module pbdebounce(
	input wire clk_1ms,
	input wire button, 
	output reg pbreg
	);
 
	reg [7:0] pbshift;

	always@(posedge clk_1ms) begin
		pbshift=pbshift<<1;
		pbshift[0]=button;
		if (pbshift==8'b0)
			pbreg=0;
		if (pbshift==8'hFF)
			pbreg=1;	
	end
endmodule
复制成功

2.2.5 计分板的逻辑功能

  • btn[3:0] 这4个按钮控制数码管数值变化。每个按钮按动一次,对应数码管的值加1

  • 用 SW0~SW3 这4个开关控制每个数码管的小数点

  • 用 SW4~SW7 这4个开关控制每个数码管的消隐

  • SEGMENT[7:0] 对应7段数码管的 a-p

  • BN 开关控制按钮行状态。BN = 0 时,按钮行有效,否则失效。

图表10 BN开关

3. 主要仪器设备

  • 实验设备装有Xilinx ISE 14.7的计算机 1台SWORD开发板      1套

  • 实验材料

4. 操作方法和实验步骤

4.1 数据选择器设计

4.1.1 原理图绘制多路选择器

4.1.1.1 Mux4to1

    1. 新建工程,命名为 Mux4to1,top-level source type 为 schematic

    2. 新建类型为 schematic 的源文件,命名为 Mux4to1_Number

    3. 用原理图方式设计,具体如下所示:

图表11 4选1多路选择器电路逻辑图

    4. 生成逻辑符号和.vf文件:点击 Process 窗口下 Design Utilities -> Create schematic symbol,在工程文件夹里可以找到相应的 .sym 文件。

4.1.1.2 Mux4to1b4

    1. 新建工程,命名为 Mux4to1b4_sch,top-level source type 为 schematic

    2. 新建类型为 schematic 的源文件,命名为 Mux4to1b4

    3. 用原理图方式设计,具体如下所示:

图表12 4位4选1多路选择器逻辑电路图

    4. 生成逻辑符号和.vf文件:点击 Process 窗口下 Design Utilities -> Create schematic symbol,在工程文件夹里可以找到相应的.sym文件

    5. 输入仿真信号进行测试,具体代码如下:

代码块
Rust
自动换行
复制代码
`timescale 1ns / 1ps

module Mux4to14b_Mux4to14b_sch_tb();
// Inputs
   reg [1:0] S;
   reg [3:0] I0;
   reg [3:0] I1;
   reg [3:0] I2;
   reg [3:0] I3;
// Output
   wire [3:0] O;
// Bidirs
// Instantiate the UUT
   Mux4to14b UUT (
		.S(S), 
		.I0(I0), 
		.I1(I1), 
		.I2(I2), 
		.I3(I3), 
		.O(O)
   );
// Initialize Inputs
	integer i;
   initial begin
		S = 00;
		I0 = 0001;
		I1 = 0010;
		I2 = 0100;
		I3 = 1000;
		for( i = 0; i <= 3;i = i+1)begin
			{S} <= i; #50;
		end
	end
		
endmodule
复制成功

4.2 记分板设计

4.2.1 Verilog 代码实现 clkdiv 模块设计

    1. 新建工程,Top Level Source Type 为 HDL,命名为 clkdiv_Number

    2. 新建类型为 Verilog Module 的源文件,命名为 clkdiv_Number

    3. 用 Verilog 代码进行设计,具体实现代码如下:

代码块
Rust
自动换行
复制代码
module clkdiv_3190103044(
	input clk,
	input rst,
	output reg[31:0]clkdiv
    );

always @ (posedge clk or posedge rst) begin
	if (rst) clkdiv <= 0;
	else clkdiv <= clkdiv + 1'b1;
end

endmodule
复制成功

    4. 生成逻辑符号和.vf文件:点击 Process 窗口下 Design Utilities -> Create schematic symbol,在工程文件夹里可以找到相应的.sym文件

4.2.2 计分板实现

    1. 新建工程,Top Level Source Type 为 schematic,命名为 scoreBoard_Number

    2. 新建类型为 verilog module 的源文件,命名为 CreateNumber

    3. 用 Verilog 代码进行设计,具体实现代码如下:

代码块
Rust
自动换行
复制代码
module CreateNumber(
	input wire clk,
	input wire [3:0] btn,
	output reg [15:0] num
    );
	 wire [3:0] A,B,C,D;
	 wire [3:0] temp_btn;
	
	initial num <= 16'b 0001001000110100;
	
	assign A = num[3:0] + 1'b1;
	assign B = num[7:4] + 1'b1;
	assign C = num[11:8] + 1'b1;
	assign D = num[15:12] + 1'b1;
	
	pbdebounce p0(.clk(clk),.button(btn[0]),.pbreg(temp_btn[0]));
	pbdebounce p1(.clk(clk),.button(btn[1]),.pbreg(temp_btn[1]));
	pbdebounce p2(.clk(clk),.button(btn[2]),.pbreg(temp_btn[2]));
	pbdebounce p3(.clk(clk),.button(btn[3]),.pbreg(temp_btn[3]));
	
	always@(posedge temp_btn[0]) num[ 3: 0] <= A;
	always@(posedge temp_btn[1]) num[ 7: 4] <= B;
	always@(posedge temp_btn[2]) num[11: 8] <= C;
	always@(posedge temp_btn[3]) num[15:12] <= D;
	
endmodule
复制成功

    4. 新建类型为 verilog module 的源文件,命名为 pbdebounce(防抖动模块)

    5. 用 Verilog 代码进行设计,具体实现代码如下:

代码块
Rust
自动换行
复制代码
module pbdebounce(
	input wire clk,
	input wire button, 
	output reg pbreg
	);
 
	reg [7:0] pbshift;

	always@(posedge clk) begin
		pbshift = pbshift<<1;
		pbshift[0] = button;
		if (pbshift == 8'b0)
			pbreg=0;
		if (pbshift == 8'hFF)
			pbreg=1;	
	end
endmodule
复制成功

    6. Check Syntax 无误后,点击 Process 窗口下 Design Utilities -> Create schematic symbol生成逻辑符号和.vf文件

    7. 新建类型为 schematic 的源文件,命名为 scoreBoard_Number,右键设置为 Top Source

    8. 将 MyMC14495.v 、MyMC14495.sym 、Mux4to1.v 、Mux4to1.sym 、Mux4to1b4.v 、Mux4to1b4.sym、clkdiv.v 、clkdiv.sym 添加到工程目录,并通过 Add Source 将其添加到工程中

    9. 用原理图方式实现计分板的逻辑功能,具体如下:

图表13 计分板逻辑电路图

    10. 进行引脚约束,下载到 SWORD 板进行验证。

        新建类型为 Implementation constraints file 的源文件,命名为 constraints,具体代码如下所示:

代码块
Rust
自动换行
复制代码
/*
输入
	时钟:clk
	使能控制:SW[7:4]为 LES[3:0]
	小数点输入:SW[3:0]为point[3:0]
	按键输入数字:SW[15:12]为btn[3:0]
输出
	a-g, p = SEGMENT
	AN[3:0]
*/
NET "clk"				LOC = AC18		| IOSTANDARD = LVCMOS18;
NET "RST"				LOC = AF10  	| IOSTANDARD = LVCMOS15;

NET "SW[0]"				LOC = AA10  	| IOSTANDARD = LVCMOS15;#POINT
NET "SW[1]"				LOC = AB10  	| IOSTANDARD = LVCMOS15;
NET "SW[2]"				LOC = AA13  	| IOSTANDARD = LVCMOS15;
NET "SW[3]"				LOC = AA12  	| IOSTANDARD = LVCMOS15;

NET "SW[4]"				LOC = Y13   	| IOSTANDARD = LVCMOS15;#LES
NET "SW[5]"				LOC = Y12   	| IOSTANDARD = LVCMOS15;
NET "SW[6]"				LOC = AD11  	| IOSTANDARD = LVCMOS15;
NET "SW[7]"				LOC = AD10  	| IOSTANDARD = LVCMOS15;               		

NET "SEGMENT[0]"		LOC = AB22      | IOSTANDARD = LVCMOS33 ;#a
NET "SEGMENT[1]" 		LOC = AD24		| IOSTANDARD = LVCMOS33 ;#b
NET "SEGMENT[2]" 		LOC = AD23		| IOSTANDARD = LVCMOS33 ;
NET "SEGMENT[3]" 		LOC = Y21		| IOSTANDARD = LVCMOS33 ;
NET "SEGMENT[4]" 		LOC = W20		| IOSTANDARD = LVCMOS33 ;
NET "SEGMENT[5]" 		LOC = AC24		| IOSTANDARD = LVCMOS33 ;
NET "SEGMENT[6]" 		LOC = AC23		| IOSTANDARD = LVCMOS33 ;#g
NET "SEGMENT[7]" 		LOC = AA22		| IOSTANDARD = LVCMOS33 ;#point

NET "AN[3]" 			LOC = AC22      | IOSTANDARD = LVCMOS33 ;
NET "AN[2]" 			LOC = AB21      | IOSTANDARD = LVCMOS33 ;
NET "AN[1]" 			LOC = AC21      | IOSTANDARD = LVCMOS33 ;
NET "AN[0]" 			LOC = AD21      | IOSTANDARD = LVCMOS33 ;

NET "btn[3]"			LOC = V18 		| IOSTANDARD = LVCMOS18;
NET "btn[2]"			LOC = V19   	| IOSTANDARD = LVCMOS18 ;
NET "btn[1]"			LOC = V14   	| IOSTANDARD = LVCMOS18 ;
NET "btn[0]"			LOC = W14   	| IOSTANDARD = LVCMOS18 ;

NET "K_ROW" 			LOC = V17  		| IOSTANDARD = LVCMOS18 ;
NET "BN"				LOC = AF13 		| IOSTANDARD = LVCMOS15 ;
复制成功

5. 实验结果和分析

5.1 数据选择器设计

        运行仿真代码后波形图如下图所示,与理论结果一致,故元件逻辑功能正确。

图表14 仿真波形

5.2 计分板应用设计

        将计分板下载到 SWORD 实验板上,根据相应的引脚约束进行物理验证。

        引脚对应按键如下图所示:

图表15 对应引脚示意图

 

        

        结果与理论预期一致,因此计分板逻辑功能正确。

6. 讨论和心得

6.1 仿真激励代码

        有C语言的基础学习Verilog的语法能容易一些,网上也有很多 verilog 语言的教程。思路就是赋值、延时。需要搞清楚阻塞赋值和非阻塞赋值的区别与使用环境。

6.2 原理图绘制相关

    1. 希望将多条线路引到总线时,可以先实现一条线,确认总线、字线命名无误后再将其他线连上

    2. 在生成元件以后,若再修改原理图,需要删除原有的 .v 文件再生成才能覆盖原结果

    3. 切记线的命名要与后续引脚约束和其他元器件的代码相统一

cut-off

        欢迎评论区或私信讨论,感谢三连与批评指正。