问一个stm32控制伺服电机的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了问一个stm32控制伺服电机的问题相关的知识,希望对你有一定的参考价值。

stm32控制机械臂,实现直线插补,就是每20ms插补一个点,然后控制伺服电机运行这段直线,现在是可以算出stm32该发出的脉冲数,但是这个脉冲数该怎么分配呢,伺服电机工作在位置控制模式,是要经过上升,匀速,减速的过程吗,这样理解的话,没插补一个点就要控制伺服电机经过上升,匀速,下降这样一个过程,该怎么编程实现呢

我怎么看也是一个轴啊?一个轴哪来的插补这一说啊。另外伺服可以直接设置好加减速时间,甚至是S型加减速或是梯形加减速。追问

机械臂是四轴的,伺服电机工作在位置控制模式,加减速得自己编程实现
就是插补计算这个时间是不发脉冲的,然后下个20ms发送脉冲,这20ms发送的脉冲数是计算出来的,然后该怎么分配

追答

也就是 你4个轴做直线插补?一般直线插补都是2轴的啊

追问

恩 我用是四轴,就是不知道该怎么处理插补之后该怎么处理电机运行这段,就是电机加速匀速减速这段,希望指点

追答

你用STM32什么控制?PWM输出?

参考技术A 用S曲线控制。上网找一个步进电机的S曲线计算软件就OK了追问

每个插补线段结束时 伺服电机速度都变成零吗

追答

肯定的,电机还有速度,电机肯定还在走,如何保证位置?所以,每走一步,电机都是从0到高速再回到0速。

stm32控制电机

一、总体思路

      使用端口GPIOA来连接电机,所以给GPIOA编程就可以控制电机。使用系统时钟SysTick来周期性的给电机发送脉冲。用四个按钮来控制需要发送脉冲的个数,每个按钮被按下就设置给电机发送脉冲的个数,如果上一次给电机发送的脉冲没有发送完成,这次按钮发送的脉冲将不被响应。
 

二、GPIOA端口的设置

      由于需要控制两个电机,所以将GPIOA端口的1,2,3号引脚与电机0相连(分别控制电机的使能,旋转方向和脉冲),GPIOA的4,5,6号引脚与电机1相连。具体对端口的初始化代码为:
复制代码
GPIO_InitTypeDef GPIO_InitStruct;  
//开启电机0外设时钟
DJ_EnablePeriphClock_0();
//初始化电机0
GPIO_InitStruct.GPIO_Pin = DJ_EN_0 | DJ_DR_0 | DJ_MC_0;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(DJ_GPIO_0, &GPIO_InitStruct);
//设置电机0的初始化状态
DJ_DisEnable(DJ_GPIO_0, DJ_EN_0);  //关闭电机0
复制代码
上面的代码是对与电机0连接的引脚的初始化,电机1的初始化是一样的,只是引脚不同了。从上面的代码可以看到引脚的输出模式是推挽的(为了做Debug),实际应该使用开漏的,由于我们要给电机输入5V的高电平,所以我们应该在外部接一个上拉电阻,电源为5V。
 

三、SysTick设置

     SysTick是一个系统定时器,系统的滴答是可以配置的,在控制电机的程序中我们将系统滴答设置为100us,理论上可以将系统滴答设置为1/72000000s,由于系统的时钟为72MHz。每个脉冲间隔为5个滴答。也就是说每隔500us发送一个脉冲,脉冲周期为1ms。
     设置系统滴答通过宏:
     #define TICK 10000  //100us一个滴答
     实际的配置是通过下面代码:
    SysTick_Config(SystemCoreClock / TICK);
    为了实现每隔5个系统滴答发送一个脉冲,定义了两个全局变量TimingDelay和TimingLoad ,可以通过函数Timer来设置这个变量的值:
      void Timer(__IO uint32_t nTime)
      {
        TimingDelay = nTime;
        TimingLoad = nTime;
      }
     TimingDelay表示当前距离发送下一个脉冲还需要等待的滴答数,TimingLoad 表示发送脉冲的间隔,如果每个脉冲间隔为5个滴答,则TimingLoad =5。 这样在系统时钟的每次中断代码中将TimingDelay减1,当TimingDelay为0时就向电机发送脉冲(将对应电机脉冲的引脚的值变反就可以了),然后重新将TimingLoad赋值给TimingDelay来准备下一个脉冲的发送。具体代码如下:
复制代码
if (TimingDelay)
        TimingDelay--;
    else
    {
        TimingDelay = TimingLoad; 
        if (dj_GetMc())  //判断是否还需要发送脉冲
        {
            printfd("\\r\\nsend %dth pulse, %d", dj_GetMc(), 1 - GPIO_ReadOutputDataBit (DJ_GPIO_0, DJ_MC_0));  //用于调试
            DJ_IO(1 - GPIO_ReadOutputDataBit (DJ_GPIO_0, DJ_MC_0), DJ_GPIO_0, DJ_MC_0);   //用于发送脉冲
            dj_DesMc();  
        }
        else
            SysTick_Shutdown();  //关闭系统时钟
    }
复制代码
      dj_GetMc函数和dj_DesMc函数分别获得全局变量dj_McCount的值和对该全局变量减1,这个全局变量代表总共需要发送几个脉冲。正如开头说的,按下一个键就设置需要发送的脉冲数,当脉冲发完了,就关闭系统定时器。
 

四、按键设置

     使用ARM板自带的WAKEUP,TAMPER,USER1,USER2四个键来配置需要发送脉冲的个数,它们分别配置为需要发送2,20,200,2000个脉冲。我们通过中断的方式来检查哪个键被按下了。配置将四个按键与EXTI相连,让EXTI产生中断到中断控制器NVIC。首先需要配置NVIC的抢占优先级和响应优先级,直接调用库函数就可以了:

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

然后是配置按键与EXTI相连,具体配置代码如下:
复制代码
static void NVIC_SetVector( IRQn_Type IRQn, uint8_t PreemptionPriority, uint8_t SubPriority)
{
     NVIC_InitTypeDef NVIC_InitStruct;     
     NVIC_InitStruct.NVIC_IRQChannel = IRQn;//EXTI0_IRQn | EXTI9_5_IRQn | EXTI3_IRQn |  EXTI15_10_IRQn;
     NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
     NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = PreemptionPriority;
     NVIC_InitStruct.NVIC_IRQChannelSubPriority = SubPriority;
     NVIC_Init(&NVIC_InitStruct);
}
//WAKEUP键
static void EXTI_PA0_Config(void)
{
     GPIO_InitTypeDef  GPIO_InitStruct;
     EXTI_InitTypeDef  EXTI_InitStruct;
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO |  RCC_APB2Periph_GPIOA, ENABLE);
     NVIC_SetVector(EXTI0_IRQn, 0, 0);  //配置NVIC
     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
     GPIO_Init(GPIOA, &GPIO_InitStruct);     
     GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);   //配置GPIOA_Pin0为EXTI0线
     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);
}
复制代码

     上面的代码显示了配置WAKEUP键,其它键也是同样的配置。当按下一个键时,对应的中断响应函数就会执行,我们在响应函数中判断全局变量dj_McCount是否为0,如果不为0,说明上一次按键的脉冲还没有发生完成,则直接退出中断响应函数;如果为0,说明当前没有在发生脉冲,则设置dj_McCount为2,开启系统定时器来发送脉冲。代码如下:
复制代码
//WAKEUP
void EXTI0_IRQHandler(void)
{    
    if (EXTI_GetFlagStatus(EXTI_Line0) != RESET)  //看是否产生了EXTI_Line0中断
    {
        printfd("\\r\\nexti0");
        if (dj_GetMc() == 0)
        {
            dj_SetMc(1);
            SysTick_Startup();
        }
        EXTI_ClearFlag(EXTI_Line0);  //清除中断标志位
    }
}
复制代码

 

源代码:http://pan.baidu.com/s/1uy6PK

以上是关于问一个stm32控制伺服电机的问题的主要内容,如果未能解决你的问题,请参考以下文章

42步进电机怎么用stm32控制加减速

STM32串口控制步进电机(原创)

stm32输出pwm,怎么控制直流电机的正反转?

STM32的PWM控制步进电机,怎么实现精确控制输出脉冲数

stm32控制电机

基于STM32闭环步进电机控制系统设计(仿真,程序,说明)