生成占空比50%的奇数分频
占空比50%的偶数分频,由计数器生成,比如N分频(N为偶数),则计数从0~2*N-1,输出时钟在cnt = N的时候跳转,这样就可以得到占空比50%的方波。
但是,生成奇数分频的占空比50%方波,就不能使用上面的办法了,解决方案是用时钟的上升和下降沿两个信号分别生成一个计数器。如下图所示。
由pos_cnt==3时生成第一个pos_wave,而neg_cnt == 3时生成第二个neg_wave。最后生成的5分频时钟就是由pos_wave和neg_wave取或得到,这样就可以得到5分频的占空比为50%的时钟。
生成PWM波
首先需要确定的是PWM周期,这里以呼吸灯作为例子。
1、首先确定PWM的周期,也就是一个PWM波的作用时间,这里以2s为例,将这2s分为1000份,则每个pwm周期是2s/1000 = 0.002,也就是2个ms,而因为pwm有高低,将这个pwm周期均分1000份,则每一份的时间是2us。50m时钟的每个周期是20ns,则每个PWM单元由100个时钟脉冲组成。
2、计数方法是,每100个时钟周期得到一个pwm_cyc_cnt,也就是计算有多少个pwm单元。而每1000个pwm单元得到一个pwm周期。
3、pwm波形产生的方法是,当pwm_cyc_cnt>pwm_cnt时,输出拉高,当所有的pwm_cnt计数到999并且有pwm_cyc_cnt时,pwm_flag翻转。pwm波形由低到高输出。
4、verilog中计数器一定要注意1、计数什么时候开始。2、计数什么时候结束。3、计数什么时候清零。 举个栗子,pwm_cyc_cnt 计数结束的时候,是在pwm_cyc_cnt999时clkcnt99,才能保证所有的数都计满。
module breath_led(
clk,rst_n,led
);
input clk;
input rst_n;
output led;
reg led;
reg led_flag;
reg [6:0] clk_cnt;
reg [9:0] pwm_cyc_cnt;
reg [9:0] pwm_cnt;
always @ (posedge clk)begin
if(!rst_n)begin
clk_cnt <= 0;
end
else if(clk_cnt == 7'd99)begin
clk_cnt <= 0;
end
else begin
clk_cnt <= clk_cnt + 1'b1;
end
end
always @ (posedge clk)begin
if(!rst_n)begin
pwm_cyc_cnt <= 0;
end
else if(clk_cnt == 7'd99 && pwm_cyc_cnt == 10'd999)begin
pwm_cyc_cnt <= 0;
end
else if(clk_cnt == 7'd99)begin
pwm_cyc_cnt <= pwm_cyc_cnt + 1'b1;
end
end
always @ (posedge clk)begin
if(!rst_n)begin
pwm_cnt <= 0;
end
else if(clk_cnt == 7'd99 && pwm_cyc_cnt == 10'd999 && pwm_cnt == 10'd999)begin
pwm_cnt <= 0;
end
else if(clk_cnt == 7'd99 && pwm_cyc_cnt == 10'd999)begin
pwm_cnt <= pwm_cnt + 1'b1;
end
end
always @ (posedge clk)begin
if(!rst_n)begin
led_flag <= 0;
end
else if(clk_cnt == 7'd99 && pwm_cyc_cnt == 10'd999 && pwm_cnt == 10'd999)
led_flag <= ~ led_flag;
end
always @ (posedge clk)begin
if(!rst_n)begin
led <= 0;
end
else if(led_flag)begin
if(pwm_cnt < pwm_cyc_cnt)
led <= 1'b0;
else
led <= 1'b1;
end
else begin
if(pwm_cnt < pwm_cyc_cnt)
led <= 1'b1;
else
led <= 1'b0;
end
end
endmodule