平衡车编码器
最近在开始研究平衡小车但在编码器的使用上就遇到了许多的麻烦,后来在网上查阅了众多资料和大佬的讲解,终于有一点明白。
首先,我使用得是电机自带的编码器。
这里介绍下编码器的原理。编码器的核心元器件是霍尔元件。霍尔元器件是一种基于霍尔效应的元器件,用它们可以检测磁场及其变化,可在各种与磁场有关的场合中使用。一般他有三个引脚,一个接VCC,一个接GND,另一个就是输出端。输入端的电压大小和磁场大小有关,N极越近输出电压越大。线性原件是就会产生电位的转变。
这里可以看一下B站一个视屏:我觉得真的挺生动形象的。霍尔元件的描述
霍尔编码器是由霍尔码盘和霍尔元件组成。霍尔码盘是在一 定直径的圆板上等分地布置有不同的磁极。霍尔码盘与电动机同轴,电动机旋转时,霍尔元件检测输出若干脉冲信号,为判断转向,一般输出两组存在一定相位差的方波信号。下面是示意图:
这里我们可以查看一下电机编码器的数据:车轮转一圈,电机输出260个脉冲(单个相位如A相),倍频后是1040(其实就是下文提到的stm32定时器的编码器模式下,可以同时不活上升沿和下降沿,所以26022=1040)。脉冲就是上图中的方波。如果我们可以在特定的时间内算出输出的脉冲数n,n除以260再除以时间,就是车轮的转速了。所以关键就在脉冲数的计算方面。
这时候就用到单片机了。一般来说电机上的编码器都自带上拉电阻,可以直接连接单片机的io口。单片机的处理方式分两种1.自带编码器接口的单片机如STM32,可以以直接用硬件技术2.没有编码器接口的单片机 可通过外部中断读取。我这里使用的是stm32F103RCT6(正点原子的mini板)。
方法1:M法,会通过测量单位时间内A相输出的脉冲数来得到速度信息。(这里可以使用stm32定时器的捕获模式,选择上升沿或下降沿,进行单位时间脉冲的计数。)方法2:4倍频法,会通过同时测量单位时间内A相和B相的上升沿和下降沿,1234为一组。相对于上种方法,精度提高了4倍。我们使用这种方法。
用stm32做编码器接口的好处是计数比较智能,容许接口出现抖动而不影响结果。而且配置的代码多,可以直接使用。所以下面就是stm32定时器做编码器接口的介绍。
选择编码器接口模式的方法是:如果计数器只在TI2的边沿计数,则置TIMx_SMCR寄存器中的 SMS=001;如果只在TI1边沿计数,则置SMS=010;如果计数器同时在TI1和TI2边沿计数,则 置SMS=011。通过设置TIMx_CCER寄存器中的CC1P和CC2P位,可以选择TI1和TI2极性;如果需要,还可以 对输入滤波器编程。根据两个输入信号的跳变顺序,产生了计数脉冲和方向信号。依据两个输入信号 的跳变顺序,计数器向上或向下计数,同时硬件对TIMx_CR1寄存器的DIR位进行相应的设置。 不管计数器是依靠TI1计数、依靠TI2计数或者同时依靠TI1和TI2计数,在任一输入端(TI1或者 TI2)的跳变都会重新计算DIR位。编码器接口模式基本上相当于使用了一个带有方向选择的外部时钟。这意味着计数器只在0到 TIMx_ARR寄存器的自动装载值之间连续计数(根据方向,或是0到ARR计数,或是ARR到0计 数)。所以在开始计数之前必须配置TIMx_ARR(一般配置到最大值);同样,捕获器、比较器、预分频器、重复计数 器、触发输出特性等仍工作如常。编码器模式和外部时钟模式2不兼容,因此不能同时操作。 在这个模式下,计数器依照增量编码器的速度和方向被自动的修改,因此计数器的内容始终指 示着编码器的位置。计数方向与相连的传感器旋转的方向对应。下表列出了所有可能的组合, 假设TI1和TI2不同时变换。
表1计数方向和编码器的关系。
一个外部的增量编码器可以直接与MCU连接而不需要外部接口逻辑。但是,一般会使用比较器 将编码器的差动输出转换到数字信号,这大大增加了抗噪声干扰能力。编码器输出的第三个信 号表示机械零点,可以把它连接到一个外部中断输入并触发一个计数器复位。 下图是一个计数器操作的实例,显示了计数信号的产生和方向控制。它还显示了当选择了双边 沿时,输入抖动是如何被抑制的;抖动可能会在传感器的位置靠近一个转换点时产生。在这个 例子中,我们假定配置如下:
● CC1S=’01’ (TIMx_CCMR1寄存器,IC1FP1映射到TI1)
● CC2S=’01’ (TIMx_CCMR2寄存器,IC2FP2映射到TI2)
● CC1P=’0’ (TIMx_CCER寄存器,IC1FP1不反相,IC1FP1=TI1)
● CC2P=’0’ (TIMx_CCER寄存器,IC2FP2不反相,IC2FP2=TI2)
● SMS=’011’ (TIMx_SMCR寄存器,所有的输入均在上升沿和下降沿有效).
● CEN=’1’ (TIMx_CR1寄存器,计数器使能)下图编码器模式下实例操作。
下面对于计数器的加减做一个说明:在上图中,观察到这和TI1和TI2的相对电平有关,这时就可以根据表一进行理解。
仅在TI1计数时 相对信号的电平其实就是TI2的电平(不考虑反向的情况)这样再看这张表就会比较容
易理解了。
在TI2为高电平的时候TI1为上升沿时脉冲计数减1,TI1位下降沿时脉冲计数加1
在TI2为低电平的时候TI1为上升沿时脉冲计数加1,TI1位下降沿时脉冲计数减1后面可以同理类推。
具体配置如下:
#include "timer.h"
#include "led.h"
void TIM3_Encoder_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
// NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/*- 正交编码器输入引脚 PA->6 PA->7 -*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*- TIM3编码器模式配置 -*/
//TIM_DeInit(TIM3);
TIM_TimeBaseStructure.TIM_Period = 65535;//计次数;
TIM_TimeBaseStructure.TIM_Prescaler = 0;//
TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1 ;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge);
//配置编码器模式触发源和极性双边沿检测 不知道可以看技术手册上面有介绍编码器模式
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_BothEdge; //上升沿捕获
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM_ICInitStructure.TIM_ICFilter = 0x01;//IC1F=0000 配置输入滤波器 不滤
//
TIM_ICInit(TIM3, &TIM_ICInitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
TIM_ClearFlag(TIM3, TIM_FLAG_Update);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_SetCounter(TIM3,0);
TIM_Cmd(TIM3, ENABLE); //启动TIM4定时器
}
int main(void)
{
u8 t;
int Encoder_TIM;
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//延时函数初始化
LED_Init(); //初始化与LED连接的硬件接口
uart_init(9600);
KEY_Init();
TIM3_Encoder_Init();
while(1)
{
Encoder_TIM=(short)TIM3 -> CNT;
t=KEY_Scan(1);
printf("%d ",Encoder_TIM);
if(t==KEY1_PRES)
{
TIM3 -> CNT=0;
}
}
}
工程文件,公众号:电子小陈陈,内回复“编码器”,即可获取。
最后,如果觉得写得还可以或有帮助的评论个1.如果文中有错误的地方也请指正。
`
`