利用PWM脉宽调制实现呼吸灯
1.设计目标
完成一个呼吸灯,从亮到灭的时间为2秒,从灭到亮的时间为2秒,以此不断往复。
2.设计步骤
2.1设计分析
利用PWM(脉冲宽度调制)实现led灯亮度的变化,只需要改变占空比就可以实现,具体操作是将2秒分为1000份,每份即2/1000(2ms),也就是说一个pwm周期为2ms。在这样一个2ms周期内,改变占空比,且随着周期数变化,占空比也在变化,就可以显示出亮度变化的过程。
比如在第一个2s内,这个2秒内led灯的亮度是越来越暗的,所以具体操作为:把每个周期(2ms)再分成1000份,即一份为2us(这个2us称之为pwm的最小分辨率),在第一个2ms内高电平为1000个2us;在第二个2ms内低电平的个数为1个2us,高电平的个数为999个2us;第三个2ms内低电平的个数为2个2us,高电平的个数为998个2us;以此类推,最后一个2ms,低电平的个数为1000个2us。从而实现,每2ms亮度变化一次,一个2s内亮度变化了一千次,在肉眼看来,这个亮度的变化过程是非常平滑的。
反过来,亮度增加过程也是一样的,只要按2ms增大占空比即可实现。
2.2设计波形图
由图可知,一共需要三个计数器:T20us_count、T2us_count、T2ms_count。分别用于计算20ns,2us,2ms的个数。当T20us_count等于99时,代表计时2us(20ns*100)已到;当T2us_count等于999、T20us_count等于99时,代表2ms(2us*1000)已到;同理,当T2ms_count等于999、T2us_count等于999、T20us_count等于99时,代表2s(2ms*1000)已到。
观察波形图,在第一个2ms内,led_pwm都为高电平。在第二个2ms内,led_pwm在T2us_count为0时为低电平,大于等于0时为高电平。在第三个2ms,T2ms_count等于2,则在T2us_count等于0、1时,led_pwm为低电平,大于1时为高电平。因此可以得到一般规律,T2ms_count是用于计算2ms的个数,从0逐渐增长到999,代表第1个2ms到第1000个2ms,所以在任意一个2ms内,T2us_count小于T2ms_count,led_pwm为低电平,大于则为高电平。
第2个2s,亮度是慢慢增加的,过程与亮度减少是相逆的,T2us_count小于T2ms_count,led_pwm为高电平,大于则为低电平,从而实现占空比越来越大,从而实现亮度慢慢增加。
3.Verilog 代码
module pwm_led(
input wire Clk,
input wire Rst_n,
output wire led_pwm
); wire Rst;
assign Rst=~Rst_n; //定时2us,即pwm脉冲的最小分辨率
parameter T2us=8'd99;
reg [7:0]T20ns_count; //计算20ns的个数
always@(posedge Clk or posedge Rst)
if(Rst)
begin
T20ns_count<='d0;
end
else if(T20ns_count==T2us) //20ns*100=2us定时时间到
begin
T20ns_count<='d0;
end
else
T20ns_count<=T20ns_count+1'b1; //20us时间到,计数器加一 //定时2ms,即pwm的一个周期
parameter T2ms=12'd999;
reg [11:0]T2us_count;
always@(posedge Clk or posedge Rst)
if(Rst)
begin
T2us_count<='b0;
end
else if((T2us_count==T2ms)&&(T20ns_count==T2us)) //2us*1000=2ms定时时间到
begin
T2us_count<='b0;
end
else if(T20ns_count==T2us) //2us时间到,计数器加一
T2us_count<=T2us_count+1'b1; //定时2s
reg H_L_flag;//亮到灭,灭到亮的标志位
parameter T2s=12'd999;
reg [11:0]T2ms_count;
always@(posedge Clk or posedge Rst)
if(Rst)
begin
T2ms_count<='b0;
H_L_flag<='b0;
end
else if((T2ms_count==T2s)&&(T2us_count==T2ms)&&(T20ns_count==T2us)) //2ms*1000=2s定时时间到
begin
T2ms_count<='b0;
H_L_flag<=~H_L_flag;
end
else if((T2us_count==T2ms)&&(T20ns_count==T2us)) //2ms时间到,计数器加一
T2ms_count<=T2ms_count+1'b1; //PWM控制模块
assign led_pwm=(T2us_count<T2ms_count)?H_L_flag:~H_L_flag; endmodule
4.testbench代码
`timescale 1ns/1ns
`define clock_period 20
module pwm_led_tb; reg Clk;
reg Rst_n;
wire led_pwm_out;
pwm_led U0(
.Clk (Clk),
.Rst_n (Rst_n),
.led_pwm (led_pwm)
); initial Clk=1'b0;
always #(`clock_period/2) Clk=~Clk; initial
begin
Rst_n<=1'b0;
#(`clock_period*2);
Rst_n<=1'b1;
end endmodule
5.结语
以上程序经过ModelSim仿真,仿真通过后,也经过了上板验证,开始2s,led灯的亮度能够很平滑的下降,后一个2s,亮度能够慢慢提高,如此往复操作,实现4s为周期的呼吸灯。
最新文章
- Spring 自带的定时任务
- Spring 下载与安装以及spring 3.2.9 jar包详解
- vim编辑器配置
- bzoj2436
- Sublime Text 前端插件推荐
- oracle的存储过程语法(转)
- C++中的函数指针
- android码农神器 偷懒工具 android懒人框架 LoonAndroid 3 讲解
- git使用图解
- perl 之eval
- voa 2015 / 4 / 27
- VS 2017 激活码
- 使用css设置三角形
- HBase篇(2)-数据模型与操作
- Hbase记录-shell脚本嵌入hbase shell命令
- 在使用 #import <;objc/message.h>;时 xcode 报 :Too many arguments to function call, expected 0 , have * 解决方法
- MikroTik RouterOS获取在线终端和在线IP总数并自动对IP做限速(转)
- 树结构数据的展示和编辑-zTree树插件的简单使用
- BZOJ 1007 [HNOI2008]水平可见直线 (栈)
- 原生js 实现jquery addClass,removeClass