FPGA实现:特定序列生成,特定子序列检测以及子序列出现次数数码管显示的方法及应用

本文详细描述了一种使用Verilog编程语言实现的实验,涉及特定周期序列的产生、状态机设计以检测序列0101,以及计数器和数码管显示部分。文章还介绍了如何通过分频确保每秒输入一个序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:实验要求

  使用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;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值