码迷,mamicode.com
首页 > 其他好文 > 详细

PWM控制灯亮暗的verilog实现

时间:2015-08-12 16:29:28      阅读:136      评论:0      收藏:0      [点我收藏+]

标签:

PWM的全称为Pulse-Width Modulation(脉冲宽度调制),即调节脉冲的占空比。当输出的脉冲频率一定时,输出的脉冲占空比越大,相当于输出的有效电平越大,这样也就简单实现了由FPGA来控制模拟量。

设计原理框图:

技术分享

按键消抖,首先采用状态机实现,用状态机做键盘消抖,很好用,不必等待延时,当检测到有按键按下或弹起时能发出相应的键盘消息。设置状态机有 4中状态,A0,A1,A2,A3状态转换图如下:

技术分享

技术分享检测这几个管脚是否为低电平,来判断按键是否被按下

AO: 初始时位于A0状态,当扫描发现有按键按下时,转入到A1状态。当处于A1状态时,当扫描有按键按下并且键值等于A1状态下的键值时,转入到A2状态,否则转入A0状态。当处于A2状态时,当扫描发现有按键按下并且键值等于A3状态下的键值时,转入到A3状态,否则转入A0状态,当处于A3状态时,当扫描发现无键按下时,转入A0状态,同时发出键弹起消息或弹起键的键值入队。

always @(posedge clk)
 begin
    case (state)
     s0:
      begin 
       key_out<=1b1;
       if(key==1b0)
          state<=s1;
       else 
          state<=s0;
      end
     s1:
      begin 
       if(key==1b0)
         state<=s2;
       else 
         state<=s0;
       end 
     s2:
      begin 
       if(key==1b0)
         state<=s3;
       else 
         state<=s0;    
       end 
     s3:
       begin 
        if(key==1b0)
         begin
         key_out<=1b0;
         state<=s3;
         end 
        else 
         begin
         key_out<=1b1;
         state<=s0;
         end
       end
     default:
         state<=s0;
    endcase
 end

计数器按键消抖:1.检测管教电平是否拉低;2.若检测到低电平,启动计数器,延时20ms左右的时间;3.再次检测管脚是否低电平;4.若还是低电平,确定按键被按下,输出控制信号。在此例程中,最终LED控制实现的功能:按键 Key2 连接到 rst_n 信号,key1 连接到 key1 信号。最终的结果是:当按下 key2 键的时候,系统复位,只有一个 LED 点亮。松开 key2,没有键按下的时候, 四个 LED 交替两灭, 流水灯操作。 当按下 key1 键时, 执行下面语句 else if(key_low) led_r <= 4‘b0;四个灯全亮。

module led (
clk,rst_n,key1,
led
);
input clk;                  //时钟信号输入
input rst_n;               //复位信号输入
input key1;               //按键按下
output[3:0] led;         //LED灯点亮
//------------------------键盘消抖程序---------------------------------------------------
reg reg0_key;          
reg reg1_key;          
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) begin
reg0_key <= 1b1;     //将1‘b1赋值给reg0_key寄存器
reg1_key <= 1b1;     //将1’b1赋值给reg1_key寄存器
end
else begin
reg0_key <= key1;         //将按键输入赋值给reg0_key
reg1_key <= reg0_key; //根据非阻塞赋值的原理,reg1_key 存储的值是
reg0_key 上一个时钟的值
end
end
//当寄存器 key1 由 1 变为 0 时,led_an 的值变为高,维持一个时钟周期
wire key_an;
assign key_an = reg1_key & ( ~reg0_key);   //用来检测下降沿的典型程序
//---------------------------------------------------------------------------
reg[19:0] cnt_key; //计数寄存器                //检测完下降沿,启动计时器,延时20ms
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
cnt_key <= 20d0;  //异步复位
else if(key_an)
cnt_key <=20d0;
else
cnt_key <= cnt_key + 1b1;
end
reg reg_low;
reg reg1_low;
always @(posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
reg_low <= 1b1;
end
else if(cnt_key == 20hfffff)
begin
reg_low <= key1; //cnt == 20‘hfffff,20ms
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
reg1_low <= 1b1;
else
reg1_low <= reg_low;
end
//---------------------------------------------------------------------------
//当寄存器 reg_low 由 1 变为 0 时,key_low 的值变为高,维持一个时钟周期
wire key_low = reg1_low & ( ~reg_low);
//===============LED 控制==================================
reg[21:0] cnt; //
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt <= 22b0;
else
cnt <= cnt + 1b1;
end
reg enable_r;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
enable_r <= 1b0;
else
if (cnt == 22h3fffff) enable_r <= 1b1;
else
enable_r <= 1b0;
end
wire enable;
assign enable = enable_r;
reg[3:0] led_r;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
led_r <= 4b0111;
else if(key_low)
led_r <= 4b0;
else if(enable && !key_low)
led_r <= {led_r[0],led_r[3:1]};
else ;
end
wire[3:0] led;
assign led = led_r;
endmodule

回到PWM控制灯光亮暗,通过时钟计时器的计数与脉宽的计数比较大小,去定义灯光的亮暗。当时钟计数器到达设定的数值时,如果脉宽加满则溢出清0,并在此时判断按键有无按下,若按下,则调节脉宽的宽度,来进行下一轮的占空比比较,若脉宽未满,亦将其加满。对应的程序为:

module pwm(clk,reset,key,led);
input clk,reset,key;
output led;

reg pwm_out;

reg key_out;
parameter s0=2b00,s1=2b01,s2=2b10,s3=2b11;
reg [1:0] state;

reg [31:0] clk_counter;
reg [9:0]  pwm_counter;
reg flag;
/******************按键消抖**************************/
always @(posedge clk)
 begin
    case (state)
     s0:
      begin 
       key_out<=1b1;
       if(key==1b0)
          state<=s1;
       else 
          state<=s0;
      end
     s1:
      begin 
       if(key==1b0)
         state<=s2;
       else 
         state<=s0;
       end 
     s2:
      begin 
       if(key==1b0)
         state<=s3;
       else 
         state<=s0;    
       end 
     s3:
       begin 
        if(key==1b0)
         begin
         key_out<=1b0;
         state<=s3;
         end 
        else 
         begin
         key_out<=1b1;
         state<=s0;
         end
       end
     default:
         state<=s0;
    endcase
 end
always @(posedge clk)
 begin 
   clk_counter<=clk_counter+1b1;
    if (clk_counter[13:4]<pwm_counter)
        pwm_out=1;
    else
        pwm_out=0;

    if (clk_counter[15]==1b1)
    begin
        if (flag==1b1)
        begin
            flag<=1b0;
            if (key_out==1b0) 
                pwm_counter<=(pwm_counter+10b0000000011);
            else 
                pwm_counter<=pwm_counter;
        end
    end
    else
    flag<=1b1;
 end 
assign led=pwm_out;
endmodule

最后板子亮灯,显示平均电压。

技术分享

PWM控制灯亮暗的verilog实现

标签:

原文地址:http://www.cnblogs.com/Fun-with-FPGA/p/4724650.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!