FPGA学习-状态机

利用FPGA构建一个状态机控制小灯亮灭,以便理解状态机的实际十几下应用。

1.例程介绍:

        假设有输入数据流,这个数据流会任意输入A~Z或a~z字母,其中某一段时刻会接连输入“Hellow”。现在设计一个状态机,当检测到Hellow时LED灯亮灭翻转。

2.设计分析:

         整个检测过程可以拆分成以下各个状态:

                1.等待H到来,如果检测到H那么进入2开始检测e,否则一直等待H;

                2.检测是否为e,如果是e->进入3开始检测l,如果不是e->返回1继续等待H;

                3.检测是否为l,如果是l->进入4开始检测l,如果不是l->返回1继续等待H;

                4.检测是否为l,如果是l->进入5开始检测o,如果不是l->返回1继续等待H;

                5.检测是否为o,如果是o->进入6开始检测w,如果不是o->返回1继续等待H;

                6.检测是否为w,如果是w->翻转LED并且返回1等待下一个H;如果不是w->返回1继续等待H;

3.rtl程序:

module Hellow(clk50M,rst_n,data,led);

	input clk50M;
	input rst_n;
	input [7:0] data;                              //输入的数据流是8位2进制ASCII码
	output reg led;

	reg [5:0] state;                               //各个状态使用编码密度低的独热码。这里6个状态,所以6位就够用

	localparam                                     //定义状态对应的独热码,以便case语句中调用(localparam用法与parameter一样)
		CHECK_H=6'b000001,
		CHECK_e=6'b000010,
		CHECK_la=6'b000100,
		CHECK_lb=6'b001000,
		CHECK_o=6'b010000,
		CHECK_w=6'b100000;
		
	always @ (posedge clk50M or negedge rst_n) begin

		if(!rst_n) begin					       //复位的时候LED灭,状态为1“等待H到来”
			led<=1'd0;
			state<=CHECK_H;
		end

		else begin
			case(state)						       //case语句检测属于什么状态					
			CHECK_H:                	           //例如:当是CHECK_H状态时
					if(data=="H")                  //每次进入一个数据都判断data是不是H
						state<=CHECK_e;	           //如果是->进入下一状态
					else
						state<=CHECK_H;	           //如果不是->返回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: 
					if(data=="o")
						state<=CHECK_w;
					else
						state<=CHECK_H;
				CHECK_w: 
					if(data=="w") begin
						led<=~led;
						state<=CHECK_H;
					end
					else
						state<=CHECK_H;
				default: 
					state<=CHECK_H;
			endcase
		end	
	end
endmodule

        注意:

                最后加上default,避免输入无对应的输出产生latch锁存器;6位独热码只用了6个数值,当state为其他数值时执行default后面的语句。

4.testbench测试文件:

`timescale 1ns/1ps
`define clock_period 20
module Hellow_tb;

	reg clk;
	reg rst_n;
	reg [7:0] ASCII;
	wire led;

	Hellow Hellow1(
		.clk50M(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;
		forever begin
			ASCII="a";                       //abc
			#(`clock_period);
			ASCII="b";
			#(`clock_period);
			ASCII="c";
			#(`clock_period);
			
			
			
			ASCII="H";                       //Hellow
			#(`clock_period);
			ASCII="e";
			#(`clock_period);
			ASCII="l";
			#(`clock_period);
			ASCII="l";
			#(`clock_period);
			ASCII="o";
			#(`clock_period);
			ASCII="w";
			#(`clock_period);
		end
	end	
endmodule

        注意:

                1.这里设置仿真数据流时设置了一个干扰数据(abc),目的就是为了检验是不是只有Hellow才能实现状态机功能;

                2.初始化激励数据流时使用的是forever语句,程序会一直跑下去;我们需要在配置modelsim中手动设定仿真时间;

                3.Quartus中“H”完全等价于大写H对应的16进制数据0x48。

5.波形图:

         上图可以看到LED的翻转。

         上图通过前仿真可以看到,每次翻转与时钟上升沿是对齐的。

        上图后仿真可以观察到是真实情况。每次检测到w后,下一拍LED才翻转 。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值