打印
[控制方法]

STM32电子齿轮实现方法试验

[复制链接]
2128|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhuyjgh|  楼主 | 2014-5-22 15:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近几天一直在关注运动控制器的事,纠结这个电子齿轮是怎么实现的,就用STM32试了一下。
我的想法是捕获每个输入脉冲的周期,然后根据齿轮比计算输出脉冲的周期实现输出。测试程序贴在下面。其中用TIM2完成编码器四倍频的程序,同时捕获四倍频后单个脉冲的周期。TIM1实现通过比较输出的PWM模式1实现根据齿轮比换算后的脉冲输出。
我的编码器是600线,四倍频后是2400个脉冲每转,步进电机设定为1200步每转,这样为了编码器和步进电机同速度旋转,只要输出脉冲周期是输入脉冲周期的2倍就可以了,其他的齿轮比就是一个乘法,一个除法,计算也很快的。
目前的问题是,这样做速度基本可以说是同步了,但是位置并不能保证同步,不是严格意义上的电子齿轮。不知道现在的电子齿轮实际是怎么实现的,查了资料看应该是FPGA来实现,思路是这样吗?如果是我也试一下。希望大家多多指点。

#define PPSIN (GPIOA->IDR & 0x03)

u32 tempTIMIndex;
u32 tempTIM[4];

uint32_t ppState;
uint32_t ppState2;
const uint32_t ppStateTab[4] = {0x02, 0x00, 0x03, 0x01};
//const uint32_t ppStateTab[4] = {0x01, 0x03, 0x00, 0x02};

//编码器输入配置
void SSINInit(void)
{
   RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;//使能GPIOA的时钟
  RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;//使能TIM2的时钟

  GPIOA->ODR |= GPIO_ODR_ODR0 + GPIO_ODR_ODR1;
   GPIOA->CRL &= ~((GPIO_CRL_MODE0_0 * mode_reset) + (GPIO_CRL_MODE1_0 * mode_reset));
   GPIOA->CRL |= ((GPIO_CRL_MODE0_0 * pull_in) + (GPIO_CRL_MODE1_0 * pull_in));

   //时基模式
  TIM2->CNT = 0;
   TIM2->PSC = 0;
   TIM2->ARR = 0xffff;
   TIM2->CR1 = TIM_CR1_CKD_1+TIM_CR1_URS;//边沿向上计数,选择更新源

  //信号输入、滤波
  TIM2->CCMR1 =  TIM_CCMR1_CC1S_0//IC1映射在TI1
                  //+ TIM_CCMR1_IC1F_3//采样频率及滤波长度
                 //+ TIM_CCMR1_IC1F_2
                  //+ TIM_CCMR1_IC1F_1
                  //+ TIM_CCMR1_IC1F_0
                  + TIM_CCMR1_CC2S_0//IC2映射在IT2
                  //+ TIM_CCMR1_IC2F_3//采样频率及滤波长度
                 //+ TIM_CCMR1_IC2F_2
                  //+ TIM_CCMR1_IC2F_1
                  //+ TIM_CCMR1_IC2F_0
                  ;
   TIM2->CCER =  TIM_CCER_CC1E//捕获
                + TIM_CCER_CC2E
                 //+ TIM_CCER_CC1P
                 //+ TIM_CCER_CC2P
                 ;
   TIM2->SMCR =  TIM_SMCR_TS_0//配置从模式为复位模式
                + TIM_SMCR_TS_2
                 + TIM_SMCR_SMS_2
                 ;
   //配置中断
  NVIC_SetPriority(TIM2_IRQn, 1);
   NVIC_EnableIRQ(TIM2_IRQn);

   //初始化并开启
  TIM2->EGR |= TIM_EGR_UG;//初始化缓冲寄存器
  TIM2->SR &= ~(TIM_SR_CC1IF + TIM_SR_CC2IF + TIM_SR_UIF);//清除CC1 CC2捕获中断标志、更新中断标志
  TIM2->DIER |= (TIM_DIER_CC1IE + TIM_DIER_CC2IE + TIM_DIER_UIE);//开启CC1 CC2捕获中断、更新中断
  TIM2->CR1 |= TIM_CR1_CEN;//开启TIM2
}


//编码器输入中断
void TIM2_IRQHandler(void)
{
   if (TIM2->SR & TIM_SR_CC1IF)
   {
     TIM2->SR &= ~TIM_SR_CC1IF;
     ppState = PPSIN;
     if (ppStateTab[ppState] == ppState2)
     {
       Y10 = !Y10;
       ppState2 = ppState;
       TIM2->CCER ^=  TIM_CCER_CC1P;//切换边沿
      TIM2->SMCR &=  ~TIM_SMCR_TS_0;//切换复位信号
      TIM2->SMCR |=  TIM_SMCR_TS_1;
      
       //totalCounter = ((TIM2OverCounter << 16) + TIM2->CCR1) / 72;
       //TIM2OverCounter = 0;
      
       tempTIMIndex++;
       if (tempTIMIndex > 3)
       {
         tempTIMIndex = 0;
       }
       tempTIM[tempTIMIndex] = TIM2->CCR1;
       totalCounter = (tempTIM[0] + tempTIM[1] + tempTIM[2] + tempTIM[3]) >> 2;
      
       TIM1->ARR = totalCounter << 1;
       TIM1->CCR1 = totalCounter;
     }
   }
   if (TIM2->SR & TIM_SR_CC2IF)
   {
     TIM2->SR &= ~TIM_SR_CC2IF;
     ppState = PPSIN;
     if (ppStateTab[ppState] == ppState2)
     {
       Y10 = !Y10;
       ppState2 = ppState;
       TIM2->CCER ^=  TIM_CCER_CC2P;//切换边沿
      TIM2->SMCR &=  ~TIM_SMCR_TS_1;//切换复位信号
      TIM2->SMCR |=  TIM_SMCR_TS_0;
     
       //totalCounter = ((TIM2OverCounter << 16) + TIM2->CCR2) / 72;   
       //TIM2OverCounter = 0;
      
       tempTIMIndex++;
       if (tempTIMIndex > 3)
       {
         tempTIMIndex = 0;
       }
       tempTIM[tempTIMIndex] = TIM2->CCR2;
       totalCounter = (tempTIM[0] + tempTIM[1] + tempTIM[2] + tempTIM[3]) >> 2;
      
       TIM1->ARR = totalCounter << 1;
       TIM1->CCR1 = totalCounter;
     }
   }
   if (TIM2->SR & TIM_SR_UIF)
   {
     TIM2->SR &= ~TIM_SR_UIF;
     TIM2OverCounter++;
   }
}


//脉冲输出配置
void PWMTimerInit(void)
{
   RCC->APB2ENR|= RCC_APB2ENR_IOPAEN//使能GPIOA的时钟
                 +RCC_APB2ENR_TIM1EN;//使能TIM1的时钟
  //端口配置
  GPIOA->CRH&=~(GPIO_CRH_MODE8_0*mode_reset);
   GPIOA->CRH|= (GPIO_CRH_MODE8_0*afio_pp_10);//PA8 TIM1CH1 复用10M输出

  //时基模式
  TIM1->CNT = 0;
   TIM1->PSC = 0;//
   TIM1->ARR = 0xffff;//
   TIM1->RCR = 0;
   TIM1->CR1 = TIM_CR1_ARPE;//使用预装入,边沿向上计数

  //比较模式
  TIM1->CCR1 = 0x8000;//脉冲低电平宽度,,值加18宽度加1uS
   TIM1->CCMR1 = TIM_CCMR1_OC1PE//OC1使能比较寄存器预加载
                +(TIM_CCMR1_OC1M_2+TIM_CCMR1_OC1M_1);//OC1使用PWM模式1

   //使能输出
  TIM1->BDTR = TIM_BDTR_MOE;//TIM1主输出使能
  TIM1->CCER = TIM_CCER_CC1E;//OC1输出使能

  //配置中断
  //NVIC_SetPriority(TIM1_UP_IRQn,15);
   //NVIC_EnableIRQ(TIM1_UP_IRQn);

   //初始化并开启
  TIM1->EGR |= TIM_EGR_UG;//初始化缓冲寄存器
  //TIM1->SR &= ~TIM_SR_UIF;//清更新中断标志
  //TIM1->DIER |= TIM_DIER_UIE;//开启更新中断
  TIM1->CR1 |= TIM_CR1_CEN;//开启TIM1
}

相关帖子

沙发
受不了了| | 2014-5-23 12:02 | 只看该作者
步进电机也用电子齿轮比啊,高级

使用特权

评论回复
板凳
zhuyjgh|  楼主 | 2014-5-26 18:35 | 只看该作者
受不了了 发表于 2014-5-23 12:02
步进电机也用电子齿轮比啊,高级

什么电机没关系的,伺服步进都可以,就是不知道怎么实现的。

使用特权

评论回复
地板
受不了了| | 2014-5-27 12:19 | 只看该作者
以前用安川∑Ⅱ伺服,设置时没注意65535和65536的区别,每圈少1/65536个脉冲的误差,转上一天那玩意还真的给累积出来了:D

使用特权

评论回复
5
zhuyjgh|  楼主 | 2014-5-27 16:42 | 只看该作者
受不了了 发表于 2014-5-27 12:19
以前用安川∑Ⅱ伺服,设置时没注意65535和65536的区别,每圈少1/65536个脉冲的误差,转上一天那玩意还真的 ...

呵呵,这个比较牛,能做到这个精度肯定不是用我现在的方法~~

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

13

主题

336

帖子

0

粉丝