您的位置:首页 > 其它

如何计算产生SPWM所需要的占空比

2016-12-01 19:25 225 查看
[cpp] view
plain copy

/** @author Mei Jilin 

    @date   2013/9/2 

    @brief  加入生成SPWM部分 

**/  

#include "timer.h"  

#include "led.h"  

static uint16_t CCR3_Val = 1800;  

static uint16_t PrescalerValue = 0;  

  

/*PWM输出配置说明,*/  

/* - Prescaler = (TIM3CLK / TIM3 counter clock) - 1 选择TIMER工作在36MHZ 

 

    The TIM3 is running at 36 MHz: TIM3 Frequency = TIM3 counter clock/(ARR + 1) 

                                                  = 36 MHz / 3600 = 10 KHz 

    TIM3 Channel1 duty cycle = (TIM3_CCR1/ TIM3_ARR)* 100 */  

    /*转换周期10K*/  

void PWM_Init(void)  

{  

    TIM_TimeBaseInitTypeDef     TIM_TimeBaseStructure;  

    TIM_OCInitTypeDef           TIM_OCInitStructure;  

    GPIO_InitTypeDef            GPIO_InitStructure;  

    NVIC_InitTypeDef NVIC_InitStructure;      

        /* TIM3 clock enable */  

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);  

  

    /* GPIOA and GPIOB clock enable */  

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|  

                             RCC_APB2Periph_AFIO, ENABLE);  

    /* GPIOA Configuration:TIM3 Channel1, 2, 3 and 4 as alternate function push-pull */  

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;  

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  

    GPIO_Init(GPIOA, &GPIO_InitStructure);  

      

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;      //TIM1_CH1N  

    GPIO_Init(GPIOB, &GPIO_InitStructure);  

      

     /* Compute the prescaler value */  

    PrescalerValue = (uint16_t) (SystemCoreClock / 36000000) - 1; //TIMER2 - 36MHZ  

    /* Time base configuration */  

    TIM_TimeBaseStructure.TIM_Period = 3600;                    /*TIM3_ARR = 2879,12.5Khz*/  

    TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;  

    TIM_TimeBaseStructure.TIM_ClockDivision = 0;  

    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  

    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;  

    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);  

  

    /* Channel 1, 2,3 and 4 Configuration in PWM mode */  

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;  

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  

    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; //关闭互补输出  

    TIM_OCInitStructure.TIM_Pulse = CCR3_Val;  

    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;  

    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;  

    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;  

    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Set;  

    TIM_OC1Init(TIM1, &TIM_OCInitStructure);  

      

    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); //这句的功能是让改变CCR2之后马上有效      

    TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);  

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);  

    NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;  

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 6;  

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  

    NVIC_Init(&NVIC_InitStructure);      

          

    TIM_Cmd(TIM1, ENABLE);    

    /* TIM1 Main Output Enable */  

    TIM_CtrlPWMOutputs(TIM1, ENABLE);   //TIM1需要加上这句,貌似低级定时器不需要  

}  

uint16_t Duty[] = {1800,1856,1912,1968,2023,2078,2131,2183,2233,2282,2329,2373,2416,2456,2493,  

    2528,2559,2588,2614,2636,2655,2671,2684,2692,2698,2699,2698,2692,2684,2671,2655,2636,2614,  

    2588,2559,2528,2493,2456,2416,2373,2329,2282,2233,2183,2131,2078,2023,1968,1912,1856,1800,  

    1743,1687,1631,1576,1521,1468,1416,1366,1317,1270,1226,1183,1143,1106,1071,1040,1011,985,  

    963,944,928,915,907,901,900,901,907,915,928,944,963,985,1011,1040,1071,1106,1143,1183,1226,  

    1270,1317,1366,1416,1468,1521,1576,1631,1687,1743,1799,1799};  

uint16_t count = 0;  

uint16_t num = sizeof(Duty)/(sizeof(Duty[0]));  

void TIM1_CC_IRQHandler(void)  

{  

  if (TIM_GetITStatus(TIM1, TIM_IT_CC1) != RESET)  

  {  

    TIM1->SR = (uint16_t)~TIM_IT_CC1;  

    TIM1->CCR1 = Duty[count];  

    count++;  

    if(count==num)  

    {  

        count=0;  

    }  

  }  

}  

在上一篇文章里粘贴了STM32产生SPWM的代码,我在编写这些代码时最大的问题就是如何得到占空比,就是代码中的数组 Duty[]。他的思想就是对正弦波采样,在采样点出用PWM的占空比来代替正弦波在该点的数值。最容易想到就是用定时器的ARR值乘以sin(2*pi*f*t),就可以得到对应的寄存器CCR值。但是CCR值不能为负,所以要把sin(2*pi*f*t)变为

A*sin(2*pi*f*t)+B的形式,取A=B=0.5;那么计算公式为ARR*(0.5*sin(2*pi*f*t)+0.5),上传一个C++写的exe文件,可以帮助产生Duty[]数组.

http://download.csdn.NET/detail/mjlsuccess/6205567

软件使用vs2010编写的可能在有些电脑上无法运行,如果你装有VS2010,我可以把原工程发给你
转载于http://blog.csdn.net/mjlsuccess/article/details/11019805

自己思考:10KZ为载波(锯齿波)的频率,最终输入给电机为100HZ正弦波,则载波比为100,也就是100个数据,同时ccr不能为负值,故进行抬升,原本应该为0-1800,进行抬升1800的0.5倍
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: