赞
踩
我们在设计完一个方向的流水灯的设计时,总是会想实现让流水灯倒着流水回去的设计,这里我也是一样,实现这种设计的方法有很多种,其中就有直接使用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)begin
- if(!rst_n)begin
- cnt<=0;
- end
- else if(add_cnt)begin
- if(end_cnt)
- cnt<=0;
- else
- cnt<=cnt+1;
- end
- else
- cnt<=0;
- end
- assign add_cnt=1'b1;
- assign end_cnt=add_cnt && cnt ==(TIME_500ms-1);
-
- //LED从左往右,在从右往左流水
- always @(posedge clk or negedge rst_n)begin
- if(!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)begin
- if(!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)begin
- if(!rst_n)begin
- cnt<=0;
- end
- else if(add_cnt)begin
- if(end_cnt)
- cnt<=0;
- else
- cnt<=cnt+1;
- end
- else
- cnt<=0;
- end
- assign add_cnt=1'b1;
- assign end_cnt=add_cnt && cnt ==(TIME_500ms-1);
-
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt_state<=0;
- end
- else if(add_cnt_state)begin
- if(end_cnt_state)
- cnt_state<=0;
- else
- cnt_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)begin
- if(!rst_n)begin
- cnt_flag<=0;
- end
- else if(end_cnt_state)begin
- cnt_flag<=~cnt_flag;
- end
- else
- cnt_flag<=cnt_flag;
- end
-
- //功能编写
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)
- led_out<=4'b0001;
- else if(cnt_flag==1'b0 && end_cnt)begin
- led_out<={led_out[2:0],led_out[3]};//循环以为实现轮流闪烁
- end
- else if(cnt_flag==1'b1 && end_cnt)begin
- led_out<={led_out[0],led_out[3:1]};//循环以为实现轮流闪烁
- end
- else
- led_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 begin
- rst_n =1'b0;
- #(CLK_CLY*2);
- #3;
- rst_n =1'b1;
- end
- //激励
-
- endmodule
从波形图中我们可以看到LED灯首先会从0001——1000进行流水,然后又会从1000——0001进行反方向流水,与我们设计的要求一致,设计简单,所以就不进行下板验证了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。