个人网站制作手绘,免费发布招聘的网站,图片外链,壹搜网站建设这里写目录标题 起因一、电机及编码器的参数二、硬件三、接线四、驱动电机1、TB6612电机驱动2、定时器的PWM模式驱动电机 五、编码器测速1、定时器的编码器接口模式2、定时器编码器模式测速的原理3、编码器模式的配置4、编码器模式相关代码5、测速方法 六、相关问题以及解答1、… 这里写目录标题 起因一、电机及编码器的参数二、硬件三、接线四、驱动电机1、TB6612电机驱动2、定时器的PWM模式驱动电机 五、编码器测速1、定时器的编码器接口模式2、定时器编码器模式测速的原理3、编码器模式的配置4、编码器模式相关代码5、测速方法 六、相关问题以及解答1、编码器模式下的自动重装值ARR和预分频PSC应该如何设置2、如何判断正反转3、圈数如何计算4、转速如何计算5、为什么我的编码器没有输出获取到的脉冲数是0 七、测速硬件展示及测速现象八、总结九、大家可以参考参考链接1参考链接2参考链接3参考链接4 起因
最近在学习编码电机以及尝试使用编码电机测速。遇到了很多问题花费了很多时间在这里做一个记录对自己学习到的知识进行一个总结
找了很多资料看了很多视频这些太多了以至于让我不知道究竟哪一个是正确的今天看这个明天看这个导致自己的学习效率低下
当然有很多大佬的文章和资料给了我很大的启发
这个电机我玩了四天把自己觉得重要的东西和大家分享一下
现在一般都是用编码器电机参加比赛啥的编码电机常用于测速所以编码电机就成了一个必须学习的知识点
编码器被广泛应用于电机测速实现电机闭环控制。
相关的知识点有定时器的输出比较输出PWM、定时器的输入捕获定时器的编码器接口、速度控制 一、电机及编码器的参数
编码电机其实就是一个带有编码器的电机我的这个电机是一个增量式的带霍尔传感器的电机
电机的型号是JGB37-520电机
下方是电机的参数 主要关注的就是电机的额定电压 12V 电机的减速比 30这个很重要
编码器的参数 主要关注编码器的线数 11线 也就是说电机转一圈会产生11个脉冲 供电电压 5V 输出类型 方波
编码器的连接
一般这种编码器都有六根线 两边靠外的两根线是电机电源线 往里两根是编码器的电源线 中间两根是编码器的A,B相
具体大概是啥意思呢 就是电机转动的时候编码器会通过编码电机的A相和B相输出两个正交的方波
通过输出的两个方波就可以对电机进行测速和识别电机的方向 二、硬件
整体结构采用洞洞板TB6612Stm32C8T6编码电机(起初采用的是这种结构)
后面采用Stm32ZET6TB6612洞洞板编码电机12V电源(原因是C8T6烧坏了哭)
主控Stm32C8T6 or Stm32ZET6 电机驱动 TB6612由于上一个L298N烧了 520霍尔编码电机 12V电源 三、接线
这里展示驱动一个编码电机的示例毕竟先从一个电机玩起弄懂后后面就会使用的更加得心应手啦
主要使用到了定时器的PWM模式输出比较功能
大家一定要认真接线看清出每根线的作用不要随便接线一不小心电机驱动就烧了或者是单片机烧了在学习的时候就烧了一个单片机人民币-15
注意这个是我实现的接线大家可以根据自己单片机的片上资源合理选择选择合适的IO口
电机驱动
TB6612C8T6STBY高电平(3.3V)AIN1PB14AIN2PB15PWMAPA8 TIM1-CH1AO1电机电源AO2电机电源-VM12VVCC3.3VGND和单片机共地
编码器
编码器的A、B相C8T6A相PA0 (TIM2-CH1)B相PA1 (TIM2-CH2) 四、驱动电机
1、TB6612电机驱动
首先了解一下TB6612
下图是TB6612驱动模块 原理图 STBY接高电平 清零电机全部停止 置 1 通过 AIN1 AIN2 BIN1BIN2 引脚来控制正反转 PWM引脚控制占空比 VM 接 12V 以内电源 VCC 接 5V 电源 GND 接电源负极
下图是驱动逻辑 可以看出IN引脚控制正反转PWM引脚控制速度
2、定时器的PWM模式驱动电机
使用定时器的PWM模式 生成一个需要的 占空比可调的 频率 符合要求的方波信号。
方波信号的频率不宜过高或者过低过高容易导致电机驱动的晶闸管经常处于开关状态–发热巨大过低则容易产生噪音对电机也低频的冲击
这里输出PWM信号的定时器是TIM1-CH1
设置成PWM模式频率和占空比可调
有关定时器PWM模式可以看其他大佬的文章和资料看看手册
可以看看江科大的教学视频比我讲的详细多了也很好理解
我贴出视频链接大家学习32的时候可以跟他 TIM输出比较PWM模式
下方的PWM模式的代码作为一个参考
Motor.h
#ifndef __MOTOR_H
#define __MOTOR_H
#include sys.h #define PWMA TIM1-CCR1 //PA8 PWMA TIM1_CH1
#define AIN2 PBout(15)
#define AIN1 PBout(14)void Motor_PWM_Init(u16 arr,u16 psc);
void Motor_SetSpeed(u8 mode ,u16 speed);#endifMotor.c
void Motor_Init(void) //IN引脚初始化
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟GPIO_InitStructure.GPIO_Pin GPIO_Pin_14|GPIO_Pin_15; //端口配置GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; //推挽输出GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; //50MGPIO_Init(GPIOB, GPIO_InitStructure); //根据设定参数初始化GPIOB
}
void Motor_PWM_Init(u16 arr,u16 psc) //PWM引脚初始化
{GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure;Motor_Init();RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1 | RCC_APB2Periph_AFIO,ENABLE);//开启时钟//输出TIM1 CH1 GPIO_InitStructure.GPIO_Pin GPIO_Pin_8; //TIM_CH1 GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; //复用推挽输出GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA, GPIO_InitStructure);TIM_TimeBaseStructInit(TIM_TimeBaseStructure);//初始化定时器。TIM_TimeBaseStructure.TIM_Period arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler psc; //设置用来作为TIMx时钟频率除数的预分频值 不分频TIM_TimeBaseStructure.TIM_ClockDivision 0; //设置时钟分割:TDTS Tck_timTIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; //TIM向上计数模式TIM_TimeBaseInit(TIM1, TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; //比较输出使能TIM_OCInitStructure.TIM_Pulse 0; //设置待装入捕获比较寄存器的脉冲值TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; //输出极性:TIM输出比较极性高TIM_OC1Init(TIM1, TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMxTIM_CtrlPWMOutputs(TIM1,ENABLE); //MOE 主输出使能 高级定时器一定要写这个语句TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的预装载寄存器TIM_Cmd(TIM1, ENABLE); //使能TIM1
}void Motor_SetSpeed(u8 mode ,u16 speed) //mode 代表正反转 speed PWM占空比即速度
{PWMA speed;if(mode1){AIN1 1;AIN2 0;}else {AIN1 0;AIN2 1;}
}
五、编码器测速
编码器一般应用于电机控制使用PWM驱动电机然后再使用编码器测量速度再使用PID算法进行闭环控制
记住下面这句话
在一定的时间内电机转动一圈通过霍尔传感器的A、B两相输出一定数量的脉冲我们可以根据一定时间内的脉冲数计算出电机的瞬时速度。
1、定时器的编码器接口模式
采用的是定时器的编码器接口模式Stm32中的定时器只有TIM1-5和TIM8才有编码器接口功能而且只有CH1通道和CH2通道有用。
2、定时器编码器模式测速的原理
原理接收编码器的A、B相产生的正交信号根据编码器产生的正交信号脉冲自动控制CNT自增或自减根据计数方向和编码器的信号关系来指示编码器的位置、旋转方向和旋转速度利用脉冲值来计算电机的转动位移
这个可以参考手册里定时器的编码器模式比我讲的清楚多了 定时器的编码器接口托管了输入捕获的前两个接口
还有一句话记住编码器模式下就相当于一个带有方向选择的外部时钟
3、编码器模式的配置
具体配置流程就是
时钟–GPIO–时基单元配置–编码器接口配置–开启定时器–读取一个时间段内的脉冲–计算电机旋转轴转速
使用这个函数把定时器设置为编码器接口模式
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);采用的是编码器模式3在TI1和TI2边沿都计数也就是在一个周期内对A相和B相的上升沿下降沿都计数一个周期内计4次所以采用这种模式后,相应的计数值CNT就会变成4倍这就是很多资料里说的四倍频计数。
4、编码器模式相关代码
采用的是定时器2的编码器接口模式通道1和通道2捕获 encoder.c
/*** brief 把TIM2初始化为编码器接口模式* param psc 预分频系数* param arr 自动重装载值* retval None*/
void Encoder_Init_TIM2(uint16_t psc,uint16_t arr)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_ICInitTypeDef TIM_ICInitStructure;GPIO_InitTypeDef GPIO_InitStructure;//NVIC_InitTypeDef NVIC_InitStructure;//使能定时器2的时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能PB端口时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//端口配置GPIO_InitStructure.GPIO_Pin GPIO_Pin_0|GPIO_Pin_1;//浮空输入GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING;//根据设定参数初始化GPIOBGPIO_Init(GPIOA, GPIO_InitStructure);TIM_TimeBaseStructInit(TIM_TimeBaseStructure);// 预分频器TIM_TimeBaseStructure.TIM_Prescaler psc;//设定计数器自动重装值TIM_TimeBaseStructure.TIM_Period arr;//选择时钟分频不分频TIM_TimeBaseStructure.TIM_ClockDivision TIM_CKD_DIV1;//TIM向上计数TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up;TIM_TimeBaseInit(TIM2, TIM_TimeBaseStructure);//使用编码器模式3TIM_EncoderInterfaceConfig(TIM2, \TIM_EncoderMode_TI12, \TIM_ICPolarity_Rising, \TIM_ICPolarity_Rising);TIM_ICStructInit(TIM_ICInitStructure);TIM_ICInitStructure.TIM_ICFilter 10;TIM_ICInit(TIM2, TIM_ICInitStructure);//清除TIM的更新标志位TIM_ClearFlag(TIM2, TIM_FLAG_Update);TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//Reset counterTIM_SetCounter(TIM2,0);TIM_Cmd(TIM2, ENABLE);
}/*** brief 单位时间读取编码器计数* param TIMX 定时器* retval 速度值 是编码器返回的脉冲*/
int Read_Encoder()
{int Encoder_TIM;Encoder_TIM (short)TIM2 - CNT;//Encoder_TIM (int)((int16_t)(TIM4-CNT));;TIM2 - CNT0;return Encoder_TIM;
}encoder.h
#ifndef __ENCODER_H
#define __ENCODER_H#include sys.hvoid Encoder_Init_TIM2(uint16_t psc,uint16_t arr);
int Read_Encoder();#endif5、测速方法
在一个时间周期T0内定时的读取编码器产生的脉冲以我的编码器为例11线减速比30转一圈会产生1320个脉冲因为采用的是编码模式3 这个1320 11 * 30 * 4
通过在固定的周期T0内产生的脉冲就相当于路程而这个固定的周期就相当于时间
所以速度就等于 在T0这段时间获取到的脉冲总数/编码器单圈产生的总脉冲数*T0
对于我的电机就是 T0这段时间获取到的脉冲总数/1320*T0 六、相关问题以及解答
在看了前面之后应该对编码器模式和编码器测速有了一个大概的认识知道了它测速的原理但肯定有好多疑问我把我学习过程中遇到的问题和解决方法做一个总结你肯定也有这些疑问不要着急看下去。
1、编码器模式下的自动重装值ARR和预分频PSC应该如何设置 ARR自动重装值指的是CNT计数自增或自减到ARR就会溢出可以产生中断然后继续从0开始计数。 PSC,预分频系数前面不是说过编码器相当于一个外部时钟吗PSC相当于外部时钟的频率如果分频(假设PSC2)的话就会比如电机转一圈产生100个脉冲此时编码器模式下只能计数50个脉冲。 所以我们应该如何设置
PSC呢 PSC没有必要设置因为我要计数的本来就是电机转动一圈产生的真实脉冲所以PSC给0就好啦
ARR呢 目前在各种论坛和博客和资料中有两种版本。
第一种根据电机的线数和减速比来设置比如我的电机是11线减速比30转动一圈的脉冲数是1320这个值就可以设置为1320。
产生的脉冲数恰好是你定时器溢出的时候溢出一次记录一次这个的次数就是电机的圈数当然这种误差很大
也就是说电机转一圈正好是1320当CNT计数到ARR时计数器就会清零并且重新计数所以这个ARR就是电机转一圈产生的脉冲数的最大值。
第二种,直接设置成定时器ARR的最大值也就是655352^16-1,这样设置的目的就是无论你电机产生多少脉冲都可以记录且不会溢出。
不过使用65535的话就要在最开始的时候初始化编码器模式提前把CNT清零然后再开始计数。再在一个周期内定时读取脉冲数再清零这个脉冲也是周期内读取到的脉冲值。
电机旋转一圈能产生脉冲那么我们就能记录一段时间产生的脉冲数来计算速度
2、如何判断正反转
可以通过判断CR1寄存器中的DIR位这个位是计数方向位 正转就是CNT向上计数DIR0
反转就是CNT向下计数DIR1
3、圈数如何计算
就是上方说的把ARR设置为电机旋转一周产生的脉冲数
电机转一圈CNT达到ARR溢出进中断设置一个变量正转–反转
4、转速如何计算
规定某个某个时钟周期内读取有多少脉冲从而计算转速
这里采用的是M法测速测出的是电机是多少转/s
脉冲相当于路程某个时钟周期相当于时间
这个上方有描述可以往上翻翻
5、为什么我的编码器没有输出获取到的脉冲数是0
检查一下接线从硬件开始一步一步排查对应的引脚是否正确
检查电源编码器的电源是否打开相应的PWM波是否有效
硬件确认没有错误检查软件编码器接口是否打开,PWM模式是否输出电机IN引脚是否配置
七、测速硬件展示及测速现象
硬件展示 测速展示 可以看到当转速为1的时候产生的脉冲是66-68而我设置的闸门时间是50ms,结合电机转一圈是1320个脉冲也就是说测量的脉冲数几乎正确。
66*2132 和编码器的线数完全吻合测速成功
八、总结
这个编码器花费了我几乎四天的时间也可能是自己比较小白不懂得如何通过电机转一圈产生的脉冲数来计算速度第一天就实现了读取脉冲
但是后面几天执着于测速没有采取正确的方法导致自己无线内耗浪费了大量时间。
由于网上资料繁杂找不到自己想要的浪费了很多时间很多只是一笔带过没有系统的讲解原理和方法我也不知道自己这篇文章是否正解
所以将这个学习总结分享给大家
当然这都是在借鉴了前人的肩膀下谢谢各位大佬和优秀的文章我会在下方贴出自己觉得值得一看大佬们的链接大家可以一看
欢迎大家指错看到了就会修改大家一起共同进步。
九、大家可以参考
参考链接1
带霍尔传感器编码器的直流减速电机测速原理讲解附源码-OpenEdv-开源电子网
参考链接2
编码器分类及原理和测速应用含代码 - 古月居
参考链接3
stm32平衡小车(2)-----编码器电机驱动
参考链接4
带编码器的直流减速电机——基于STM32F407_编码器直流减速电机磁极数目_谁还不是个程序猿的博客
谢谢各位大佬的文章让我受益匪浅站在前人的肩膀下才能看的更远