文章目录
前言
本次主要介绍一下关于EDA的实验:序列信号发生器,包括两种考虑分频和不考虑分频的模12计数器型序列信号发生器、以及长度为N的序列信号发生器。
一、设计内容及原理
1.1 设计内容
(1)基础任务:不考虑分频,设计一个计数器型序列信号发生器(12位序列信号),首先设计一个模为12的计数器,然后设计组合逻辑电路序列输出。输出是发光二极管显示输出,看看发生什么现象,为什么?
(2)提高任务:设计一个计数器型序列信号发生器(12位序列信号),首先设计一个模为12的计数器(时钟要分频,计数器的频率),然后设计组合逻辑电路序列输出。输入是系统时钟100MHZ时钟频率(需 要分频),输出是发光二极管显示输出。
(3)扩展任务:设计一个长度为N的序列信号发生器。首先设计模为N的计数器(时钟要分频,计数器的频率),然后设计组合逻辑电路序列输出。输入是系统时钟 100MHZ 时钟频率(需要分频),输出是发光二极管显示输出。N 由拨码开关外部给入。
1.2 设计原理
(1)基础、提高任务:基础、提高任务均为设计一个计数器型的12位序列信号发生器,只是提高任务要求进行分频。首先设计一个模为12的计数器,位数是4位,然后将计数过程四位中的第一位和第三位进行同或运算,输出到对应的结果z中,最后硬件仿真时,对应的流水灯会根据计数过程依次循环显示对应位是否亮起,进而表示序列信号的发生。具体情况下面表格。
(2)拓展任务:我程序中,N设置的可取2到15,硬件仿真时首先由拨码开关确定N的值,然后进行N进制的计数,将计数过程四位中的第一位和第三位进行异或运算,输出到对应的结果z中,对应的流水灯会根据计数过程依次循环显示对应位是否亮起,进而表示序列信号的发生。具体情况下面表格。
计数过程 | 基础、提高任务:输出z | 扩展任务:输出z |
---|---|---|
0000 | 1 | 0 |
0001 | 0 | 1 |
0010 | 1 | 0 |
0011 | 0 | 1 |
0100 | 0 | 1 |
0101 | 1 | 0 |
0110 | 0 | 1 |
0111 | 1 | 0 |
1000 | 1 | 0 |
1001 | 0 | 1 |
1010 | 1 | 0 |
1011 | 0 | 1 |
1100 | — | 1 |
1101 | — | 0 |
1111 | — | 0 |
二、设计过程(及设计步骤)
2.1 基础任务
(1)源程序:
module mod12xulie(rst,clk,z); //声明模块名,端口信号
input clk; //时钟
input rst; //清零端
output reg [11:0] z; //12位的序列信号
always@(posedge rst or posedge clk) //模12计数器
begin
if(!rst)
led<=0;
else if(led==11)
begin
led<=0;
z<=0;
end
else begin
led<=led+1;
z[led]<=led[2]~^led[0]; //同或运算
end
end
endmodule
(2)仿真程序:
module sim_mod12xulie;
reg rst;
reg clk;
wire[11:0] z;
mod12xulie u0( //实例化序列信号发生器
.rst(rst),
.clk(clk),
.z(z)
);
parameter PERIOD = 10; //参数声明,并赋值为10
always
begin //每隔5,时钟翻转一次
clk = 1'b0;
#(PERIOD/2) clk = 1'b1;
#(PERIOD/2);
end
initial
begin //对clk,rst进行赋值
clk = 1'b0;
rst = 1'b0;
#100;
rst = 1'b1;
end
endmodule
(3)约束程序:
set_property -dict {PACKAGE_PIN P17 IOSTANDARD LVCMOS33} [get_ports clk ]
set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports rst ]
set_property -dict {PACKAGE_PIN J5 IOSTANDARD LVCMOS33} [get_ports {z[11]}]
set_property -dict {PACKAGE_PIN H5 IOSTANDARD LVCMOS33} [get_ports {z[10]}]
set_property -dict {PACKAGE_PIN H6 IOSTANDARD LVCMOS33} [get_ports {z[9]}]
set_property -dict {PACKAGE_PIN K1 IOSTANDARD LVCMOS33} [get_ports {z[8]}]
set_property -dict {PACKAGE_PIN K2 IOSTANDARD LVCMOS33} [get_ports {z[7]}]
set_property -dict {PACKAGE_PIN J2 IOSTANDARD LVCMOS33} [get_ports {z[6]}]
set_property -dict {PACKAGE_PIN J3 IOSTANDARD LVCMOS33} [get_ports {z[5]}]
set_property -dict {PACKAGE_PIN H4 IOSTANDARD LVCMOS33} [get_ports {z[4]}]
set_property -dict {PACKAGE_PIN J4 IOSTANDARD LVCMOS33} [get_ports {z[3]}]
set_property -dict {PACKAGE_PIN G3 IOSTANDARD LVCMOS33} [get_ports {z[2]}]
set_property -dict {PACKAGE_PIN G4 IOSTANDARD LVCMOS33} [get_ports {z[1]}]
set_property -dict {PACKAGE_PIN F6 IOSTANDARD LVCMOS33} [get_ports {z[0]}]
2.2 提高任务
(1)源程序:
module mod12xulie(rst,clk,z); //声明模块名,端口信号
input clk; //时钟
input rst; //清零端
output reg [11:0] z; //12位的序列信号
reg [3:0] led;
reg [31:0] sum;
reg clk1;
always@(posedge rst or posedge clk) //时钟分频
begin
if(!rst)
begin
sum<=0;
clk1<=0;
end
else if(sum==50000000) //分频50M次
begin
clk1<=~clk1; //时钟翻转
sum<=0; //sum清零
end
else
sum<=sum+1'b1; //sum累加直至50M
end
always@(posedge rst or posedge clk1) //模12计数器
begin
if(!rst)
led<=0;
else if(led==11)
begin
led<=0;
z<=0;
end
else begin
led<=led+1;
z[led]<=led[2]~^led[0]; //同或运算
end
end
endmodule
(2)仿真程序:
module sim_mod12xulie;
reg rst;
reg clk;
wire[11:0] z;
mod12xulie u0( //实例化序列信号发生器
.rst(rst),
.clk(clk),
.z(z)
);
parameter PERIOD = 10; //参数声明,并赋值为10
always
begin //每隔5,时钟翻转一次
clk = 1'b0;
#(PERIOD/2) clk = 1'b1;
#(PERIOD/2);
end
initial
begin //对clk,rst进行赋值
clk = 1'b0;
rst = 1'b0;
#100;
rst = 1'b1;
end
endmodule
(3)约束程序:
set_property -dict {PACKAGE_PIN P17 IOSTANDARD LVCMOS33} [get_ports clk ]
set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports rst ]
set_property -dict {PACKAGE_PIN J5 IOSTANDARD LVCMOS33} [get_ports {z[11]}]
set_property -dict {PACKAGE_PIN H5 IOSTANDARD LVCMOS33} [get_ports {z[10]}]
set_property -dict {PACKAGE_PIN H6 IOSTANDARD LVCMOS33} [get_ports {z[9]}]
set_property -dict {PACKAGE_PIN K1 IOSTANDARD LVCMOS33} [get_ports {z[8]}]
set_property -dict {PACKAGE_PIN K2 IOSTANDARD LVCMOS33} [get_ports {z[7]}]
set_property -dict {PACKAGE_PIN J2 IOSTANDARD LVCMOS33} [get_ports {z[6]}]
set_property -dict {PACKAGE_PIN J3 IOSTANDARD LVCMOS33} [get_ports {z[5]}]
set_property -dict {PACKAGE_PIN H4 IOSTANDARD LVCMOS33} [get_ports {z[4]}]
set_property -dict {PACKAGE_PIN J4 IOSTANDARD LVCMOS33} [get_ports {z[3]}]
set_property -dict {PACKAGE_PIN G3 IOSTANDARD LVCMOS33} [get_ports {z[2]}]
set_property -dict {PACKAGE_PIN G4 IOSTANDARD LVCMOS33} [get_ports {z[1]}]
set_property -dict {PACKAGE_PIN F6 IOSTANDARD LVCMOS33} [get_ports {z[0]}]
2.3 拓展任务
(1)源程序:
module mod(rst,clk,n,wei,b,z); //声明模块名,端口信号
input clk; //时钟
input rst; //清零端
input [3:0] n; //模的取值
output reg [14:0] z; //12位的序列信号
output reg [7:0] b; //段选
reg [3:0] led;
output reg wei=1'b1; //位选
reg [31:0] sum=0;
reg clk1=0;
always@(*)
begin
case(n) //不同模的取值,对应数码管的显示
0:b=8'b00000000;
1:b=8'b00000000;
2:b=8'b11011010;
3:b=8'b11110010;
4:b=8'b01100110;
5:b=8'b10110110;
6:b=8'b10111110;
7:b=8'b11100000;
8:b=8'b11111110;
9:b=8'b11110110;
10:b=8'b11101110;
11:b=8'b00111110;
12:b=8'b10011100;
13:b=8'b01111010;
14:b=8'b10011110;
15:b=8'b10001110;
endcase
end
always@(posedge rst or posedge clk) //时钟分频
begin
if(!rst)
begin
sum<=0;
clk1<=0;
end
else if(sum==50000000) //分频50M次
begin
clk1<=~clk1; //时钟翻转
sum<=0; //sum清零
end
else
sum<=sum+1'b1; //sum累加直至50M
end
always@(posedge rst or posedge clk1) //模n计数器
begin
if(!rst)
led<=0;
else if(n<2)
begin
led<=0;
z<=0;
end
else if(led==(n-1)) //当led为n-1时,立即清零
begin
led<=0;
z<=0;
end
else begin
led<=led+1;
z[led]<=led[2]^led[0]; //异或运算
end
end
endmodule
(2)仿真程序:
module sim_mod12xulie;
reg rst;
reg clk;
reg [3:0] n;
wire[7:0] b;
wire[14:0] z;
mod12xulie u0( //实例化模n序列信号发生器
.rst(rst),
.clk(clk),
.n(n),
.z(z),
.b(b)
);
parameter PERIOD = 10; //参数声明,并赋值为10
always
begin //每隔5,时钟翻转一次
clk = 1'b0;
#(PERIOD/2) clk = 1'b1;
#(PERIOD/2);
end
initial
begin //不同n的取值对应的计数器
n=4'b0011; // 模3序列信号发生器
clk = 1'b0;
rst = 1'b0;
#100;
rst = 1'b1;
#200;
n=4'b0111; // 模7序列信号发生器
clk = 1'b0;
rst = 1'b0;
#100;
rst = 1'b1;
#200;
n=4'b1001; // 模9序列信号发生器
clk = 1'b0;
rst = 1'b0;
#100;
rst = 1'b1;
#200;
n=4'b1011; // 模11序列信号发生器
clk = 1'b0;
rst = 1'b0;
#100;
rst = 1'b1;
#200;
n=4'b1111; // 模15计数器序列信号发生器
clk = 1'b0;
rst = 1'b0;
#200;
rst = 1'b1;
end
endmodule
(3)约束程序:
set_property -dict {PACKAGE_PIN P17 IOSTANDARD LVCMOS33} [get_ports clk ]
set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports rst ]
set_property -dict {PACKAGE_PIN R1 IOSTANDARD LVCMOS33} [get_ports {n[0]}]
set_property -dict {PACKAGE_PIN N4 IOSTANDARD LVCMOS33} [get_ports {n[1]}]
set_property -dict {PACKAGE_PIN M4 IOSTANDARD LVCMOS33} [get_ports {n[2]}]
set_property -dict {PACKAGE_PIN R2 IOSTANDARD LVCMOS33} [get_ports {n[3]}]
set_property -dict {PACKAGE_PIN M1 IOSTANDARD LVCMOS33} [get_ports {z[14]}]
set_property -dict {PACKAGE_PIN L1 IOSTANDARD LVCMOS33} [get_ports {z[13]}]
set_property -dict {PACKAGE_PIN K6 IOSTANDARD LVCMOS33} [get_ports {z[12]}]
set_property -dict {PACKAGE_PIN J5 IOSTANDARD LVCMOS33} [get_ports {z[11]}]
set_property -dict {PACKAGE_PIN H5 IOSTANDARD LVCMOS33} [get_ports {z[10]}]
set_property -dict {PACKAGE_PIN H6 IOSTANDARD LVCMOS33} [get_ports {z[9]}]
set_property -dict {PACKAGE_PIN K1 IOSTANDARD LVCMOS33} [get_ports {z[8]}]
set_property -dict {PACKAGE_PIN K2 IOSTANDARD LVCMOS33} [get_ports {z[7]}]
set_property -dict {PACKAGE_PIN J2 IOSTANDARD LVCMOS33} [get_ports {z[6]}]
set_property -dict {PACKAGE_PIN J3 IOSTANDARD LVCMOS33} [get_ports {z[5]}]
set_property -dict {PACKAGE_PIN H4 IOSTANDARD LVCMOS33} [get_ports {z[4]}]
set_property -dict {PACKAGE_PIN J4 IOSTANDARD LVCMOS33} [get_ports {z[3]}]
set_property -dict {PACKAGE_PIN G3 IOSTANDARD LVCMOS33} [get_ports {z[2]}]
set_property -dict {PACKAGE_PIN G4 IOSTANDARD LVCMOS33} [get_ports {z[1]}]
set_property -dict {PACKAGE_PIN F6 IOSTANDARD LVCMOS33} [get_ports {z[0]}]
set_property -dict {PACKAGE_PIN H1 IOSTANDARD LVCMOS33} [get_ports wei]
set_property -dict {PACKAGE_PIN B4 IOSTANDARD LVCMOS33} [get_ports {b[7]}]
set_property -dict {PACKAGE_PIN A4 IOSTANDARD LVCMOS33} [get_ports {b[6]}]
set_property -dict {PACKAGE_PIN A3 IOSTANDARD LVCMOS33} [get_ports {b[5]}]
set_property -dict {PACKAGE_PIN B1 IOSTANDARD LVCMOS33} [get_ports {b[4]}]
set_property -dict {PACKAGE_PIN A1 IOSTANDARD LVCMOS33} [get_ports {b[3]}]
set_property -dict {PACKAGE_PIN B3 IOSTANDARD LVCMOS33} [get_ports {b[2]}]
set_property -dict {PACKAGE_PIN B2 IOSTANDARD LVCMOS33} [get_ports {b[1]}]
set_property -dict {PACKAGE_PIN D5 IOSTANDARD LVCMOS33} [get_ports {b[0]}]
三、仿真结果
3.1 基础任务
结果分析:z对应显示的序列,每隔一定时间,[11:0]z从最低位依次显示最高位。如图所示,红框中是一个周期,只需看该周期的最后一列表示的高低电平,即可看出信号的发生序列,本图中可以看出是101001011010。
3.2 提高任务
结果分析:与基础任务近似,只是添加了时钟分频,显示的序列和基础任务一致,为101001011010。
3.3 拓展任务
结果分析:N对应不同序列的长度, N可取[2:15], z对应显示的序列。如图所示,仿真时,这里我N分别取的是3,7,9,11,15。从上面红色框中可以看出信号的发生序列。n=3时,产生的序列信号为010; n=7时,产生的序列信号为0101101; n=9时,产生的序列信号为010110100; n=11时,产生的序列信号为01011010010; n=15时,产生的序列信号为010110100101100。
四、 硬件验证
4.1 基础任务
结果分析:硬件仿真时,有试验现象,流水灯显示的序列为101001011010,但是没有按照预期的进行循环显示。是因为没有进行时钟分频,时钟的频率太高,为100Mhz,led进行循环一次的时间太短,加上人眼的分辨能力有限,故无法识别,看上去是流水灯一直亮。
4.2 提高任务
结果分析:硬件仿真时,流水灯显示的序列为101001011010。
4.3 拓展任务
结果分析:上图是N取不同值的两个过程:第一幅图:N取9时,流水灯显示的序列为010110100;第二幅图:N取15时,流水灯显示的序列为010110100101100。
五、 问题解决
1.问题:基础任务添加逻辑关系时,不知道如何添加。
解决办法:最开始我是另外添加了一个always语句,只要计数过程中led(程序中定义的计数的中间变量)变化,就进行对应的逻辑运算,但是硬件仿真时,流水灯不会循环变化。后来,我直接在计数器中添加了逻辑关系,当led为11时,输出的序列z为0;否则,z[led]<=led[2]~^led[0],第0位和第2位 进行同或运算。
2.问题:编写序列长度为N的仿真文件时,添加的n每隔一定时间,n=n+1’b1,但是仿真出来的现象和预期不符。
解决办法:我选取了N为3,7,9,11,15的时候,进行仿真计数,同时为了观察方便,我在每一段计数过程前添加了一段清零端作用的过程,将不同N取值的序列信号隔开。
3.问题:编写的约束文件总是显示到某一行有错误。
解决办法:编写的约束文件时我犯过几个错误,主要有三个地方需要注意:(1)约束文件的注释符和源文件不一样,应该用##,而不是//。(2)引脚间要注意有空格。(3)端口信号是一位时,不需要用{}。例如[get_ports {wei}]是错误的,应该写成[get_ports wei]。
六、 心得体会
在进行本次实验时,我首先从产生序列信号发生器的原理入手,明白了要先实现对应模值的计数器,然后按照一定的组合逻辑序列来显示输出。由于这里并没有对序列进行硬性规定,因此,并不需要推导组合逻辑关系,来输出特定的序列,可以自己规定逻辑关系。
做基础任务时,编写源代码时,其中:由于序列信号长度为12,故我定义了一个4位的中间寄存器变量reg[3:0]led,来进行计数过程。其中逻辑关系我选取的是z[led]=led[2]~^led[0],led从0到11计数时,z对应位数的结果等于led的第两位和第零位的同或。然后在Vivado中进行软件仿真,顺利地出现了结果,但是硬件仿真时没有按照预期的进行循环显示,只是对应的流水灯常亮。后来发现是因为没有进行时钟分频,时钟的频率太高,为100Mhz,led进行循环一次的时间太短,加上人眼的分辨能力有限,故无法识别,看上去是流水灯一直亮。
因此做提高任务时,我只在基础任务里添加时钟分频,进而观察EGO1板子上显示z对应的流水灯是否依次亮起,完成一次循环周期的流水灯即是序列信号的产生。
最后我做扩展任务,设计源文件时遇到了很大的困难,不知道如何改变N,不知道如何控制输出序列的长度等等。经过一番努力,我发现N是由拨码开关确定的,可以用一个case语句,将n对应的模值输出到数码管上。确定N后,开始对应的计数,然后将计数过程的结果进行逻辑运算。后来我巧妙用了z[led],虽然z设定的是15位,但是由于N的取值,我只是选了其中对应的前N-1位,很好的控制了输出序列的长度。