FPGA通过一个按键控制三个LED灯亮灭(状态机法)

FPGA型号:Cyclone IV EPFCE10F17C8    开发工具:Quartus13.0专业版  Modelsim 10.1d

文章目录

  • 状态机
  • 一、设计思路
  • 二、代码设计
    • 1.顶层代码
    • 2.测试代码
  • 三、仿真

状态机

状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。状态机的4个要素:现态、条件、动作、次态。“现态”和“条件”是因 ,“动作”和“次态”是果。

1)现态:指当前所处状态;

2)条件:又称“事件”。当条件被满足时,将会触发一个动作,或者执行一次状态的迁移。

3)动作:条件满足后执行的动作。条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必须的,当条件满足后,也可以不执行任何动作,迁移到新状态。

4)次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就变成新的“现态”了。

有限状态机简写为FSM(Finite State Machine),主要分为2大类:

第一类,若输出只和状态有关而与输入无关,则称为Moore状态机。

第二类,输出不仅和状态有关而且和输入有关系,则称为Mealy状态机

常用的三段式状态机的设计思路为:

1)一段式:利用一个进程来描述状态的转换及输出信号的定义;

2)二段式:一个为时序电路主要负责状态变量的更新,此进程为同步电路,而另一个进程语句主要是描述下次态变量和输出的更新;

3)三段式:第一个进程主要负责状态变量的更新,第二个进程语句负责描述次态变量,而最后一个则是负责输出信号的更新。

一、设计思路

FPGA实现一个按键控制三个LED灯亮灭的状态机如图所示。在初始状态下,LED灯全部处于熄灭状态。当按键被按下时,会启动消抖程序,默认按键按下时,延迟10ms,若按键仍处于低电平,则说明按键确实被按下,系统进入进入状态1,即LED_r处于低电平,红色LED灯亮起,并保持。当按键再次被按下时,继续进行消除抖动检测,若满足,则系统进入状态2,即LED_g处于低电平,绿色LED灯亮起,并保持。同理,当系统进入状态3时,LED_b处于低电平,蓝色LED灯亮起,并保持。当系统复位时,系统返回至初始状态。FPGA通过一个按键控制三个LED灯亮灭(状态机法)_第1张图片

 时序图如图所示:

FPGA通过一个按键控制三个LED灯亮灭(状态机法)_第2张图片

 二、代码

1.顶层代码

`timescale 1ns/1ps

//模块定义
module FSM(
		clk,
	  rst_n,
	    key,
	  led_r,
	  led_g,
	  led_b
);

//输入输出
input      clk;
input    rst_n;
input      key;
output   led_r;
output   led_g;
output   led_b;

//信号类型定义
parameter ms_10 = 250_000;

reg         key_en;
reg [17:0] low_cnt;
reg [17:0] hig_cnt;
reg [1:0]  led_cnt;
reg          led_r;
reg          led_g;
reg          led_b;

wire      key_flag;

//按键消抖
always @ (posedge clk or negedge rst_n)  begin
		if (!rst_n) begin
			key_en  <= 1'd0;
			low_cnt <= 18'd0;
			hig_cnt <= 18'd0;
		end
		else if (key_en) begin                     //检测按键为高电平时,延时10ms将状态读取
			low_cnt <= 18'd0;
			if (hig_cnt == ms_10) begin
					key_en <= key;
				   hig_cnt <= hig_cnt;
			end
			else begin
				   hig_cnt <= hig_cnt +1'd1;
			end
		end
		 else  begin                               //检测按键为低电平时,延时10ms将状态读取
			hig_cnt <= 18'd0;
			if (low_cnt == ms_10) begin
					 key_en <= key;
				   low_cnt <= low_cnt;
			end
			else  begin
				   low_cnt <= low_cnt +1'd1;
			end
		 end
end

assign  key_flag = key_en;

//按键下降沿控制led状态切换
always @ (negedge key_flag or negedge rst_n) begin
		if (!rst_n) begin
				led_cnt <= 2'd0;
		end
		else if (led_cnt == 2'd2) begin
				led_cnt <= 2'd0;
		end
	   else  begin
				led_cnt <= led_cnt +2'd1;
		end
end

//状态机:led状态切换
always @ (posedge clk or negedge rst_n) begin
		if (!rst_n) begin
				led_r <= 1'd1;
				led_g <= 1'd1;
				led_b <= 1'd1;
		end
		else case(led_cnt) 
			2'd0: begin             //红灯亮
				led_r <= 1'd0;
				led_g <= 1'd1;
				led_b <= 1'd1;
			end
			2'd1: begin             //绿灯亮
				led_r <= 1'd1;
				led_g <= 1'd0;
				led_b <= 1'd1;
			end
			2'd2: begin             //蓝灯亮
				led_r <= 1'd1;
				led_g <= 1'd1;
				led_b <= 1'd0;
			end
			default: begin          //都不亮
				led_r <= 1'd1;
				led_g <= 1'd1;
				led_b <= 1'd1;
			end
	    endcase
end

endmodule

2.测试代码

`timescale 1 ps/ 1 ps
module FSM_vlg_tst();
reg clk;
reg key;
reg rst_n;
// wires                                               
wire led_b;
wire led_g;
wire led_r;
// wires                                               
// assign statements (if any)                          
FSM i1 (
// port map - connection between master ports and signals/registers   
	.clk(clk),
	.led_b(led_b),
	.led_g(led_g),
	.led_r(led_r),
	.rst_n(rst_n)
);
initial                                                
begin                                                  
clk = 0;
key = 0;
forever #5 clk = ~clk;                          
end   

initial
begin
rst_n = 1;
#30 rst_n = ~rst_n; 
#10 rst_n = ~rst_n;    
end
                                                
always                                                                
begin                                                  
 #50 key = ~key;                                                                  
end                                                    
endmodule

三、仿真

 由图可见,仿真结果基本符合预期。 

你可能感兴趣的:(fpga开发,嵌入式硬件)