用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]);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM