差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
book_excise_pwm [2021/08/17 17:29]
zili
book_excise_pwm [2021/08/17 17:40] (当前版本)
zili
行 30: 行 30:
 </​WRAP>​ </​WRAP>​
 整个程序的架构如图8 2所示,主要由两个模块PWM_Controller和PWM_basic1~PWM_basic8组成:\\ 整个程序的架构如图8 2所示,主要由两个模块PWM_Controller和PWM_basic1~PWM_basic8组成:\\
-  - PWM_controller实现对8个LED灯亮度的控制,即决定每个LED灯的亮度应该是多少; +1. PWM_controller实现对8个LED灯亮度的控制,即决定每个LED灯的亮度应该是多少;\\ 
-  ​- ​PWM_basic1~PWM_basic8每一个模块用于控制一个LED灯亮度的实现,也就是使得LED灯的亮度满足PWM_controller提出的要求; +2. PWM_basic1~PWM_basic8每一个模块用于控制一个LED灯亮度的实现,也就是使得LED灯的亮度满足PWM_controller提出的要求;\\ 
-  ​- ​Counter是一个从0到PERIOD_WIDTH的一个计数器,PERIOD_WIDTH是脉宽调制信号的周期。 ​+3. Counter是一个从0到PERIOD_WIDTH的一个计数器,PERIOD_WIDTH是脉宽调制信号的周期。 ​\\
   ​   ​
 \\ \\
行 40: 行 40:
  
 PWM_Basic的输入输出接口如下: PWM_Basic的输入输出接口如下:
 +<code verilog>
  
 input clk, reset;​ //​时钟和复位信号。 input clk, reset;​ //​时钟和复位信号。
行 59: 行 59:
 end end
  
 +</​code>​
 +
 +在注释1处,当计数器clk_tick为0时点亮LED灯,Pwm_out为低时点亮LED灯。在注释2处,当计数器clk_tick等于pulse_width,也就是脉冲宽度达到所需要的脉冲宽度时,熄灭LED灯。如此,就完成对脉宽调制。
  
 \\ \\
-\\ 
-### 仿真结果 
  
 +#### 3.3 PWM_controller模块(PWM_controller.v)
 +PWM_controller的主要功能如下:\\
 +1)控制每个LED的初始亮度,也就是初始脉宽;\\
 +2)更新每个LED的亮度,让每个LED灯逐渐变亮或变暗。\\
 +<code verilog> ​
  
 +always @(posedge clk or negedge reset ) begin : PWM_controller
 +integer loop;
 +if( !reset ) begin
 +state_counter <= 7'd0;
 +add <= 8'​b1111_1111; ​                  
 +//​add的每一位用来控制一个LED是变亮还是变暗,初始时都要求变亮。
 +trigger_pointer[0] <= 16'd0;
 +trigger_pointer[1] <= `RESET_PHASE;​
 +trigger_pointer[2] <= 2*`RESET_PHASE;​
 +trigger_pointer[3] <= 3*`RESET_PHASE;​
 +trigger_pointer[4] <= 4*`RESET_PHASE;​
 +trigger_pointer[5] <= 5*`RESET_PHASE;​
 +trigger_pointer[6] <= 6*`RESET_PHASE;​
 +trigger_pointer[7] <= 7*`RESET_PHASE;​
 +// reg[15:0] trigger_pointer[7:​0];​
 +//​trigger_pointer是一个二维数组,用于控制LED灯的脉宽,上列8行对每个LED灯进行了初始化,从上面可以看出,LED7的初始值最大,也就是初始时最亮。RESET_PHASE是宏定义。
 +end
 +else begin
 +if( clk_tick == 16'd0 ) begin
 +if( state_counter == `STAT_TRANSFER_NUM ) begin
 + //​clk_tick和State_counter共同决定了亮度变化的间隔,为STAT_TRANSFER_NUM*PERIOD_WIDTH个时钟周期。如果设STAT_TRANSFER_NUM为20,PERIOD_WIDTH为25000,时钟为50MHz,则亮度约10ms变化依次。
 + state_counter <= 7'd0;
 + for( loop = 0; loop < 8; loop = loop + 1 ) begin
 +//​对每个LED灯,更新其亮度,也就是脉宽。
 + if( add[loop] == 1 ) begin
 + if( trigger_pointer[loop] >= `PERIOD_WIDTH - `STEP )
 + add[loop] <= 0;
 + trigger_pointer[loop] <= trigger_pointer[loop] + `STEP;
 + end
 +//​如果是add为1,则要求变亮,即使脉宽加上一个步长STEP;但如果亮度为最亮,则将add置为0,使其开始变暗。
 + else begin
 + if( trigger_pointer[loop] <= 2*`STEP )
 + add[loop] <= 1;
 +
 + trigger_pointer[loop] <= trigger_pointer[loop] - `STEP;
 + end
 +//​如果add不为1,也就是0,则要求变暗,即使脉宽减去一个步长STEP;但如果亮度为最暗,则将add置为1,使其开始变亮。
 + end
 + end
 + else
 + state_counter <= state_counter + 7'd1;
 + end
 + end
 + end
  
 +</​code>​
 +
 +上述涉及的宏包括脉宽增加步长STEP、脉宽调制的周期PERIOD_WIDTH、亮度变化控制STAT_TRANSFER_NUM,这些宏可以设置成不同的值以观察控制效果。
  
 \\ \\
 \\ \\
-### 演示程序文件说明 +### 4. 程序仿真 
 +Ledtest.v是仿真模块,用于产生需要的时钟和复位信号,同时实例化PWM模块。 
 +{{ :​图_8_3.png |图 8 3  PWM程序仿真结果}} 
 +<WRAP centeralign>​ 
 +图 8 3  PWM程序仿真结果 
 +</​WRAP>​ 
 +图 8 3为仿真的结果,由于仿真时间不能太长,因此三个宏的设置如下: 
 +<code verilog> ​
  
 +`define STEP 16'd1
 +`define PERIOD_WIDTH 16'd10
 +`define RESET_PHASE 16'd1
 +`define STAT_TRANSFER_NUM 7'd2
  
 +</​code>​
  
 +上面三个宏都设的很小,便于仿真。从图中可以看出,每个LED灯的脉宽调制信号的脉宽都不一样的;同时由于STAT_TRANSFER_NUM为 2,每个脉宽调制信号是每三个周期变一次,也就是每三个周期亮度变化一次。
  
 +\\
 +\\
 +### 5. 演示程序文件说明
 +|文件名|功能|
 +|PWM.v|顶层模块,并包含PWM_Controller模块|
 +|Counter.v|Counter定时器模块|
 +|PWM_Basic.v|PWM_Basic模块|
 +|Pwmtest.mpf|ModelSim仿真工程|
 +|Ledtest.v|仿真顶层模块|
 +|PWM.qpf|Quartus II项目文件|
  
 \\ \\
 \\ \\
-### 演示程序使用+### 6. 演示程序使用 
 +  演示设备:核心板。 
 +  演示方法:把程序下载到开发系统中后,可以观察到核心板上8个LED灯不断地变亮或变暗,reset为复位键。
  
 +### 7. 实验中注意的问题
 +由于核心板上的LED灯数量有限,而且观察距离近,亮灭的变化不是很明显。在本实验中采用的是线性脉宽调制,即脉冲宽度的变化是个常数。事实上,LED的亮度和脉冲宽度不是线性的关系,是一个指数曲线,因此要使得LED的亮度线性地变化,脉冲宽度的变化就不应该是线性的,这就是伽玛校正。有兴趣的同学可以自己尝试对脉冲宽度进行非线性调制使得LED亮度按线性进行变化。