查看: 895|回复: 0

【ZYNQ Ultrascale+ MPSOC FPGA教程】第十章 PWM呼吸灯实验

[复制链接]
  • TA的每日心情
    开心
    2021-1-12 14:00
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2021-1-12 13:50:31 | 显示全部楼层 |阅读模式
    分享到:
    原创声明:
    本原创教程由芯驿电子科技(上海)有限公司(ALINX)创作,版权归本公司所有,如需转载,需授权并注明出处。
    适用于板卡型号:
    AXU2CGA/AXU2CGB/AXU3EG/AXU4EV-E/AXU4EV-P/AXU5EV-E/AXU5EV-P /AXU9EG/AXU15EG
    实验Vivado工程为“pwm_led”。
    本文主要讲解使用PWM控制LED,实现呼吸灯的效果。
    1.实验原理
    如下图所示,用一个N比特的计数器,最大值可以表示为2的N次方,最小值0,计数器以“period”为步进值累加,加到最大值后会溢出,进入下一个累加周期。当计数器值大于“duty”时,脉冲输出高,否则输出低,这样就可以完成图中红色线所示的脉冲占空比可调的脉冲输出,同时“period”可以调节脉冲频率,可以理解为计数器的步进值。
    PWM脉宽调制示意图
    不同的脉冲占空比的方波输出后加在LED上,LED灯就会显示不同的亮度,通过不断地调节方波的占空比,从而实现LED灯亮度的调节。
    2. 实验设计
    PWM模块设计非常简单,在上面的原理中已经讲到,这里不再说原理。
    信号名称方向说明
    clkin时钟输入
    rstin异步复位输入,高复位
    periodinPWM脉宽周期(频率)控制。period = PWM输出频率 * (2 的N次方) / 系统时钟频率。显然N越大,频率精度越高。
    dutyin占空比控制,占空比 = duty / (2的N次方)* 100%
    PWM模块(ax_pwm)端口
    `timescale1ns/1psmodule ax_pwm#(        parameter N =16//pwm bit width )(input         clk,input         rst,input[N -1:0]period,        //pwm step valueinput[N -1:0]duty,                //duty valueoutput        pwm_out         //pwm output);reg[N -1:0] period_r;                //period registerreg[N -1:0] duty_r;                //duty registerreg[N -1:0] period_cnt;        //period counterreg pwm_r;assign pwm_out = pwm_r;always@(posedge clk orposedge rst)beginif(rst==1)begin        period_r <={ N {1'b0}};        duty_r <={ N {1'b0}};endelsebegin        period_r <= period;        duty_r   <= duty;endend//period counter, step is period valuealways@(posedge clk orposedge rst)beginif(rst==1)        period_cnt <={ N {1'b0}};else        period_cnt <= period_cnt + period_r;endalways@(posedge clk orposedge rst)beginif(rst==1)begin        pwm_r <=1'b0;endelsebeginif(period_cnt >= duty_r)        //if period counter is bigger or equals to duty value, then set pwm value to high            pwm_r <=1'b1;else            pwm_r <=1'b0;endend
    那么如何实现呼吸灯的效果呢?我们知道呼吸灯效果是由暗不断的变亮,再由亮不断的变暗的过程,而亮暗效果是由占空比来调节的,因此我们主要来控制占空比,也就是控制duty的值。
    在下面的测试代码中,通过设置period的值,设定PWM的频率为200Hz,PWM_PLUS状态即是增加duty值,如果增加到最大值,将pwm_flag置1,并开始将duty值减少,待减少到最小的值,则开始增加duty值,不断循环。其中PWM_GAP状态为调整间隔,时间为100us。
    `timescale1ns/1psmodule pwm_test(input                clk,                //25MHzinput                rst_n,                //low active        output        led                        //high-off, low-on);                                        localparam CLK_FREQ =25;                                //25MHzlocalparam US_COUNT = CLK_FREQ ;                //1 us counterlocalparam MS_COUNT = CLK_FREQ*1000;        //1 ms counterlocalparam DUTY_STEP        =32'd100000;        //duty steplocalparam DUTY_MIN_VALUE =32'h6fffffff;        //duty minimum valuelocalparam DUTY_MAX_VALUE =32'hffffffff;        //duty maximum value                                        localparam IDLE                    =0;        //IDLE statelocalparam PWM_PLUS          =1;//PWM duty plus statelocalparam PWM_MINUS          =2;//PWM duty minus statelocalparam PWM_GAP          =3;//PWM duty adjustment gapwire                pwm_out;        //pwm outputreg[31:0]        period;                //pwm step valuereg[31:0]        duty;                //duty valuereg                        pwm_flag ;        //duty value plus and minus flag, 0: plus; 1: minusreg[3:0]        state;reg[31:0]        timer;                //duty adjustment counterassign led =~pwm_out ;//led low activealways@(posedge clk ornegedge rst_n)begin        if(rst_n ==1'b0)        begin                period                 <=32'd0;                timer                 <=32'd0;                duty                 <=32'd0;                pwm_flag         <=1'b0;                state                 <= IDLE;        end        else                case(state)                        IDLE:                        begin                                period                 <=32'd17179;//The pwm step value, pwm 200Hz(period = 200*2^32/50000000)                                state                  <= PWM_PLUS;                                duty                   <= DUTY_MIN_VALUE;                                                        end                        PWM_PLUS :                        begin                                if(duty > DUTY_MAX_VALUE - DUTY_STEP)        //if duty is bigger than DUTY MAX VALUE minus DUTY_STEP , begin to minus duty value                                begin                                        pwm_flag         <=1'b1;                                        duty                   <= duty - DUTY_STEP ;                                end                                else                                begin                                        pwm_flag         <=1'b0;                                                                                duty                   <= duty + DUTY_STEP ;                                        end                                                                state                  <= PWM_GAP ;                        end                        PWM_MINUS :                        begin                                if(duty < DUTY_MIN_VALUE + DUTY_STEP)        //if duty is little than DUTY MIN VALUE plus duty step, begin to add duty value                                begin                                        pwm_flag         <=1'b0;                                        duty                   <= duty + DUTY_STEP ;                                end                                else                                begin                                        pwm_flag         <=1'b1;                                        duty                   <= duty - DUTY_STEP ;                                        end                                        state                  <= PWM_GAP ;                        end                        PWM_GAP:                        begin                                if(timer >= US_COUNT*100)//adjustment gap is 100us                                begin                                        if(pwm_flag)                                                state <= PWM_MINUS ;                                        else                                                state <= PWM_PLUS ;                                                                                        timer <=32'd0;                                end                                else                                begin                                        timer <= timer +32'd1;                                end                        end                        default:                        begin                                state <= IDLE;                                        end                                        endcaseend//Instantiate pwm moduleax_pwm#(.N(32))ax_pwm_m0(.clk      (clk),.rst      (~rst_n),.period   (period),.duty     (duty),.pwm_out  (pwm_out));        endmodule
    3. 下载验证
    生成bitstream,并下载bit文件,可以看到PL LED1灯产生呼吸灯效果。PWM是比较常用的模块,比如风扇转速控制,电机转速控制等等。

    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-6-3 10:25 , Processed in 0.102996 second(s), 15 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.