求助用STM32产生SPWM

2019-08-13 22:58发布

打算用F407 TIM1来产生三相各相差120度的SPWM波控制BLDC,现在的问题是不太理解中心对齐模式1的用法,好像在控制BLDC电机时 最好采用这种计数模式 希望有用过的且路过的大神指点下  还有就是我打算用公式法来产生sin数组,但是中断里面的一些具体程序不知道思路,不知从何下手,希望高人指点一二!!感谢啦
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
3条回答
dossdesmend
1楼-- · 2019-08-14 04:28
已解决
dossdesmend
2楼-- · 2019-08-14 09:23
[mw_shl_code=c,true]/* Defines */附上一个老外写的程序
#define  F_PWM       10000                        
#define  MAX_CNT     ((SystemCoreClock / F_PWM) - 1)
#define  PI          3.141592

/* Globales Sinusarray */
uint16_t sin_arr[360];

/* Funktion initialisiert die 3-Phasen-PWM */
void init_3_phase_pwm( void )
{
   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
   TIM_OCInitTypeDef  TIM_OCInitStructure;
   TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
   GPIO_InitTypeDef GPIO_InitStructure;

   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

   /* PWM-Funktion der Pins aktivieren */
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
   GPIO_Init(GPIOA, &GPIO_InitStructure);
   GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_TIM1);
   GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1);
   GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_TIM1);
   GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_TIM1);

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
   GPIO_Init(GPIOB, &GPIO_InitStructure);
   GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_TIM1);
   GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_TIM1);

   /* Timer konfigurieren */
   TIM_TimeBaseStructure.TIM_Prescaler = 0;
   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
   TIM_TimeBaseStructure.TIM_Period = MAX_CNT;
   TIM_TimeBaseStructure.TIM_ClockDivision = 0;
   TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
   TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

   /* PWM 1,2 und 3 konfigurieren */
   TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
   TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
   TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
   TIM_OCInitStructure.TIM_Pulse = 0;
   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_Reset;
   TIM_OC1Init(TIM1, &TIM_OCInitStructure);
   TIM_OC2Init(TIM1, &TIM_OCInitStructure);
   TIM_OC3Init(TIM1, &TIM_OCInitStructure);

   /* Totzeit konfigurieren */
   TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
   TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
   TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
   TIM_BDTRInitStructure.TIM_DeadTime = 100;
   TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
   TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
   TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
   TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);

   /* Timer einschalten */
   TIM_Cmd(TIM1, ENABLE);

   /* PWM-Ausgänge aktivieren */
   TIM_CtrlPWMOutputs(TIM1, ENABLE);
}


C

/* Funktion füllt ein Sinusarray */
void init_sin_arr( void )
{
   int n;

   /* Sinusarray im Abstand von einem Grad füllen */
   for(n=0;n<360;n++)
   {
      /* Duty für den jeweiligen Winkel berechnen */
      sin_arr[n] = (uint16_t) ( MAX_CNT * 0.5 * (1.0 + sin( 2 * PI * n / 360) ) + 0.5 );
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
/* Funktion füllt ein Sinusarray */
void init_sin_arr( void )
{
   int n;

   /* Sinusarray im Abstand von einem Grad füllen */
   for(n=0;n<360;n++)
   {
      /* Duty für den jeweiligen Winkel berechnen */
      sin_arr[n] = (uint16_t) ( MAX_CNT * 0.5 * (1.0 + sin( 2 * PI * n / 360) ) + 0.5 );
   }
}
C

/* Funktion initialisiert den externen Interrupt */
void init_ext_int(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    EXTI_InitTypeDef EXTI_InitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

    /* Externen Interrupt konfigurieren */
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource0);

    /* Auf steigende Flanke triggern */
    EXTI_InitStruct.EXTI_Line = EXTI_Line0;
    EXTI_InitStruct.EXTI_LineCmd = ENABLE;
    EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_Init(&EXTI_InitStruct);

    /* Interrupt einschalten */
    NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
}

/* ISR des externen Interrupts */
void EXTI0_IRQHandler( void )
{
   static int angle;
   if ( EXTI-&gtR & EXTI_Line0 )                       
   {
          /* PWM 1 --> sin(a + 0°)             */
      TIM1->CCR1 = sin_arr[  angle         % 360 ] + 50;
      /* PWM 2 --> sin(a + 120°)           */          
      TIM1->CCR2 = sin_arr[ (angle + 120 ) % 360 ] + 50;
      /* PWM 3 --> sin(a + 240°)           */          
      TIM1->CCR3 = sin_arr[ (angle + 240 ) % 360 ] + 50;   
      /* Winkel um ein Grad inkrementieren */
      angle++;                                       

      if ( !(angle % 180) ) GPIOA->ODR ^= GPIO_Pin_5;
      if ( !(angle % 360) ) angle = 0;

      EXTI-&gtR = EXTI_Line0;                        
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/* Funktion initialisiert den externen Interrupt */
void init_ext_int(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    EXTI_InitTypeDef EXTI_InitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

    /* Externen Interrupt konfigurieren */
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource0);

    /* Auf steigende Flanke triggern */
    EXTI_InitStruct.EXTI_Line = EXTI_Line0;
    EXTI_InitStruct.EXTI_LineCmd = ENABLE;
    EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_Init(&EXTI_InitStruct);

    /* Interrupt einschalten */
    NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
}

/* ISR des externen Interrupts */
void EXTI0_IRQHandler( void )
{
   static int angle;
   if ( EXTI-&gtR & EXTI_Line0 )                       
   {
          /* PWM 1 --> sin(a + 0°)             */
      TIM1->CCR1 = sin_arr[  angle         % 360 ] + 50;
      /* PWM 2 --> sin(a + 120°)           */          
      TIM1->CCR2 = sin_arr[ (angle + 120 ) % 360 ] + 50;
      /* PWM 3 --> sin(a + 240°)           */          
      TIM1->CCR3 = sin_arr[ (angle + 240 ) % 360 ] + 50;   
      /* Winkel um ein Grad inkrementieren */
      angle++;                                       

      if ( !(angle % 180) ) GPIOA->ODR ^= GPIO_Pin_5;
      if ( !(angle % 360) ) angle = 0;

      EXTI-&gtR = EXTI_Line0;                        
   }
}
C

/* AD9850 */
#define AD9850_RESET       GPIOC, GPIO_Pin_1
#define AD9850_SCK         GPIOC, GPIO_Pin_3
#define AD9850_DATA        GPIOC, GPIO_Pin_2
#define AD9850_LATCH       GPIOC, GPIO_Pin_0

void ad9850_init( void )
{
   GPIO_WriteBit(AD9850_SCK, Bit_RESET);
   GPIO_WriteBit(AD9850_LATCH, Bit_RESET);
   GPIO_WriteBit(AD9850_RESET, Bit_RESET);
   delay_ms(10);
   GPIO_WriteBit(AD9850_RESET, Bit_SET);
   delay_ms(10);
   GPIO_WriteBit(AD9850_RESET, Bit_RESET);

   GPIO_WriteBit(AD9850_LATCH, Bit_SET);
   delay_ms(10);
   GPIO_WriteBit(AD9850_LATCH, Bit_RESET);
   delay_ms(10);
}

void ad9850_write_byte( unsigned char b )
{
   unsigned char i;
   GPIO_WriteBit(AD9850_SCK, Bit_RESET);
   for (i=0; i<8; i++)
   {
      GPIO_WriteBit(AD9850_DATA, (b&0x01)?Bit_SET:Bit_RESET);
      b>>=1;
      GPIO_WriteBit(AD9850_SCK, Bit_RESET);
      GPIO_WriteBit(AD9850_SCK, Bit_SET);
   }
}

void ad9850_set_freq( double f )
{
   unsigned long int y;
   f/=1000000;
   f=f*(4294967295/125);
   y=f;

   GPIO_WriteBit(AD9850_LATCH, Bit_RESET);

   ad9850_write_byte( y & 0xFF );
   y>>=8;
   ad9850_write_byte( y & 0xFF );
   y>>=8;
   ad9850_write_byte( y & 0xFF );
   y>>=8;
   ad9850_write_byte( y & 0xFF );

   ad9850_write_byte( 0 );

   GPIO_WriteBit(AD9850_LATCH, Bit_SET);
   GPIO_WriteBit(AD9850_LATCH, Bit_RESET);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/* AD9850 */
#define AD9850_RESET       GPIOC, GPIO_Pin_1
#define AD9850_SCK         GPIOC, GPIO_Pin_3
#define AD9850_DATA        GPIOC, GPIO_Pin_2
#define AD9850_LATCH       GPIOC, GPIO_Pin_0

void ad9850_init( void )
{
   GPIO_WriteBit(AD9850_SCK, Bit_RESET);
   GPIO_WriteBit(AD9850_LATCH, Bit_RESET);
   GPIO_WriteBit(AD9850_RESET, Bit_RESET);
   delay_ms(10);
   GPIO_WriteBit(AD9850_RESET, Bit_SET);
   delay_ms(10);
   GPIO_WriteBit(AD9850_RESET, Bit_RESET);

   GPIO_WriteBit(AD9850_LATCH, Bit_SET);
   delay_ms(10);
   GPIO_WriteBit(AD9850_LATCH, Bit_RESET);
   delay_ms(10);
}

void ad9850_write_byte( unsigned char b )
{
   unsigned char i;
   GPIO_WriteBit(AD9850_SCK, Bit_RESET);
   for (i=0; i<8; i++)
   {
      GPIO_WriteBit(AD9850_DATA, (b&0x01)?Bit_SET:Bit_RESET);
      b>>=1;
      GPIO_WriteBit(AD9850_SCK, Bit_RESET);
      GPIO_WriteBit(AD9850_SCK, Bit_SET);
   }
}

void ad9850_set_freq( double f )
{
   unsigned long int y;
   f/=1000000;
   f=f*(4294967295/125);
   y=f;

   GPIO_WriteBit(AD9850_LATCH, Bit_RESET);

   ad9850_write_byte( y & 0xFF );
   y>>=8;
   ad9850_write_byte( y & 0xFF );
   y>>=8;
   ad9850_write_byte( y & 0xFF );
   y>>=8;
   ad9850_write_byte( y & 0xFF );

   ad9850_write_byte( 0 );

   GPIO_WriteBit(AD9850_LATCH, Bit_SET);
   GPIO_WriteBit(AD9850_LATCH, Bit_RESET);
}
C

int main(void)
{
   SystemInit();                    /* MCU initialisieren               */
   SystemCoreClockUpdate();         /* Kernfrequenz updaten             */
   delay_init();                    /* Delay-Funktionen initialisieren  */
   ports_init();                    /* Ports initialisieren             */
   init_sin_arr();                  /* Sinusarray vorbereiten           */
   init_3_phase_pwm();              /* 3-Phasen-PWM initialisieren      */
   if (SysTick_Config(SystemCoreClock / 1000)) while (1);

   ad9850_init();                   /* AD9850 initialisieren            */
   init_ext_int();                  /* Externen Interrupt konfigurieren */

   ad9850_set_freq( 10 * 360.0 );

   while(1)
   {
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main(void)
{
   SystemInit();                    /* MCU initialisieren               */
   SystemCoreClockUpdate();         /* Kernfrequenz updaten             */
   delay_init();                    /* Delay-Funktionen initialisieren  */
   ports_init();                    /* Ports initialisieren             */
   init_sin_arr();                  /* Sinusarray vorbereiten           */
   init_3_phase_pwm();              /* 3-Phasen-PWM initialisieren      */
   if (SysTick_Config(SystemCoreClock / 1000)) while (1);

   ad9850_init();                   /* AD9850 initialisieren            */
   init_ext_int();                  /* Externen Interrupt konfigurieren */

   ad9850_set_freq( 10 * 360.0 );

   while(1)
   {
   }
}[/mw_shl_code]
呵呵呵开西寨
3楼-- · 2019-08-14 11:03
厉害厉害

一周热门 更多>