基于FPGA实现呼吸灯原理
实现呼吸灯,我们首先要生成一个PWM(脉冲宽度调制)信号。
脉宽调制(PWM)基本原理:控制方式就是对逆变电路开关器件的通断进行控制,使输出端得到一系列幅值相等但宽度不一致的脉冲,用这些脉冲来代替正弦波或所需要的波形。也就是在输出波形的半个周期中产生多个脉冲,使各脉冲的等值电压为正弦波形,所获得的输出平滑且低次谐波少。按一定的规则对各脉冲的宽度进行调制,既可改变逆变电路输出电压的大小,也可改变输出频率。
以上是百度的介绍,自己的理解便是一个占空比可以调整变化的信号,调整占空比来控制输出的电压,使其可以类似与线性变化,LED灯对于不同的电压会产生对应的亮度,我们让PWM电压逐渐增加再逐渐减小便可以得到呼吸灯。

实现:
系统时钟为:50_000_000Hz
我们这里采用多个计数器来实现1s变化呼吸灯,我们定义三个计数器cnt_us,cnt_ms,cnt_s他们分别需要计数TIME_US = 50,TIME_MS = 1000,TIME_S = 1000。
至于为什么这么把1s计数器分割为1000份,1ms计数器分割为1000份下方有解释。
我们想要实现这个逐渐增大的操作可以用到C语言中for的嵌套语句帮助我们理解:

↑此刻为占空比逐渐变大
从C语言代码理解,我们可以看出我们制作的该PWM信号的周期为1ms(cnt_ms所记时间),在1s内占空比从0%逐渐增大到100%
7/31补:此时我们来分析一下cnt_s以及cnt_ms的大小对比(此时读者不必要把cnt_s固定为1s所记,cnt_ms同理,我们单纯看作两个cnt来比较大小看结果):
(cnt_s)=(cnt_ms),输出的out可以占空比达到100%且到达100%就从0%再次开始
(cnt_s)<(cnt_ms),最大占空比只能到cnt_s / cnt_ms,到达最大占空比后就从0%再次开始
(cnt_s)>(cnt_ms),当计数值相等后保持100%占空比到记满cnt_s清零后,再次从0%开始
而变为Verilog描述则是三个计数器计数(其中MS计数器起始标志位为US计数器结束标志位;S计数器的起始标志位为US计数器结束标志位),而为什么需要第三个计数器是因为我们把1s分割为了1000份,因为上方分析后我们知道我们需要要把cnt_ms原本的50_000分割为与cnt_s相同的1000份,所以我们需要第三个计数器来分割50_000->1000,所以我们增加了一个计数到50的微秒计数器。此时我们则得到类似C语言中的for循环部分而我们的输出部分则再加上
led = cnt_s > cnt_ms ? 1'b1:1'b0;则得到了我们verilog中的实现占空比增大的代码
逐渐增大有了,在最亮时我们则需要占空比逐渐变小,我们可以逆向思维,我们使用
led = cnt_s > cnt_ms ? 1'b1:1'b0;逐渐增大,那说明高电平在逐渐变大,那么我们将三目运算符后1/0互换不就变成低电平逐渐变多就相当于占空比逐渐变小了吗。那我们就只需要定义一个FLAG值当S计数器计数完成时将FLAG值取反,再通过对FLAG值的判断选择是
led = cnt_s > cnt_ms ? 1'b1:1'b0;还是led = cnt_s > cnt_ms ? 1'b0:1'b1;我们就完成了一个1s逐渐变亮然后再1s逐渐熄灭的呼吸灯。
最后贴上代码:
module breath_led#(parameter TIME_US = 50,TIME_MS = 1000,TIME_S = 1000) (input clk,input rst_n,output reg led
);reg [5:0] cnt_us;
reg [9:0] cnt_ms;
reg [9:0] cnt_s ;
reg flag;wire add_cnt_us;
wire end_cnt_us;
wire add_cnt_ms;
wire end_cnt_ms;
wire add_cnt_s;
wire end_cnt_s;always @(posedge clk or negedge rst_n) beginif(!rst_n)begincnt_us <= 0;endelse if(add_cnt_us)beginif(end_cnt_us)begincnt_us <= 0;endelse begincnt_us <= cnt_us + 1'b1;endendelse begincnt_us <= cnt_us ;end
endassign add_cnt_us = 1'b1;assign end_cnt_us = add_cnt_us && cnt_us == TIME_US - 1'b1;always @(posedge clk or negedge rst_n) beginif(!rst_n)begincnt_ms <= 0;endelse if(add_cnt_ms)beginif(end_cnt_ms)begincnt_ms <= 0;endelse begincnt_ms <= cnt_ms + 1'b1;endendelse begincnt_ms <= cnt_ms ;end
endassign add_cnt_ms = end_cnt_us;assign end_cnt_ms = add_cnt_ms && cnt_ms == TIME_MS - 1'b1;always @(posedge clk or negedge rst_n) beginif(!rst_n)begincnt_s <= 0;endelse if(add_cnt_s)beginif(end_cnt_s)begincnt_s <= 0;endelse begincnt_s <= cnt_s + 1'b1;endendelse begincnt_s <= cnt_s ;end
endassign add_cnt_s = end_cnt_ms;assign end_cnt_s = add_cnt_s && cnt_s == TIME_S - 1'b1;always @(posedge clk or negedge rst_n) beginif (!rst_n) beginflag <= 0;endelse if (end_cnt_s) beginflag <= ~flag;endelse beginflag <= flag;end
endalways @(posedge clk or negedge rst_n) beginif (!rst_n) beginled <= 1'b0;endelse if(!flag) beginled <= (cnt_s > cnt_ms)?1'b1:1'b0;endelse beginled <= (cnt_s > cnt_ms)?1'b0:1'b1;end
endendmodule
感谢观看!
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
