门户网站建设工作的自查报告/百度人工
既然是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 @(posedgeclk )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 @ ( posedgeclk)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 @ (posedgeclk)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 @(posedgeclk)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 @ ( posedgeclk )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]);