[FPGA学习]第五部分:玩转LED

        本部分我们所用的都是四颗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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值