一:实验要求
使用verilog产生特定周期序列 100 101 101 000 010 101 001 101 010 (且每秒输入一个序列值,此功能将在“目录八”中展示,“目录八”之前主要以仿真测试为主)并检测序列0101,并将程序下载后使序列出现次数通过数码管显示
后期可能会在bilbil中更新相关内容,感兴趣的读者可关注B站: 食不相瞒
如果会调试的读者可跳过七:1:测试版部分
二:序列产生模块
使用位拼接符号循环左移的方法实现特定序列x的产生
//循环左移
output reg x;
reg [26:0] Sequ = 27'b1001_0110_1000_0101_0100_1101_010;//端口定义
always@(posedge clk or posedge clr)//时序电路部分
begin
if(clr)
begin
Sequ<= 27'b1001_0110_1000_0101_0100_1101_010;
end
else
begin
Sequ<={Sequ[25:0],Sequ[26]};//位拼接符号实现循环左移
end
end
//产生序列
always@(posedge clk or posedge clr)
begin
if(clr)
begin
x <=1'b0;
end
else
begin
x <=Sequ[26];
end
end
三:次态&现态的定义
//将次态赋给现态
always@(posedge clk or posedge clr)
begin
if(clr)
begin
state<=s0;
end
else
state<=next_state;
end
四:状态机实现状态0101的检测
1:状态检测图
Quartus状态检测图
手绘版状态检测图:根据具体情况具体分析,此处以可重叠计数为例(不重复设计相对来说更简单,但是原理都相同,注意状态之间的转换)
2:检测到指定序列时标识端口z输出为高
每当state为s4时z输出为高否则为低;
assign z=(state==s4)?1:0;
五:计数器计数模块
每当z为高时计数器加1
//计数部分,计数5次,到4计数值为0
always@(posedge clk or posedge clr)
begin
if(clr)
count=0;
else
if(next_state == s4)
if(count<=4)
count=count+1;
else
count=0;
else
count=count;
end
六:数码管显示部分
FPGA开发板EP4CE22F17C6硬件下载,数码管实时显示计数值,即指定子序列出现次数(例程仿真已经验证无误,“目录八”以前的代码因为工作频率的问题下载到硬件上不能正常显示,如果需要下载请参考“目录八”以后的代码以及管脚配置)
1:注意下载板子上是共阴还是共阳的数码管
2:因为本例所举例子一个周期序列内只有4个指定检测的子序列所以这里只写了0-4的显示部分
其实4是不需要的,因为0,1,2,3,0就已经计数4次;
//7段数码管显示部分
always @ (posedge clk or posedge clr)
begin
case (count)
0:seg = 8'b11111100;
1:seg = 8'b01100000;
2:seg = 8'b11011010;
3:seg = 8'b11110010;
4:seg = 8'b01100110;
default:seg = 8'b11111100;
endcase
end
七:完整代码展示
(此处展示测试版和最终版,读者可用相同的方法定义端口,由此检测输出和状态每个时刻的值)
注:测试版和最终版的区别
<1>代码部分的区别在于最开始对state,next_state端口的定义不同(测试版更好观察state和next_state在每个clk时钟的值,最终版没有把他们引出来)
<2>测试文件部分是一样的,都只对clk和clr的状态和clk的翻转周期进行定义
1:测试版
<代码>
module xuliejiance (clk,clr,z,seg,state,x,next_state);//序列:100 101 101 000 010 101 001 101 010 检测序列0101
input clk,clr;
output z;
output reg [7:0] seg;
reg [3:0]count;//计数器
output reg [3:0] state;
output reg [3:0] next_state;
parameter s0=3'b000,s1=3'b001,
s2=3'b010,s3=3'b011,s4=3'b100;
//循环左移
output reg x;
reg [26:0] Sequ = 27'b1001_0110_1000_0101_0100_1101_010;
always@(posedge clk or posedge clr)
begin
if(clr)
begin
Sequ<= 27'b1001_0110_1000_0101_0100_1101_010;
end
else
begin
Sequ<={Sequ[25:0],Sequ[26]};//位拼接符号实现循环左移
end
end
//产生序列
always@(posedge clk or posedge clr)
begin
if(clr)
begin
x <=1'b0;
end
else
begin
x <=Sequ[26];
end
end
//将次态赋给现态
always@(posedge clk or posedge clr)
begin
if(clr)
begin
state<=s0;
end
else
state<=next_state;
end
//根据现态和序列输入判断下一个状态
//状态机部分
always@(state,clr)
begin
if(clr)
begin
next_state=0;
end
else
case(state)
s0:
begin
if(!x)
next_state<=s1;
else next_state<=s0;
end
s1:
begin
if(x)
next_state<=s2;
else
next_state<=s1;
end
s2:
begin
if(!x)
next_state<=s3;
else
next_state<=s0;
end
s3:
begin
if(x)
next_state<=s4;
else
next_state<=s1;
end
s4:
begin
if(x)
next_state<=s0;
else
next_state<=s3;
end
default:
begin
next_state<=s0;
end
endcase
end
assign z=(state==s4)?1:0;
//计数部分,计数5次,到4为0
always@(posedge clk or posedge clr)
begin
if(clr)
count=0;
else
if(next_state == s4)
if(count<=4)
count=count+1;
else
count=0;
else
count=count;
end
//7段数码管显示部分
always @ (posedge clk or posedge clr)
begin
case (count)
0:seg = 8'b11111100;
1:seg = 8'b01100000;
2:seg = 8'b11011010;
3:seg = 8'b11110010;
4:seg = 8'b01100110;
default:seg = 8'b11111100;
endcase
end
endmodule
<测试文件>
`timescale 1 ns/ 1 ns
module xuliejiance_vlg_tst();
// constants
// general purpose registers
//reg eachvec;
// test vector input registers
reg clk;
reg clr;
// wires
wire [7:0] seg;
wire x;
wire z;
// assign statements (if any)
xuliejiance i1 (
// port map - connection between master ports and signals/registers
.clk(clk),
.clr(clr),
.seg(seg),
.x(x),
.z(z)
);
initial
begin
clr=0;
clk=0;
// --> end
$display("Running testbench");
end
always
// optional sensitivity list
// @(event1 or event2 or .... eventn)
begin
// code executes for every event on sensitivity list
// insert code here --> begin
#300
clk=~clk;
//@eachvec;
// --> end
end
endmodule
<仿真波形>
2:最终版(仿真可实现,下载会因为频率过快不能正常显示,如需下载请看“目录八”部分的内容)
<代码>
module xuliejiance (clk,clr,z,seg,x);//序列:100 101 101 000 010 101 001 101 010 检测序列0101
input clk,clr;
output z;
output reg [7:0] seg;
reg [3:0]count;//计数器
reg [3:0] state,next_state;//output reg [3:0] state;
//output reg [3:0] next_state;
parameter s0=3'b000,s1=3'b001,
s2=3'b010,s3=3'b011,s4=3'b100;
//循环左移
output reg x;
reg [26:0] Sequ = 27'b1001_0110_1000_0101_0100_1101_010;
always@(posedge clk or posedge clr)
begin
if(clr)
begin
Sequ<= 27'b1001_0110_1000_0101_0100_1101_010;
end
else
begin
Sequ<={Sequ[25:0],Sequ[26]};//位拼接符号实现循环左移
end
end
//产生序列
always@(posedge clk or posedge clr)
begin
if(clr)
begin
x <=1'b0;
end
else
begin
x <=Sequ[26];
end
end
//将次态赋给现态
always@(posedge clk or posedge clr)
begin
if(clr)
begin
state<=s0;
end
else
state<=next_state;
end
//根据现态和序列输入判断下一个状态
//状态机部分
always@(state,clr)
begin
if(clr)
begin
next_state=0;
end
else
case(state)
s0:
begin
if(!x)
next_state<=s1;
else next_state<=s0;
end
s1:
begin
if(x)
next_state<=s2;
else
next_state<=s1;
end
s2:
begin
if(!x)
next_state<=s3;
else
next_state<=s0;
end
s3:
begin
if(x)
next_state<=s4;
else
next_state<=s1;
end
s4:
begin
if(x)
next_state<=s0;
else
next_state<=s3;
end
default:
begin
next_state<=s0;
end
endcase
end
assign z=(state==s4)?1:0;
//计数部分,计数5次,到4为0
always@(posedge clk or posedge clr)
begin
if(clr)
count=0;
else
if(next_state == s4)
if(count<=4)
count=count+1;
else
count=0;
else
count=count;
end
//7段数码管显示部分
always @ (posedge clk or posedge clr)
begin
case (count)
0:seg = 8'b11111100;
1:seg = 8'b01100000;
2:seg = 8'b11011010;
3:seg = 8'b11110010;
4:seg = 8'b01100110;
default:seg = 8'b11111100;
endcase
end
endmodule
<测试文件>
`timescale 1 ns/ 1 ns
module xuliejiance_vlg_tst();
// constants
// general purpose registers
//reg eachvec;
// test vector input registers
reg clk;
reg clr;
// wires
wire [7:0] seg;
wire x;
wire z;
// assign statements (if any)
xuliejiance i1 (
// port map - connection between master ports and signals/registers
.clk(clk),
.clr(clr),
.seg(seg),
.x(x),
.z(z)
);
initial
begin
clr=0;
clk=0;
// --> end
$display("Running testbench");
end
always
// optional sensitivity list
// @(event1 or event2 or .... eventn)
begin
// code executes for every event on sensitivity list
// insert code here --> begin
#300
clk=~clk;
//@eachvec;
// --> end
end
endmodule
<仿真波形>
八:进阶分频部分(利用分频实现每秒钟输入一个序列)
(因为在下载的时候数码管常亮8------没有分频时工作频率太快,硬件问题以及“余晖效应--视觉暂留”不能正常显示,所以修改了部分代码,主要加了一个分频部分)
<分频部分>
//产生1s的时钟信号,同步复位,若分频信号复位仍为异步,则无法保持一致
always@(posedge clkin or posedge clr)
if (clr)
Cnt_1s <= 0;
else if (Cnt_1s == 49999999)
Cnt_1s <= 0;
else
Cnt_1s <= Cnt_1s + 1;
//由Cnt_1s计数调整占空比-50%
always@(posedge clkin or posedge clr)
if (clr)
clkout_1s <= 0;
else if (Cnt_1s <= 24999999)
clkout_1s <= 0;
else
clkout_1s <= 1;
<完整代码>
module xuliejiance (clkin,clkout_1s,clr,z,seg,x,G1);//序列:100 101 101 000 010 101 001 101 010 检测序列0101
input clkin,clr;
output z,G1;//G1为EP4CE22F17C6数码管1的使能端口,clkin为R8系统时钟输入,clkout_1s为例程工作时钟
output reg clkout_1s;
output reg [7:0] seg;
reg [3:0]count;//计数器
reg [31:0]Cnt_1s;
reg [3:0] state,next_state;//output reg [3:0] state;
//output reg [3:0] next_state;
parameter s0=3'b000,s1=3'b001,
s2=3'b010,s3=3'b011,s4=3'b100;
output reg x;
reg [26:0] Sequ = 27'b1001_0110_1000_0101_0100_1101_010;
//产生1s的时钟信号,同步复位,若分频信号复位仍为异步,则无法保持一致
always@(posedge clkin or posedge clr)
if (clr)
Cnt_1s <= 0;
else if (Cnt_1s == 49999999)
Cnt_1s <= 0;
else
Cnt_1s <= Cnt_1s + 1;
//由Cnt_1s计数调整占空比-50%
always@(posedge clkin or posedge clr)
if (clr)
clkout_1s <= 0;
else if (Cnt_1s <= 24999999)
clkout_1s <= 0;
else
clkout_1s <= 1;
//循环左移
always@(posedge clkout_1s or posedge clr)
begin
if(clr)
begin
Sequ<= 27'b1001_0110_1000_0101_0100_1101_010;
end
else
begin
Sequ<={Sequ[25:0],Sequ[26]};//位拼接符号实现循环左移
end
end
//产生序列
always@(posedge clkout_1s or posedge clr)
begin
if(clr)
begin
x <=1'b0;
end
else
begin
x <=Sequ[26];
end
end
//将次态赋给现态
always@(posedge clkout_1s or posedge clr)
begin
if(clr)
begin
state<=s0;
end
else
state<=next_state;
end
//根据现态和序列输入判断下一个状态
//状态机部分
always@(state,clr)
begin
if(clr)
begin
next_state=0;
end
else
case(state)
s0:
begin
if(!x)
next_state<=s1;
else next_state<=s0;
end
s1:
begin
if(x)
next_state<=s2;
else
next_state<=s1;
end
s2:
begin
if(!x)
next_state<=s3;
else
next_state<=s0;
end
s3:
begin
if(x)
next_state<=s4;
else
next_state<=s1;
end
s4:
begin
if(x)
next_state<=s0;
else
next_state<=s3;
end
default:
begin
next_state<=s0;
end
endcase
end
assign z=(state==s4)?1:0;
//计数部分,计数5次,到4为0
always@(posedge clkout_1s or posedge clr)
begin
if(clr)
count=0;
else
if(next_state == s4)
if(count<3)
count=count+1;
else
count=0;
else
count=count;
end
//7段数码管显示部分
always @ (posedge clkout_1s or posedge clr)
begin
case (count)
0:seg = 8'b11111100;
1:seg = 8'b01100000;
2:seg = 8'b11011010;
3:seg = 8'b11110010;
4:seg = 8'b01100110;
default: seg = 8'b00000000;
endcase
end
endmodule
<管脚分配>
九:实物下载效果展示
(gift动图太大放不了)
注:从左往右:LED1为输入的x序列;LED2为z,每计数一次亮一次;LED3为每秒的时钟输入;
其余灯为无效灯
数电选手应该不需要解释:0-3-0为什么是4个数的了吧?
修改过后数字4不亮,例程指定序列在周期序列中包括重复次数只有4次,所以只亮0-3;