stm32驱动步进电机的玄学

使用stm32f103野火指南者开发板驱动一个两相闭环步进电机的问题,单片机连接步进电机驱动器,共阳极连接。程序正常,但是上电后步进电机不是每次都能正常运转,经常无反应,但是没有修改程序也没有修改线路,偶尔电机又可以受控制的运转。经测试:当电机能正常控制时,关掉开发板电源,在打开开发板电源,电机受控;但是关掉驱动器的电源,再启动,电机不受控制。而且下一次电机能否受控制是随机的,经常都是单片机发出脉冲后无反应,太玄学了,有知道的朋友可以解答吗

用代码块功能插入
void USUALL_TIM_GPIO_Config(void) 
{
     GPIO_InitTypeDef GPIO_InitStructure;
  // 输出比较通道1-4初始化
    RCC_APB2PeriphClockCmd( 
                                                    USUALL_TIM_CH2_GPIO_CLK |
                                                    USUALL_TIM_CH3_GPIO_CLK |
                                                    USUALL_TIM_CH4_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =     //通道1-4
                                                                 USUALL_TIM_CH2_PIN |
                                                                 USUALL_TIM_CH3_PIN |
                                                                 USUALL_TIM_CH4_PIN;
  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_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_SetBits(GPIOA,GPIO_Pin_5);
}
void USUALL_TIM_Mode_Config(uint16_t CCR1_Val,uint16_t CCR2_Val,uint16_t CCR3_Val,uint16_t CCR4_Val)
{
    // 开启定时器时钟,即内部时钟CK_INT=72M
    USUALL_TIM_APBxClock_FUN(USUALL_TIM_CLK,ENABLE);
    /*--------------------时基结构体初始化-------------------------*/
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

    // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
    TIM_TimeBaseStructure.TIM_Period=USUALL_TIM_PERIOD;    //100
    // 驱动CNT计数器的时钟 = Fck_int/(psc+1)
    TIM_TimeBaseStructure.TIM_Prescaler= USUALL_TIM_PSC;    //19
    // 时钟分频因子 ,配置死区时间时需要用到
//    TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;        
    // 计数器计数模式,设置为向上计数
    TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;        
    // 重复计数器的值,没用到不用管
    TIM_TimeBaseStructure.TIM_RepetitionCounter=0;    
    // 初始化定时器
    TIM_TimeBaseInit(USUALL_TIM, &TIM_TimeBaseStructure);
    
     
    /*--------------------输出比较结构体初始化-------------------*/    
// 占空比配置
        
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    // 配置为PWM模式1
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
    // 输出使能
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    // 互补输出不使能
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; 
    // 输出通道电平极性配置
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
        
        
// 设置通道1占空比大小        
    TIM_OCInitStructure.TIM_Pulse = CCR1_Val;    
    TIM_OC1Init(USUALL_TIM, &TIM_OCInitStructure);
    TIM_OC1PreloadConfig(USUALL_TIM, TIM_OCPreload_Enable);

    // 设置通道2占空比大小        
    TIM_OCInitStructure.TIM_Pulse = CCR2_Val;    
    TIM_OC2Init(USUALL_TIM, &TIM_OCInitStructure);
    TIM_OC2PreloadConfig(USUALL_TIM, TIM_OCPreload_Enable);
    
    // 设置通道3占空比大小        
    TIM_OCInitStructure.TIM_Pulse = CCR3_Val;    
    TIM_OC3Init(USUALL_TIM, &TIM_OCInitStructure);
    TIM_OC3PreloadConfig(USUALL_TIM, TIM_OCPreload_Enable);
    
    // 设置通道4占空比大小        
    TIM_OCInitStructure.TIM_Pulse = CCR4_Val;    
    TIM_OC4Init(USUALL_TIM, &TIM_OCInitStructure);
    TIM_OC4PreloadConfig(USUALL_TIM, TIM_OCPreload_Enable);
    TIM_ITConfig(USUALL_TIM,TIM_IT_Update,ENABLE);
    // 使能计数器
    TIM_Cmd(USUALL_TIM, ENABLE);    
//    TIM_CtrlPWMOutputs();启动或暂停输出PWM,
    
}
static void USUALL_TIM_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure; 
    // 设置中断组为0
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);        
        // 设置中断来源
    NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn ;    
        // 设置主优先级为 0
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;     
      // 设置抢占优先级为3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;    
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void TIM5_IRQHandler (void)
{
if ( TIM_GetITStatus( USUALL_TIM, TIM_IT_Update) != RESET ) 
    {
        count_pwm++;
        
        TIM_ClearITPendingBit(USUALL_TIM , TIM_FLAG_Update);
    }
}
void BUJIN_MOTer(void)
{
    count_pwm=0;
    USUALL_TIM_GPIO_Config();
    USUALL_TIM_Mode_Config(50,50,50,50);
    USUALL_TIM_NVIC_Config();

}

extern uint16_t count_pwm;
    
int main(void)
{
    LED_config();
    USART_Config();
    key_config();
    
    while ( 1 )
    {

        if (1)    //按键调速
        {
                if(key_san(key2_port,key2_pin)==key_on)
                    {
                        LED_RED;
                        BUJIN_MOTer();        
                        GPIO_SetBits(GPIOA,GPIO_Pin_5);
                    }
                    if ( (count_pwm==6400) &(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5)))
                        {
                            count_pwm=0;
                            TIM_Cmd(USUALL_TIM, DISABLE); 
                        
                            LED_WHITE;
                        }
                        if ( (count_pwm==3200 )&(~GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5)))
                        {
                            count_pwm=0;
                            TIM_Cmd(USUALL_TIM, DISABLE); 
                            
                            LED_WHITE;
                        }
                if(key_san(key1_port,key1_pin)==key_on)
                {
                    LED_BLUE;
                    BUJIN_MOTer();
                    GPIO_ResetBits(GPIOA,GPIO_Pin_5);
                }
        }
    }
}
```代码,请勿粘贴截图 

连接图如下:
![img](https://img-mid.csdnimg.cn/release/static/image/mid/ask/295969149366123.JPG "#left")

1.关闭开发板电源,再打开开发板电源,这个时候程序已经重新开始跑了。
2.关闭驱动器电源,这个时候开发板还有电,如果程序不能够很好的处理电机掉线问题,估计程序就跑飞出bug了。
3.建议看一下闭环控制是不是有问题,包括电机数据采集等涉及电机控制部分的变量和数据。

驱动器意外断电可能让驱动器进入了保护或者休眠状态,启动器重新上电后能复位一下驱动芯片最好,不然的话就一起上电。

根据您提供的代码和连接图,我注意到您正在使用定时器TIM5来驱动步进电机,并通过定时器中断来计数脉冲。我还注意到您将步进电机驱动器连接到GPIOA的Pin 5引脚。

根据您的描述,电机在上电后无法稳定运转,并且关掉驱动器电源再启动后,电机也无法受控制。这可能涉及到电源和GPIO引脚的初始化以及步进电机驱动器的操作。

以下是几个可能的问题和建议的解决方案:

1、GPIO引脚配置:请确保在初始化GPIO引脚时,将其配置为正确的模式和状态。对于Pin 5引脚,您当前将其配置为推挽输出模式(GPIO_Mode_Out_OD),但步进电机驱动器一般需要使用开漏输出模式。请尝试将GPIO模式配置为GPIO_Mode_Out_PP。

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

2、电源问题:确保步进电机驱动器和开发板之间的共地连接良好,且电源稳定。检查电源供应是否满足电机和驱动器的要求,以及电源供应的稳定性。还请确保开发板和驱动器的地线连接正确,以避免信号干扰或地回路问题。

3、中断处理函数:在中断处理函数TIM5_IRQHandler()中,您需要清除TIM的中断标志位,以便下一次中断可以触发。确保您使用了正确的标志位。

TIM_ClearITPendingBit(USUALL_TIM, TIM_IT_Update);

4、中断优先级:请确保您正确配置了中断优先级,并与其他中断优先级进行适当的调整。根据您的代码,您设置了中断优先级组为NVIC_PriorityGroup_0,并将中断优先级设置为0和3,这取决于您的需求和其他中断的优先级设置。

5、正确的计数器设置:请检查步进电机驱动器的配置和工作模式是否正确。确保步进电机驱动器的步进模式、旋转方向等设置正确。根据您的代码,我无法确定CCR1_Val、CCR2_Val、CCR3_Val和CCR4_Val的值是否正确设置。