状态机专题练习

第一题

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

  • 代码
module six_state (            //90s内六个状态切换
   input  wire       clk,	   //时钟,50M
	input  wire       rst_n,	//复位信号
	
	output wire [3:0] led      //4个led灯
);

//6个转态空间
parameter S0= 3'd0; //准备状态
parameter S1= 3'd1; //启动测试
parameter S2= 3'd2; //停止测试
parameter S3= 3'd3; //查询测试结果
parameter S4= 3'd4; //显示测试结果
parameter S5= 3'd5; //测试结束返回初始状态

//切换时间状态为1s
parameter MAX_NUM=26'd49_999_999;//1秒寄存器

reg [3:0] led_r; //灯寄存器·
reg [2:0] cstate;//现态
reg [2:0] nstate;//次态
reg [25:0] cnt;  //时间寄存器

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

//现态跟随次态
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cstate <= S0;
	end
	else begin
		cstate <= nstate;
	end
end

//状态切换
always @(posedge clk or negedge rst_n) begin
	if(!rst_n)begin
		nstate <= S1;
	end
   else begin
   case(cstate)
		3'd0: begin
				if(cnt == MAX_NUM)begin
					nstate = S1;
				end
				else begin
					nstate = nstate;
				end
			end
		3'd1:begin
				if(cnt == MAX_NUM)begin
					nstate = S2;
				end
				else begin
					nstate = nstate;
				end
			end
		3'd2:begin
				if(cnt == MAX_NUM)begin
					nstate = S3;
				end
				else begin
					nstate = nstate;
				end
			end
		3'd3:begin
				if(cnt == MAX_NUM)begin
					nstate = S4;
				end
				else begin
					nstate = nstate;
				end
			end
		3'd4:begin
				if(cnt == MAX_NUM)begin
					nstate = S5;
				end
				else begin
					nstate = nstate;
				end
			end
		3'd5:begin
				if(cnt == MAX_NUM)begin
					nstate = S0;
				end
				else begin
					nstate = nstate;
				end
			end
	   default :begin
				if(cnt == MAX_NUM)begin
					nstate = S0;
				end
				else begin
					nstate = nstate;
				end
		end
	endcase
	end
end

//跟随状态输出
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
		led_r <= 4'b0;
	else begin
        case (cstate)
            3'd0: led_r <= 4'b0001;
            3'd1: led_r <= 4'b0010;
            3'd2: led_r <= 4'b0100;
            3'd3: led_r <= 4'b1000;
            3'd4: led_r <= 4'b0011;
            3'd5: led_r <= 4'b1111;
            default : led_r <= led_r ;
        endcase
    end
end

assign led = led_r ;

endmodule


  • 效果

FPGA状态机实现六种状态转换

第二题

画出可以检测10010串的状态图, 并用verilog编程实现之。

  • 状态图:
    在这里插入图片描述

  • 按键消抖:

module key_debounce(
    input     wire       clk,
	 input     wire       rst_n,
	 input     wire       key,
	 
	 output    wire       leaf,
	 output    wire       key_value
);

parameter TIMER_20MS = 20'd1_000_000;//20ms

reg [19:0] timer_20ms_r;
reg key_r;
reg key_value_r;
reg leaf_r;

//将按键值存入寄存器
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
	     key_r <= 1'b0;
	 end
	 else begin
	     key_r <= key;
	 end
end

//按键消抖
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
	     timer_20ms_r <= 20'd0;
	 end
	 else if(key_r == key && key != 1'b1)begin
	     if(timer_20ms_r <= TIMER_20MS - 1'b1)begin
		      timer_20ms_r <= timer_20ms_r + 1'b1;
		  end
		  else begin
		      timer_20ms_r <= TIMER_20MS;
		  end
	 end
	 else begin
	     timer_20ms_r <= 20'd0;
	 end
end

//按键按下标志
assign leaf_w = (timer_20ms_r == TIMER_20MS - 1'b1)? 1'b1:1'b0;

//保存当前按键值
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
	     key_value_r <= 1'b0;
	 end
	 else if(leaf_w)begin
	     key_value_r <= ~key_value_r;
	 end
	 else begin
	     key_value_r <= 1'b0;
	 end
end

//使信号输出,延迟一个clk周期
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
	     leaf_r <= 1'b0;
	 end
	 else begin
	     leaf_r <= leaf_w;
	 end
end

assign leaf = leaf_r;
assign key_value = key_value_r;
endmodule

  • 识别10010:
/* 密码:10010  */
module password(
	input wire clk,                //时钟
	input wire rst_n,              //复位信号
	input wire [1:0] key,          //按键
         
	output wire [3:0] led          //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; //1s计数
parameter CNT_02 = 21'd1_999_999; //0.2s计数

reg [2:0]  cstate;                 //现态
reg [2:0]  nstate;                 //次态
reg [3:0]  led_r;                  //led灯寄存器
reg [25:0] cnt;                    //1s寄存器
reg [20:0] cnt_200ms;              //0.2s寄存器
//1s计时器
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt <= 26'd0;
	end
	else if (cnt == MAX_NUM)begin 
		cnt <= 26'd0;
	end
	else begin
		cnt <= cnt + 1'd1;
	end
end

//0.2s计时器
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
	     cnt_200ms <= 26'd0;
	 end
	 else if(cnt == CNT_02)begin
	     cnt_200ms <= 26'd0;
	 end
	 else begin
	     cnt_200ms <= cnt + 1'd1;
	 end
end
//现态跟随次态
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cstate <= IDLE;
	end
	else begin
	   cstate <= nstate;
	end
end
//状态转换
always@(posedge clk or negedge rst_n)begin
	if(!rst_n) begin
		nstate <= IDLE;
	end
	else begin
		case(cstate)
			IDLE:begin
				if(key[1])begin
					nstate <= S1;
					end
				else if(key[0])
					nstate <= IDLE;
				else
					nstate <= nstate;
				end
				
			S1:begin
				if(key[0])begin
					nstate <= S2;
					end
				else if(key[1])
					nstate <= IDLE;
				else
					nstate <= nstate;
				end
				
			S2:begin
				if(key[0])begin
					nstate <= S3;
					end
				else if(key[1])
					nstate <= IDLE;
				else
					nstate <= nstate;
				end
				
			S3:begin
				if(key[1])begin
					nstate <= S4;
					end
				else if(key[0])
					nstate <= IDLE;
				else
					nstate <= nstate;
				end
            S4:begin
				if(key[0])begin
					nstate <= S5;
					end
				else if(key[1])
					nstate <= IDLE;
				else
					nstate <= nstate;
				end
			S5:begin
					if(cnt == MAX_NUM)begin
						nstate <= IDLE;
					end
					else begin
						nstate <= nstate;
					end	
				end
			default:nstate <= IDLE;
		endcase
	end

end

//状态输出
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		led_r <= 4'b0000;
	else begin
		case(cstate)
			IDLE: led_r <= 4'b0000;
			S1  : led_r <= 4'b0001;
			S2  : led_r <= 4'b0011;
			S3  : led_r <= 4'b0111;
            S4  : led_r <= 4'b1111;
            S5  : begin
				      if(cnt_200ms == CNT_02)begin
							led_r <= ~led_r;
						end
						else begin
							led_r <= led_r;
						end
				   end
			default led_r <= led_r;
		endcase
	end
	
end

assign led =led_r;

endmodule 

  • 顶层文件
module password_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] leaf;

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

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

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

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

.led			(led)

);

endmodule

  • 效果:

FPGA状态机实现识别10010密码串

总结

状态机还是比较容易理解,用状态机进行状态的转换可以有效解决因为时序产生的毛刺。实现的效果都比较简单,如果下功夫可以玩出新花样,我算是抛砖引玉了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值