关于STM32利用PWM和SPWM驱动步进电机的问题

2019-03-23 17:57发布

本帖最后由 lizoyu 于 2016-3-27 22:36 编辑

    最近在做毕业设计,其中涉及到了步进电机,本来用驱动器驱动得很顺利的,但是因为便携的需求改用了小得多驱动模块,tb买了用2个L9110的驱动模块,如下图.
sku_153951_2.jpg
电路图如下:
原理图.jpg

    首先,我根据最常见的三种励磁方式写了程序,实现的时序如下图所示,图从左到右分别是一相励磁,二相励磁,一-二相励磁(8拍).
    四个通道从上到下分别是A+,B+,A-,B-.
2beat.PNG 4beat.PNG 8beat.PNG
    但是将这三种励磁时序分别输出到驱动模块后,电机产生比较大的震动和噪声(与驱动器相比),只转动了1秒左右就停下来,震动依然持续.
    PWM程序代码如下:
#include "stm32f10x.h"
void RCC_Configuration(void);
void GPIO_Configuration(void);
void TIM_Configuration_8beat(void);
void TIM_Configuration_2beat(void);
void TIM_Configuration_4beat(void);
void NVIC_Configuration(void);
u16 LowBitVal;
u16 HighBitVal;
void Delay(u32 ms)
{                        
      u16 count;
      while(ms)
      {
            count = 1800;
            while(count--);
                                                ms--;
      }
}

int main()
{
        RCC_Configuration();
        NVIC_Configuration();
        GPIO_Configuration();
        //选择励磁方式
        //TIM_Configuration_8beat();
        //TIM_Configuration_4beat();
        //TIM_Configuration_2beat();
        while(1);
}

void RCC_Configuration()
{
        SystemInit();
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);
}

void GPIO_Configuration()
{
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;  //PA0: A+; PA1: B+; PA2: A-; PA3: B-
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void NVIC_Configuration()
{
        NVIC_InitTypeDef NVIC_InitStructure;
#ifdef        VECT_TAB_RAM
        NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
#else
        NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);
#endif
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
}

//一-二相励磁(8拍)
void TIM_Configuration_8beat()
{
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        TIM_OCInitTypeDef TIM_OCInitStructure;
        
        LowBitVal = 37500;    //高电平时的比较值,即其持续时间
        HighBitVal = 22500;   //低电平时的比较值,即其持续时间
        TIM_TimeBaseStructure.TIM_Period = 65535-1;  
        TIM_TimeBaseStructure.TIM_Prescaler = 100-1;
        TIM_TimeBaseStructure.TIM_ClockDivision = 0;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
        
        TIM_PrescalerConfig(TIM2, 4, TIM_PSCReloadMode_Immediate);
        
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;   //使用比较输出翻转模式,计数到达比较值自动翻转,并触发中断
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
        TIM_OCInitStructure.TIM_Pulse = 7500-1;                        //初始比较值设置,能够产生移相效果
        TIM_OC1Init(TIM2, &TIM_OCInitStructure);
        TIM_OCInitStructure.TIM_Pulse = 22500-1;
        TIM_OC2Init(TIM2, &TIM_OCInitStructure);
        TIM_OCInitStructure.TIM_Pulse = 37500-1;
        TIM_OC3Init(TIM2, &TIM_OCInitStructure);
        TIM_OCInitStructure.TIM_Pulse = 52500-1;
        TIM_OC4Init(TIM2, &TIM_OCInitStructure);
        
        //禁止计数溢出事件
        TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
        TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);
        TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);
        TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable);

        TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);
        TIM_Cmd(TIM2, ENABLE);
}
//一相励磁
void TIM_Configuration_2beat()
{
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        TIM_OCInitTypeDef TIM_OCInitStructure;
        
        LowBitVal = 45000;
        HighBitVal = 15000;
        TIM_TimeBaseStructure.TIM_Period = 65535-1;
        TIM_TimeBaseStructure.TIM_Prescaler = 150-1;           
        TIM_TimeBaseStructure.TIM_ClockDivision = 0;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
        
        TIM_PrescalerConfig(TIM2, 4, TIM_PSCReloadMode_Immediate);
        
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
        TIM_OCInitStructure.TIM_Pulse = 15000-1;
        TIM_OC1Init(TIM2, &TIM_OCInitStructure);
        TIM_OCInitStructure.TIM_Pulse = 30000-1;
        TIM_OC2Init(TIM2, &TIM_OCInitStructure);
        TIM_OCInitStructure.TIM_Pulse = 45000-1;
        TIM_OC3Init(TIM2, &TIM_OCInitStructure);
        TIM_OCInitStructure.TIM_Pulse = 60000-1;
        TIM_OC4Init(TIM2, &TIM_OCInitStructure);
        TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
        TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);
        TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);
        TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable);

        TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);
        TIM_Cmd(TIM2, ENABLE);
}
//二相励磁
void TIM_Configuration_4beat()
{
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        TIM_OCInitTypeDef TIM_OCInitStructure;
        
        LowBitVal = 30000;
        HighBitVal = 30000;
        TIM_TimeBaseStructure.TIM_Period = 65535-1;
        TIM_TimeBaseStructure.TIM_Prescaler = 100-1;           
        TIM_TimeBaseStructure.TIM_ClockDivision = 0;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
        
        TIM_PrescalerConfig(TIM2, 4, TIM_PSCReloadMode_Immediate);
        
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
        TIM_OCInitStructure.TIM_Pulse = 15000-1;
        TIM_OC1Init(TIM2, &TIM_OCInitStructure);
        TIM_OCInitStructure.TIM_Pulse = 30000-1;
        TIM_OC2Init(TIM2, &TIM_OCInitStructure);
        TIM_OCInitStructure.TIM_Pulse = 45000-1;
        TIM_OC3Init(TIM2, &TIM_OCInitStructure);
        TIM_OCInitStructure.TIM_Pulse = 60000-1;
        TIM_OC4Init(TIM2, &TIM_OCInitStructure);
        TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
        TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);
        TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);
        TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable);

        TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);
        TIM_Cmd(TIM2, ENABLE);
}

其中断程序如下:
        void TIM2_IRQHandler(void)
        {
                u16 capture = 0;
                extern u16 LowBitVal;
                extern u16 HighBitVal;
                if(TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
                {
                        TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
                        capture = TIM_GetCapture1(TIM2);
                        //通过控制高低电平时的比较值,控制了高低电平的持续时间,即占空比
                        if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0))
                                TIM_SetCompare1(TIM2, capture + HighBitVal-1);//自动翻转后电平为高电平时,比较值=原值+HighBitVal
                        else
                                TIM_SetCompare1(TIM2, capture + LowBitVal-1); //自动翻转后电平为低电平时,比较值=原值+LowBitVal
                }
                else if(TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)
                {
                        TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
                        capture = TIM_GetCapture2(TIM2);
                        if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1))
                                TIM_SetCompare2(TIM2, capture + HighBitVal-1);
                        else
                                TIM_SetCompare2(TIM2, capture + LowBitVal-1);
                }
                else if(TIM_GetITStatus(TIM2, TIM_IT_CC3) != RESET)
                {
                        TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
                        capture = TIM_GetCapture3(TIM2);
                        if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2))
                                TIM_SetCompare3(TIM2, capture + HighBitVal-1);
                        else
                                TIM_SetCompare3(TIM2, capture + LowBitVal-1);
                }
                else if(TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET)
                {
                        TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);
                        capture = TIM_GetCapture4(TIM2);
                        if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3))
                                TIM_SetCompare4(TIM2, capture + HighBitVal-1);
                        else
                                TIM_SetCompare4(TIM2, capture + LowBitVal-1);
                }
        }

PWM失败之后,我参考了论坛的STM32产生SPWM来驱动步进电机的教程,因为我不是相关专业的,不懂脉冲调制的原理,直接实现了SPWM时序如下图,直接用查表法,SPWM数据来自教程里的matlab程序.
同样,四个通道从上到下分别是A+,B+,A-,B-.可以看出A+和A-,B+和B-是互补的,而且A和B相差90度相位,符合教程的正弦波要求
SPWM.PNG
但是输出到驱动模块后,依然无法成功驱动步进电机,现象是:步进电机转动了一个小角度后自动回到原位置,然后不断重复.震动依然存在,但是比PWM的小.
程序代码如下:
  1. #include "stm32f10x.h"
  2. void RCC_Configuration(void);
  3. void GPIO_Configuration(void);
  4. void TIM_Configuration(void);
  5. void NVIC_Configuration(void);
  6. /*****************************************
  7. * 函数名      : main
  8. ******************************************/
  9. int main()
  10. {
  11.         RCC_Configuration();
  12.         GPIO_Configuration();
  13.         NVIC_Configuration();
  14.         TIM_Configuration();
  15.         while(1);
  16. }
  17. /*****************************************
  18. * 函数名       : RCC_Configuration
  19. ******************************************/
  20. void RCC_Configuration()
  21. {
  22.         SystemInit();
  23.         //RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
  24.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO | RCC_APB2Periph_TIM1,ENABLE);
  25. }
  26. /*****************************************
  27. * 函数名       : GPIO_Configuration
  28. ******************************************/
  29. void GPIO_Configuration()
  30. {
  31.         GPIO_InitTypeDef GPIO_InitStructure;
  32.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11; //PA8: A+; PA9: B+; PA10: A-; PA11: B-
  33.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  34.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  35.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  36. }
  37. /*****************************************
  38. * 函数名      : NVIC_Configuration
  39. ******************************************/
  40. void NVIC_Configuration()
  41. {
  42.         NVIC_InitTypeDef NVIC_InitStructure;
  43. #ifdef        VECT_TAB_RAM
  44.         NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
  45. #else
  46.         NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);
  47. #endif
  48.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
  49.         
  50.         //TIM1更新事件NVIC设置
  51.         NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
  52.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  53.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  54.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  55.         NVIC_Init(&NVIC_InitStructure);
  56. }
  57. /*****************************************
  58. *  函数名       : TIM_Configuration
  59. ******************************************/
  60. void TIM_Configuration()
  61. {
  62.         TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  63.         TIM_OCInitTypeDef TIM_OCInitStructure;

  64.         TIM_TimeBaseStructure.TIM_Period = 16050 - 1;
  65.         TIM_TimeBaseStructure.TIM_Prescaler = 100 - 1;           
  66.         TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  67.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  68.         TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
  69.         TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
  70.         TIM_ARRPreloadConfig(TIM1, ENABLE);
  71.         TIM_ClearFlag(TIM1, TIM_FLAG_Update);
  72.         
  73.         TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  74.         TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  75.         TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  76.         TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
  77.         TIM_OCInitStructure.TIM_Pulse = 0;
  78.         TIM_OC1Init(TIM1, &TIM_OCInitStructure);
  79.         TIM_OC2Init(TIM1, &TIM_OCInitStructure);
  80.         TIM_OC3Init(TIM1, &TIM_OCInitStructure);
  81.         TIM_OC4Init(TIM1, &TIM_OCInitStructure);
  82.         
  83.         TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
  84.         TIM_CtrlPWMOutputs(TIM1, ENABLE);
  85.         TIM_Cmd(TIM1, ENABLE);
  86. }
复制代码其中断程序为:
        void TIM1_UP_IRQHandler(void)
        {
                #define TIM1_CH1_Pulse TIM1->CCR1 //A+
                #define TIM1_CH2_Pulse TIM1->CCR2 //B+
                #define TIM1_CH3_Pulse TIM1->CCR3 //A-
                #define TIM1_CH4_Pulse TIM1->CCR4 //B-
                //半个周期的正弦表
                static vu16 SinwaveTable[128] = {
                0,392,785,1177,1568,1958,2347,2735,3121,3505,3887,4267,4644,5018,5390,5758,
6122,6483,6840,7193,7542,7886,8225,8559,8889,9212,9531,9843,10150,10450,10744,11032,
11313,11587,11855,12115,12368,12613,12851,13081,13303,13517,13723,13921,14110,14291,14463,14627,
14782,14927,15064,15192,15311,15420,15520,15611,15692,15764,15826,15879,15922,15956,15980,15995,
16000,15995,15980,15956,15922,15879,15826,15764,15692,15611,15520,15420,15311,15192,15064,14927,
14782,14627,14463,14291,14110,13921,13723,13517,13303,13081,12851,12613,12368,12115,11855,11587,
11313,11032,10744,10450,10150,9843,9531,9212,8889,8559,8225,7886,7542,7193,6840,6483,
6122,5758,5390,5018,4644,4267,3887,3505,3121,2735,2347,1958,1568,1177,785,392
};
                static u8 stepcounter_A = 0;
                static u8 stepcounter_B = 64;  //控制相位
                static u8 WhosTurnFlag_A = 1;
                static u8 WhosTurnFlag_B = 1;
                if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)
                {
                        //A+和A-交替产生半个周期的SPWM,组成一个完整的正弦波
                        //A+
                        if (WhosTurnFlag_A)
                        {
                                if (stepcounter_A > 127)
                                {
                                        stepcounter_A = 0;
                                        WhosTurnFlag_A = 0;
                                }
                                TIM1_CH1_Pulse = SinwaveTable[stepcounter_A];
                                stepcounter_A++;
                        }
                        //A-
                        else
                        {
                                if (stepcounter_A > 127)
                                {
                                        stepcounter_A = 0;
                                        WhosTurnFlag_A = 1;
                                }
                                TIM1_CH3_Pulse = SinwaveTable[stepcounter_A];
                                stepcounter_A++;
                        }
                        //B+和B-交替产生半个周期的SPWM,组成一个完整的正弦波
                        //B+
                        if (WhosTurnFlag_B)
                        {
                                if (stepcounter_B > 127)
                                {
                                        stepcounter_B = 0;
                                        WhosTurnFlag_B = 0;
                                }
                                TIM1_CH2_Pulse = SinwaveTable[stepcounter_B];
                                stepcounter_B++;
                        }
                        //B-
                        else
                        {
                                if (stepcounter_B > 127)
                                {
                                        stepcounter_B = 0;
                                        WhosTurnFlag_B = 1;
                                }
                                TIM1_CH4_Pulse = SinwaveTable[stepcounter_B];
                                stepcounter_B++;
                        }
                }
                TIM_ClearITPendingBit(TIM1, TIM_FLAG_Update);
        }

对于一些基本问题的排除:1. 供电: 采用的是24V转5V降压模块,输出5V/3A,我用驱动器时使用0.3A即可驱动步进电机,所以供电应该没有问题;
2. 接线: 步进电机的接线方式与使用驱动器时的相同,由于驱动器能够顺利地驱动步进电机,所以接线应该没有问题;
3. 工作频率: 我需求的运转速度不高,不超过50Hz,而这种速度在驱动器上能够顺利运转,因此不是速度过高的问题.

希望论坛的各位大神能够帮我这个门外汉分析一下是哪里出了问题,事关毕业,感激不尽!






此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
11条回答
Li_Lei
1楼-- · 2019-03-24 04:07
 精彩回答 2  元偷偷看……
tianshuihu
2楼-- · 2019-03-24 07:23
使用4Hz 8拍驱动
如果有示波器分别观察一下两个驱动器的A+输出吧,同理A-,B,B-,有问题应该会看到差异
flashtt
3楼-- · 2019-03-24 08:02
应该是时序的问题,楼主可以先写个简单代码把步进电机的单步运行弄明白,网上的一些开发板资料都有简单程序,PWM波足矣,代码没仔细看,给个建议
lizoyu
4楼-- · 2019-03-24 09:05
 精彩回答 2  元偷偷看……
lizoyu
5楼-- · 2019-03-24 13:21
huo_hu 发表于 2016-3-28 10:27
输出的波形不对,感觉你每次输出了两个正弦半周期

捕获1.JPG
这是放大后的一个SPWM波形,您看看是不是有问题?
lizoyu
6楼-- · 2019-03-24 14:21
tianshuihu 发表于 2016-3-28 10:34
使用4Hz 8拍驱动
如果有示波器分别观察一下两个驱动器的A+输出吧,同理A-,B,B-,有问题应该会看到差异

谢谢!我去实验室用示波器测一测

一周热门 更多>