FPGA基于 DE2-115 8路彩灯控制

前言

第一次写博客,第一次自主设计fpga,verilog语法只是粗略了解,做出来的东西只是能跑,深层次的理解和优化还在学习中。

设计要求

1、 8 路彩灯能演示三种花型(花型自拟);
2.、要求用 Verilog HDL 语言写出代码,用 QuartusPrime 平台编译并生成原理图,并能够用软件实现仿真;
3、彩灯可以实现多种节拍的变换;
4、 最终设计要求在 DE2-115 实验开发板上实现:彩灯用开发板上的发光二极管模拟,花型
控制开关用开发板上的按键进行选择。

设计思路

花型选择状态参量及花型状态按钮(key0-2)状态寄存

将花型状态按钮(key0-2)状态传递进寄存器 key_state,并以此寄存器状态作为不同花型的触发条件。这里对 key0-2 的状态进行传递,是为了演示更方便。

时钟信号分频及 ledr 状态参量寄存器 cnt

系统晶振为 50MHZ,及一次时钟为 20ns,频率过高,肉眼不能分辨。使用计数器,对系统时钟分频,达到肉眼可分辨闪烁频率。通过频率状态参量 sw,控制 ledr 闪烁状态参量 cnt
的变化频率,以此实现 ledr 不同频率闪烁。

彩灯 ledr 控制设计

通过 case 语句实现不同 cnt 状态的 ledr 输出,同时通过判断寄存器 key_state 状态,,
实现不同 ledr 花型输出。

上代码

/*        ┌─┐       ┌─┐
#      ┌──┘ ┴───────┘ ┴──┐
#      │                 │
#      │       ───       │
#      │  ─┬┘       └┬─  │
#      │                 │
#      │       ─┴─       │
#      │                 │
#      └───┐         ┌───┘
#          │         │
#          │         │
#          │         │
#          │         └──────────────┐
#          │                        │
#          │                        ├─┐
#          │                        ┌─┘
#          │                        │
#          └─┐  ┐  ┌───────┬──┐  ┌──┘
#            │ ─┤ ─┤       │ ─┤ ─┤
#            └──┴──┘       └──┴──┘
#                神兽保佑
#                代码无BUG!
*/


module top_led(
input   clk,
input   rst_n,            //复位,低电平触发
input   wire[2:0]key,     //花型按钮,低电平输入
input   wire[2:0]sw,      //频率状态选择
output  reg [7:0] led_g,  //复位状态指示灯
output  reg [7:0] led_r   //led花型
);


reg[2:0]key_state;        //花型按钮状态寄存器
reg[31:0]cnt_clk;         //分频计数器
reg[3:0]cnt;              //ledr状态参量
 

//按钮信号寄存
always@(posedge clk or negedge rst_n)
begin
    if (!rst_n)
		      key_state<=3'b0;
	 else	if(key ==3'b110)
	         key_state<=3'b001;	 
	 else if(key ==3'b101)
	         key_state<=3'b010;	 
	 else	if(key ==3'b011)
	         key_state<=3'b100;	
	 else begin 
	         key_state<=key_state;
		end		
end 


//分频
always @(posedge clk or negedge rst_n) 
begin
    if (!rst_n)
	  begin
       cnt<=4'd0;
	    cnt_clk<=32'd0;
	  end
    else 
	   begin
	   case (sw)
	   3'b000 :begin
	           if(cnt_clk <32'd4_999_999)  // 0.1s一周期
				     begin
					  cnt_clk<=cnt_clk +32'd1;
					  cnt<=cnt;
					  end
					else if(cnt==4'd7)
				           cnt<=4'd0;
			      else
				     begin	
				         cnt<=cnt +4'd1;
							cnt_clk<=32'd0;
					  end		
	            end
	   3'b001 :begin
	           if(cnt_clk <32'd9_999_999)  // 0.2s一周期
				     begin
					  cnt_clk<=cnt_clk +32'd1;
					  cnt<=cnt;
					  end
					else if(cnt==4'd8)
				           cnt<=4'd0;
			      else
				     begin	
				         cnt<=cnt +4'd1;
					      cnt_clk<=32'd0;
					  end		
	            end
	   3'b011 :begin
	           if(cnt_clk <32'd19_999_999)  // 0.4s一周期
				     begin
					  cnt_clk<=cnt_clk +32'd1;
					  cnt<=cnt;
					  end
					else if(cnt==4'd8)
				           cnt<=4'd0;
			      else
				     begin	
				         cnt<=cnt +4'd1;
							cnt_clk<=32'd0;
					  end		
	            end
	   3'b111 :begin
	           if(cnt_clk <32'd49_999_999)  // 0.8s一周期
				     begin
					  cnt_clk<=cnt_clk +32'd1;
					  cnt<=cnt;
					  end
					else if(cnt==4'd8)
				           cnt<=4'd0;
			      else
				     begin	
				         cnt<=cnt +4'd1;
							cnt_clk<=32'd0;
					  end		
	            end
      endcase
		end
end		
	 


//led
always @(posedge clk or negedge rst_n) 
begin 
	if(!rst_n)
	begin
	led_g<=9'b11_111_111;//9'b00_000_000;
	led_r<=8'b00_000_000;
	end
	else if(key_state==3'b001)//流水灯
	begin
    case (cnt)
	        4'd1  : led_r<=8'b00_000_001;
	        4'd2  : led_r<=8'b00_000_010;
		    4'd3  : led_r<=8'b00_000_100;
	        4'd4  : led_r<=8'b00_001_000;
	        4'd5  : led_r<=8'b00_010_000;
		    4'd6  : led_r<=8'b00_100_000;
		    4'd7  : led_r<=8'b01_000_000;
		    4'd8  : led_r<=8'b10_000_000;
		  default : led_r<=8'b00_000_000;
    endcase
	 end
  else if(key_state==3'b010)//跳变
  begin
	 case (cnt)
	        4'd1  : led_r<=8'b11_001_100;
	        4'd2  : led_r<=8'b11_001_100;
		    4'd3  : led_r<=8'b00_110_011;
	        4'd4  : led_r<=8'b00_110_011;
	        4'd5  : led_r<=8'b11_001_100;
		    4'd6  : led_r<=8'b11_001_100;
		    4'd7  : led_r<=8'b00_110_011;
		    4'd8  : led_r<=8'b00_110_011;
		  default : led_r<=8'b00_000_000;
	 endcase
	end 
  else if(key_state==3'b100) //累加
  begin
	 case (cnt)
	        4'd1  : led_r<=8'b00_000_001;	
	        4'd2  : led_r<=8'b00_000_011;
	        4'd3  : led_r<=8'b00_000_111;
		    4'd4  : led_r<=8'b00_001_111;
		    4'd5  : led_r<=8'b00_011_111;
	        4'd6  : led_r<=8'b00_111_111;
		    4'd7  : led_r<=8'b01_111_111;
		    4'd8  : led_r<=8'b11_111_111;
		  default : led_r<=8'b00_000_000;
	 endcase 
  end
  else begin  
    led_g<=9'b00_000_000;//9'b11_111_111;
	 end
end	
	
endmodule   
	

结语

在时序逻辑和组合逻辑的设计上,参考两段式状态机模型,即一个 always 语块处理时钟信号和输入并进行 状态传递,一个 always 语块控制输出,使代码更加简洁,层次清晰。 后续的改进上面,可以使用 PLL 管理时钟的方式来控制频率选择,可以使用更少的 logic elements 实现功能。在使用PLL实现不同频率后,logic elements使用量只需要不到一半,但我还没跑出来。害,继续学吧。
因为全是自学的,对语法的理解和运用上可能有错误,大家仁者见仁,智者见智吧。
有大佬愿意给我指出的话,不胜感激!

改进版本

http://t.csdn.cn/Jd5U6

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值