带编码器的直流减速电机 | 您所在的位置:网站首页 › stm32f407接线图 › 带编码器的直流减速电机 |
首先,什么是编码器?
编码器是将信号或数据进行编制、转换为可用以通讯、传输和存储的信号形式的设备。在这里,编码器就是能够将电机的转动信息(比如转速、转动角度等)转换为脉冲信号的设备。按照原理可分为(常见的)光电编码器(光学式)和霍尔编码器(磁式)。 接着,编码器的作用以及为什么要用编码器?如上所述,编码器能够将电机的机械几何位移转化为脉冲信号或数字量。也就是说,有了编码器,我们通过检测编码器输出的脉冲信号,就能获取电机转动角度、转速等相关信息。这样我们不但能定性的控制电机的转向、转速,还能定量的测量。 那么,编码器的原理是什么以及怎么运用呢?简单来说,就是电机带动码盘转动,码盘的结构使得当电机在转动时会产生A、B两相的脉冲信号,且这两路脉冲信号的相位差为90度(即正交)。如下图: 好了,现在我们的处境是,我们有一个带编码器的直流减速电机,我们知道当电机转动的时候,它会产生A、B两相正交脉冲信号,通过检测脉冲信号我们就可以获取电机的运动状况。 那么,我们通过什么手段来检测脉冲数呢? 其中一种思路是,我们通过定时器的输入捕获或者GPIO引脚的外部中断来检测边沿变化,以此来检测脉冲数。这方法好像没毛病,当电机正常运转时行得通。但是如果电机输出的脉冲信号出现了毛刺呢?这样误差就来了,怎么办?通过软件编写算法来滤去毛刺似乎有点困难,于是我们想到通过硬件来处理这个毛刺。(而STM32正好有硬件编码器,nice!) 这里的脉冲输入是一种特殊的输入捕获情况,因此stm32专门在定时器中提供了编码器模式,可大大简化解析过程。 STM32的编码器接口模式 在该模式下能计算电机输出脉冲信号的个数,且stm32根据其内部机制能够消除毛刺的干扰。 配置过程: 由于编码器接口模式是一种特殊的输入捕获,所以要先配置一下输入捕获(毕竟你要通过捕获边沿来检测脉冲)。在输入捕获过程中,我们把A6、A7复用为TIM3,作为输入捕获的引脚,对电机的A、B相脉冲进行输入捕获。 输入捕获配置完成之后再配置一下编码器模式就可以开始工作了。 于是紧接着我们来看看编码器模式的配置函数TIM_EncoderInterfaceConfig: 至此,为了避免我们忘了初衷,现在我们来回顾一下我们最开始用编码器的初衷,前面我们说要用编码器来干嘛来着?获取电机转动角度、转速。 现在的处境是,我们通过STM32的TIM3的编码器模式,能够测出任意时刻的脉冲值了。现在要解决的就是如何将这个脉冲值转换成我们所要得到的信息(即转动角度、转速)。 首先,根据带编码器的直流减速电机的原理,显然无论电机的转速如何,每转产生的脉冲数是固定的。这里假设电机每转产生260个脉冲(具体数据各位自行查看自己的电机参数啦),那么只要我们用‘电机已产生的脉冲数’除以‘260个/转’,就可以得到电机转了多少圈,一圈即为360度,由此便可将脉冲数和转动角度联系起来。 这里要注意一点,由于我们用的是编码器模式3(也就是TIM_EncoderMode_TI12),我们得到的脉冲数是电机实际产生的脉冲数的四倍。则电机实际产生的脉冲数应为‘得到的计数值’除以4。于是,电机转动圈数为脉冲数除以260再除以4。 转动角度算出来了,转速呢?则是根据计数方向(递增计数或递减计数)来判断的,所以我们接下来的工作就是要搞清楚计数方向和编码器信号的关系。 让我们来看一下STM32的中文参考手册: 接下来是代码部分,有些容易让人迷惑的地方(至少是让我迷惑了很久): 输入捕获初始化时Period和Prescaler的作用: 这里的period即为计数器的重装载值,prescaler即为预分频系数。注意在编码器模式时,要把TIM理解为计数器,而不是定时器,这样的话,时钟信号就不是系统内部产生的,而是通过PA6、PA7输入到TIM3的TI1和TI2的。 有了这么个理解,再来看Period和Prescaler就不难理解了。Period就是计数器每一次能检测脉冲的最大值,每来一个脉冲计数值就加一,当计数值超过period就溢出中断。Prescaler就是对电机产生的脉冲信号进行分频的分频系数。比如当分频系数为2时,每当电机产生两个脉冲,stm32才认为接收到一个有效脉冲,计数值才加一。 以下为部分代码 //思路:初始化TIM的编码器模式后,在main函数里死循环不断的读取CNT的值,从而来获得电机的脉冲数数据,以此来计算电机的转速、所转圈数等参数 #include "sys.h" #include "delay.h" #include "usart.h" #include "pwm.h" #include "encode.h" #include "exti.h" #include "key.h" u32 pwm = 50000; int main(void) { uint32_t cnt_temp; //用于暂存TIM的计数值,即TIM检测到的脉冲的数量 float pulse; //电机产生的实际脉冲值 float round; //电机转的圈数 encoder_init(); //TIM3编码器模式初始化,A6、A7分别作为A相和B相的脉冲输入 exti_init(); //外部中断,用于通过按键修改数据(比如PWM) NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置系统中断优先级分组2 delay_init(168); //初始化延时函数 uart_init(115200); //初始化串口波特率为115200 TIM4_PWM_Init(50000-1,84-1); //TIM4初始化,用于产生PWM供给直流减速电机 //84M/84=1Mhz的计数频率,重装载值50000,所以PWM频率为100000/50000=2hz,即整个周期为500ms while(1) { TIM_SetCompare1(TIM4,pwm); //设置供给电机的PWM值 cnt_temp = read_cnt(); //得到脉冲计数值 pulse = cnt_temp/4.0f; //由于是TIM_EncoderMode_TI12,所以要四分频,即除以四,得到实际的脉冲值 round = cnt_temp/4.0f/260.0f; //假设电机每转产生260个脉冲,则通过该公式可求出电机转了几圈 printf("cnt_temp:%d\r\n", cnt_temp); //向串口打印脉冲计数值 printf("pulse:%f\r\n", pulse); //向串口打印实际脉冲值 printf("round:%f\r\n", round); //向串口打印电机转了几圈 delay_ms(1000); //每1s循环更新一次 // if(TIM3->CR1&1TIM_Channel = TIM_Channel_1; // TIM_ICInitStruct->TIM_ICPolarity = TIM_ICPolarity_Rising; // TIM_ICInitStruct->TIM_ICSelection = TIM_ICSelection_DirectTI; // TIM_ICInitStruct->TIM_ICPrescaler = TIM_ICPSC_DIV1; // TIM_ICInitStruct->TIM_ICFilter = 0x00; // } TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising ,TIM_ICPolarity_Rising); //配置为编码器模式,计数器在TI1和TI2上升沿处均计数 TIM_SetCounter(TIM3, 0); //将脉冲计数值设为零 TIM_Cmd(TIM3, ENABLE); //使能TIM3 } // 读取定时器计数值 uint32_t read_cnt(void) { uint32_t encoder_cnt; encoder_cnt = TIM3->CNT; //读取计数器CNT的值,CNT系uint32_t型的变量 TIM_SetCounter(TIM3, 0); //每一次读取完计数值后将计数值清零,重新开始累加脉冲,方便下一次计数 return encoder_cnt; //返回的值就是本次读到的计数值 } |
CopyRight 2018-2019 实验室设备网 版权所有 |