电机编码器测速
编码器(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位绝对编码器。
直流有刷电机参数:
然后生成代码
编码器是上升沿触发还是下降沿触发,还是双边沿触发,这个后面生成代码再改
- 关键代码解读
伪代码:
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);