嵌入式课上老师提到了单片机实现呼吸灯,那会儿说可以控制亮灭的时间间隔来控制灯的亮灭程度,然后我就下面这样的操作:
// 单片机伪代码意思一下
LED = 1; Delay(10); LED = 0; Delay(10);
LED = 1; Delay(20); LED = 0; Delay(20);
LED = 1; Delay(30); LED = 0; Delay(30);
LED = 1; Delay(40); LED = 0; Delay(40);
LED = 1; Delay(30); LED = 0; Delay(30);
LED = 1; Delay(20); LED = 0; Delay(20);
LED = 1; Delay(10); LED = 0; Delay(10);
太草率了,弄了四组数据
下板之后确实肉眼看到亮灭,但是不流畅,可以这样试一下,就会发现这样不配叫呼吸灯。。。。
一、 PWM工作原理
用渐变的PWM(脉冲宽度调制)信号实现LED呼吸灯。 LED由暗逐渐变亮,再由亮逐渐变暗循环。
**先分频,再设置占空比。**在一个时钟周期内,高电平时长与一个周期的时长的比值叫做占空比,占空比越高,相当于通过led的电流越大,肉眼就觉得很亮。
led高有效
完全熄灭到完全点亮
led高电平亮
在每一个T内,如何让低电平的保持时间持续的增长?
当1ms计数器的计数值≤1s计数器的计数值,led就保持高电平,其他时间保持低电平
上面实现的是由完全熄灭到完全点亮,完全点亮到完全熄灭是一个取反的过程,添加一个en使能信号
三个计数器之间存在倍数关系
当都使用时钟信号计数,1s的计数值是最大的,1ms第二大,1us第三大
如果用1ms针对1us进行计数,1m针对1ms进行计数,这样的计数值最大就是999,可以节省逻辑资源
二、代码实现
100MHz系统时钟
module breath_led
#(
parameter CNT_1US_MAX = 7'd99,
parameter CNT_1MS_MAX = 10'd999,
parameter CNT_1S_MAX = 10'd999
)
(
input wire sys_clk, // 100MHz
input wire sys_rst_n,
output reg led
);
reg [9:0] cnt_1s;
reg [9:0] cnt_1ms;
reg [6:0] cnt_1us;
reg cnt_en;
always @ (posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
cnt_1us <= 6'd0;
else if (cnt_1us == CNT_1US_MAX)
cnt_1us <= 6'd0;
else
cnt_1us <= cnt_1us + 1'b1;
always @ (posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
cnt_1ms <= 10'd0;
else if ( (cnt_1ms == CNT_1MS_MAX) && (cnt_1us == CNT_1US_MAX) )
cnt_1ms <= 10'd0;
else if (cnt_1us == CNT_1US_MAX)
cnt_1ms <= cnt_1ms + 1'b1;
else
cnt_1ms <= cnt_1ms;
always @ (posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
cnt_1s <= 10'd0;
else if ( (cnt_1s == CNT_1S_MAX) && (cnt_1ms == CNT_1MS_MAX) && (cnt_1us == CNT_1US_MAX) )
cnt_1s <= 10'd0;
else if ( (cnt_1ms == CNT_1MS_MAX) && (cnt_1us == CNT_1US_MAX) )
cnt_1s <= cnt_1s + 1'b1;
else
cnt_1s <= cnt_1s;
// 亮灭渐变反转
always @ (posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
cnt_en <= 1'b1;
else if ( (cnt_1s == CNT_1S_MAX) && (cnt_1ms == CNT_1MS_MAX) && (cnt_1us == CNT_1US_MAX) )
cnt_en <= ~cnt_en;
else
cnt_en <= cnt_en;
// led高有效
always @ (posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
led <= 1'b0;
else if ( ((cnt_en == 1'b1) && (cnt_1ms <= cnt_1s)) // 完全熄灭到完全点亮
|| ((cnt_en == 1'b0) && (cnt_1ms > cnt_1s)) ) // 完全点亮到完全熄灭
led <= 1'b1;
else
led <= 1'b0;
endmodule
下板之后确实看到期待的现象