zoukankan      html  css  js  c++  java
  • 用VerilogHDL编写的可调占空比的PWM波形设计

    既然是PWM,当然需要占空比可调,我选用的是CycloneII系列的FPGA,使用50MHz的时钟源。

    开发板如下图:

    通过开发板上的K2,K1键控制PWM的大小,具体是如何实现的呢?

    系统采用50MHz的晶振作为时钟源,设定PWM的周期为1ms,也就是说计数器需要计数50000次,计数器一旦大于50000,自动清零,并重新进行下一轮的计数。

    在这50000次计数中,可以设定n(0<=n<=50000),只要计数器值小于n(n=duty_cycle*sd),则令PWM输出为1,否则输出为0,这就是PWM占空比调节原理。

    理想情况下,我们可以设定50000个级数用于调节PWM的占空比,但现实中没必要也不可能设置这么多的级数,所以根据需要,代码设置了五级,这样从0开始,每调一级(duty_cycle的值加1或减1),占空比增加20%,每一级的计数间隔为sd=10000。

    代码实现:

     1 always@ (posedge clk or posedge key_ctrl[3]) begin
     2     if(key_ctrl[3]) counter <= 16'd0;          //计数器复位
     3     else 
     4     begin
     5     counter <= counter+1;
     6         if ( counter <= duty_cycle*sd )    //设置PWM为1的时间间隔
     7             PWM_out <= 1;
     8         else
     9             PWM_out <= 0;
    10         if (counter >=50000)
    11             counter <= 16'd0;
    12     end
    13 end

    下面的问题就是怎么通过K2,K1控制duty_cycle大小的问题了。

    在设计中曾试着通过两个always语句对duty_cycle赋值,其中一个是加,一个是减。结果是编译出错,原因是不能在并行块中对同一个变量进行赋值。

    错误代码1:

     1 always @(posedge key_ctrl[1])begin 
     2     duty_cycle <= duty_cycle + 1'b1;
     3     if(duty_cycle >=5)
     4         duty_cycle <=5;  //最大值不超过5
     5     else
     6         duty_cycle <= duty_cycle;
     7 end
     8 
     9 always @(posedge key_ctrl[0])begin    
    10     duty_cycle1 <= duty_cycle1 - 1'b1;
    11         if(duty_cycle1 <= 0)
    12         duty_cycle1 <=0; //最小值不小于0
    13             else
    14          duty_cycle1 <= duty_cycle1;
    15 end
    16 
    17 assign duty_cycle = duty_cycle1;

    然后试着写在一个always语句中,这次虽然编译通过,可还是无法实现。如果有网友知道还望不吝赐教。

    错误代码2:

     1 always@(posedge key_ctrl[1] or posedge key_ctrl[0])begin                   
     2      if(key_ctrl[1])                             //如果key_ctrl[1]按下
     3         begin
     4           if(duty_cycle < 3'b110)                //且duty_cycle值小于6
     5             duty_cycle <= duty_cycle + 3'b001;   //则duty_cycle值加1
     6           else
     7             duty_cycle <= duty_cycle;            //否则duty_cycle值不变  
     8         end
     9      else
    10      if(key_ctrl[0])                             //如果key_ctrl[0]按下
    11         begin
    12           if(duty_cycle > 3'b000)                //且duty_cycle值大于0
    13             duty_cycle <= duty_cycle - 3'b001;   //则duty_cycle值减1
    14           else
    15             duty_cycle <= duty_cycle;            //否则duty_cycle值不变
    16         end
    17          
    18       else
    19             duty_cycle <= duty_cycle;
    20 end

    最后又在网上查阅了好多资料,对于如何通过不同的按键对一个变量赋值找到了一种完美的解决办法,就是利于case语句。

    正确代码:

     1 always@( posedge clk or negedge rst_n )  begin   
     2   if( !rst_n )   
     3    begin
     4     duty_cycle <= 0; 
     5    end
     6   else
     7    begin
     8     case ( {key_ctrl[1],key_ctrl[0]} )
     9      2'b00:begin
    10               duty_cycle <= duty_cycle;
    11            end
    12      2'b10:begin
    13            if ( duty_cycle >= 5 )
    14                begin
    15                duty_cycle <= duty_cycle;
    16                end
    17            else
    18                begin
    19                duty_cycle <= duty_cycle + 1'b1;
    20                end
    21            end
    22      2'b01:begin
    23            if ( duty_cycle == 'h00 )
    24               begin
    25                 duty_cycle <= duty_cycle;
    26              
    27               end
    28            else
    29               begin
    30                duty_cycle <= duty_cycle - 1'b1;
    31               end
    32            end
    33      2'b11:begin
    34            duty_cycle <= duty_cycle;
    35            end
    36     endcase
    37    end  
    38  end

    你们可能发现了,代码中控制duty_cycle的是key_ctrl[1],key_ctrl[0],而不是K2,K1,这是因为采用独立按键会产生抖动,key_ctrl[1],key_ctrl[0]是K2,K1经按键消抖后的值。

    下面附上采用吴厚航(网名特权同学)的按键消抖代码:

     1 reg[3:0] key_rst; 
     2 
     3 always @(posedge clk )
     4 //    if (!rst_n) key_rst <= 4'b1111;
     5 //    else 
     6      key_rst <= {rst_n,key3,key2,key1};
     7 
     8 reg[3:0] key_rst_r; 
     9 
    10 always @ ( posedge clk)
    11 //    if (!rst_n) key_rst_r <= 4'b1111;
    12 //    else 
    13      key_rst_r <= key_rst;
    14    
    15 
    16 wire[3:0] key_an = key_rst_r & (~key_rst);
    17 reg[19:0]  cnt;    
    18 
    19 always @ (posedge clk)
    20 //    if (!rst_n) cnt <= 20'd0;    
    21 //    else 
    22     if(key_an) cnt <=20'd0;
    23     else cnt <= cnt + 1'b1;
    24   
    25 reg[3:0] low_sw;
    26 
    27 always @(posedge clk)
    28 //    if (!rst_n) low_sw <= 4'b1111;
    29 //    else 
    30      if (cnt == 20'hfffff)     
    31       low_sw <= {rst_n,key3,key2,key1};
    32       
    33 
    34 reg  [3:0] low_sw_r;      
    35 
    36 always @ ( posedge clk )
    37 //    if (!rst_n) low_sw_r <= 4'b1111;
    38 //    else 
    39      low_sw_r <= low_sw;
    40      
    41      wire[3:0] key_ctrl = low_sw_r[3:0] & ( ~low_sw[3:0]);
  • 相关阅读:
    第二月 day 2,内置函数
    第二月 day3 闭包,递归
    day4 装饰器
    第二月 day1生成器
    第一个月 总结
    day 16 迭代器
    day 15 编码
    Docker常用命令
    DRF源码刨析
    django中使用qiniu作为第三方存储
  • 原文地址:https://www.cnblogs.com/bigpo/p/3722979.html
Copyright © 2011-2022 走看看