STM32??编码器测速原理及STM32编码器模式

发布时间:2021-09-23 19:04:57

1. 编码器概述

编码器是一种将角位移或者角速度转换成一连串电数字脉冲的旋转式传感 器,我们可以通过编码器测量到底位移或者速度信息。编码器从输出数据类型上 分,可以分为增量式编码器和绝对式编码器。


从编码器检测原理上来分,还可以分为光学式、磁式、感应式、电容式。常 见的是光电编码器(光学式)和霍尔编码器(磁式)。


2. 编码器原理

光电编码器是一种通过光电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器。光电编码器是由光码盘和光电检测装置组成。光码盘是在一 定直径的圆板上等分地开通若干个长方形孔。由于光电码盘与电动机同轴,电动机旋转时,检测装置检测输出若干脉冲信号,为判断转向,一般输出两组存在一 定相位差的方波信号。


霍尔编码器是一种通过磁电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器。霍尔编码器是由霍尔码盘和霍尔元件组成。霍尔码盘是在一 定直径的圆板上等分地布置有不同的磁极。霍尔码盘与电动机同轴,电动机旋转时,霍尔元件检测输出若干脉冲信号,为判断转向,一般输出两组存在一定相位差的方波信号。


可以看到两种原理的编码器目的都是获取 AB 相输出的方波信号,其使用方法也是一样,下面是一个简单的示意图。


3. 编码器接线说明

具体到我们的编码器电机,我们可以看看电机编码器的实物。


4. 编码器软件四倍频技术

下面我们说一下编码器倍频的原理。为了提高大家下面学*的兴趣,我们先明确,这是一项实用的技术,可以真正地把编码器的精度提升 4 倍。作用可类比 于单反相机的光学变焦,而并非牺牲清晰度来放大图像的数码变焦。OK,先看看下面编码器输出的波形图。
这里,我们是通过软件的方法实现四倍频。首先可以看到上图编码器输出的AB 相波形,正常情况下我们使用 M 法测速的时候,会通过测量单位时间内 A 相输出的脉冲数来得到速度信息。常规的方法,我们只测量 A 相(或 B 相)的上升 沿或者下降沿,也就是上图中对应的数字 1234 中的某一个,这样就只能计数 3次。而四倍频的方法是测量 A 相和 B 相编码器的上升沿和下降沿。这样在同样的 时间内,可以计数 12 次(3 个 1234 的循环)。这就是软件四倍频的原理。


5. STM32编码器模式

在STM32中,编码器使用的是定时器接口,通过数据手册可知,定时器1,2,3,4,5和8有编码器的功能,而其他没有。编码器输入信号TI1,TI2经过输入滤波,边沿检测产生TI1FP1,TI2FP2接到编码器模块,通过配置编码器的工作模式,即可以对编码器进行正向/反向计数。

STM32编码器有三种工作模式,其中模式三即为上文中提到的四倍频模式。

在使用编码器模式时需要注意以下几点:


编码器有个转速上限,超过这个上限是不能正常工作的,这个是硬件的限制,原则上线数越多转速就越低,这点在选型时要注意。定时器初始化好以后,任何时候CNT寄存器的值就是编码器的位置信息,正转他会加反转他会减这部分是不需要软件干预的,初始化时给的TIM_Period 值应该是码盘整圈的刻度值,在减溢出会自动修正为这个数.加超过此数值就回0.计数值偶尔也会有出错误的情况,一圈多计一个或少计一个数都是很正常的特别是转速比较高的时候尤其明显,有个绝对位置信号做修正是很有必要的.绝对位置信号不需要一定在零位置点,收到这个信号就将CNT修正为一个固定的数值即可.
6. STM32编码器模式例程

此例程用于初始化定时器2和定时器3为编码器模式,得到小车底盘上两个直流电机的运转速度。


#.c文件
#include "encoder.h"

/**************************************************************************
* 函数功能:把TIM2初始化为编码器接口模式
*
* 入口参数:无
*
* 返 回 值:无
**************************************************************************/
void Encoder_Init_TIM2(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定时器2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);//使能PA PB端口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //端口配置 PA15
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //端口配置 PB3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB

TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器
TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //设定计数器自动重装值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//边沿计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //初始化定时器2

TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3

TIM_ICStructInit(&TIM_ICInitStructure); //把TIM_ICInitStruct 中的每一个参数按缺省值填入
TIM_ICInitStructure.TIM_ICFilter = 10; //设置滤波器长度
TIM_ICInit(TIM2, &TIM_ICInitStructure);//根据 TIM_ICInitStruct 的参数初始化外设 TIMx

TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新标志位
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//使能定时器中断

TIM_SetCounter(TIM2,0);
TIM_Cmd(TIM2, ENABLE); //使能定时器2
}

/**************************************************************************
函数功能:把TIM3初始化为编码器接口模式
入口参数:无
返回 值:无
**************************************************************************/
void Encoder_Init_TIM3(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能定时器3的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PA端口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //端口配置 PA6 PA7
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA

TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器
TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //设定计数器自动重装值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//边沿计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化定时器3

TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12,TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3(TIM_ICPolarity_Rising或者TIM_ICPolarity_Falling效果相同,都是4倍频)

TIM_ICStructInit(&TIM_ICInitStructure); //把TIM_ICInitStruct 中的每一个参数按缺省值填入
TIM_ICInitStructure.TIM_ICFilter = 10; //设置滤波器长度
TIM_ICInit(TIM3, &TIM_ICInitStructure);//根据 TIM_ICInitStruct 的参数初始化外设 TIMx

TIM_ClearFlag(TIM3, TIM_FLAG_Update);//清除TIM的更新标志位
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);//使能定时器中断
TIM_SetCounter(TIM3,0);
TIM_Cmd(TIM3, ENABLE); //使能定时器
}

/**************************************************************************
函数功能:单位时间读取编码器A计数
入口参数:无
返回 值:计数值
**************************************************************************/
float Read_EncoderA(void)
{
int Encoder_TIM = 0;
float Speed = 0.0;
Encoder_TIM= (short)TIM2 -> CNT;
TIM2 -> CNT=0;
return -Encoder_TIM;
}
/**************************************************************************
函数功能:单位时间读取编码器B计数
入口参数:无
返回 值:计数值
**************************************************************************/
float Read_EncoderB(void)
{
int Encoder_TIM = 0;
float Speed = 0.0;
Encoder_TIM= (short)TIM3 -> CNT;
TIM3 -> CNT=0;
return Encoder_TIM;
}

/**************************************************************************
* 函数功能:TIM2中断服务函数
*
* 入口参数:无
*
* 返 回 值:无
**************************************************************************/
void TIM2_IRQHandler(void)
{
if(TIM2->SR&0X0001)//溢出中断
{
}
TIM2->SR&=~(1<<0);//清除中断标志位
}


/**************************************************************************
* 函数功能:TIM3中断服务函数
*
* 入口参数:无
*
* 返 回 值:无
**************************************************************************/
void TIM3_IRQHandler(void)
{
if(TIM3->SR&0X0001)//溢出中断
{
}
TIM3->SR&=~(1<<0);//清除中断标志位
}


#.h文件
#define __ENCODER_H
#include
#include "init.h" //include了所有需要的头文件
#define ENCODER_TIM_PERIOD (u16)(65535) //不可大于65535 因为F103的定时器是16位的。

void Encoder_Init_TIM2(void);
void Encoder_Init_TIM3(void);

float Read_EncoderA(void);
float Read_EncoderB(void);

void TIM2_IRQHandler(void);
void TIM3_IRQHandler(void);

#endif

相关文档

  • 比较文学论文
  • 县工商局副局长述职述廉报告范文
  • 报错:Unknown custom element: swiper-slide did you register the component correctly?
  • 幼儿园大班优秀语言教案《冰糖葫芦》含反思
  • 汉英翻译_汉英广告语的双关修辞及其作用
  • 关于大队委竞选的演讲稿怎么写
  • 用牛奶去黑眼圈的方法是什么
  • [MySQL 5.6] Innodb后台线程之master线程
  • 手机看黄网后变卡怎么办
  • 《黑色党徒》观后感1000字
  • 现代简欧设计理念之简欧客厅效果图
  • HttpClient 加载本地证书发送请求
  • Fast.ai:指标是一把双刃剑,用不好就成了垃圾食品自助站
  • 科目二曲线行车技巧解析
  • 娃认人娘掉发是真的吗哺乳期妈妈掉头发怎么办
  • 羊肚菌的功效_羊肚菌图片
  • 手机短信祝福语集锦
  • 校园食品中毒常识
  • 渗透测试之hackme2
  • 2020年甘肃口腔助理医师实践技能考试准考证打印(已开通)
  • 意大利面好吃吗是什么口味的
  • 名人宽容的故事精选
  • 什么是观摩课
  • 新鲜牛肉煎牛排怎样才好吃
  • 假期游记作文
  • 同桌的你现代抒情散文
  • 以龟和狗为题目的作文
  • 名校失节与公平失落 失节事大
  • 生产班组长个人简历范文
  • SQL Server数据库关系图中,此数据库没有有效所有者......的两种解决办法
  • 猜你喜欢

    电脑版