DIY编程器网

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 1435|回复: 0
打印 上一主题 下一主题

[待整理] 单片机驱动CPLD的PWM正弦信号发生器设计

[复制链接]
跳转到指定楼层
楼主
发表于 2014-10-12 16:26:33 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本文将挖掘CPLD潜力,给出一种单片机驱动CPLD的PWM正弦信号发生器设计,充分体现了CPLD的灵活多变,配合单片机控制,其妙无穷,以下方案均在Mini51板上实现。
         
        脉宽调制PWM(Pulse Width Modulation)是利用数字输出信号对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。
       
        一、PWM原理
       
        PWM是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。PWM信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被断开的时候。
       
        只要带宽足够,任何模拟值都可以使用PWM进行编码。
       
        如图1所示,用一系列等幅不等宽的脉冲来代替一个正弦半波,正弦半波N等分,看成N个相连的脉冲序列,宽度相等,但幅值不等;用矩形脉冲代替,等幅,不等宽,中点重合,面积(冲量)相等,宽度按正弦规律变化。
       
        图1 用PWM波代替正弦半波
        SPWM波形——脉冲宽度按正弦规律变化而和正弦波等效的PWM波形。
       
        二、基于CPLD的PWM方案
       
        一个PWM发生器必须包括计数器,数据比较器,另外就是配置PWM参数的时钟分频寄存器和占空比寄存器,结构框图如图2所示,这些电路都可以用CPLD来实现。
       
        图2 PWM控制器结构框图
        高频时钟信号经分频器驱动计数器,计数器如图3所示,总是从Bottom到Top的循环计数,计数器的输出和占空比寄存器里的数据经数据比较器比较,输出PWM信号,当计数器输出小于占空比设定值时输出低电平(0),否则输出高电平(1),如图3(b)(c)所示。
       
        图3 PWM信号发生器时序波形图
        从图中还可以看出,计数器的周期就是PWM信号的周期,通过修改占空比寄存器从而实现对输出PWM信号高低电平比例控制,图3(b)是占空比为P1的PWM输出,图3(c)是占空比为P2的PWM输出,它们周期相同,高低电平的比例不同。
       
        下面用硬件描述语言来设计CPLD的内部电路,这里给出VerilogHDL版本的参考代码。
       
        module Mini51b_PWM(P0,ALE,P27,WR,PWM);//模块电路命名和端口说明。
       
        input [7:0]P0;//数据输入接MCU数据P0口
       
        input ALE,P27,WR;//几个MCU读写控制引脚
       
        output PWM;//PWM信号输出
       
        wire [7:0]addr;//内部地址线
       
        reg [7:0]daPWMc,daPWMs;//定义计数器和占空比设定寄存器
       
        reg [3:0]divPWM,divPWMc;//分频控制变量
       
        reg PWM;//输出锁存器
       
        assign addr = ALE?P0 : addr; //低八位地址锁存
       
        always @(negedge WR)//在MCU写信号有效时执行寄存器设定
       
        begin
       
        case({P27,addr[4:0]}) //根据地址选择寄存器
       
        6'b10_1000: daPWMs <= P0;//写带地址的寄存器
       
        6'b10_1001: divPWM <= P0[3:0];//写带地址的寄存器
       
        default:begin//其它地址则让寄存器保持不变
       
        daPWMs <= daPWMs;
       
        divPWM <= divPWM;
         
       
        end
       
        endcase
       
        end
       
        always @(posedge ALE) begin//这里利用MCU的ALE做时钟信号
       
        if(divPWMc == divPWM) begin //与分频系数比较
       
        divPWMc<=0;
       
        if(daPWMc<100) daPWMc <= daPWMc+1; //PWM调整精度1%
       
        else daPWMc <= 0;
       
        if(daPWMs < daPWMc) PWM <= 0;//PWM发生器
       
        else PWM <= 1;
       
        end
       
        else divPWMc <= divPWMc+1;//时钟分频
       
        end
       
        endmodule
       
        关于单片机与CPLD之间的接口请读者参考本刊前几期笔者撰写的文章。
       
        与之对应的MCU测试程序为:
       
        #include
       
        #include
       
        #define PWM XBYTE[0xffe8]
       
        #define DIV XBYTE[0xffe9]
       
        void main()
       
        {
       
        DIV = 15; //PWM信号频率计算晶振22.1184M/6/100/
       
        (DIV+1)=2.30K(实测2.281K)
       
        PWM=50; // 设定占空比50%,前面计数器范围为0~99
       
        while(1);
       
        }
       
        执行单片机程序,选择不同的分频系数和占空比值,从CPLD的引脚输出PWM信号示波器截图如图4所示。
       
       
       
        图4 不同占空比的PWM信号示波器截图
         
        三、SPWM
       
        如果将占空比按正弦规律随着时间变化,就可以得到正弦调制的PWM信号,也就是SPWM。如图5所示,该信号经过阻容滤波可以得到正弦模拟信号,这里的运放做电压跟随器用,对信号驱动能力进行放大。实际得到的正弦信号示波器截图效果如图6所示。
       
        图5 SPWM阻容滤波电路
       
         
        图6 正弦信号示波器截图
         
        正弦信号发生器MCU演示程序:
       
        #include
       
        #include
       
        #define PWM XBYTE[0xffe8]
       
        unsigned char code sine_dot[32]={49,59,68,77,84,90,95,98,99,98,95,90,84,77,68,59,49,40,30,22,14,8,4,1,0,1,4,8,14,22,30,40};//正弦表
       
        void main()
       
        {
       
        unsigned char i=0;
       
        while(1) {
       
        PWM = sine_dot;
       
        i=(i++)&0x1f;
       
        }//如果要严格控制SPWM的周期,这里的while循环请用定时器来驱动
       
        }
        四、三路精确相位差正弦信号发生器
       
        对CPLD改进设计,很容易实现多路PWM输出。
       
        例如设计具有精确相位差的三相正弦信号,CPLD电路VerilogHDL程序如下:
       
        module Mini51b_PWM(P0,ALE,P27,WR,PWM);
       
        input [7:0]P0;
       
        input ALE,P27,WR;
       
        output [2:0]PWM;
       
        wire [3:0]addr;
       
        reg [7:0]daPWMc;
       
        reg [7:0]daPWMs0,daPWMs1,daPWMs2;
       
        reg [2:0]PWM;
       
        wire clk,nclk,a,b,c,d;
       
        assign addr= (ALE)?P0[3:0]:addr; //低八位地址锁存
       
        always @(negedge WR)
       
        begin
       
        case({P27,addr})
       
        5'H10: daPWMs0 <= P0;//写带地址的寄存器
       
        5'H11: daPWMs1 <= P0;//写带地址的寄存器
       
        5'H12: daPWMs2 <= P0;//写带地址的寄存器
       
        default:
       
        begin
       
        daPWMs0 <= daPWMs0;
       
        daPWMs1 <= daPWMs1;
       
        daPWMs2 <= daPWMs2;
       
        end
       
        endcase
       
        end
       
        always @(posedge clk) begin
       
        daPWMc <= daPWMc+1; //PWM调整精度1%
       
        if(daPWMs0 < daPWMc) PWM[0] <= 0;//PWM发生器
       
        else PWM[0] <= 1;
       
        if(daPWMs1 < daPWMc) PWM[1] <= 0;//PWM发生器
       
        else PWM[1] <= 1;
       
        if(daPWMs2 < daPWMc) PWM[2] <= 0;//PWM发生器
       
        else PWM[2] <= 1;
       
        end
       
        assign nclk=!clk;
       
        LCELL A0(。in(nclk), .out(a));
       
        LCELL A1(。in(a), .out(b));
       
        LCELL A2(。in(b), .out(c));
       
        LCELL A3(。in(c), .out(d));
       
        LCELL A4(。in(d), .out(clk));//PWM时钟来自CPLD内部
       
        LCELL延迟电路振荡器
       
        endmodule
       
        与之对应的MCU演示程序:
       
        #include
       
        #include
       
        #define PWM0 XBYTE[0xfff0]
       
        #define PWM1 XBYTE[0xfff1]
       
        #define PWM2 XBYTE[0xfff2]
       
        unsigned char code sine_dot[36]= //8阶,36点正弦表
       
        {
       
        0x80,0x96,0xab,0xbf,0xd2,0xe2,0xee,0xf8,0xfe,0xff,0xfe,0xf8,
       
        0xee,0xe2,0xd2,0xc0,0xab,0x96,0x80,0x69,0x54,0x40,0x2
       
        d,0x1e,
       
        0x11,0x07,0x01,0x00,0x01,0x07,0x10,0x1d,0x2d,0x3f,0x53,
       
        0x69
       
        };
         
       
        void main()
       
        {
       
        unsigned char a,b,c;
       
        a=0;
       
        while(1) {
       
        a %= 36;// 对36取余数及0~35
       
        b=(a+12)%36;//较a路滞后120度相位
       
        c=(a+24)%36;//较a路滞后240度相位
       
        PWM0 = sine_dot[a];
       
        PWM1 = sine_dot;
       
        PWM2 = sine_dot[c];
       
        a++;
       
        }
       
        }
       
        实际得到的三相正弦信号示波器截图效果如图7所示,只是双踪示波器同时只能看两路信号。
       
       
        图7 具有精确相位差的三相正弦信号示波器截图
         
        五、结束语
       
        今后,MCU+CPLD结构将是很多电子系统设计的一种基本架构,MCU可以用程序实现复杂智能的控制与检测,CPLD又可以实现灵活多变的外围扩展电路设计,尤其是可以用硬件实现特殊的MCU无法实现的功能,弥补MCU响应速度慢影响实时性问题,两者互补,完全实现硬件软设计,使得同一硬件平台能够通过软件实现更多的功能。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|文字版|手机版|DIY编程器网 ( 桂ICP备14005565号-1 )

GMT+8, 2025-8-3 05:33 , 耗时 0.092735 秒, 21 个查询请求 , Gzip 开启.

各位嘉宾言论仅代表个人观点,非属DIY编程器网立场。

桂公网安备 45031202000115号

DIY编程器群(超员):41210778 DIY编程器

DIY编程器群1(满员):3044634 DIY编程器1

diy编程器群2:551025008 diy编程器群2

QQ:28000622;Email:libyoufer@sina.com

本站由桂林市临桂区技兴电子商务经营部独家赞助。旨在技术交流,请自觉遵守国家法律法规,一旦发现将做封号删号处理。

快速回复 返回顶部 返回列表