呼吸灯
- 如何通过高低电平-数字信号输出实现呼吸灯的效果?
灯“呼吸”的效果分为两部分,一个过程是从灭到亮,另一个过程是从亮到灭。 led 灯供的电压越大 led 灯也就越亮,通过改变led灯的电压来控制亮度,但I/O口是输出数字信号,所以这里通过控制 PWM 的占空比来实现 led 灯呼吸的效果。
PWM
PWM详解
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。PWM就是在合适的信号频率下,通过一个周期里改变占空比的方式来改变输出的有效电压。
要输出不同的模拟电压,就要用到PWM,通过改变IO口输出的方波的占空比从而获得使用数字信号模拟成的模拟电压信号。比如下图
-
怎么改变占空比?
在本次实验中取 n 个相同的时间段,然后让高电平的持续时间按照相等的时间间隔逐渐增多,这样子我们看上去的 led 灯就会越来越亮了。相反,让低电平的持续时间按照相等的时间间隔逐渐增多,led等就会越来越暗。 -
对于亮暗怎么区分这两个过程?
为了区分从灭到亮和从亮到灭两个过程我们使用一个模式(标志)信号,这个模式信号不是脉冲,而是一个电平,更准确的来讲应该叫使能信号。在高低电平期间实现两个过程。 -
代码
module breath_led
#(
parameter CNT_MAX1us = 6'd49,
parameter CNT_MAX1ms = 10'd999,
parameter CNT_MAX1s = 10'd999
)
(
input wire sys_clk,
input wire sys_rst_n,
output reg led_out
);
reg [5:0] cnt_1us;
reg [9:0] cnt_1ms;
reg [9:0] cnt_1s;
reg mode;
//cnt_1us:1us 计数器
always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 0 )
cnt_1us <= 6'd0;
else if (cnt_1us == CNT_MAX1us)
cnt_1us <= 6'd0;
else
cnt_1us <= cnt_1us + 1;
//cnt_1ms:1ms 计数器
always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 0)
cnt_1ms <= 10'b0;
else if (cnt_1us == CNT_MAX1us)
cnt_1ms <= cnt_1ms + 10'b1;
else if (cnt_1ms == CNT_MAX1ms && cnt_1us == CNT_MAX1us )
//这里并不是1ms计数到最大值就归0,而是要1us也到最大值才能清零,
//否则最后一个1ms会很短
cnt_1ms <= 10'b0;
//cnt_1s:1s 计数器
always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 0 )
cnt_1s <= 10'd0;
else if (cnt_1ms == CNT_MAX1ms && cnt_1us == CNT_MAX1us)
cnt_1s <= cnt_1s + 10'd1;
else if (cnt_1s == CNT_MAX1s && cnt_1ms == CNT_MAX1ms && cnt_1us == CNT_MAX1us )
cnt_1s <= 10'd0;
//mode:1s 计数器标志信号
always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 0 )
mode<= 1'd1;
else if (cnt_1s == CNT_MAX1s && cnt_1ms == CNT_MAX1ms && cnt_1us == CNT_MAX1us)
mode <= ~mode;
//led_out:输出信号连接到外部的 led 灯
always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 0 )
led_out <= 1'd0;
else if ((mode == 1'b1 && cnt_1ms <= cnt_1s) || (mode == 1'b0 && cnt_1ms >= cnt_1s))
led_out <= 1'b1;
else
led_out <= 1'b0;
endmodule