slamugv使用说明--5.电机编码测速

电机编码器测速
编码器(encoder)是将信号(如比特流)或数据进行编制、转换为可用以通讯、传输和存储的信号形式的设备。编码器把角位移或直线位移转换成电信号
编码器分类及原理:
按编码器原理分增量式和绝对式
增量式编码器:增量式编码器是将位移转换成周期性的电信号,再把这个电信号转变成计数脉冲,用脉冲的个数表示位移的大小。
增量式编码器通常有A,B,Z三相,A,B相之间延迟1/4的周期(90度)的脉冲输出,根据延时的关系可以区别正反转。而且通过A,B相的上升沿和下降沿可以进行2倍频和4倍频,用来提高精度,Z相为单圈脉冲,我们的直流有刷电机比较便宜,所以没带Z相,所以我就不解释了。想知道的可以自行了解

绝对式编码器:绝对编码器光码盘上有许多道刻线,每道刻线依次以2线、4线、8线、16线。。。。。。编排,这样,

在编码器的每一个位置,通过读取每道刻线的通、暗,获得一组从2的零次方到2的n-1次方的唯一的2进制编码(格雷码),这就称为n位绝对编码器。
直流有刷电机参数:

  • 减速比30
  • 空载电流<400ma
  • 空载转速415rpm
  • 额定扭矩3.9Kg.cm
  • 额定转速350rpm
  • 额定电流 <1.9A
  • 最大扭矩30kg.cm
  • 停转电流11.0A
    1.编码器测速cube配置教程
    定时器有编码器模式直接配置
    ![在这里插入图片描述在这里插入图片描述(https://img-blog.csdnimg.cn/20200410221231830.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTQwNTQ2Ng==,size_16,color_FFFFFF,t_70)
    我之前的定义都定义好了编码器接口对应的引脚和定时器,直接配置就行

然后生成代码
编码器是上升沿触发还是下降沿触发,还是双边沿触发,这个后面生成代码再改

  • 寄存器讲解
    选择编码器接口模式时,如果计数器仅在 TI2 边沿处计数,在 TIMx_SMCR 寄存器中写入SMS=001;如果计数器仅在 TI1 边沿处计数,写入 SMS=010;如果计数器在 TI1 和 TI2 边沿处均计数,则写入 SMS=011。通过编程 TIMx_CCER 寄存器的 CC1P 和 CC2P 位,选择 TI1 和 TI2 极性。如果需要,还可对输入滤波器进行编程。在这里插入图片描述
    编码器定时器计数的是cnt,debug可以看到,后面我会抽空做一篇关于mdk debug的小技巧
    1. 关键代码解读
      伪代码:
      1. 初始化编码器GPiO引脚
      2. 初始化编码器定时器
      3. 通过编码器触发中断计数
      4. 通过读编码器定时器计算小车轮子的转速

```c

```c
/* 私有变量 ------------------------------------------------------------------*/
__IO uint16_t time_count=0;         // 时间计数,每1ms增加一(与滴答定时器频率有关)

__IO int32_t CaptureNumber[4]={0};       // 输入捕获数



#define ENCODER     16    // 编码器线数
#define SPEEDRATIO  30   // 电机减速比
#define PPR         (SPEEDRATIO*ENCODER*4) // Pulse/r 每圈可捕获的脉冲数

TIM_HandleTypeDef    TIM1_Encoder;
TIM_HandleTypeDef    TIM2_Encoder;
TIM_HandleTypeDef    TIM3_Encoder;
TIM_HandleTypeDef    TIM4_Encoder;

			float Speed1 	= 	0;
			float Speed2	= 	0;	
			float Speed3	= 	0;	
			float Speed4	= 	0;		

__IO int16_t OverflowCount[4] = {0};//定时器溢出次数



void Encoder_Tim1_Init(void)
{
	TIM_Encoder_InitTypeDef EncoderConfig;


	TIM_MasterConfigTypeDef sMasterConfig;
	
//  __HAL_RCC_TIM1_CLK_ENABLE();
 
		
  
	/* 定时器基础配置 */
	TIM1_Encoder.Instance = TIM1;
  TIM1_Encoder.Init.Prescaler = 0;//预分频系数
  TIM1_Encoder.Init.CounterMode = TIM_COUNTERMODE_UP;//定时器计数方式
  TIM1_Encoder.Init.Period = 0xFFFF;//定时器周期
  TIM1_Encoder.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;//时钟分频
  TIM1_Encoder.Init.RepetitionCounter = 0;//重复计数器
  /* 定时器编码器模式配置 */
  EncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12;
	 /* 定时器编码器IC1配置 */
  EncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
  EncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  EncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  EncoderConfig.IC1Filter = 0;
	/* 定时器编码器IC2配置 */
  EncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
  EncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  EncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  EncoderConfig.IC2Filter = 0;
	
	__HAL_TIM_SET_COUNTER(&TIM1_Encoder,0);
	  /* 初始化编码器接口 */
  HAL_TIM_Encoder_Init(&TIM1_Encoder, &EncoderConfig);

  //
  __HAL_TIM_CLEAR_IT(&TIM1_Encoder, TIM_IT_UPDATE);  //清除更新中断标志位
  __HAL_TIM_URS_ENABLE(&TIM1_Encoder);               //仅允许计数器溢出才产生更新中断
  __HAL_TIM_ENABLE_IT(&TIM1_Encoder,TIM_IT_UPDATE);  //使能更新中断
  
  HAL_NVIC_SetPriority(ENCODER_TIM1_IRQn, 1, 3);
  HAL_NVIC_EnableIRQ(ENCODER_TIM1_IRQn);
 
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
	HAL_TIMEx_MasterConfigSynchronization(&TIM1_Encoder, &sMasterConfig);

}
void Encoder_Tim2_Init(void)
{
 
//	 __HAL_RCC_TIM2_CLK_ENABLE();
	TIM_Encoder_InitTypeDef EncoderConfig;


//	TIM_MasterConfigTypeDef sMasterConfig;
	
  /* 定时器基础配置 */
  TIM2_Encoder.Instance = TIM2;
  TIM2_Encoder.Init.Prescaler = 0;
  TIM2_Encoder.Init.CounterMode = TIM_COUNTERMODE_UP;
  TIM2_Encoder.Init.Period = 0xFFFF;
	
	/* 定时器编码器模式配置 */
  TIM2_Encoder.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
	 /* 定时器编码器IC1配置 */
  EncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12;
  EncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
  EncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  EncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  EncoderConfig.IC1Filter = 0;
	 /* 定时器编码器IC2配置 */
  EncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
  EncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  EncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  EncoderConfig.IC2Filter = 0;
	
	__HAL_TIM_SET_COUNTER(&TIM2_Encoder,0);
	
	  /* 初始化编码器接口 */
  HAL_TIM_Encoder_Init(&TIM2_Encoder, &EncoderConfig);
 
  //
  __HAL_TIM_CLEAR_IT(&TIM2_Encoder, TIM_IT_UPDATE);  //清除更新中断标志位
  __HAL_TIM_URS_ENABLE(&TIM2_Encoder);               //仅允许计数器溢出才产生更新中断
  __HAL_TIM_ENABLE_IT(&TIM2_Encoder,TIM_IT_UPDATE);  //使能更新中断
  
  HAL_NVIC_SetPriority(ENCODER_TIM2_IRQn, 1, 3);
  HAL_NVIC_EnableIRQ(ENCODER_TIM2_IRQn);




}
void Encoder_Tim3_Init(void)
{
  
//	__HAL_RCC_TIM3_CLK_ENABLE();
	TIM_Encoder_InitTypeDef EncoderConfig;



	/* 定时器基础配置 */
  TIM3_Encoder.Instance = TIM3;
  TIM3_Encoder.Init.Prescaler = 0;
  TIM3_Encoder.Init.CounterMode = TIM_COUNTERMODE_UP;
  TIM3_Encoder.Init.Period = 0xFFFF;
	TIM3_Encoder.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
	
  /* 定时器编码器模式配置 */
  EncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12;
	
	/* 定时器编码器IC1配置 */
  EncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
  EncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  EncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  EncoderConfig.IC1Filter = 0;
	
	 /* 定时器编码器IC2配置 */
  EncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
  EncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  EncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  EncoderConfig.IC2Filter = 0;
	
		__HAL_TIM_SET_COUNTER(&TIM3_Encoder,0);
		  /* 初始化编码器接口 */
  HAL_TIM_Encoder_Init(&TIM3_Encoder, &EncoderConfig);
  
	__HAL_TIM_CLEAR_IT(&TIM3_Encoder, TIM_IT_UPDATE);  //清除更新中断标志位
  __HAL_TIM_URS_ENABLE(&TIM3_Encoder);               //仅允许计数器溢出才产生更新中断
  __HAL_TIM_ENABLE_IT(&TIM3_Encoder,TIM_IT_UPDATE);  //使能更新中断
  
  HAL_NVIC_SetPriority(ENCODER_TIM3_IRQn, 1, 3);
  HAL_NVIC_EnableIRQ(ENCODER_TIM3_IRQn);
	


}
void Encoder_Tim4_Init(void)
{ 
//	__HAL_RCC_TIM4_CLK_ENABLE();	
	TIM_Encoder_InitTypeDef EncoderConfig;


//	TIM_MasterConfigTypeDef sMasterConfig;
	/* 定时器基础配置 */

	/* 定时器基础配置 */
	TIM4_Encoder.Instance = TIM4;
  TIM4_Encoder.Init.Prescaler = 0;
  TIM4_Encoder.Init.CounterMode = TIM_COUNTERMODE_UP;
  TIM4_Encoder.Init.Period = 0xFFFF;
  TIM4_Encoder.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
	/* 定时器编码器模式配置 */
  EncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12;
	  /* 定时器编码器IC1配置 */
  EncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
  EncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  EncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  EncoderConfig.IC1Filter = 0;
	 /* 定时器编码器IC2配置 */
  EncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
  EncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  EncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  EncoderConfig.IC2Filter = 0;
	
	__HAL_TIM_SET_COUNTER(&TIM4_Encoder,0);
	  /* 初始化编码器接口 */
  HAL_TIM_Encoder_Init(&TIM4_Encoder, &EncoderConfig);
 
  //
  __HAL_TIM_CLEAR_IT(&TIM4_Encoder, TIM_IT_UPDATE);  //清除更新中断标志位
  __HAL_TIM_URS_ENABLE(&TIM4_Encoder);               //仅允许计数器溢出才产生更新中断
  __HAL_TIM_ENABLE_IT(&TIM4_Encoder,TIM_IT_UPDATE);  //使能更新中断
  
  HAL_NVIC_SetPriority(ENCODER_TIM4_IRQn, 1, 3);
  HAL_NVIC_EnableIRQ(ENCODER_TIM4_IRQn);
 

	
 }

 /**
  * 函数功能: 基本定时器硬件初始化配置
  * 输入参数: htim_base:基本定时器句柄类型指针
  * 返 回 值: 无
  * 说    明: 该函数被HAL库内部调用
  */

void HAL_TIM_Encoder_MspInit(TIM_HandleTypeDef* htim_base)
{  
	
	 GPIO_InitTypeDef  GPIO_InitStruct ;
	
	 if(htim_base->Instance == ENCODER_TIM1)
  {
		__HAL_RCC_TIM1_CLK_ENABLE();
  
    __HAL_RCC_GPIOE_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**TIM1 GPIO Configuration    
    PE9     ------> TIM1_CH1
    PA9     ------> TIM1_CH2 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;

    GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);	
	}
	
	 else if(htim_base->Instance == ENCODER_TIM2)
  {
		__HAL_RCC_TIM2_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**TIM2 GPIO Configuration    
    PA0     ------> TIM2_CH1
    PA1     ------> TIM2_CH2 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0; //PA0
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_1; //PA1
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	}
	
	 else if(htim_base->Instance == ENCODER_TIM3)
  {
		__HAL_RCC_TIM3_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**TIM3 GPIO Configuration    
    PA6     ------> TIM3_CH1
    PA7     ------> TIM3_CH2 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	}
	 else if(htim_base->Instance == ENCODER_TIM4)
  {
     __HAL_RCC_TIM4_CLK_ENABLE();
  
    __HAL_RCC_GPIOD_CLK_ENABLE();
    /**TIM4 GPIO Configuration    
    PD12     ------> TIM4_CH1
    PD13     ------> TIM4_CH2 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13; //PD12 ,PD13
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM4;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

   
	}
}

 /**
  * 函数功能: 基本定时器硬件反初始化配置
  * 输入参数: htim_base:基本定时器句柄类型指针
  * 返 回 值: 无
  * 说    明: 该函数被HAL库内部调用
  */
void HAL_TIM_Encoder_MspDeInit(TIM_HandleTypeDef* tim_encoderHandle)
{

  if(tim_encoderHandle->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspDeInit 0 */

  /* USER CODE END TIM1_MspDeInit 0 */
      /* 基本定时器外设时钟禁用 */
    __HAL_RCC_TIM1_CLK_DISABLE();
  
    /**TIM1 GPIO Configuration    
    PE9     ------> TIM1_CH1
    PA9     ------> TIM1_CH2 
    */
    HAL_GPIO_DeInit(GPIOE, GPIO_PIN_9);

    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9);

  }
  else if(tim_encoderHandle->Instance==TIM2)
  {
       /* 基本定时器外设时钟禁用 */
    __HAL_RCC_TIM2_CLK_DISABLE();
  
    /**TIM2 GPIO Configuration    
    PA5     ------> TIM2_CH1
    PB3     ------> TIM2_CH2 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5);

    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_3);

 
  }
  else if(tim_encoderHandle->Instance==TIM3)
  {
       /* 基本定时器外设时钟禁用 */
    __HAL_RCC_TIM3_CLK_DISABLE();
  
    /**TIM2 GPIO Configuration    
    PA6     ------> TIM3_CH1
    PA7     ------> TIM3_CH2 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_6);

    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_7);

 
  }
  else if(tim_encoderHandle->Instance==TIM4)
  {
  /* USER CODE BEGIN TIM4_MspDeInit 0 */

  /* USER CODE END TIM4_MspDeInit 0 */
    /* 基本定时器外设时钟禁用 */
    __HAL_RCC_TIM4_CLK_DISABLE();
  
    /**TIM4 GPIO Configuration    
    PD12     ------> TIM4_CH1
    PD13     ------> TIM4_CH2 
    */
    HAL_GPIO_DeInit(GPIOD, GPIO_PIN_12);
		HAL_GPIO_DeInit(GPIOD, GPIO_PIN_13);

  
  }
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	OSIntEnter();
  if(htim == &TIM1_Encoder)
  {
    if(__HAL_TIM_IS_TIM_COUNTING_DOWN(htim))
      OverflowCount[Encoder_1]--;       //向下计数溢出
    else
      OverflowCount[Encoder_1]++;       //向上计数溢出
  }
	
  else if(htim == &TIM2_Encoder)
  {
    if(__HAL_TIM_IS_TIM_COUNTING_DOWN(htim))
      OverflowCount[Encoder_2]--;       //向下计数溢出
    else
      OverflowCount[Encoder_2]++;       //向上计数溢出
  }
	
   else if(htim == &TIM3_Encoder)
  {
    if(__HAL_TIM_IS_TIM_COUNTING_DOWN(htim))
      OverflowCount[Encoder_3]--;       //向下计数溢出
    else
      OverflowCount[Encoder_3]++;       //向上计数溢出
  }
	 else if(htim == &TIM4_Encoder)
  {
    if(__HAL_TIM_IS_TIM_COUNTING_DOWN(htim))
      OverflowCount[Encoder_4]--;       //向下计数溢出
    else
      OverflowCount[Encoder_4]++;       //向上计数溢出
  }
	OSIntExit();
}

/**************************************************************************
函数功能:单位时间读取编码器计数
入口参数:定时器
返回  值:速度值
**************************************************************************/


float Read_Encoder(uint16_t TIMX)
{ 
	    int Speed;
	    switch(TIMX)
			{
				case 1:
			CaptureNumber[Encoder_1] = ( int16_t )__HAL_TIM_GET_COUNTER(&TIM1_Encoder)+OverflowCount[Encoder_1]*65535; 
	    Speed = (float)CaptureNumber[Encoder_1]/PPR;
			__HAL_TIM_SET_COUNTER(&TIM1_Encoder,0);
				break ;
				case 2:
			CaptureNumber[Encoder_2] = ( int16_t )__HAL_TIM_GET_COUNTER(&TIM2_Encoder)+OverflowCount[Encoder_2]*65535;
			Speed = (float)CaptureNumber[Encoder_2]/PPR;
			__HAL_TIM_SET_COUNTER(&TIM2_Encoder,0); 
				break ;
				case 3:
			CaptureNumber[Encoder_3] = ( int16_t )__HAL_TIM_GET_COUNTER(&TIM3_Encoder)+OverflowCount[Encoder_3]*65535;
			Speed = (float)CaptureNumber[Encoder_3]/PPR;
			__HAL_TIM_SET_COUNTER(&TIM3_Encoder,0);
				break ;
				case 4:
			CaptureNumber[Encoder_4] = ( int16_t )__HAL_TIM_GET_COUNTER(&TIM4_Encoder)+OverflowCount[Encoder_4]*65535;
			Speed = (float)CaptureNumber[Encoder_4]/PPR;
			__HAL_TIM_SET_COUNTER(&TIM4_Encoder,0); 
				break ;
			}
			return Speed ;

} 

```c
在主函数里添加这函数,可以用printf函数打印
	int Encoder_A,Encoder_B,Encoder_C,Encoder_D;          //编码器的脉冲计数
    Encoder_A= Read_Encoder(1);
    Encoder_A= Read_Encoder(2);
	Encoder_C= Read_Encoder(3);
	Encoder_D= Read_Encoder(4);
	printf("Encoder_A%d",Encoder_A);
    printf("Encoder_B%d",Encoder_B);
    printf("Encoder_C%d",Encoder_C);
    printf("Encoder_D%d",Encoder_D);

发布了8 篇原创文章 · 获赞 1 · 访问量 823

猜你喜欢

转载自blog.csdn.net/weixin_41405466/article/details/105443614