FPGA入门笔记006——状态机设计实例

发布时间 2023-11-23 16:20:43作者: Yamada_Ryo

状态分析:

微信图片_20231123142212

状态1:等待“H”的到来,如果检测到“H”,进入状态2,检测“e”,否则一直等待“H”;

状态2:检测当前字符是否是“e”,如果是“e”,跳转到状态3,检测“l”,否则,回到状态1,重新等待“H”;

状态3:检测当前字符是否是“l”,如果是“l”,跳转到状态4,检测“l”,否则,回到状态1,重新等待“H”;

状态4:检测当前字符是否是“l”,如果是“l”,跳转到状态5,检测“o”,否则,回到状态1,重新等待“H”;

状态5:检测当前字符是否是“o”,如果是“o”,驱动led控制引脚发生状态翻转,同时回到状态1,等待下一个“H”的到来,否则,回到状态1,重新等待“H”;

代码实现:

module Hello(
	Clk,
	Rst_n,
	data,
	led
);
	input Clk;	//50M
	input Rst_n;	//低电平复位
	
	input [7:0]data;	//存储字符的ASCII码
	
	output reg led;
	
	localparam
		CHECK_H  = 5'b0_0001,
		CHECK_e  = 5'b0_0010,
		CHECK_la = 5'b0_0100,
		CHECK_lb = 5'b0_1000,
		CHECK_o  = 5'b1_0000;
		
	reg[4:0]state;	//状态
	
	//一段式状态机、两段式状态机、三段式状态机
	
	always@(posedge Clk or negedge Rst_n)begin
	if(!Rst_n)begin
		led <= 1'b1;	//led低电平有效
		state <= CHECK_H;	//当复位时,等待H状态
	end
	else
		case(state)
			CHECK_H:
				if(data == "H")
					state <= CHECK_e;
				else
					state <= CHECK_H;
			CHECK_e:
				if(data == "e")
					state <= CHECK_la;
				else
					state <= CHECK_H;
			CHECK_la:
				if(data == "l")
					state <= CHECK_lb;
				else
					state <= CHECK_H;
			CHECK_lb:
				if(data == "l")
					state <= CHECK_o;
				else
					state <= CHECK_H;
			CHECK_o:
				begin
					state <= CHECK_H;
					if(data == "o")
						led <= ~led;
					else
						led <= led;
				end
			default:state <= CHECK_H;
		endcase
	end
		
endmodule 

语法知识:

localparam

在Verilog中,可以使用localparam(本地参数)来声明常量。

(注:parameter可用作在顶层模块中例化底层模块时传递参数的接口,localparam的作用域仅仅限于当前module,不能作为参数传递的接口。)

testbench文件代码如下:

`timescale 1ns/1ns
`define clock_period 20

module Hello_tb;
	
	reg Clk;
	reg Rst_n;
	reg [7:0]ASCII;
	
	wire led;
	
	Hello Hello0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.data(ASCII),
		.led(led)
	);
	
	initial Clk = 1;
	always #(`clock_period/2) Clk = ~Clk;
	
	initial begin
		Rst_n = 0;
		ASCII = 0;
		#(`clock_period*200);
		Rst_n = 1;
        #(`clock_period*200 + 1);	//"+1"操作使ASCII信号与时钟信号上升沿不对齐,方便查看仿真结果
		forever begin
			ASCII = "I";
			#(`clock_period);
			ASCII = "A";
			#(`clock_period);
			ASCII = "M";
			#(`clock_period);
			ASCII = "X";
			#(`clock_period);
			ASCII = "i";
			#(`clock_period);
			ASCII = "a";
			#(`clock_period);
			ASCII = "o";	
			#(`clock_period);
			ASCII = "M";
			#(`clock_period);
			ASCII = "e";
			#(`clock_period);
			ASCII = "i";
			#(`clock_period);
			ASCII = "g";
			#(`clock_period);
			ASCII = "e";	
			
			#(`clock_period);
			ASCII = "H";
			#(`clock_period);
			ASCII = "E";
			
			#(`clock_period);
			ASCII = "M";
			#(`clock_period);
			ASCII = "l";
			
			#(`clock_period);
			ASCII = "H";
			#(`clock_period);
			ASCII = "E";
			#(`clock_period);
			ASCII = "L";
			#(`clock_period);
			ASCII = "L";
			#(`clock_period);
			ASCII = "O";
			#(`clock_period);
			
			ASCII = "H";
			#(`clock_period);
			ASCII = "e";
			#(`clock_period);
			ASCII = "l";
			#(`clock_period);
			ASCII = "l";
			#(`clock_period);
			ASCII = "o";
			
			#(`clock_period);
			ASCII = "l";
		end
	end
endmodule

语法知识:

forever 循环

forever 循环语法格式如下:

forever begin
    …
end

forever 语句表示永久循环,不包含任何条件表达式,一旦执行便无限的执行下去,系统函数 $finish 可退出 forever。forever 相当于

while(1) 。通常,forever 循环是和时序控制结构配合使用的。