欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 明星 > FPGA开发——LED流水灯实现先从左往右流水,再从右往左流水

FPGA开发——LED流水灯实现先从左往右流水,再从右往左流水

2024/10/24 17:22:10 来源:https://blog.csdn.net/weixin_63553972/article/details/140710865  浏览:    关键词:FPGA开发——LED流水灯实现先从左往右流水,再从右往左流水

一、概述

我们在设计完一个方向的流水灯的设计时,总是会想实现让流水灯倒着流水回去的设计,这里我也是一样,实现这种设计的方法有很多种,其中就有直接使用case语句将所有可能包含进去编写,这种设计方法是最简单的,还有就是使用多个计数器的方式进行标志判断,实现方向流水的切换,以及我们最常用的状态机方法的实现。因为这里的设计不太难,所以我就讲解前面两种实现方式,至于最后一种方法感兴趣的可以去实现一下。

二、实现思路

1、方法一

这个方法就是不考虑其他条件,直接从第一个LED状态开始编写,一直编写到所有的LED状态编写完(这里以四个LED为例)

2、方法二

这个方法的实现思路就是在第一个计数器(LED流水间隔时间计数器)计数的基础上叠加一个计数器统计不同方向流水完成,使用次计数器编写状态标志位。从而利用标志位实现不同方向流水。

三、测试文件的编写

1、方法一

//模块定义
module  led(input rst_n,input clk,output reg [3:0]  led_out
);//参数定义
parameter TIME_500ms= 25_000_000;
//内部信号定义
reg [24:0]  cnt;//计数500ms所需要的二进制位数
wire        add_cnt;//计数器开启条件
wire        end_cnt;//计数器结束条件
reg  [3:0]  state_n;//计数器实现功能,0.5秒技术
always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt<=0;endelse if(add_cnt)beginif(end_cnt)cnt<=0;elsecnt<=cnt+1;endelsecnt<=0; 
end
assign add_cnt=1'b1;
assign end_cnt=add_cnt && cnt ==(TIME_500ms-1);//LED从左往右,在从右往左流水always @(posedge clk or negedge rst_n)beginif(!rst_n)led_out<=4'b0001;else case(state_n)3'd0:led_out<=4'b0001;3'd1:led_out<=4'b0010;3'd2:led_out<=4'b0100;3'd3:led_out<=4'b1000;3'd4:led_out<=4'b0100;3'd5:led_out<=4'b0010;3'd6:led_out<=4'b0001;default:led_out<=4'b0001;endcase
end  always @(posedge clk or negedge rst_n)beginif(!rst_n)state_n <=0;else if(state_n==3'd6 && end_cnt)state_n<=0;else if(state_n<3'd6 && end_cnt)state_n<=state_n+1;
end 
endmodule

2、方法二

//模块定义
module  led(input rst_n,input clk,output reg [3:0]  led_out
);//参数定义
parameter TIME_500ms= 25_000_000;
//内部信号定义
reg [24:0]  cnt;//计数500ms所需要的二进制位数
wire        add_cnt;//计数器开启条件
wire        end_cnt;//计数器结束条件
reg  [3:0]  state_n;
reg  [1:0]  cnt_state;
wire        add_cnt_state;//计数器开启条件
wire        end_cnt_state;//计数器结束条件reg         cnt_flag;
//计数器实现功能,0.5秒技术
always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt<=0;endelse if(add_cnt)beginif(end_cnt)cnt<=0;elsecnt<=cnt+1;endelsecnt<=0; 
end
assign add_cnt=1'b1;
assign end_cnt=add_cnt && cnt ==(TIME_500ms-1);always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_state<=0;endelse if(add_cnt_state)beginif(end_cnt_state)cnt_state<=0;elsecnt_state<=cnt_state+1;end
end
assign add_cnt_state=end_cnt;
assign end_cnt_state=add_cnt_state && (cnt_state ==3);always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_flag<=0;endelse if(end_cnt_state)begincnt_flag<=~cnt_flag;endelsecnt_flag<=cnt_flag;
end//功能编写
always @(posedge clk or negedge rst_n)beginif(!rst_n)led_out<=4'b0001;else if(cnt_flag==1'b0 && end_cnt)beginled_out<={led_out[2:0],led_out[3]};//循环以为实现轮流闪烁end else if(cnt_flag==1'b1 && end_cnt)beginled_out<={led_out[0],led_out[3:1]};//循环以为实现轮流闪烁end elseled_out<=led_out;
end 
endmodule

四、测试文件的编写

这里我们要放着的条件都是一样的,所以只要使用同一个测试文件就可以

//定义时间尺度
`timescale 1ns/1ps
module led_tb();//重定义
defparam  led_inst.TIME_500ms = 25;
//内部变量定义
reg clk;
reg rst_n;
wire [3:0] led_out;//模块实例化
led led_inst(/*input              */ .rst_n    (rst_n     ),/*input            */ .clk      (clk       ),/*output reg [3:0] */ .led_out  (led_out   )
);//时钟
parameter CLK_CLY =20;
initial clk=0;
always  #(CLK_CLY/2) clk=~clk;//复位
initial beginrst_n =1'b0;#(CLK_CLY*2);#3;rst_n =1'b1;
end 
//激励endmodule

五、仿真波形图

从波形图中我们可以看到LED灯首先会从0001——1000进行流水,然后又会从1000——0001进行反方向流水,与我们设计的要求一致,设计简单,所以就不进行下板验证了。 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com