打印

STM32编码测速问题

[复制链接]
12830|23
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wenwenyuanyuan|  楼主 | 2013-10-24 09:36 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
请问有谁做过相关的STM32F103XXX的正交编码测速?
问题是这样的:要求定时器配置为正交编码模式,在TI1和TI2两个通道同时对A,B两路增量式的360线码盘的上升沿输入捕获,没10ms产生一次中断后计算出此时的电机转速。
有哪个高手做过的,请共享一下例程好吧?再次非常感谢。
沙发
wenwenyuanyuan|  楼主 | 2013-10-24 12:18 | 只看该作者
我的这个问题很难吗?为什么每次我发表问题都看不到高手回帖呢??

使用特权

评论回复
板凳
huzi2099| | 2013-10-24 14:09 | 只看该作者
wenwenyuanyuan 发表于 2013-10-24 12:18
我的这个问题很难吗?为什么每次我发表问题都看不到高手回帖呢??

取个时间差就是转速了.

使用特权

评论回复
地板
wenwenyuanyuan|  楼主 | 2013-10-24 14:44 | 只看该作者
huzi2099 发表于 2013-10-24 14:09
取个时间差就是转速了.

那样测出来的转速不精确

使用特权

评论回复
5
huzi2099| | 2013-10-24 14:45 | 只看该作者
wenwenyuanyuan 发表于 2013-10-24 14:44
那样测出来的转速不精确

为何?那你又想怎?

使用特权

评论回复
6
wenwenyuanyuan|  楼主 | 2013-10-24 15:26 | 只看该作者
huzi2099 发表于 2013-10-24 14:45
为何?那你又想怎?

我想要利用M/T来测速的,不知道你有没有ST官方的正交编码程序和解释?我这里下载了官方的例程,就是有几点不明白

使用特权

评论回复
7
trumpxp| | 2013-10-24 16:06 | 只看该作者
兄弟   这一块   我不是很了解   帮你顶一个吧   呼唤一下版主   他应该能够给你一点指导意见

使用特权

评论回复
8
weifengdq| | 2013-10-24 16:36 | 只看该作者
貌似是200线的能读出来800 1000线的编码器能读出来4000 测的是一个编码器脉冲的时钟周期 STM32 72M 所以测的很准确 这是传统定时器没有的 与传统的M/T法有所差别 比较准确

使用特权

评论回复
9
weifengdq| | 2013-10-24 16:37 | 只看该作者
/******************** (C) COPYRIGHT 2007 STMicroelectronics ********************
* File Name          : stm32f10x_encoder.c
* Author             : IMS Systems Lab  
* Date First Issued  : 21/11/07
* Description        : This file contains the software implementation for the
*                      encoder unit
********************************************************************************
* History:
* 21/11/07 v1.0
********************************************************************************
* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
//#include <stm32f10x_lib.h>
#include "encoder.h"
#include "lcd1602.h"
#include "usart.h"

/* Private variables ---------------------------------------------------------*/
s16 hPrevious_angle, hSpeed_Buffer[SPEED_BUFFER_SIZE], hRot_Speed;
//static s16 hPrevious_angle, hSpeed_Buffer[SPEED_BUFFER_SIZE];
static u8 bSpeed_Buffer_Index = 0;
static volatile u16 hEncoder_Timer_Overflow;

#define TRUE 1
#define FALSE 0
static unsigned char bIs_First_Measurement = TRUE;

/*******************************************************************************
* Function Name  : ENC_Init
* Description    : General Purpose Timer x set-up for encoder speed/position
*                  sensors
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void ENC_Init(void)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_ICInitTypeDef TIM_ICInitStructure;
  
/* Encoder unit connected to TIM3, 4X mode */   
  GPIO_InitTypeDef GPIO_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* TIM3 clock source enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
  /* Enable GPIOA, clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  
  GPIO_StructInit(&GPIO_InitStructure);
  /* Configure PA.06,07 as encoder input */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
  /* Enable the TIM3 Update Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = TIMx_PRE_EMPTION_PRIORITY;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = TIMx_SUB_PRIORITY;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  /* Timer configuration in Encoder mode */
  TIM_DeInit(ENCODER_TIMER);
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  
  TIM_TimeBaseStructure.TIM_Prescaler = 0x0;  // No prescaling         //72M捕获?
  TIM_TimeBaseStructure.TIM_Period = (4*ENCODER_PPR)-1;  
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   
  TIM_TimeBaseInit(ENCODER_TIMER, &TIM_TimeBaseStructure);

  TIM_EncoderInterfaceConfig(ENCODER_TIMER, TIM_EncoderMode_TI12,
                             TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
  TIM_ICStructInit(&TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_ICFilter = ICx_FILTER;
  TIM_ICInit(ENCODER_TIMER, &TIM_ICInitStructure);
  
// Clear all pending interrupts
  TIM_ClearFlag(ENCODER_TIMER, TIM_FLAG_Update);
  TIM_ITConfig(ENCODER_TIMER, TIM_IT_Update, ENABLE);
  //Reset counter
  TIM2->CNT = COUNTER_RESET;
  
  ENC_Clear_Speed_Buffer();
  
  TIM_Cmd(ENCODER_TIMER, ENABLE);  
}

/*******************************************************************************
* Function Name  : ENC_Get_Electrical_Angle
* Description    : Returns the absolute electrical Rotor angle
* Input          : None
* Output         : None
* Return         : Rotor electrical angle: 0 -> 0 degrees,
*                                          S16_MAX-> 180 degrees,
*                                          S16_MIN-> -180 degrees                  
*******************************************************************************/
s16 ENC_Get_Electrical_Angle(void)
{
  s32 temp;
  
  temp = (s32)(TIM_GetCounter(ENCODER_TIMER)) * (s32)(4294967295 / (4*ENCODER_PPR));
  return((s16)(temp/65536)); // s16 result
}

/*******************************************************************************
* Function Name  : ENC_Clear_Speed_Buffer
* Description    : Clear speed buffer used for average speed calculation  
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void ENC_Clear_Speed_Buffer(void)
{   
  u32 i;

  for (i=0;i<SPEED_BUFFER_SIZE;i++)
  {
    hSpeed_Buffer[i] = 0;
  }
  bIs_First_Measurement = TRUE;
}

/*******************************************************************************
* Function Name  : ENC_Calc_Rot_Speed
* Description    : Compute return latest speed measurement
* Input          : None
* Output         : s16
* Return         : Return the speed in 0.1 Hz resolution.                    
*******************************************************************************/
s16 ENC_Calc_Rot_Speed(void)
{   
  s32 wDelta_angle;
  u16 hEnc_Timer_Overflow_sample_one, hEnc_Timer_Overflow_sample_two;
  u16 hCurrent_angle_sample_one, hCurrent_angle_sample_two;
  signed long long temp;
  s16 haux;
  
  if (!bIs_First_Measurement)
  {
    // 1st reading of overflow counter   
    hEnc_Timer_Overflow_sample_one = hEncoder_Timer_Overflow;
    // 1st reading of encoder timer counter
    hCurrent_angle_sample_one = ENCODER_TIMER->CNT;
    // 2nd reading of overflow counter
    hEnc_Timer_Overflow_sample_two = hEncoder_Timer_Overflow;  
    // 2nd reading of encoder timer counter
    hCurrent_angle_sample_two = ENCODER_TIMER->CNT;      

    // Reset hEncoder_Timer_Overflow and read the counter value for the next
    // measurement
    hEncoder_Timer_Overflow = 0;
    haux = ENCODER_TIMER->CNT;   
   
    if (hEncoder_Timer_Overflow != 0)
    {
      haux = ENCODER_TIMER->CNT;
      hEncoder_Timer_Overflow = 0;            
    }
     
    if (hEnc_Timer_Overflow_sample_one != hEnc_Timer_Overflow_sample_two)
    { //Compare sample 1 & 2 and check if an overflow has been generated right
      //after the reading of encoder timer. If yes, copy sample 2 result in
      //sample 1 for next process
      hCurrent_angle_sample_one = hCurrent_angle_sample_two;
      hEnc_Timer_Overflow_sample_one = hEnc_Timer_Overflow_sample_two;
    }
   
    if ( (ENCODER_TIMER->CR1 & TIM_CounterMode_Down) == TIM_CounterMode_Down)  
    {// encoder timer down-counting
      wDelta_angle = (s32)(hCurrent_angle_sample_one - hPrevious_angle -
                    (hEnc_Timer_Overflow_sample_one) * (4*ENCODER_PPR));
    }
    else  
    {//encoder timer up-counting
      wDelta_angle = (s32)(hCurrent_angle_sample_one - hPrevious_angle +
                    (hEnc_Timer_Overflow_sample_one) * (4*ENCODER_PPR));
    }
   
    // speed computation as delta angle * 1/(speed sempling time)
    temp = (signed long long)(wDelta_angle * SPEED_SAMPLING_FREQ);
    temp *= 10;  // 0.1 Hz resolution
    temp /= (4*ENCODER_PPR);
        
  } //is first measurement, discard it
  else
  {
    bIs_First_Measurement = FALSE;
    temp = 0;
    hEncoder_Timer_Overflow = 0;
    haux = ENCODER_TIMER->CNT;      
    // Check if Encoder_Timer_Overflow is still zero. In case an overflow IT
    // occured it resets overflow counter and wPWM_Counter_Angular_Velocity
    if (hEncoder_Timer_Overflow != 0)
    {
      haux = ENCODER_TIMER->CNT;
      hEncoder_Timer_Overflow = 0;            
    }
  }
  
  hPrevious_angle = haux;  

  return((s16) temp);
}

/*******************************************************************************
* Function Name  : ENC_Calc_Average_Speed
* Description    : Compute smoothed motor speed based on last SPEED_BUFFER_SIZE
                   informations and store it variable  
* Input          : None
* Output         : s16
* Return         : Return rotor speed in 0.1 Hz resolution. This routine
                   will return the average mechanical speed of the motor.
*******************************************************************************/
void ENC_Calc_Average_Speed(void)
{   
  s32 wtemp,wtemp_1=0;
  u32 i;
  
//  wtemp = ENC_Calc_Rot_Speed();
//        
///* Compute the average of the read speeds */  
//  hSpeed_Buffer[bSpeed_Buffer_Index] = (s16)wtemp;
//  bSpeed_Buffer_Index++;
//  
//  if (bSpeed_Buffer_Index == SPEED_BUFFER_SIZE)
//  {
//    bSpeed_Buffer_Index = 0;
//  }

//  wtemp=0;

//  for (i=0;i<SPEED_BUFFER_SIZE;i++)
//  {
//    wtemp += hSpeed_Buffer[i];
//  }
//  wtemp /= SPEED_BUFFER_SIZE;


                for (i=0;i<SPEED_BUFFER_SIZE;i++)
                {
                  if (bSpeed_Buffer_Index == SPEED_BUFFER_SIZE)
                        {
                                bSpeed_Buffer_Index = 0;
                        }

                        wtemp = ENC_Calc_Rot_Speed();
                        hSpeed_Buffer[bSpeed_Buffer_Index] = (s16)wtemp;
                        bSpeed_Buffer_Index++;
                        wtemp_1 += wtemp;       
                }       
  wtemp_1 /= SPEED_BUFFER_SIZE;
  
  hRot_Speed = ((s16)(wtemp_1));
}

/*******************************************************************************
* Function Name  : LCD_Display
* Description    : This function handles the display of timer counter, theta and
                    electronical frequency:
                    theta --- resolution: 1 degree;
                    electronical frequency --- resolution: 0.1Hz.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
//void LCD_Display(DisplayType DisplayStatus)
//{
//  u16 hValue;
//  s16 Theta;
//  s16 hSpeed;
//  char *pstr;
//  
//  switch (DisplayStatus)
//  {
//    case DISPLAY_TIMCNT:
//      hValue = TIM_GetCounter(ENCODER_TIMER);
//      LCD_ShowNum(0,0,(hValue),5);  
//                        printf("%d,",hValue);
//    break;
//   
//    case DISPLAY_THETA:      
//      Theta = ENC_Get_Electrical_Angle()*360/65535;        //U16_MAX;
//      if (Theta < 0)
//      {
//        hValue = (u16)(-Theta);
////        pstr = int2char(hValue);
//        *pstr = '-';
//      }
//      else
//      {
//        hValue = (u16)Theta;
////        pstr = int2char(hValue);
//        if (hValue != 0) *pstr = '+';  
//      }
//     LCD_ShowChar(0,8,*pstr);
//                LCD_ShowNum(0,9,hValue,5);
//    break;
//   
//    default:
//      hSpeed = hRot_Speed;
//      if (hSpeed < 0)
//      {
//        hValue = (u16)(-hSpeed);
////        pstr = int2char(hValue);
//        *pstr = '-';
//      }
//      else
//      {
//        hValue = (u16)hSpeed;
////        pstr = int2char(hValue);
//        if (hValue != 0) *pstr = '+';  
//      }
//                        LCD_ShowChar(0,8,*pstr);
//      LCD_ShowNum(1,0,*pstr,5);
//    break;
//  }
//}

/*******************************************************************************
* Function Name  : TIM2_IRQHandler
* Description    : This function handles TIMx Update interrupt request.
                   Encoder unit connected to TIM2
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void TIM3_IRQHandler(void)
{  
  /* Clear the interrupt pending flag */
  TIM_ClearFlag(ENCODER_TIMER, TIM_FLAG_Update);
  
  if (hEncoder_Timer_Overflow != 65535)  
  {
   hEncoder_Timer_Overflow++;
  }
}





//寄存器版本
/******************* (C) COPYRIGHT 2007 STMicroelectronics *****END OF FILE****/


//#include "encoder.h"

//void Encoder_Init(void)
//{
//        /* TIM3 clock source enable */
//        RCC->APB1ENR|=1<<1;       //TIM3时钟使能
//        /* Enable GPIOA, clock */
//        RCC->APB2ENR|=1<<2;    //使能PORTA时钟

//        /* Configure PA.06,07 as encoder input */
//        GPIOA->CRL&=0XF0FFFFFF;//PA6
//        GPIOA->CRL|=0X04000000;//浮空输入
//        GPIOA->CRL&=0X0FFFFFFF;//PA7
//        GPIOA->CRL|=0X40000000;//浮空输入

//        /* Enable the TIM3 Update Interrupt */
//        //这两个东东要同时设置才可以使用中断
//        TIM3->DIER|=1<<0;   //允许更新中断                               
//        TIM3->DIER|=1<<6;   //允许触发中断
//        MY_NVIC_Init(1,3,TIM3_IRQChannel,2);

//        /* Timer configuration in Encoder mode */
//        TIM3->PSC = 0x0;//预分频器
//        TIM3->ARR = ENCODER_TIM_PERIOD-1;//设定计数器自动重装值
//        TIM3->CR1 &=~(3<<8);// 选择时钟分频:不分频
//        TIM3->CR1 &=~(3<<5);// 选择计数模式:边沿对齐模式
//               
//        TIM3->CCMR1 |= 1<<0; //CC1S='01' IC1FP1映射到TI1
//        TIM3->CCMR1 |= 1<<8; //CC2S='01' IC2FP2映射到TI2
//        TIM3->CCER &= ~(1<<1);         //CC1P='0'         IC1FP1不反相,IC1FP1=TI1
//        TIM3->CCER &= ~(1<<5);         //CC2P='0'         IC2FP2不反相,IC2FP2=TI2
//        TIM3->CCMR1 |= 3<<4; //        IC1F='1000' 输入捕获1滤波器
//        TIM3->SMCR |= 3<<0;         //SMS='011' 所有的输入均在上升沿和下降沿有效
//        TIM3->CNT = COUNTER_RESET;
//        TIM3->CR1 |= 0x01;    //CEN=1,使能定时器
//}

使用特权

评论回复
10
weifengdq| | 2013-10-24 16:38 | 只看该作者
#ifndef __ENCODER_H__
#define __ENCODER_H__

#include "sys.h"

//void Encoder_Init(void);

//#endif

/******************** (C) COPYRIGHT 2007 STMicroelectronics ********************
* File Name          : stm32f10x_encoder.h
* Author             : IMS Systems Lab
* Date First Issued  : 21/11/07
* Description        : This file contains the software implementation for the
*                      encoder position and speed reading.
********************************************************************************
* History:
* 21/11/07 v1.0
********************************************************************************
* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/

/* Define to prevent recursive inclusion -------------------------------------*/


/* Private typedef -----------------------------------------------------------*/
typedef enum {DISPLAY_TIMCNT = 0,DISPLAY_THETA,DISPLAY_W} DisplayType;

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define ENCODER_TIMER   TIM3  // Encoder unit connected to TIM3
#define ENCODER_PPR           (u16)(200)   // number of pulses per revolution
#define SPEED_BUFFER_SIZE 2//8

#define COUNTER_RESET   (u16)0
#define ICx_FILTER      (u8) 6 // 6<-> 670nsec

#define TIMx_PRE_EMPTION_PRIORITY 1
#define TIMx_SUB_PRIORITY 0

#define SPEED_SAMPLING_FREQ (u16)(2000/(SPEED_SAMPLING_TIME+1))

extern s16 hRot_Speed;


/* Private functions ---------------------------------------------------------*/
s16 ENC_Calc_Rot_Speed(void);


/* Includes ------------------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define SPEED_SAMPLING_TIME  9     // (9+1)*500usec = 5msec

/* Exported functions ------------------------------------------------------- */
void ENC_Init(void);
s16 ENC_Get_Electrical_Angle(void);
void ENC_Clear_Speed_Buffer(void);
void ENC_Calc_Average_Speed(void);
//void LCD_Display(DisplayType DisplayStatus);
s16 ENC_Get_Speed(void);
void TIM3_IRQHandler(void);;

#endif  
/*__STM32F10x_ENCODER_H*/
/******************* (C) COPYRIGHT 2007 STMicroelectronics *****END OF FILE****/

使用特权

评论回复
11
weifengdq| | 2013-10-24 16:40 | 只看该作者
这是暑假参加电赛时(做的倒立摆)山寨的代码 当时用着很好用(放了放编译不通过了 某些地方有问题 你参考参考吧) 一个enconder.c 一个是encoder.h

使用特权

评论回复
12
huzi2099| | 2013-10-24 18:07 | 只看该作者
wenwenyuanyuan 发表于 2013-10-24 15:26
我想要利用M/T来测速的,不知道你有没有ST官方的正交编码程序和解释?我这里下载了官方的例程,就是有几 ...

哪里不明白?

使用特权

评论回复
13
huzi2099| | 2013-10-24 18:14 | 只看该作者
weifengdq 发表于 2013-10-24 16:36
貌似是200线的能读出来800 1000线的编码器能读出来4000 测的是一个编码器脉冲的时钟周期 STM32 72M 所以测 ...

上下沿都计数的模式是四倍

使用特权

评论回复
14
MCUWYL| | 2013-10-24 18:55 | 只看该作者
围观、、、

使用特权

评论回复
15
wenwenyuanyuan|  楼主 | 2013-10-25 07:52 | 只看该作者
有知道的请帮忙一下,不知道的请把它顶起来,让高手们看到!

使用特权

评论回复
16
wenwenyuanyuan|  楼主 | 2013-10-25 07:59 | 只看该作者
weifengdq 发表于 2013-10-24 16:37

你好!很感谢你的分享,但有一点我不太懂,就是void ENC_Init(void)这个函数中的倒数第三行程序“TIM2->CNT = COUNTER_REST”我想知道的是,我们的正交编码配置不是配置的是TIM3吗,为什么计数器清零清的是TIM2呢?应该是写成“TIM3->CNT = COUNTER_REST”才对吧?求指导

使用特权

评论回复
17
leebai_001| | 2013-10-25 08:19 | 只看该作者
STM32单片机原厂提供的代码,只能实现M法测速,测速闸门时间取决于查询周期,这在高速运行时没问题。M法不适合低速,如果需要控制电机在低速或极低速下运行,会有问题。

原厂单片机提供的测速方式是在TIM2上实现的,如果你需要更换定时器,自己需要把对应的定时器设计进行修改。

使用特权

评论回复
18
weifengdq| | 2013-10-25 12:49 | 只看该作者
wenwenyuanyuan 发表于 2013-10-25 07:59
你好!很感谢你的分享,但有一点我不太懂,就是void ENC_Init(void)这个函数中的倒数第三行程序“TIM2- ...

嗯 应该是我改错了 是TIM3 源代码给你 用的是MDK 4.72a编译的 或许某些地方还有类似的错误 仅供参考
http://pan.baidu.com/s/1ABZJD

使用特权

评论回复
评分
参与人数 1威望 +3 收起 理由
wenwenyuanyuan + 3 谢谢了!你的程序对我帮助很大。.
19
weifengdq| | 2013-10-25 12:57 | 只看该作者

使用特权

评论回复
20
wenwenyuanyuan|  楼主 | 2013-10-25 13:24 | 只看该作者
顺便问一句,为什么我在结贴的时候,总是弹出说“没有结贴权限”呢?求吧主解释下!

使用特权

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

本版积分规则

8

主题

56

帖子

0

粉丝