打印
[应用相关]

STM32电子齿轮实现方法试验

[复制链接]
3795|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhuyjgh|  楼主 | 2014-5-22 14:56 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 zhuyjgh 于 2014-5-22 14:58 编辑

最近几天一直在关注运动控制器的事,纠结这个电子齿轮是怎么实现的,就用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
}

沙发
mmuuss586| | 2014-5-22 16:26 | 只看该作者
具体不是很清楚;
手摇的那种电子齿轮???带刻度的?

使用特权

评论回复
板凳
wallace_tsou| | 2014-5-22 17:25 | 只看该作者
使用TIM1->PSC去算輸出脈波數,數目到了要關閉TIM1,不然再送下去,位置就錯了。

使用特权

评论回复
地板
zhuyjgh|  楼主 | 2014-5-26 18:30 | 只看该作者
mmuuss586 发表于 2014-5-22 16:26
具体不是很清楚;
手摇的那种电子齿轮???带刻度的?

手摇的电子齿轮什么意思啊?没见过啊,我说的是运动控制器、伺服驱动器的电子齿轮比。

使用特权

评论回复
5
zhuyjgh|  楼主 | 2014-5-26 18:31 | 只看该作者
wallace_tsou 发表于 2014-5-22 17:25
使用TIM1->PSC去算輸出脈波數,數目到了要關閉TIM1,不然再送下去,位置就錯了。 ...

哦,这样是比较好,谢谢提醒啊,
不知道别人说用FPGA是不是也是同样的实现原理呢?

使用特权

评论回复
6
mmuuss586| | 2014-5-26 19:00 | 只看该作者
zhuyjgh 发表于 2014-5-26 18:30
手摇的电子齿轮什么意思啊?没见过啊,我说的是运动控制器、伺服驱动器的电子齿轮比。 ...

哦,那个类似于步进的细分

使用特权

评论回复
7
wallace_tsou| | 2014-5-27 09:23 | 只看该作者
FPGA的話會使用DDA(Digital differential analyzer) 去實現脈波輸出。以脈波數做一回授控制去追。
而DDA只需要增量值去產生輸出脈波且精度高。和MCU控制方式不太相同。
不過使用TIM1->PSC加上回授控制其實也可以。只是精度差一些。

使用特权

评论回复
8
zhuyjgh|  楼主 | 2014-5-27 16:59 | 只看该作者
wallace_tsou 发表于 2014-5-27 09:23
FPGA的話會使用DDA(Digital differential analyzer) 去實現脈波輸出。以脈波數做一回授控制去追。
而DDA只 ...

谢谢指点,不过对回授控制还是不太明白。我是这样理解的,使用脉波数做回授控制就是要去控制DDA的累积速度,也就是控制DDA时钟脉波的频率。编码器输入脉波和DDA产生的一路脉波进行比较,然后再进行PID运算,这样达到控制输出频率及输出脉波数一致的目的。
感觉很复杂,还是思路不对?

使用特权

评论回复
9
wallace_tsou| | 2014-5-27 17:10 | 只看该作者
是這樣沒有錯,FPGA和MCU都是用 PID回授。
只是不用DDA的話,因為差值小,運算成數值跳動大。
而MCU的Timer對頻率的輸出,其單位跳格也較大。
為了穩定,只能使用較大的取樣時間,所以反應會較慢。

使用特权

评论回复
10
zhuyjgh|  楼主 | 2014-5-28 16:49 | 只看该作者
wallace_tsou 发表于 2014-5-27 17:10
是這樣沒有錯,FPGA和MCU都是用 PID回授。
只是不用DDA的話,因為差值小,運算成數值跳動大。
而MCU的Timer ...

您的回复对我帮助很大,十分感谢。
看来简单的功能要想做好还是要做很多事情的。

使用特权

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

本版积分规则

13

主题

336

帖子

0

粉丝