AA55 发表于 2005-10-19 21:34:12

兑现:前两天扯过的CPLD实现PWM的一种方法

是用verilog实现的。



能实现8位PWM,有8位预分频,能够随机读写pPWM设定值和分频系数,最高使用频率为20MHz,可以产生305Hz到78KHz的PWM波形 。



我是用MAXPLUS仿真测试的。注意:MAXPLUS自动选定的是MAX7096,但是在工程中不能选用MAX7096

。原因是具体实现上,管脚分配不同于MAXPLUS自动分配的管脚,具体绑定到管脚时候,要损失一些路径、导致实际占用逻辑单元增加;2、MAX7096比较难购买,MAX7128更容易采购到。





/* 有预分频功能的8位PWM可读写模块 */

module chinesemode( CLOCK, DATA, A0, RD, WR, CE, RESET, PWM_OUT );



input CLOCK;                            /* 系统时钟 */

inout DATA;                     /* 数据总线 */

reg   DATA_switch;                      /* 数据总线方向控制寄存器 */

input RD, WR, CE, RESET;                /* 输入控制端口(全部为低有效) */

input A0;                               /* 寄存器地址操作选择: 0 - PWM控制寄存器; 1 - 预分频器*/



reg pwm_count;                  /* PWM计数器 */

reg prescale_count;               /* 预分频计数器 */

reg pwm_reg;                      /* 比较数据寄存器 */

reg DATA_out;                     /* 单片机数据总线输出驱动寄存器 */

reg prescale_reg;               /* 预分频寄存器 */

output PWM_OUT;                         /* PWM输出端口 */

reg pwm_status;                         /* PWM输出状态 */



assign DATA = ( DATA_switch == 1'b0 )? DATA_out : 8'hzz;   /* 数据总线控制(低为输出) */

assign PWM_OUT = ( pwm_status == 1'b1 )? 1'b1 : 1'b0;      /* PWM输出驱动 */



always@( posedge CLOCK or negedge RESET )                  /* 计数器块:对CLOCK上升沿敏感 */

begin

    if( RESET == 1'b0 )                                    /* 如果复位,清除计数器内容 */

    begin

      pwm_count = 8'h00;

      prescale_count = 8'h00;

    end

    else

    begin

      if( WR == 1'b0 )

      begin

      if( A0 == 0 )

      begin

          pwm_count = 8'h00;         /* 如果写入新的PWM控制数据,清除计数器 */

      end

      else

      begin

          pwm_count = 8'h00;

          prescale_count = 8'h00;      /* 如果写入新的分频系数数据,清除预分频计数器和计数器 */

      end

      end

      else

      begin

      if( prescale_count == prescale_reg )

      begin

          pwm_count = pwm_count + 1;   /* 行波计数。对这种计数器进行比较、译码特别容易产生竞争冒险,所以要采用同步逻辑避免 */

          prescale_count = 0;

      end

      else

      begin

          prescale_count = prescale_count + 1;

      end

      end

    end

end



always@( negedge CLOCK or negedge RESET )         /* 单片机读写数据块。注意:这对CLOCK下降沿敏感,不在逐级翻转计数器的上升沿做比较,消除了竞争冒险 */

begin

    if( RESET == 1'b0 )                           /* 如果复位,清除寄存器内容 */

    begin

      DATA_switch <= 1'b1;

      pwm_reg <= 8'h00;

      prescale_reg <= 8'h00;

      pwm_status <= 1'b0;

    end

    else

    begin

      if( pwm_count > pwm_reg )                     /* PWM比较过程 */

      begin

      pwm_status <= 1'b1;

      end

      else

      begin

      pwm_status <= 1'b0;

      end



      if (CE == 1'b0 )                              /* 如果芯片使能有效,执行读写操作 */

      begin

      if( WR == 1'b0 )

      begin

          DATA_switch <= 1'b1;

          if( A0 == 0 )

          begin

            pwm_reg <= DATA;                        /* PWM控制数据写入PWM寄存器 */

          end

          else

          begin

            pwm_reg <= DATA;                        /* PWM控制数据写入预分频寄存器 */

          end

      end

      else

      begin

          if( RD == 1'b0 )

          begin

            DATA_switch <= 1'b0;

            if( A0 == 0 )

            begin

            DATA_out <= pwm_reg;               /* PWM寄存器内容传送到总线(读出) */

            end

            else

            begin

            DATA_out <= prescale_reg;            /* 预分频寄存器内容传送到总线(读出) */

            end

          end

          else

          begin

            DATA_switch <= 1'b1;

          end

      end

      end

      else

      begin

      DATA_switch <= 1'b1;

      end

    end

end

endmodule

jackiezeng 发表于 2005-10-20 16:24:15

7064能用吗?

AA55 发表于 2005-10-21 00:09:02

不能。因为综合的结果是占用了76个逻辑单元,所以maxplus自动选用了7096。



如果去掉预分频部分,就能缩减到30多个逻辑单元,7064就可以用了。不过要注意:当您锁定管脚后,有可能布线路径不够了,导致实际占用的逻辑单元增加。

monkey_jin 发表于 2007-10-2 19:26:23

原来也想回复一个现在正在用的,但是由于是在其他工程里的,摘出来比较麻烦。看了AA55 的已经很完善了,思路基本一样,没必要拿来献丑了。只是想说一点。为什么还要用 EPM7000 论性能、价格、采购方便 MAXII 和 MAX3000系列都比他强的多。而且MAXII 逻辑容量要高出 MAX7000和MAX3000 系列很多。
我在北京中发买一次10片 EPM7128 40多RMB EPM3128 20RMB EPM240 15RMB 容量EPM7128=3128<240 而且240还有User Flash 可用

monkey_jin 发表于 2007-10-2 19:46:05

不好意思,没看时间是2005的帖子 不过那时候也应该是 MAX3000系列为主了

cyjun99 发表于 2007-11-13 20:59:23

明天我帮你写一个

qilong73 发表于 2013-7-25 14:50:47

学习一下

simon51 发表于 2014-12-19 10:08:32

感谢lz,试着用ise综合了一下,居然要xc95144以上才能搞定,打算做个16位带分频的pwm(如82c54这样的芯片),资源耗得真多

source.ant 发表于 2014-12-22 22:46:39

不错,还是喜欢用FPGA产生PWM好用

xh2008email 发表于 2015-1-17 10:29:48

不错的东东。赞一个

liyang53719 发表于 2015-1-25 22:12:47

这是我现在用的PWM,交流一下。使用FPGA实现的。
module pwm(clk,pwm0,pwm1,pwm2,pwm3,in_pwm_0,in_pwm_1,in_pwm_2,in_pwm_3,rst);

input clk;                                                                                                   //50MHz时钟信号
input rst;
input         in_pwm_0,in_pwm_1,in_pwm_2,in_pwm_3;        //PWM控制波输入
output reg         pwm0,pwm1,pwm2,pwm3;                                           //PWM波输出

reg cnt,cnt50;   //计时变量
reg clk_50;

always @(posedge clk or negedge rst)
begin
//---------------计数器计数-----------------------------
if (!rst)
        begin
                cnt=0;
        end
else if(cnt=='d999)
    begin
                cnt<='b00000;
                clk_50=1;
       end
else
    begin
                cnt<=cnt+1;
                clk_50=0;
       end
end
//--------------pwm的产生---------------
always @(posedge clk_50 or negedge rst)
begin
        if (!rst)
                begin
                        pwm0=0;
                        pwm1=0;
                        pwm2=0;
                        pwm3=0;
                end
        else
                begin
                        if (cnt50==999)                 cnt50=0;        else        cnt50=cnt50+1;
                        if (cnt50<in_pwm_0)        pwm0=1;        else        pwm0=0;
                        if (cnt50<in_pwm_1)        pwm1=1;        else        pwm1=0;
                        if (cnt50<in_pwm_2)        pwm2=1;        else        pwm2=0;
                        if (cnt50<in_pwm_3)        pwm3=1;        else        pwm3=0;
                end
end

endmodule
页: [1]
查看完整版本: 兑现:前两天扯过的CPLD实现PWM的一种方法