FPGA之状态机练习

FPGA之状态机练习


一、状态机1

实现一个测试过程,该过程包括启动准备状态、启动测试、停止测试、查询测试结果、显示测试结果、测试结束返回初始化6个状态;用时间来控制该过程,90秒内完成该过程.



新建工程后,创建fsm_test.v文件(新建工程可参考Quartus II的使用):

module fsm_test(
	input	wire clk,
	input wire rst_n,
	
	output	wire [3:0]	led
);

	parameter T = 33'd449_999_999; // 测试使用9s
	reg [32:0] cnt;	// 计时器
	
	
	parameter READY_STATE = 0;			// 准备状态, 0.5s
	parameter STARTUP_STATE = 1;		// 启动测试状态, 1s
	parameter STOPTEST_STATE = 2;		// 停止测试状态, 1s
	parameter QUERY_STATE = 3;			// 查询测试结果状态, 3s
	parameter DISPLAY_STATE = 4;		// 显示测试结果状态, 3s
	parameter STOP_STATE = 5;			// 测试结束状态, 0.5s
	
	
	reg [3:0] now_state = READY_STATE;   // 当前状态
	
	reg [3:0] led_r;
	
	// 计时
	always @(posedge clk or negedge rst_n) begin
		if (!rst_n)
			cnt <= 33'd0;
		else if(cnt == T)
			cnt <= 33'd0;
		else
			cnt <= cnt + 1'd1;
	end
		
	
	// 状态改变
	always @(posedge clk or negedge rst_n) begin
		if (!rst_n)
			now_state <= READY_STATE;
		
		else begin
			case (now_state)
				READY_STATE: begin
					if (cnt == T/18)
						now_state <= STARTUP_STATE;
					else
						now_state <= now_state;
				end
				STARTUP_STATE: begin
					if (cnt == T*3/18)
						now_state <= STOPTEST_STATE;
					else
						now_state <= now_state;
				end
				STOPTEST_STATE: begin
					if (cnt == T*5/18)
						now_state <= QUERY_STATE;
					else
						now_state <= now_state;
				end
				QUERY_STATE: begin
					if (cnt == T*11/18)
						now_state <= DISPLAY_STATE;
					else
						now_state <= now_state;
				end
				DISPLAY_STATE: begin
					if (cnt == T*17/18)
						now_state <= STOP_STATE;
					else
						now_state <= now_state;
				end
				STOP_STATE: begin
					if (cnt == T)
						now_state <= READY_STATE;
					else
						now_state <= now_state;
				end
				default: begin
					now_state <= now_state;
				end
			endcase
		end
	end
	
	
	
	// led根据状态显示
	always @(posedge clk or negedge rst_n) begin
		if (!rst_n)
			led_r <= 4'b0000;
		else if(now_state == READY_STATE)
			led_r <= 4'b0001;
		else if(now_state == STARTUP_STATE)
			led_r <= 4'b0010;
		else if(now_state == STOPTEST_STATE)
			led_r <= 4'b0011;
		else if(now_state == QUERY_STATE)
			led_r <= 4'b0100;
		else if(now_state == DISPLAY_STATE)
			led_r <= 4'b0101;
		else if(now_state == STOP_STATE)
			led_r <= 4'b0110;
		else
			led_r <= 4'b1111;
	end

	assign led = led_r;


endmodule

演示结果:

请添加图片描述


二、检测10010串

检测10010的输入

状态图:

请添加图片描述

创建工程后,首先创建消抖模块文件key_dobounce.v

// 按键消抖模块
module key_dobounce(
	input wire clk,  //不写类型默认为wire
	input	wire rst_n,
	input wire key,
	
	output	reg	flag,  // 判断是否消除抖动,0为结束,1为抖动结束
	output	reg	key_value  // 消抖后稳定的按键值
);


	// 20ms延时计数器, 1s 50_000_000
	// 20ms 1_000_000
	parameter T = 1_000_000;
	reg [19:0] delay_cnt = T;

	// 寄存一次key的值,用于判断按键是否消抖成功
	reg key_reg;


	always @(posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			key_reg <= 1'b1;   // 高电平,未按
			delay_cnt <= 1'b0;
		end
		else begin
			key_reg <= key;
			if (key_reg == 1 && key == 0) // 当这一次的key值和上一次的key值不相等时,说明正在抖动
				delay_cnt <= T;  // 抖动未结束时,延迟始终为20ms
			else if (delay_cnt > 0)  // 已消除抖动,开始计数
				delay_cnt <= delay_cnt - 1;
			else
				delay_cnt <= delay_cnt;
		end
	end


	// 根据延时计数器获取按键状态及其按键值
	always @(posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			flag <= 1'b0;    // 未消除,默认值
			key_value <= 1'b1;  // 按键高电平,初始值
		end
		else begin
			if (delay_cnt == 20'd1)begin  // 记完数
				flag <= 1'b1;  // 消除抖动
				key_value <= key;
			end
			else begin  // 未记完数
				flag <= 1'b0; // 未消除
				key_value <= key_value;
			end
		end
	end



endmodule

然后创建test_str.v

module test_str(
	input wire clk,
	input wire rst_n,
	input wire key0,     // 0按键,1为按下
	input wire key1,		// 1按键,1为按下
	
	output wire[3:0] led
);


	parameter S0 = 0;		  		// 未输入状态
	parameter S1_1 = 1;	  		// 1
	parameter S2_10 = 2;			// 10
	parameter S3_100 = 3;		// 100
	parameter S4_1001 = 4;		// 1001
	parameter S5_10010 = 5;		// 10010,闪烁
	
	reg [2:0] now_state = S0;  // 当前状态
	
	
	parameter T = 49_999_999;  // 1s
	reg [25:0] cnt = 26'd0;  // 计时器,用于闪烁
	
	
	reg [3:0] led_r;
	
	// 计时
	always @(posedge clk or negedge rst_n) begin
		if (!rst_n)
			cnt <= 26'd0;
		else if (cnt == T || (now_state==S4_1001 && key0))
			cnt <= 26'd0;
		else
			cnt <= cnt + 1'd1;
	end
	
	
	
	
	// 状态切换
	always @(posedge clk or negedge rst_n) begin
		if (!rst_n)
			now_state <= S0;
			
		else begin
			case (now_state)
				S0: begin
					if (key1)
						now_state <= S1_1;
					else if (key0)
						now_state <= S0;
					else
						now_state <= now_state;
				end
				
				S1_1: begin
					if (key1)
						now_state <= S0;
					else if (key0)
						now_state <= S2_10;
					else
						now_state <= now_state;
				end
				
				S2_10: begin
					if (key1)
						now_state <= S0;
					else if (key0)
						now_state <= S3_100;
					else
						now_state <= now_state;
				end
				
				S3_100: begin
					if (key1)
						now_state <= S4_1001;
					else if (key0)
						now_state <= S0;
					else
						now_state <= now_state;
				end
				
				S4_1001: begin
					if (key1)
						now_state <= S0;
					else if (key0)
						now_state <= S5_10010;
					else
						now_state <= now_state;
				end
			endcase
		end
	end
	


	// LED
	always @(posedge clk or negedge rst_n) begin
		if (!rst_n)
			led_r <= 4'b0000;
		
		else begin
			case (now_state)
				S0: 			led_r <= 4'b0000;
				S1_1: 		led_r <= 4'b0001;
				S2_10: 		led_r <= 4'b0010;
				S3_100:	 	led_r <= 4'b0100;
				S4_1001: 	led_r <= 4'b1001;
				S5_10010: begin // 闪烁
					if (cnt < T/2)
						led_r <= 4'b1111;
					else
						led_r <= 4'b0000;
				end
				default:		led_r <= 4'b1110;
			endcase
		end
	end
				 			
	assign led = led_r;


endmodule

最后创建顶层文件test_str_top.v

module test_str_top(
	input wire clk,
	input wire rst_n,
	input wire key0_in,
	input wire key1_in,
	
	output wire [3:0]  led
);

	wire flag0;
	wire flag1;
	wire key_value0;
	wire key_value1;


	key_dobounce inst_key0_dobounce(
		.clk			(clk),
		.rst_n		(rst_n),
		.key			(key0_in),
		
		.flag			(flag0),  // 判断是否消除抖动,0为结束,1为抖动结束
		.key_value	(key_value0)  // 消抖后稳定的按键值
	);
	key_dobounce inst_key1_dobounce(
		.clk			(clk),
		.rst_n		(rst_n),
		.key			(key1_in),
		
		.flag			(flag1),  // 判断是否消除抖动,0为结束,1为抖动结束
		.key_value	(key_value1)  // 消抖后稳定的按键值
	);

	
	test_str inst_test_str(
		.clk		(clk),
		.rst_n	(rst_n),
		.key0		(flag0 && !key_value0),     // 0按键,1为按下
		.key1		(flag1 && !key_value1),		// 1按键,1为按下
		
		.led		(led)
	);


endmodule

演示结果:

请添加图片描述

猜你喜欢

转载自blog.csdn.net/weixin_46628481/article/details/124547603
今日推荐