FPGA | 按键、拨码开关控制流水灯实验(附完整代码)

FPGA 课程设计,果断选择最简单的花式点灯

实验要求

一、设计一个8路流水灯控制电路
二、有多种变化方式:
1)自左向右逐次点亮,或自右向左逐次点亮,到终点后在从头开始;
2)自左向右逐次熄灭,或自右向左逐次熄灭,到终点后再从头开始;
3)按一定间隔(自定义)逐次点亮;
4)灯工作时间可调;
三、设置复位键,独立流水灯工作模式控制键,独立流水灯速度键;
四、时钟信号为开发板上时源。
完成任务1)-4)的得分不超过65分,有扩展到内容酌情增加得分。

OK,虽然看起来很复杂,但拆分一下要求的话核心是以下几点:
基础流水灯 *、方向控制键 **、速度控制键 **、复位键 ***(*代表优先级)

实验平台

对于流水灯实验,都不需要开发板选型,随便抄起手边现有的板子就直接开始,这里我用的是安路科技的 EF2L45BG256_MINI_DEV3 开发板,原理图如下。我这里LED是低电平点亮,按键按下去是"0",按键释放是"1",拨码开关拨上ON 是"0",拨到OFF 是"1"。

学校里常用的应该是Xilinx或者Altera的板子,但其实影响不大,不同板子只需要对照原理图修改部分代码(LED是低电平点亮还是高电平点亮、按键按下是0还是1)以及管脚约束文件就可以。
在这里插入图片描述
在这里插入图片描述

设计思路

按键检测

按键开关和拨码开关不同,需要你一直按着才能保持,一旦松手就检测不到’'0"了,这里我为了达到和拨码开关一样的效果(按一下之后就可以松手了),当然你如果想一直按着按键保持流水灯点亮可以忽略这一部分。
因为按下后弹起会有一个从"0"到"1"的上升沿,通过检测这个上升沿就可以判断按键是否被按下后又弹起:

reg key1_d0,key2_d0,key3_d0;     
reg key1_out,key2_out,key3_out; 

// 检测按键是否弹起
assign key1_up = key[0] & ~key1_d0;
assign key2_up = key[1] & ~key2_d0;
assign key3_up = key[2] & ~key3_d0;

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		key1_d0 <= 1'b1; 
		key2_d0 <= 1'b1;		
		key2_d0 <= 1'b1;
	end
	else begin
		key1_d0 <= key[0];  
		key2_d0 <= key[1];		
		key3_d0 <= key[2];
	end
end 	

// 每次检测到按键弹起,令对应的key_out取反,即开/关状态切换
always@(posedge clk or negedge rst_n) begin
	if(!rst_n)begin
		key1_out <= 0;	
		key2_out <= 0;		
		key3_out <= 0;				
		end	
	else if(key1_up) 		
		key1_out <= ~key1_out;		
	else if(key2_up) 		
		key2_out <= ~key2_out;	
	else if(key3_up) 		
		key3_out <= ~key3_out;							
end
流水灯控制

这一部分基本都是大同小异的,先设置一个计数器,再设置一个状态控制,当计数到一定值(可以通过设置这个值来改变速度)的时候令状态+1,之后再根据按键选择状态即可:

// 控制流水灯方向
always @ (posedge clk or negedge rst_n) begin
    if(!rst_n)
        direction <= 1'd0;         
    else if(!switch[0])      
        direction <= 1'd1;
    else
        direction <= 1'd0;
end 

// key3控制流水灯速度
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        speed <= 25'd24_999_999;
    else if(key3_out)         
        speed <= 25'd4_999_999;
    else
        speed <= 25'd24_999_999;
end

// 计数器,控制流水灯速度
always @ (posedge clk or negedge rst_n) begin
    if(!rst_n)
        cnt <= 25'd0;         
    else if(cnt < speed)      
        cnt<=cnt+1;
    else
        cnt<=0;
end           

// 控制流水灯状态
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        led_control <= 3'b000;
    else if(cnt == speed)         
        led_control <= led_control + 1'b1;
    else
        led_control <= led_control;
end

完整代码

module key_led(
    input               clk  ,    
    input               rst_n,    
	input 		 [1:0]  switch,    // switch[0]:控制方向 switch[1]:控制间隔点亮
    input        [2:0]  key,   // key[0]/key[1]:流水灯点亮/熄灭 key[2]:控制速度
    output  reg  [7:0]  led       
    );
    
reg key1_d0,key2_d0,key3_d0;     
reg key1_out,key2_out,key3_out;  

reg direction;

reg  [24:0] cnt;
reg  [2:0]  led_control; 

reg  [24:0] speed;

// 按键弹起
wire key1_up,key2_up,key3_up;	

// 检测按键是否弹起
assign key1_up = key[0] & ~key1_d0;
assign key2_up = key[1] & ~key2_d0;
assign key3_up = key[2] & ~key3_d0;


always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		key1_d0 <= 1'b1; 
		key2_d0 <= 1'b1;		
		key2_d0 <= 1'b1;
	end
	else begin
		key1_d0 <= key[0];
		key2_d0 <= key[1];		
		key3_d0 <= key[2];
	end
end 	

always@(posedge clk or negedge rst_n) begin
	if(!rst_n)begin
		key1_out <= 0;	
		key2_out <= 0;		
		key3_out <= 0;				
		end	
	else if(key1_up) 		
		key1_out <= ~key1_out;		
	else if(key2_up) 		
		key2_out <= ~key2_out;	
	else if(key3_up) 		
		key3_out <= ~key3_out;							
end

// 用拨码开关控制流水灯方向
always @ (posedge clk or negedge rst_n) begin
    if(!rst_n)
        direction <= 1'd0;         
    else if(!switch[0])      
        direction <= 1'd1;
    else
        direction <= 1'd0;
end 

// key3控制流水灯速度,时钟25M,24_999_999=1s 
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        speed <= 25'd24_999_999;
    else if(key3_out)         
        speed <= 25'd4_999_999;
    else
        speed <= 25'd24_999_999;
end

// 计数器,控制流水灯速度
always @ (posedge clk or negedge rst_n) begin
    if(!rst_n)
        cnt <= 25'd0;         
    else if(cnt < speed)      
        cnt<=cnt+1;
    else
        cnt<=0;
end           

// 控制流水灯状态
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        led_control <= 3'b000;
    else if(cnt == speed)         
        led_control <= led_control + 1'b1;
    else
        led_control <= led_control;
end


always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
          led<=8'b0000_0000;
    end
    else if(key1_out & direction & switch[1])   // 从左向右点亮
        case (led_control)
            3'b000   : led<=8'b1111_1110;
            3'b001   : led<=8'b1111_1101;
            3'b010   : led<=8'b1111_1011;
            3'b011   : led<=8'b1111_0111;
            3'b100   : led<=8'b1110_1111;
            3'b101   : led<=8'b1101_1111;
            3'b110   : led<=8'b1011_1111;
            3'b111   : led<=8'b0111_1111;
            default  : led<=8'b1111_1111;
        endcase
    else if (key1_out & !direction & switch[1]) // 从右向左点亮 
        case (led_control)
            3'b000   : led<=8'b0111_1111;
            3'b001   : led<=8'b1011_1111;
            3'b010   : led<=8'b1101_1111;
            3'b011   : led<=8'b1110_1111;
            3'b100   : led<=8'b1111_0111;
            3'b101   : led<=8'b1111_1011;
            3'b110   : led<=8'b1111_1101;
            3'b111   : led<=8'b1111_1110;
            default  : led<=8'b1111_1111;
        endcase
    else if (key2_out & direction & switch[1])  // 从左向右熄灭
        case (led_control) 			
            3'b000   : led<=8'b0000_0000;
            3'b001   : led<=8'b0000_0001;
            3'b010   : led<=8'b0000_0011;
            3'b011   : led<=8'b0000_0111;
            3'b100   : led<=8'b0000_1111;
            3'b101   : led<=8'b0001_1111;
            3'b110   : led<=8'b0011_1111;
            3'b111   : led<=8'b0111_1111;
            default  : led<=8'b1111_1111;
        endcase            
    else if (key2_out & !direction & switch[1])  // 从右向左熄灭
        case (led_control) 			
            3'b000   : led<=8'b0000_0000;
            3'b001   : led<=8'b1000_0000;
            3'b010   : led<=8'b1100_0000;
            3'b011   : led<=8'b1110_0000;
            3'b100   : led<=8'b1111_0000;
            3'b101   : led<=8'b1111_1000;
            3'b110   : led<=8'b1111_1100;
            3'b111   : led<=8'b1111_1110;
            default  : led<=8'b1111_1111;
        endcase              
    else if (key2_out & direction & !(switch[1]))  // 从左向右间隔熄灭
        case (led_control) 			
            3'b000   : led<=8'b0000_0000;
            3'b001   : led<=8'b0000_0001;
            3'b010   : led<=8'b0000_0101;
            3'b011   : led<=8'b0001_0101;
            3'b100   : led<=8'b0101_0101;
            3'b101   : led<=8'b0000_0001;
            3'b110   : led<=8'b0000_0101;
            3'b111   : led<=8'b0001_0101;
            default  : led<=8'b0101_0101;
        endcase            
    else if (key2_out & !direction & !(switch[1]))  // 从右向左间隔熄灭
        case (led_control) 			
            3'b000   : led<=8'b0000_0000;
            3'b001   : led<=8'b0100_0000;
            3'b010   : led<=8'b0101_0000;
            3'b011   : led<=8'b0101_0100;
            3'b100   : led<=8'b0101_0101;
            3'b101   : led<=8'b0100_0000;
            3'b110   : led<=8'b0101_0000;
            3'b111   : led<=8'b0101_0100;
            default  : led<=8'b0101_0101;
        endcase            
    else if (key1_out & direction & !(switch[1]))  // 从左向右间隔点亮
        case (led_control) 			
            3'b000   : led<=8'b1111_1110;
            3'b001   : led<=8'b1111_0111;
            3'b010   : led<=8'b1011_1111;
            3'b011   : led<=8'b1111_1110;
            3'b100   : led<=8'b1111_0111;
            3'b101   : led<=8'b1011_1111;
            3'b110   : led<=8'b1111_1110;
            3'b111   : led<=8'b0111_0111;
            default  : led<=8'b1011_1111;
        endcase            
    else if (key1_out & !direction & !(switch[1]))  // 从右向左间隔点亮
        case (led_control) 			
            3'b000   : led<=8'b0111_1111;
            3'b001   : led<=8'b1110_1111;
            3'b010   : led<=8'b1111_1101;
            3'b011   : led<=8'b1011_1111;
            3'b100   : led<=8'b1111_0111;
            3'b101   : led<=8'b1111_1110;
            3'b110   : led<=8'b1101_1111;
            3'b111   : led<=8'b0111_1011;
            default  : led<=8'b0111_1111;
        endcase
    else 
        led<=8'b1111_1111;         
end

endmodule 
  • 14
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只殿鹿

爱屋及乌(滑稽

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值