赞
踩
这两天做了呼吸灯实验,今天和大家分享一下。我们采用PWM脉冲宽度调制输出连续的、占空比变化的脉冲信号来实现LED由灭到亮,再由亮到灭。
首先我们要知道,影响呼吸灯亮灭有2个因素:1.PWM波的占空比;2.PWM波的周期。
需要两者配合,方能实现效果较佳的呼吸灯。
我们假设占空比为50%,周期为2s,那么我们看到的就是LED亮一秒,灭一秒。但是如果我们把周期缩小到10ms,占空比仍然是50%。由于人眼的视觉残留效应,那么我们看见的就是LED的亮度会低一些,并不会出现亮一会灭一会的情况。
所以,根据上述分析,我们可以把PWM波的周期缩小到一个很小的值(比如10ms),然后让占空比每个周期都产生变化。(比如:从灭到亮时,每10ms占空比增加1%,增加到100%时再每10ms占空比减小1%,实现从亮到灭。这样整个亮灭过所需时间就是2s=10ms*100+10ms*100。)
首先我们需要两个计数器,一个10ms计数,另一个其实只要统计10ms的次数,200次就是2s。
然后因为在1s时我们需要将状态从灭到亮改为从亮到灭,所以我们需要一个用来切换状态的标志位及相应代码。
剩下就是占空比的调节和pwm的输出。
占空比在相应状态下,通过每次步进5000的计数值来每10ms改变一次1%的占空比;另外,我们要注意到PWM的信号输出应该和10ms计数器同步,10ms计数值小于dutycycle时,pwm输出0。反之,输出1。
- `timescale 1ns / 1ps
- module BreathLed(clk,rst_n,led);
- input wire clk;
- input wire rst_n;
- output wire led;
-
- //定义一些常量,时钟主频50M,计满10ms需要计数50_0000次,计数满2s,只要重复200次即可
- parameter CLK_10ms = 500000-1;
- parameter Times_2s = 200-1;
- parameter ChangeTime =100-1;
- //每次占空比改变整个周期的1%,0.01*500000
- parameter pwm_offset = 5000;
-
- //需要两个计数器,一个工作状态改变标志位
- reg [19:0] CLK_10MS;
- reg [7:0] Times2s;
- reg pwm;
- reg [19:0] dutyCycle;
- reg changeflag;
-
- assign led = ~pwm;
-
- /*--------10ms计数器---*/
- always @(posedge clk or negedge rst_n)
- begin
- if(rst_n==1'b0)
- begin
- CLK_10MS <='d0;
- end
- else if(CLK_10MS==CLK_10ms) CLK_10MS <='d0;
- else begin
- CLK_10MS <= CLK_10MS+1'b1;
- end
- end
-
- /*-----2s计数器----*/
- always @(posedge clk or negedge rst_n)
- begin
- if(rst_n==1'b0) Times2s <='d0;
- else if(CLK_10MS==CLK_10ms)begin
- if(Times2s==Times_2s) Times2s <='d0;
- else Times2s <= Times2s+1'b1;
- end
- end
-
- //-------亮灭状态管理切换----
- always @(posedge clk or negedge rst_n)
- begin
- if(rst_n==1'b0)
- changeflag <= 'b0;
- else if(Times2s==ChangeTime && CLK_10MS==CLK_10ms)
- begin
- changeflag <= 1'b1;//状态改为:从亮到灭
- end
- else if(Times2s==Times_2s && CLK_10MS==CLK_10ms)
- begin
- changeflag <= 1'b0;//状态改为:从灭到亮
- end
- end
-
- //-----占空比调节
- always @(posedge clk or negedge rst_n)
- begin
- if(rst_n==1'b0)dutyCycle='d0;
- else if(changeflag==1'b0)
- begin
- if(CLK_10MS==CLK_10ms) dutyCycle <= dutyCycle+pwm_offset;
- else dutyCycle <= dutyCycle;
- end
- else if(changeflag ==1'b1)
- begin
- if(CLK_10MS==CLK_10ms) dutyCycle <= dutyCycle-pwm_offset;
- else dutyCycle <= dutyCycle;
- end
- end
-
-
- always @(posedge clk or negedge rst_n)
- begin
- if(rst_n==1'b0) pwm <= 1'b0;
- else if(CLK_10MS < dutyCycle) pwm <= 1'b0;
- else pwm <= 1'b1;
- end
-
- endmodule
- /*-------testbench编写基本流程------*/
- //* module Test_bench();
- //通常无输入出 通常无输入出
- //信号或变量声明定义
- //逻辑设计中输入对应 reg型
- //逻辑设计中输出对应 wire 型
- //使用 initial 或 always语句产生激励 语句产生激励
- //例化待测试模块
- //监控和比较输出响应
- //
-
-
- module BreathLed_simul();
- //变量和信号的声明
- reg clk;
- reg rst_n;
- wire led;
-
- parameter CLK_10ms = 500000-1;
- parameter Times_2s = 200-1;
- parameter ChangeTime =100-1;
- //每次占空比改变整个周期的1%,0.01*500000
- parameter pwm_offset = 5000;
-
- //例化一个我们之前写的模块
- BreathLed #(.CLK_10ms(CLK_10ms),
- .Times_2s(Times_2s),
- .ChangeTime(ChangeTime),
- .pwm_offset(pwm_offset))
- u1(
- .clk(clk),
- .rst_n(rst_n),
- .led(led)
- );
- initial
- begin
- //初始化激励(时钟和复位信号)
- clk=1'b0;
-
- rst_n=1'b0;
- #10
- rst_n=1'b1;
- end
- always #(10) clk=~clk;
-
- endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。