实验十一 同步时序电路设计
某不烦
2021年11月22日 20:53
收录于文集
共13篇

一、实验目的和要求

  • 掌握典型同步时序电路的工作原理和设计方法

  • 掌握时序电路的激励函数、状态图、状态方程的运用

  • 掌握用Verilog进行有限状态机的设计、调试、仿真

  • 掌握用FPGA实现时序电路功能

二、实验内容和原理

2.1 实验内容

任务1:原理图方式设计4位同步二进制计数器

任务2:以Verilog行为描述方式设计16位可逆二进制同步计数器

2.2 实验原理

2.2.1 4位二进制同步计数器

1. 根据 D 触发器原理,在 clk 作用下 Q = D,4位计数器的 Q 和 D 关系如下表所示:

4位计数器 D、Q关系表

2. 激励函数如下表所示:

4位二进制同步计数器激励函数

3. 进位 RC 的输出函数

进位 RC 输出函数

4. 具体原理图设计方式如下图所示:

5. 具体代码如下所示:

代码块
JavaScript
自动换行
复制代码
module counter_4bit(clk, Qa, Qb, Qc, Qd, Rc);
input wire clk;
output wire Qa, Qb, Qc, Qd, Rc;
wire Nor_nQa_nQb, Nor_nQa_nQb_nQc;

FD FD_A(.C(clk), .D(Da), .Q(Qa)),
    FD_B(.C(clk), .D(Db), .Q(Qb)),
    FD_C(.C(clk), .D(Dc), .Q(Qc)),
    FD_D(.C(clk), .D(Dd), .Q(Qd));
defparam FD_A.INIT = 1'b0, FD_B.INIT = 1'b0;
defparam FD_C.INIT = 1'b0, FD_D.INIT = 1'b0;

INV nQa_L(.I(Qa), .O(nQa)), nQb_L(.I(Qb), .O(nQb)),
  	nQc_L(.I(Qc), .O(nQc)), nQd_L(.I(Qd), .O(nQd));
assign Da = nQa;

XNOR2 Db_L(.I0(Qa), .I1(nQb), .O(Db)),
      Dc_L(.I0(Nor_nQa_nQb), .I1(nQc), .O(Dc)),
      Dd_L(.I0(Nor_nQa_nQb_nQc), .I1(nQd), .O(Dd));
NOR4 Rc_L(.I0(nQa), .I1(nQb), .I2(nQc), .I3(nQd), .O(Rc));
NOR2 Nor_nQa_nQb_L (.I0(nQa), .I1(nQb), .O(Nor_nQa_nQb));
NOR3 Nor_nQa_nQb_nQc_L(.I0(nQa), .I1(nQb), .I2(nQc), .O(Nor_nQa_nQb_nQc));
复制成功

2.2.2 4位可逆二进制同步计数器

1. 可逆二进制同步计数器通过控制端S选择正向或者反向计数

    S = 1时,正向计数,各触发器逻辑表达式同前面

    S = 0时,反向计数,各触发器逻辑表达式如下式

各触发器逻辑表达式

2. 具体代码如下所示:

代码块
JavaScript
自动换行
复制代码
module counter_4bit_rev(clk, s, cnt, Rc);
input wire clk, s;
output reg [3:0] cnt;
output wire Rc;
Initial begin cnt = 0;
assign Rc = (~s & (~|cnt)) | (s & (&cnt));
always @ (posedge clk) begin
  if (s)
  	cnt <= cnt + 1;
  else
  	cnt <= cnt - 1;
end
endmodule
复制成功

2.2.3 分频器

1. 50 MHz信号通过 25,000,000 次分频后,得到 1 Hz 的秒脉冲方波,作为计数器的脉冲输入

2. 具体代码如下所示:

代码块
JavaScript
自动换行
复制代码
module counter_1s(clk, clk_1s);
input wire clk;
output reg clk_1s;
reg [31:0] cnt;
always @ (posedge clk) begin
  if (cnt < 25_000_000) begin
  	cnt <= cnt + 1;
  end else begin
  	cnt <= 0;
  	clk_1s <= ~clk_1s;
  end
end
endmodule
复制成功

三、主要仪器设备

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

实验材料:无

四、操作方法和实验步骤

4.1 设计4位同步二进制计数器

4.1.1 原理图设计计数器

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

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

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

4位同步二进制计数器原理图

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

5. 进行波形仿真,具体代码如下:

代码块
JavaScript
自动换行
复制代码
`timescale 1ns / 1ps
module MyCounter4b_MyCounter4b_sch_tb();
// Inputs
	reg ck;
// Output
  wire Rc;
  wire Qb;
  wire Qc;
  wire Qa;
  wire Qd;
// Bidirs
// Instantiate the UUT
  MyCounter4b UUT (
    .ck(ck),
    .Rc(Rc),
    .Qb(Qb),
    .Qc(Qc),
    .Qa(Qa),
    .Qd(Qd)
  );
// Initialize Inputs
  initial forever begin
    ck = 1'b0; #10;
    ck = 1'b1; #10;
  end
endmodule
复制成功

4.1.2 Verilog 代码设计时钟

1. 新建类型为 verilog module 的源文件,命名为 clk_1s 

2. 用 verilog 代码设计,具体如下所示:

代码块
JavaScript
自动换行
复制代码
module clk_1s(clk, clk_1s);
  input wire clk;
  output reg clk_1s;
  reg [31:0] cnt;

  always @ (posedge clk) begin
    if (cnt < 25_000_000) begin
      	cnt <= cnt + 1;
      end
    else begin
      cnt <= 0;
      clk_1s <= ~clk_1s;
    end
  end
endmodule
复制成功

3. 生成逻辑符号和.vf文件:点击 Process 窗口下 Design Utilities -> Create schematic symbol

4.1.3 Verilog 代码设计顶层模块 top

1. 新建类型为 verilog module 的源文件,命名为 top,并右键 Set as Top Module 

2. 用 verilog 代码设计,具体如下所示:

代码块
JavaScript
自动换行
复制代码
module Top(
  input wire clk,
  output wire buzzer,
  output wire LED,
  output wire [7:0] SEGMENT,
  output wire [3:0] AN
);

  wire clk_1s;
  wire [3:0] num;
	clk_1s m0(.clk(clk), .clk_1s(clk_1s));
	MyCounter4b m1(.ck(clk_1s), .Qa(num[0]), .Qb(num[1]), .Qc(num[2]),
		.Qd(num[3]), .Rc(LED));
	Disp_num m2( clk, {4'b0000, num[3:0], 4'b0000, 4'b1111}, 1'b0, AN, SEGMENT);
endmodule
复制成功

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

4. 进行引脚约束,下载到 SWORD 板进行验证。新建类型为 Implementation constraints file 的源文件,命名为 k7.ucf,具体代码如下所示:

代码块
JavaScript
自动换行
复制代码
NET "clk" LOC = AC18 | IOSTANDARD = LVCMOS18;
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 ;
复制成功

4.2 设计16位可逆同步二进制计数器

4.2.1 Verilog 设计计数器

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

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

3. 用 verilog 代码设计,具体代码如下所示:

代码块
JavaScript
自动换行
复制代码
module RevCounter(clk, s, cnt, Rc);
  input wire clk, s;
  output reg [15:0] cnt;
  output wire Rc;
  assign Rc = (~s & (~|cnt)) | (s & (&cnt));
  initial begin
  	cnt = 0;
  end
  always@(posedge clk) begin
    if (s)
    	cnt <= cnt + 1;
    else
    	cnt <= cnt - 1;
  end
endmodule
复制成功

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

5. 进行波形仿真,具体代码如下:

代码块
JavaScript
自动换行
复制代码
module RevCounter_sym;
  // Inputs
  reg clk;
  reg s;

  // Outputs
  wire [15:0] cnt;
  wire Rc;
	
  // Instantiate the Unit Under Test (UUT)
  RevCounter uut (
    .clk(clk),
    .s(s),
    .cnt(cnt),
    .Rc(Rc)
  );

  initial forever begin
    s = 1'b1; // 正向计数为 s = 1'b0
    clk = 1'b0; #10;
    clk = 1'b1; #10;
  end
  
endmodule
复制成功

4.2.2 Verilog 代码设计时钟

1. 新建类型为 verilog module 的源文件,命名为 clk_100ms 

2. 用 verilog 代码设计,具体如下所示:

代码块
JavaScript
自动换行
复制代码
module clk_100ms(clk, clk_1s);
input wire clk;
output reg clk_1s;
reg [31:0] cnt;
always @ (posedge clk) begin
  if (cnt < 25_000_000) begin
  	cnt <= cnt + 1;
  end else begin
    cnt <= 0;
    clk_1s <= ~clk_1s;
  end
end
endmodule
复制成功

3. 生成逻辑符号和.vf文件:点击 Process 窗口下 Design Utilities -> Create schematic symbol

4.2.3 Verilog 代码设计顶层模块 top

1. 新建类型为 verilog module 的源文件,命名为 top,并右键 Set as Top Module 

2. 用 verilog 代码设计,具体如下所示:

代码块
JavaScript
自动换行
复制代码
module Top(
  input wire clk,
  input wire SW,
  output wire [7:0] SEGMENT,
  output wire [3:0] AN,
  output wire Rc
  );

  wire clk_100ms;
  wire [15:0] num;

  clk_100ms m0(.clk(clk), .clk_1s(clk_1s));
  RevCounter m1(.clk(clk_1s), .s(SW), .cnt(num), .Rc(Rc));
  Disp_num m2(clk, num, 1'b0, AN, SEGMENT);
              
endmodule
复制成功

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

4. 进行引脚约束,下载到 SWORD 板进行验证。新建类型为 Implementation constraints file 的源文件,命名为 k7.ucf,具体代码如下所示:

代码块
JavaScript
自动换行
复制代码
NET "clk" LOC = AC18 | IOSTANDARD = LVCMOS18;

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 "Rc" LOC = AF24 | IOSTANDARD = LVCMOS33; #GPIOf0[0]
NET "SW" LOC = AA10 | IOSTANDARD = LVCMOS15;
复制成功

五、实验结果和分析

5.1 波形仿真结果

1. 同步正向计数器

具体仿真结果如下图所示,与理论预估结果一致,故元件逻辑功能正确。

同步正向计数器波形仿真图

2. 同步正逆向计数器

具体仿真结果如下图所示,与理论预估结果一致,故元件逻辑功能正确。

逆向技术:

同步正逆向计数器逆向计数波形仿真图

正向计数:

同步正逆向计数器正向计数波形仿真图

5.2 物理验证结果

物理验证部分图片如下所示:

六、讨论和心得

6.1 数码管显示模块

七段数码管需要分频时钟信号逐个读入数字,实现视觉暂留。如果输入的分频时钟信号间隔过大则只能看到一个数字。同时,调用模块时切记声明接口、按照顺序接入,减少语法错误。

6.2 时钟分频

正逆向计数中使用的时钟是100ms而不是1s,这个时钟分频并不影响逻辑功能的实现。但如果增减速度 过慢,实验现象不是很明显,需要很久才能达到FFFF。