【dsPIC33】PWM系列之真正独立PWM模式

本文详细介绍了dsPIC33E系列芯片的PWM模式,包括推挽、互补、冗余和独立PWM模式。重点讨论了真正独立PWM模式的配置,以及在电机控制中如何使用互补PWM模式。在配置过程中,强调了PWMLOCK位的关闭以及PWM频率、占空比和相位的设定。通过实例展示了如何解决PWM引脚输出问题,并提供了初始化代码。最后提醒读者注意不同模式下相同寄存器的不同功能,并预告了后续将探讨互补PWM和中心对齐模式。
摘要由CSDN通过智能技术生成

前言

作为一款可用作电机控制的芯片,PWM肯定是芯片中的重点,一般来讲,做电机控制会用到PWM与互补PWM,使用SVPWM时会使用中心对齐模式PWM,有些芯片也叫做中央对齐模式PWM,而SVPWM是FOC矢量控制的基础,因此能不能产生中心对齐模式的PWM,便是判定一款芯片能不能使用FOC算法的依据。下面针对dsPIC33E系列的芯片,进行这款芯片的PWM的学习。

先看手册中关于PWM的模式介绍,先了解一下dsPIC33E芯片都有哪些PWM模式:

由手册可知,便是四种PWM模式,然后逐个看这四种模式都是什么意思:

1.推挽PWM模式

在推挽模式下,PWM输出在PWMxH与PWMxL引脚上交替提供。而观察图中的寄存器介绍,PDCx同时控制两个引脚的占空比,而可以通过PHASEx来设置两个引脚不同的相位,那也就是说,这种模式,H与L引脚是不能输出不同占空比的,但是可以控制输出时间。

2.互补PWM模式

这种模式就比较好理解了,而且也常用,就是上下通道发不同的电平,中间加个死区

3.冗余PWM输出模式

如同描述一样,这种模式下,两个引脚会输出相同的PWM信号,且没有死区。

4.真正独立PWM输出模式

这种模式也比较好理解,也比较常用,这种模式下,上下引脚可以输出不同的占空比,不同的PWM频率,而且也可以产生相移。

综上,可以看出dsPIC33E系列的PWM功能还是比较强大的,当然对于我们电机控制来说,大多要用的就是两个:真正独立的PWM输出模式与互补PWM模式,当然中心对齐模式PWM也是属于互补PWM模式中的。

因此PWM系列就只着重讲一下这两种模式,然后做一下相关实验。

比如我在控制两相直流电机的时候,对于一个H桥,可以使用互补PWM模式,控制两对上下通道发送互补PWM,可以控制,同样,H桥左边上脚发PWM,下脚发低电平,H桥右边上脚发低,下脚发高,也是可以控制电机转速的。除此之外,一些普通的PWM应用,不需要那么高级的PWM功能,也会用到这种PWM输出模式,现在假定我只需要一个引脚发PWM,其他都是低电平,那么开始学习PWM的这种模式—-真正独立PWM。

永远记得在使用某个功能的时候,检查配置位有没有配置,关于PWM功能的配置位就注意两点,PWMLOCK位有没有关闭,以及PWM引脚有没有冲突,根据我的电路,我的配置如下:

代码:

// FICD
#pragma config ICS = PGD2               // ICD Communication Channel Select bits (Communicate on PGEC2 and PGED2)
#pragma config JTAGEN = OFF              // JTAG Disable bit (JTAG is Disabled)
// FPOR
#pragma config ALTI2C1 = OFF            // Alternate I2C1 pins (I2C1 mapped to SDA1/SCL1 pins)
#pragma config ALTI2C2 = OFF            // Alternate I2C2 pins (I2C2 mapped to SDA2/SCL2 pins)
#pragma config WDTWIN = WIN25           // Watchdog Window Select bits (WDT Window is 25% of WDT period)
// FWDT
#pragma config WDTPOST = PS32768        // Watchdog Timer Postscaler bits (1:32,768)
#pragma config WDTPRE = PR128           // Watchdog Timer Prescaler bit (1:128)
#pragma config PLLKEN = ON              // PLL Lock Enable bit (Clock switch to PLL source will wait until the PLL lock signal is valid.)
#pragma config WINDIS = OFF             // Watchdog Timer Window Enable bit (Watchdog Timer in Non-Window mode)
#pragma config FWDTEN = OFF             // Watchdog Timer Enable bit (Watchdog timer enabled/disabled by user software)
// FOSC
#pragma config POSCMD = XT              // 主振荡器模式选择位(XT晶体振荡器模式)
#pragma config OSCIOFNC = OFF           // OSC2 Pin Function bit (OSC2 is clock output)
#pragma config IOL1WAY = ON             // Peripheral pin select configuration (Allow only one reconfiguration)
#pragma config FCKSM = CSDCMD           // Clock Switching Mode bits (Both Clock switching and Fail-safe Clock Monitor are disabled)
// FOSCSEL
#pragma config FNOSC = PRIPLL           // 振荡器源选择(带PLL<a class="decoration-color" href="https://buy.icxbk.com/index.php?ctl=Product&met=lists&category_id=1047" target="_blank">模块</a>的主振荡器(XT + PLL,HS + PLL,EC + PLL))
#pragma config PWMLOCK = OFF             // PWM Lock Enable bit (Certain PWM registers may only be written after key sequence)
#pragma config IESO = ON                // Two-speed Oscillator Start-up Enable bit (Start up device with FRC, then switch to user-selected oscillator source)
// FGS
#pragma config GWRP = OFF               // General Segment Write-Protect bit (General Segment may be written)
#pragma config GCP = OFF                // General Segment Code-Protect bit (General Segment Code protect is Disabled)

如果忘记了吧PWMLOCK位关闭,手册中也有介绍,使用程序方式来解锁。

当PWMLOCK配置位配置为ON时,也即PWM配置位锁定时,可使用解锁代码解锁寄存器:

/@@*解锁PWM*/
    asm volatile ("mov #0xabcd,w10");       //PWM1 写保护寄存器的解锁序列
    asm volatile ("mov #0x4321,w11");
    asm volatile ("mov #0x0000,w0");
    asm volatile ("mov w10, PWMKEY");
    asm volatile ("mov w11, PWMKEY");
    asm volatile ("mov w0,FCLCON1");
    asm volatile ("mov #0xabcd,w10");
    asm volatile ("mov #0x4321,w11");
    asm volatile ("mov #0xF000,w0");
    asm volatile ("mov w10, PWMKEY");
    asm volatile ("mov w11, PWMKEY");
    asm volatile ("mov w0,IOCON1");

当然以上只是PWM1的,如果使用3路PWM,则需要将其他两个PWM,也同样解锁。虽然我也不知道这段代码具体是什么,但手册上直接给出了,直接复制粘贴即可。如果不想这么麻烦,就老实更改配置位,改成OFF,就一步。

在这之后,便是确定PWM的频率了,这里我就选用15K作为PWM频率了。确定PWM频率时,需要对自己的时钟配置非常了解,时钟不正确,PWM肯定怎么配都是不正确的,关于时钟振荡器的配置与验证,请参考我之前的有关文章。

单片机工作频率是Fosc的一半,就是60M,配置的Fosc频率是120M,根据手册中的PWM频率计算:

使用时钟预分频比1:1,因此计算出PTPER寄存器为8000,因为现在是使用真正独立PWM,因此死区设置就不需要了,给0即可,也就是说,DTRx与ALTDTRx寄存器就给0,之后,便是搞清楚在这种模式下占空比是由谁决定的,可查看上面的介绍,可以PWMxH的占空比是由PDCx决定的,而PWMxL的占空比是由SDCx决定的,因为周期寄存器是8000,所以占空比是不能高于8000的,就随便给个1000好了。至于相移,也没有必要,就给0,即PHASEx寄存器给0。

在使用PWM功能时的一个重要配置当然时把相关引脚配置成输出模式。也就是IOCONx寄存器,这个根据自己的电路来配置输出:

在配置PWM寄存器时,也就是初始化时,也要注意先把PTEN位置0,也就是先关闭PWM输出,再进行配置,之后再使能PWM输出。

独立占空比与主控占空比

这里还要注意一点,在查看手册时,经常会看到独立占空比与主控占空比,这两个是什么意思?

因为dsPIC33E系列芯片是有3组PWM的,也就是6个PWM引脚,独立占空比就是说,这三组PWM,PWM1,PWM2,PWM3的占空比是独立控制的,一般由PDCx寄存器来控制。

而主控占空比就是说,这三组PWM的占空比是相同的,统一由MDC寄存器来控制

当然,并不是这么一帆风顺,在使用真正独立PWM的时候,按照手册代码直接抄,都是不行的,他总是会以互补PWM的形势,给PWMxL通道发送互补PWM,而且,我使用SDCx寄存器都会报错,也就是说,没有这个寄存器:

我找了芯片的勘误手册,也许是芯片bug也说不定,但在芯片勘误手册也没有找到,因此可能是我使用的芯片的问题。

不过我的目标就是要实现这样的功能,是不可以半途而废的,肯定是有变通的办法,在又继续看了一遍IOCONx寄存器的时候,突然想到,可以把PWMxL引脚使用GPIO模块来控制,抛开PWM模块,这样就可以控制PWMxL引脚独立输出低电平了。

再查看GPIO手册,默认是输出低电平的,因此可以不进行操作。

完整代码如下:

//振荡器配置
void System_Colck (void)
{
    //产生Fosc = 120MHz  芯片以60MIPS工作
    CLKDIVbits.PLLPRE = 0;//N1 = 2  
    PLLFBDbits.PLLDIV = 58;//M = 60  
    CLKDIVbits.PLLPOST = 0;//N2 = 2    8 * (60 / (2 + 2)) = 120M
    while (OSCCONbits.COSC!= 0b011);
    while (OSCCONbits.LOCK!= 1) {};//PLL 处于锁定状态
}
/@@****************************************************************************
 *
 * 函数名:          Pwm_Init
 * 输入:            无
 * 输出:            无
 * 返回值:           无
 * 描述:            PWM初始化配置
 ***************************************************************************/
void Pwm_Init (void)
{
    /@@*先关闭PWM  在 PTEN = 0 的情况下,才能修改PWM配置*/
    PTCONbits.PTEN = 0;   //失能高速PWM模块    
    /@@*设置周期*/
    PTPER = 8000;
    /@@*设置相移*/
    PHASE1 = PHASE2 = PHASE3 = 0;
    /@@*初始占空比*/
    PDC1 = 1000;
//    SDC1 = 0;
    PDC2 = 0;
//    SDC2 = 0;
    PDC3 = 0;
//    SDC3 = 0;
    /@@*死区时间配置*/
    DTR1 = DTR2 = DTR3 = 0;//PWMxH死区配置
    ALTDTR1 = ALTDTR2 = ALTDTR3 = 0;//PWMxL死区配置
    /@@*PWM输出引脚控制  配置为输出*/
    IOCON1bits.PENH = 1;
    IOCON1bits.PENL = 0;
    IOCON1bits.PMOD = 0x03;
    IOCON2bits.PENH = 1;
    IOCON2bits.PENL = 0;
    IOCON2bits.PMOD = 0x03;
    IOCON3bits.PENH = 1;
    IOCON3bits.PENL = 0;
    IOCON3bits.PMOD = 0x03;
    /@@*设置主时基,边沿对齐模式*/
    PWMCON1 = PWMCON2 = PWMCON3 = 0x0000;
    /@@*配置故障*/
    FCLCON1bits.FLTPOL = FCLCON2bits.FLTPOL = FCLCON3bits.FLTPOL = 1;     //故障源低电平有效
    FCLCON1bits.FLTMOD = FCLCON2bits.FLTMOD = FCLCON3bits.FLTMOD = 0x03;  //禁止故障输入
 //   FCLCON1 = FCLCON2 = FCLCON3 = 0x0003;
    /@@*最大预分频比 1分频*/
    PTCON2 = 0x0000;//PWM 时钟分频比选择寄存器
    /@@* Enable PWM Module */
    PTCONbits.PTEN = 1;
}
/@@*
 * 
 */
void main() 
{
    int i = 0;  
    System_Colck();
    Pwm_Init();
    while(1)
    {
    }        
}

结果如图:

在这里需要告诫一下后来学习的盆友,在不同的模式下,相同的寄存器可能有不同的功能,例如:在这种模式下PHASEx寄存器是设置相移的,然而在中央对齐模式下,是控制PWM周期的,而且,不仅仅是这种不同的PWM模式,即使是相同的PWM模式,不同的控制方式,有时同一个寄存器,也有不同的意思。下篇文章会继续PWM,介绍互补PWM与中心对齐模式下的PWM,并且在互补PWM与中心对齐模式下的芯片bug是有bug的,在官方的芯片勘误手册中有很多都是关于互补PWM与中心对齐PWM的,因此在使用时需要非常小心。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值