本部分我们所用的都是四颗LED灯。
一、流水灯:
(一)位拼接:
初始状态四颗灯是其中一颗亮,每当1s到来的时候将四位led的最高位(最低位)拼接到最低位(最高位),拼接的位置不同流水的方向不同。Verilog代码:
module water_led
#(
parameter delay_1s = 50_000_000 //50Mhz时钟下1s的计数最大值
)
(
input sys_clk ,
input sys_rst_n ,
output reg [3:0] led
);
//1ms计时器
reg [25:0] cnt_1s;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1s <= 0;
else if(cnt_1s == delay_1s - 1)
cnt_1s <= 0;
else
cnt_1s <= cnt_1s + 1;
//控制led
always@(posedge sys_clk)
if(!sys_rst_n)
led <= 4'b0001;
else if(cnt_1s == delay_1s - 1)
led <= {led[2:0],led[3]};
else
led <= led;
endmodule
(二)状态机:
初始状态可以任意设计,定义五个状态:初始状态、第一颗灯亮、第二颗灯亮、第三颗灯亮、第四颗灯亮,状态转换的条件为1s的到来。Verilog代码:
module water_led
#(
parameter delay_1s = 50_000_000 //50Mhz时钟下1s的计数最大值
)
(
input sys_clk ,
input sys_rst_n ,
output reg [3:0] led
);
//1ms计时器
reg [25:0] cnt_1s;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1s <= 0;
else if(cnt_1s == delay_1s - 1)
cnt_1s <= 0;
else
cnt_1s <= cnt_1s + 1;
//流水灯状态机
//状态定义
localparam IDLE = 5'b00001; //初始状态
localparam First = 5'b00010; //第一颗灯亮
localparam Second = 5'b00100; //第二颗灯亮
localparam Third = 5'b01000; //第三颗灯亮
localparam Fourth = 5'b10000; //第四颗灯亮
reg [4:0] state; //当前状态(现态)寄存器
reg [4:0] next_state; //下一状态(次态)寄存器
//状态机第一段(给现态赋值)(时序逻辑)(固定格式)
always@(posedge sys_clk)
if(!sys_rst_n)
state <= IDLE;
else
state <= next_state;
//状态机第二段(状态转移)(给次态赋值)(组合逻辑)
always@(*)
if(!sys_rst_n)
next_state = IDLE;
else
begin
case(state)
IDLE :begin
if(cnt_1s == delay_1s -1)
next_state = First;
else
next_state = IDLE;
end
First :begin
if(cnt_1s == delay_1s -1)
next_state = Second;
else
next_state = First;
end
Second :begin
if(cnt_1s == delay_1s -1)
next_state = Third;
else
next_state = Second;
end
Third :begin
if(cnt_1s == delay_1s -1)
next_state = Fourth;
else
next_state = Third;
end
Fourth :begin
if(cnt_1s == delay_1s -1)
next_state = First;
else
next_state = Fourth;
end
default:next_state = IDLE;
endcase
end
//状态机第三段(状态输出)(时序逻辑)
always@(posedge sys_clk)
if(!sys_rst_n)
led <= 4'b0000;
else
begin
case(state)
IDLE :led <= 4'b0000;
First :led <= 4'b0001;
Second :led <= 4'b0010;
Third :led <= 4'b0100;
Fourth :led <= 4'b1000;
default:led <= 4'b1111;
endcase
end
endmodule
(三)按键控制流水:
在流水灯的基础上将灯的切换条件改为按键消抖后的信号,即按一次按键灯就流向下一位。
这里用位拼接的方法举例(状态机太长了),Verilog代码:
module water_led_key
#(
parameter delay_10ms = 500_000 //50Mhz时钟下10ms的计数最大值
)
(
input sys_clk ,
input sys_rst_n ,
input key ,
output reg [3:0] led
);
//10ms计时器
reg [18:0] cnt_10ms;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_10ms <= 0;
else if(key == 0)
begin
if(cnt_10ms == delay_10ms - 1)
cnt_10ms <= cnt_10ms;
else
cnt_10ms <= cnt_10ms + 1;
end
else
cnt_10ms <= 0;
wire key_flag;
assign key_flag = (cnt_10ms == delay_10ms - 2)?1:0;
//控制led
always@(posedge sys_clk)
if(!sys_rst_n)
led <= 4'b0001;
else if(key_flag == 1)
led <= {led[2:0],led[3]};
else
led <= led;
endmodule
这里的按键消抖部分也可以直接调用已经创建好的.v文件,就是将按键消抖例化到led控制模块,下面的例子中会有如何例化。
(四)按键控制流水灯的启停:
在流水灯的基础上加一个由按键控制的使能信号,当按键按下一次使能信号翻转,然后一直保持到下一次按键按下,在使能信号的条件下实现流水灯,从而实现按键控制流水灯的启停。这同样用位拼接的流水灯举例,Verilog代码:
module water_led_key
#(
parameter delay_1s = 50_000_000 //50Mhz时钟下1s的计数最大值
)
(
input sys_clk ,
input sys_rst_n ,
input key ,
output reg [3:0] led
);
wire key_flag;
KEY KEY_1 //后面的“KEY_1”自己想取什么都可以,但是如果有多个例化,名字不能相同
(
. sys_clk (sys_clk ),
. sys_rst_n (sys_rst_n ),
. key (key ),
. key_flag (key_flag )
);
//使能信号
always@(posedge sys_clk)
if(!sys_rst_n)
en <= 0;
else if(key_flag == 1)
en <= ~en;
else
en <= en;
//1ms计时器
reg [25:0] cnt_1s;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1s <= 0;
else if(cnt_1s == delay_1s - 1)
cnt_1s <= 0;
else
cnt_1s <= cnt_1s + 1;
//控制led
always@(posedge sys_clk)
if(!sys_rst_n)
led <= 4'b0001;
else if(cnt_1s == delay_1s - 1)
begin
if(en == 1)
led <= {led[2:0],led[3]};
else
led <= led;
end
else
led <= led;
endmodule
例化中.后面的是被调用模块里面的输入输出,括号里面是需要调用模块里面的输入输出,如果只是内部信号,则需要在例化前面用线定义出来,例化讲通俗一点就是连线。
二、翻转灯:
翻转灯其实就是在给led复制的时候将它取反。Verilog代码:
module fanzhuan_led
#(
parameter delay_1s = 50_000_000 //50Mhz时钟下1s的计数最大值
)
(
input sys_clk ,
input sys_rst_n ,
output reg [3:0] led
);
//1ms计时器
reg [25:0] cnt_1s;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1s <= 0;
else if(cnt_1s == delay_1s - 1)
cnt_1s <= 0;
else
cnt_1s <= cnt_1s + 1;
//控制led
always@(posedge sys_clk)
if(!sys_rst_n)
led <= 4'b0011;
else if(cnt_1s == delay_1s)
led <= ~led;
else
led <= led;
endmodule
三、呼吸灯:
(一)原理:
呼吸灯是指灯光在微电脑的控制之下完成由亮到暗的逐渐变化,感觉好像是人在呼吸。然而FPGA的引脚电压只有“0”和“1”两个等级,因此通过改变引脚单位时间内高电平的输出时间来实现呼吸灯,也就是让FPGA引脚输出一系列PWM波信号并不断改变PWM波的占空比。
(二)PWM(脉冲宽度调制):
脉冲宽度调制是一种模拟控制方式,根据相应载荷的变化来调制晶体管基极或MOS管栅极的偏置,来实现晶体管或MOS管导通时间的改变,从而实现开关稳压电源输出的改变。这种方式能使电源的输出电压在工作条件变化时保持恒定,是利用微处理器的数字信号对模拟电路进行控制的一种非常有效的技术。广泛应用在从测量、通信到功率控制与变换的许多领域中。
(三)占空比及其控制:
占空比是指在一个脉冲循环内,通电时间相对于总时间所占的比例。这里指的是高电平所占周期比例。通过控制占空比的不同来控制LED灯的亮度。在呼吸灯的实现中我们是通过三个不同的时钟计数来实现占空比的控制,最后通过比较占空比从而实现有暗到灭和由灭到暗。
(四)Verilog代码:
module breath_led
(
input sys_clk ,
input sys_rst_n ,
output reg [3:0] led //四颗LED灯
);
//记1us
reg [5:0] cnt_1us;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1us <= 0;
else if(cnt_1us == 49)
cnt_1us <= 0;
else
cnt_1us <= cnt_1us + 1;
//记1ms
reg [9:0] cnt_1ms;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1ms <= 0;
else if(cnt_1us == 49)
begin
if(cnt_1ms == 999)
cnt_1ms <= 0;
else
cnt_1ms <= cnt_1ms + 1;
end
else
cnt_1ms <= cnt_1ms;
//记1s
reg [9:0] cnt_1s;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1s <= 0;
else if(cnt_1us == 49 && cnt_1ms == 999)
begin
if(cnt_1s == 999)
cnt_1s <= 0;
else
cnt_1s <= cnt_1s + 1;
end
else
cnt_1s <= cnt_1s;
//1s标志信号
reg flag_1s;
always@(posedge sys_clk)
if(!sys_rst_n)
flag_1s <= 0;
else if(cnt_1us == 49 && cnt_1ms == 999 && cnt_1s == 999)
flag_1s <= !flag_1s;
else
flag_1s <= flag_1s;
//led灯的控制
always@(posedge sys_clk)
if(!sys_rst_n)
led <= 4'b0000;
else if(flag_1s == 0) //LED灯由暗到亮
begin
if(cnt_1s >= cnt_1ms)
led <= 4'b1111;
else
led <= 4'b0000;
end
else //LED灯由亮到暗
begin
if(cnt_1s <= cnt_1ms)
led <= 4'b1111;
else
led <= 4'b0000;
end
endmodule
四、流水呼吸灯:
(一)强行控制:
module breath_water
(
input sys_clk ,
input sys_rst_n ,
output reg [3:0] led
);
//记1us
reg [5:0] cnt_1us;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1us <= 0;
else if(cnt_1us == 49)
cnt_1us <= 0;
else
cnt_1us <= cnt_1us + 1;
//记1ms
reg [9:0] cnt_1ms;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1ms <= 0;
else if(cnt_1us == 49)
begin
if(cnt_1ms == 999)
cnt_1ms <= 0;
else
cnt_1ms <= cnt_1ms + 1;
end
else
cnt_1ms <= cnt_1ms;
//记1s
reg [9:0] cnt_1s;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1s <= 0;
else if(cnt_1us == 49 && cnt_1ms == 999)
begin
if(cnt_1s == 999)
cnt_1s <= 0;
else
cnt_1s <= cnt_1s + 1;
end
else
cnt_1s <= cnt_1s;
//1s标志信号
reg [2:0]flag;
always@(posedge sys_clk)
if(!sys_rst_n)
flag <= 0;
else if(cnt_1us == 49 && cnt_1ms == 999 && cnt_1s == 999)
flag <= flag + 1;
else
flag <= flag;
//led灯的控制
always@(posedge sys_clk)
if(!sys_rst_n)
led <= 4'b0000;
else if(flag == 0)
begin
if(cnt_1s >= cnt_1ms)
led <= 4'b0001;
else
led <= 4'b0000;
end
else if(flag == 1)
begin
if(cnt_1s <= cnt_1ms)
led <= 4'b0001;
else
led <= 4'b0000;
end
else if(flag == 2)
begin
if(cnt_1s >= cnt_1ms)
led <= 4'b0010;
else
led <= 4'b0000;
end
else if(flag == 3)
begin
if(cnt_1s <= cnt_1ms)
led <= 4'b0010;
else
led <= 4'b0000;
end
else if(flag == 4)
begin
if(cnt_1s >= cnt_1ms)
led <= 4'b0100;
else
led <= 4'b0000;
end
else if(flag == 5)
begin
if(cnt_1s <= cnt_1ms)
led <= 4'b0100;
else
led <= 4'b0000;
end
else if(flag == 6)
begin
if(cnt_1s >= cnt_1ms)
led <= 4'b1000;
else
led <= 4'b0000;
end
else if(flag == 7)
begin
if(cnt_1s <= cnt_1ms)
led <= 4'b1000;
else
led <= 4'b0000;
end
endmodule
注:一般不使用此方法~
(二)按位与:
module breath_water
(
input sys_clk ,
input sys_rst_n ,
output [3:0] led
);
//流水灯调用
wire [3:0] led1;
water_led water_led1
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.led (led1 )
);
//呼吸灯调用
wire [3:0] led2;
breath breath1
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.led (led2 )
);
led灯的控制
assign led = led1&&led2;
endmodule
这里的流水灯和呼吸灯都可以直接调用的前面的代码。
(三)位拼接:
module breath_water
(
input sys_clk ,
input sys_rst_n ,
output [3:0] led
);
//记1us
reg [6:0] cnt_1us;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1us <= 0;
else if(cnt_1us == 49)
cnt_1us <= 0;
else
cnt_1us <= cnt_1us+1;
//记1ms
reg [10:0] cnt_1ms;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1ms <= 0;
else if(cnt_1us == 49)
begin
if(cnt_1ms == 999)
cnt_1ms <= 0;
else
cnt_1ms <= cnt_1ms+1;
end
else
cnt_1ms <= cnt_1ms;
//记1s
reg [10:0] cnt_1s;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1s <= 0;
else if(cnt_1us == 49&&cnt_1ms == 999)
begin
if(cnt_1s == 999)
cnt_1s <= 0;
else
cnt_1s <= cnt_1s+1;
end
else
cnt_1s <= cnt_1s;
//1s标志信号
reg flag;
always@(posedge sys_clk)
if(!sys_rst_n)
flag <= 0;
else if(cnt_1ms == 999&&cnt_1s == 999&&cnt_1us == 49)
flag <= !flag;
else
flag <= flag;
always@(posedge sys_clk)
if(!sys_rst_n)
led1 <= 0;
else if(!flag)
begin
if(cnt_1ms<=cnt_1s)
led1 <= 1;
else
led1 <= 0;
end
else
begin
if(cnt_1ms>=cnt_1s)
led1 <= 1;
else
led1 <= 0;
end
//记2s
parameter delay_2s = 100_000_000;
reg [1:0] cnt_2s;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_2s <= 0;
else if(cnt_2s == delay_2s-1)
cnt_2s <= cnt_2s+1;
else
cnt_2s <= cnt_2s;
//led灯的控制
always@(posedge sys_clk)
if(!sys_rst_n)
led <= 0;
else
begin
case(cnt_2s)
0:led <= {3'b000,led1};
1:led <= {2'b00,led1,1'b0};
2:led <= {1'b0,led1,2'b00};
3:led <= {led1,3'b000};
default:led <= 0;
endcase
end
endmodule
(四)流水传递给呼吸:
module breath_water
(
input sys_clk ,
input sys_rst_n ,
output reg [3:0] led
);
//记1us
reg [6:0] cnt_1us;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1us <= 0;
else if(cnt_1us == 49)
cnt_1us <= 0;
else
cnt_1us <= cnt_1us+1;
//记1ms
reg [10:0] cnt_1ms;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1ms <= 0;
else if(cnt_1us == 49)
begin
if(cnt_1ms == 999)
cnt_1ms <= 0;
else
cnt_1ms <= cnt_1ms+1;
end
else
cnt_1ms <= cnt_1ms;
//记1s
reg [10:0] cnt_1s;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_1s <= 0;
else if(cnt_1us == 49&&cnt_1ms == 999)
begin
if(cnt_1s == 999)
cnt_1s <= 0;
else
cnt_1s <= cnt_1s+1;
end
else
cnt_1s <= cnt_1s;
//记2s
parameter delay_2s = 100_000_000;
reg [31:0] cnt_2s;
always@(posedge sys_clk)
if(!sys_rst_n)
cnt_2s <= 0;
else if(cnt_2s == delay_2s-1)
cnt_2s <= 0;
else
cnt_2s <= cnt_2s+1;
//流水灯
reg [3:0] water_led;
always@(posedge sys_clk)
if(!sys_rst_n)
water_led <= 4'b0001;
else if(cnt_2s == delay_2s-1)
water_led <= {water_led[0],water_led[3:1]};
else
water_led <= water_led;
//1s标志信号
reg flag;
always@(posedge sys_clk)
if(!sys_rst_n)
flag <= 0;
else if(cnt_1ms == 999&&cnt_1s == 999&&cnt_1us == 49)
flag <= !flag;
else
flag <= flag;
//led灯的控制
always@(posedge sys_clk)
if(!sys_rst_n)
led <= 0;
else if(!flag)
begin
if(cnt_1ms<=cnt_1s)
led <= water_led;
else
led <= 0;
end
else
begin
if(cnt_1ms<=cnt_1s)
led <= 0;
else
led <= water_led;
end
endmodule