STM32编码器速度采集


电机编码器测速

实验效果

效果图

1.目的

电机转动时,测出电机的实时转速,进而对电机进行控制。

2.简介

以光电式增量编码器为例:

原理:

•Encoder Interface 编码器接口

•编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度

•每个高级定时器和通用定时器都拥有1个编码器接口

•两个输入引脚借用了输入捕获的通道1和通道2

图片中有一个圆盘,右边是个小红外灯(发光元件),一直照向左边的光敏元件。这个圆盘上有一圈齿,光线正好可以透过小齿的空隙照到光敏元件,随着圆盘 的转动,小齿转走了,又马上挡住光,紧接着下一个小齿… 按照上面的说法,圆盘一直转,光敏元件就能得到一个如下图 A 相那样的波, 通过统计波形所有高电平的数量我们就能算出来这个盘一共转了多少刻度。并 且 也 能 推 算 出 盘 转 到 了 什 么 位 置 。 并且,通过实时计算波的频率,我们就可以测速了。 但是这样有个问题,不知道盘转的方向,正转反转都是这样一个波。 解决方法就是在小齿的内圈再刻上一圈与外圈错开 90°的小齿!就可以得到下 图 B 相的波形,这样就可分辨方向了。

image

A 和 B 两组脉冲相位差 90º,可以判断出旋转方向和旋转速度。

image

通过观察上面 AB 相的波我们发现,圆盘向某个方向一直旋转,AB 两相就是这四个状态周而复始。

image

其次我们看一下编码器的线数:

我们使用的电机后面带的霍尔编码器就是 13ppr,也就是 13 线。也就是电机每转一圈 A 或 B 相的脉冲数。 也就是电机转一圈 A 相和 B 相就分别有 13 个脉冲。

  • GMR编码器 500ppr
  • 霍尔编码器 13ppr

如果我们购买的电机为减速电机的话,那么他会有一个减速比;

一圈脉冲总数=13*减速比(减速比:电机输出转速/电机输入转速)

例:减速比为1:50,则一圈脉冲总数=13*50=650。

通过上述分析,用 STM32 的正交解码库函数就能搞定编码器。

image

TIM_EncoderMode_TI1 代表仅 TI1 计数;

TIM_EncoderMode_TI2 代表仅 TI2 计数;

TIM_EncoderMode_TI12 代表 TI1 TI2 都计数。

TI1 就是输入通道 1,就是编码器 A 相,TI2 同理。

image

image

image

3.代码

流程图:

image

void Encoder_Init(void)
{
    //开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	//TIM3  CH1、CH2
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//定时器配置
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	//输入捕获
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICStructInit(&TIM_ICInitStructure);    //给结构体附上初值
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;   //通道一
	TIM_ICInitStructure.TIM_ICFilter = 0xF;    //滤波抗噪音(0-0xf值越大效果越好)
	TIM_ICInit(TIM3, &TIM_ICInitStructure);    //写入结构体
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	
	TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);   //TI12极性配置
	
	TIM_Cmd(TIM3, ENABLE);
}

//得到CNT当前值
int16_t Encoder_Get(void)
{
	int16_t Temp;
	Temp = TIM_GetCounter(TIM3);
	TIM_SetCounter(TIM3, 0);
	return Temp;
}


//main

int16_t Speed;

int main(void)
{
	OLED_Init();
	Timer_Init();
	Encoder_Init();
	
	OLED_ShowString(1, 1, "Speed:");
	
	while (1)
	{
		OLED_ShowSignedNum(1, 7, Speed, 5);
	}
}

//TIM定时器可以有效给speed赋值,有两种选择:1.进中断次数多不溢出,且速度延迟低(当前)   2.溢出
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		Speed = Encoder_Get();
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

这样就可以对电机进行速度测量了。


文章作者: 机电22级宋科成
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 机电22级宋科成 !
评论
  目录