Verilog实现PWM呼吸灯

本文详细介绍了一种使用FPGA实现的PWM呼吸灯控制器,通过1us、1ms和1s不同时间尺度的计数器控制LED的亮灭状态,以实现1秒内由暗到亮再到暗的周期性变化。
摘要由CSDN通过智能技术生成

实验目标:实现PWM呼吸灯,1s内由灭到亮再由灭到亮

实验原理:1s内分为1000个1ms,每个1ms分为1000个1us,对于每个1ms中的亮灭占比时间进行控制,如亮的时间从0到1us一直到1000us即最亮,由灭到亮同理。

代码框架思考:

1.模块的输入输出

这个简单输入clk和rst,输出led

2.需要用几个计数器

从最小周期开始计数即一个1us的计数器,一个1ms的计数器,一个1s的计数器

    parameter CNT_1US_MAX = 6'd49   ,
    parameter CNT_1MS_MAX = 10'd999 ,
    parameter CNT_1S_MAX  = 10'd999

3.每个计数器的开始截至条件

cnt_1us对于50MHZ的fpga来说计数到50-1即可

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1us <= 6'b0;
    else    if(cnt_1us == CNT_1US_MAX)
        cnt_1us <= 6'b0;
    else
        cnt_1us <= cnt_1us + 1'b1

cnt_1ms可以由cnt_1us产生,当1us计数到最大时cnt_1ms加一,直到加了999次

//cnt_1ms:1ms计数器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1ms <= 10'b0;
    else    if(cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
        cnt_1ms <= 10'b0;
    else    if(cnt_1us == CNT_1US_MAX)
        cnt_1ms <= cnt_1ms + 1'b1;

同理,cnt_1s也由此产生

//cnt_1s:1s计数器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1s <= 10'b0;
    else    if(cnt_1s == CNT_1S_MAX && cnt_1ms == CNT_1MS_MAX 
                                        && cnt_1us == CNT_1US_MAX)
        cnt_1s <= 10'b0;
    else    if(cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
        cnt_1s <= cnt_1s + 1'b1;

注意:要满足上一个小周期的截至条件,这是为了确保在最小的那个计数周期处完成状态切换。

4.如何区分亮灭状态

加上一个标志位cnt_1s_en,由灭到亮为低电平,亮到灭相反,具体实现只需要在1s结束时取反即可,所以取反的条件和1s截至的条件一样,记得上一个的注意事项

//cnt_1s_en:1s计数器使能信号
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1s_en <= 1'b0;
    else    if(cnt_1s == CNT_1S_MAX && cnt_1ms == CNT_1MS_MAX 
                                            && cnt_1us == CNT_1US_MAX)
        cnt_1s_en <= ~cnt_1s_en

5.如何实现led的pwm效果

画出波形图观察led_out与其他信号的关系

发现:由灭到亮时 led_out为低电平时间时 cnt_1s 计数器的计数值总是小于 cnt_1ms 计数器的计数(cnt_1ms > cnt_1s),相反由亮到灭时 cnt_1s 计数器的计数值总是大于cnt_1ms 计数器(cnt_1ms < cnt_1s)),即可得到led_out的赋值条件,注意区分亮灭。

//led_out:输出信号连接到外部的led灯
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        led_out <= 1'b0;
    else    if((cnt_1s_en == 1'b1 && cnt_1ms < cnt_1s) || 
                            (cnt_1s_en == 1'b0 && cnt_1ms > cnt_1s))
        led_out <= 1'b0;
    else
        led_out <= 1'b1

完整代码如下:

module  breath_led
#(
    parameter CNT_1US_MAX = 6'd49   ,
    parameter CNT_1MS_MAX = 10'd999 ,
    parameter CNT_1S_MAX  = 10'd999
)
(
    input   wire    sys_clk     ,   //系统时钟50Mhz
    input   wire    sys_rst_n   ,   //全局复位

    output  reg     led_out         //输出信号,控制led灯
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//reg define
reg [5:0]   cnt_1us     ;
reg [9:0]   cnt_1ms     ;
reg [9:0]   cnt_1s      ;
reg         cnt_1s_en   ;

//********************************************************************/
//***************************** Main Code ****************************//
//********************************************************************//
//cnt_1us:1us计数器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1us <= 6'b0;
    else    if(cnt_1us == CNT_1US_MAX)
        cnt_1us <= 6'b0;
    else
        cnt_1us <= cnt_1us + 1'b1;

//cnt_1ms:1ms计数器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1ms <= 10'b0;
    else    if(cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
        cnt_1ms <= 10'b0;
    else    if(cnt_1us == CNT_1US_MAX)
        cnt_1ms <= cnt_1ms + 1'b1;

//cnt_1s:1s计数器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1s <= 10'b0;
    else    if(cnt_1s == CNT_1S_MAX && cnt_1ms == CNT_1MS_MAX 
                                        && cnt_1us == CNT_1US_MAX)
        cnt_1s <= 10'b0;
    else    if(cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
        cnt_1s <= cnt_1s + 1'b1;

//cnt_1s_en:1s计数器使能信号
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1s_en <= 1'b0;
    else    if(cnt_1s == CNT_1S_MAX && cnt_1ms == CNT_1MS_MAX 
                                            && cnt_1us == CNT_1US_MAX)
        cnt_1s_en <= ~cnt_1s_en;

//led_out:输出信号连接到外部的led灯
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        led_out <= 1'b0;
    else    if((cnt_1s_en == 1'b1 && cnt_1ms < cnt_1s) || 
                            (cnt_1s_en == 1'b0 && cnt_1ms > cnt_1s))
        led_out <= 1'b0;
    else
        led_out <= 1'b1;

endmodule

注意数据类型:在时序逻辑电路中的输出信号都是reg值

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值