本次选用的编码器电机为13线霍尔编码器电机,电机减速比为30:1,转动一圈输出13*30=390个脉冲。轮胎直径为75mm,轮胎周长为pi*d=3*75=225mm.定时器采用四倍频计数,一圈输出390*4=1560个脉冲。这里就不多说具体的编码器知识了。
根据速度测量原理:假设编码器输出的脉冲数为N,电机转动一圈输出1569个脉冲,转动一圈轮将向前移动225mm。当输出脉冲数为N时,前进距离应为225*(N/1560)mm,除以时间和速度。
具体代码如下:
encoder.c文件
#include "encoder.h" void Encoder_TIM2_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); GPIO_InitTypeDef GPIO_InitStruct; //配置IO口 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_Init(GPIOA, &GPIO_InitStruct); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; ///定时器初始化 TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStruct.TIM_Period = 65535; TIM_TimeBaseInitStruct.TIM_Prescaler = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); /// TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); TIM_ICInitTypeDef TIM_ICInitStruct; //输入捕获单元配置 TIM_ICStructInit(&TIM_ICInitStruct); TIM_ICInitStruct.TIM_ICFilter = 10; TIM_ICInit(TIM2, &TIM_ICInitStruct); TIM_ClearFlag(TIM2, TIM_FLAG_Update); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); TIM_SetCounter(TIM2, 0); TIM_Cmd(TIM2, ENABLE); } void Encoder_TIM4_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_Init(GPIOB, &GPIO_InitStruct); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStruct.TIM_Period = 65535; TIM_TimeBaseInitStruct.TIM_Prescaler = 0; TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStruct); TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); TIM_ICInitTypeDef TIM_ICInitStruct; TIM_ICStructInit(&TIM_ICInitStruct); TIM_ICInitStruct.TIM_ICFilter = 10; TIM_ICInit(TIM4, &TIM_ICInitStruct); TIM_ClearFlag(TIM4, TIM_FLAG_Update); TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); TIM_SetCounter(TIM4, 0); TIM_Cmd(TIM4, ENABLE); } int Read_Spead(int TIMx) ///读取编码器输出脉冲数 { int value_1; switch(TIMx) { case 2:value_1 = (short)TIM_GetCounter(TIM2);TIM_SetCounter(TIM2, 0);break; case 4:value_1 = (short)TIM_GetCounter(TIM4);TIM_SetCounter(TIM4, 0);break; default:value_1 = 0; } return value_1; } void TIM2_IRQHander(void) { if(TIM_GetITStatus(TIM2, TIM_IT_Update) == 1) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } } void TIM4_IRQHander(void) { if(TIM_GetITStatus(TIM4, TIM_IT_Update) == 1) { TIM_ClearITPendingBit(TIM4, TIM_IT_Update); } }
我用的很简单delay收集定时器捕获的编码器脉冲数,但我建议使用定时器中断来处理编码器收集。该函数只收集右轮脉冲进行计算
主函数循环体内函数:
while(1) { delay_s(1); { uint16_t right = Read_Spead(2)//采集右轮脉冲数 displacement = 0.225 * (right / 1560) speed = displacement;///因为我设置为延迟一秒,所以不需要除时间 OLED_Float(0, 0, speed, 4);//通过OLED显示速度 set_PWM(999)PWM TIM_SetCounter(TIM2, 0)///下一秒计数前再次清除计数 } }