verilog实现状态机

如愿

  • 一、使用工具
  • 二、要求
  • 三、需求分析
  • 四、时序切换
  • 五、检测10010串
  • 六、总结

一、使用工具

Quartus 18.1

二、要求

1、根据以下描述功能用verilog编写一段代码, 并用状态机来实现该功能。
(1)状态机:实现一个测试过程,该过程包括启动准备状态、启动测试、停止测试、查询测试结果、显示测试结果、测试结束返回初始化6个状态;用时间来控制该过程,90秒内完成该过程;
(2)描述状态跳转时间;
(3)编码实现。
2. 画出可以检测10010串的状态图, 并用verilog编程实现之。

三、需求分析

对于第一个要求,是实现六个状态,并且用时间来控制这个过程,说简单一点,就是根据时间切换六个状态

对于第二个要求,需要检测10010的数据串,只有当10010依次输入时,才能通过检测,而实现这个功能,可以通过按键来模拟0和1的值,并且使用6个状态,只有当输入的值正确之后,才能进入下一个状态,不然就会回到出事状态

verilog实现状态机_第1张图片

四、时序切换

  • 状态切换代码
module six_state (//90s内六个状态切换
    input wire clk,	//时钟,50M
	input wire rst_n,	//复位信号
	
	output wire [3:0] led //1s脉冲信号
);
//6个切换状态
parameter s1= 1;
parameter s2= 2;
parameter s3= 3;
parameter s4= 4;
parameter s5= 5;
parameter s6= 6;
//切换时间状态为1s
parameter MAX_NUM=26'd50_000_000;

reg [3:0] led_r;
reg [2:0] cstate;//现在的状态
reg [25:0] cnt;

//计数模块
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
		cnt <= 26'd0;
	else if (cnt == MAX_NUM)
		cnt <= 26'd0;
	else 	
		cnt <= cnt + 1'd1;
end

//状态切换模块
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
		cstate <= 3'b0;
	else if (cnt == MAX_NUM) begin
        if (cstate == 3'd6) begin
            cstate <= 3'b0;
        end else begin
            cstate <= cstate + 1'b1;
        end    
    end	
	else 	
		cstate <= cstate ;
end

//状态输出模块
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
		led_r <= 4'b0;
	else begin
        case (cstate)
            s1: led_r <= 4'b0001;
            s2: led_r <= 4'b0010;
            s3: led_r <= 4'b0100;
            s4: led_r <= 4'b1000;
            s5: led_r <= 4'b0011;
            s6: led_r <= 4'b0111;
            default : led_r <= led_r ;
        endcase
    end
end

assign led = led_r ;

endmodule
  • 效果
    verilog实现状态机_第2张图片

五、检测10010串

  • 按键消抖模块
module key_debounce( //按键消抖模块
	input wire clk,
	input wire rst_n,
	input wire key,

	output wire key_value, //按键稳定信号
	output wire flag			//按键稳定标志
);

parameter delay_time = 1_000_000;

reg [22:0] delay_cnt;
reg key_reg;
reg flag_r;
reg key_value_r;
//0.2ms计时器
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		key_reg <= 1'b0;
	else begin
		key_reg <= key;
		if(key_reg == 1'b1 && key == 1'b0)begin
			delay_cnt <= delay_time;
		end
		
		else if (delay_cnt == 20'd0) 
			delay_cnt <= 20'd0;
		
		else if (key_reg == 1'b0 && key == 1'b0)
			delay_cnt <= delay_cnt -1'd1;
		end
end

//控制flag
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		flag_r <= 1'b0;
	else if (delay_cnt == 20'd1)
		flag_r <=	1'b1;
	else 
		flag_r <=	1'b0;
end

assign flag = flag_r;
//得到输出值
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		key_value_r <= 1'b0;
	else if (delay_cnt == 20'd1)
		key_value_r <= ~key	;
	else 
		key_value_r <= key_value_r;
end

assign key_value =key_value_r;

endmodule

  • 密码模块
/* 密码:10010  */
module password(
	input wire clk,
	input wire rst_n,
	input wire [1:0] key,

	output wire [3:0] led

);

//转态空间

parameter IDLE = 3'd0;
parameter S1 = 3'd1;//按对一个
parameter S2 = 3'd2;//按对两个
parameter S3 = 3'd3;//按对三个
parameter S4 = 3'd4;//按对四个
parameter S5 = 3'd5;//按对五个
parameter MAX_NUM=26'd49_999_999;

reg [2:0] cstate;
reg [3:0] led_r;
reg [25:0] cnt;

//1s计时器
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		cnt <= 26'd0;
	else if (cnt == MAX_NUM)
		cnt <= 26'd0;
	else 
		cnt <= cnt + 1'd1;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n) begin
		cstate <= IDLE;
		end
	
	else begin
		case(cstate)
			IDLE:begin
				if(key[1])begin
					cstate <= S1;
					end
				else if(key[0])
					cstate <= IDLE;
				else
					cstate <= cstate;
				end
				
			S1:begin
				if(key[0])begin
					cstate <= S2;
					end
				else if(key[1])
					cstate <= IDLE;
				else
					cstate <= cstate;
				end
				
			S2:begin
				if(key[0])begin
					cstate <= S3;
					end
				else if(key[1])
					cstate <= IDLE;
				else
					cstate <= cstate;
				end
				
			S3:begin
				if(key[1])begin
					cstate <= S4;
					end
				else if(key[0])
					cstate <= IDLE;
				else
					cstate <= cstate;
				end
            S4:begin
				if(key[0])begin
					cstate <= S5;
					end
				else if(key[1])
					cstate <= IDLE;
				else
					cstate <= cstate;
				end
				
			default:cstate <= cstate;
		endcase
		end

end

//状态输出
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		led_r <= 4'b0;
	else begin
		case(cstate)
			IDLE: led_r <= 4'b0001;
			S1: led_r <= 4'b0010;
			S2: led_r <= 4'b0100;
			S3: led_r <= 4'b1000;
            S4: led_r <= 4'b1110;
            S5: led_r <= 4'b1111;
			default led_r <= led_r;
		endcase
	end
	
end

assign led =led_r;

endmodule 
  • 状态检测顶层模块
module state_judge_top(
    input wire clk,
	input wire rst_n,
	input wire [1:0] key,

	output wire [3:0] led
);

wire [1:0] key_value;
wire [1:0] flag;

key_debounce i0_key_debounce(
.clk			(clk),
.rst_n		(rst_n),
.key			(key[0]),

.key_value	(key_value[0]), //按键稳定信号
.flag			(flag[0])//按键稳定标志
);
key_debounce i1_key_debounce(
.clk			(clk),
.rst_n		(rst_n),
.key			(key[1]),

.key_value	(key_value[1]), //按键稳定信号
.flag			(flag[1])//按键稳定标志
);

password i_password(
.clk			(clk),
.rst_n		(rst_n),
.key			({key_value[1]&&flag[1],key_value[0]&&flag[0]}),

.led			(led)

);

endmodule
  • 效果

六、总结

  • 在序列串较短的时候,用状态切换不仅思路清晰,而且比较简单,但是在序列串比较长的时候,这种方法就不适用了,是否可以考虑存储之后再进行比较,但这样又怎么发挥FPGA并行的优势呢。

你可能感兴趣的:(FPGA,fpga开发)