接线
编码器电机、电机驱动(这里用的L298n)、STM32、电源(可以是12V电池)的接线如下
3.3 代码编写
encoder.h中的内容
#ifndef _ENCODER_H_
#define _ENCODER_H_
#include "stm32f1xx.h"
//电机1的编码器输入引脚
#define MOTO1_ENCODER1_PORT GPIOA
#define MOTO1_ENCODER1_PIN GPIO_PIN_0
#define MOTO1_ENCODER2_PORT GPIOA
#define MOTO1_ENCODER2_PIN GPIO_PIN_1
//定时器号
#define ENCODER_TIM htim2
#define PWM_TIM htim3
#define GAP_TIM htim4
#define MOTOR_SPEED_RERATIO 45u //电机减速比
#define PULSE_PRE_ROUND 11 //一圈多少个脉冲
#define RADIUS_OF_TYRE 34 //轮胎半径,单位毫米
#define LINE_SPEED_C RADIUS_OF_TYRE * 2 * 3.14
#define RELOADVALUE __HAL_TIM_GetAutoreload(&ENCODER_TIM) //获取自动装载值,本例中为20000
#define COUNTERNUM __HAL_TIM_GetCounter(&ENCODER_TIM) //获取编码器定时器中的计数值
typedef struct _Motor
{
int32_t lastCount; //上一次计数值
int32_t totalCount; //总计数值
int16_t overflowNum; //溢出次数
float speed; //电机转速
uint8_t direct; //旋转方向
}Motor;
#endif
encoder.c中的内容
#include "encoder.h"
Motor motor1;
void Motor_Init(void)
{
HAL_TIM_Encoder_Start(&ENCODER_TIM, TIM_CHANNEL_ALL); //开启编码器定时器
__HAL_TIM_ENABLE_IT(&ENCODER_TIM,TIM_IT_UPDATE); //开启编码器定时器更新中断,防溢出处理
HAL_TIM_Base_Start_IT(&GAP_TIM); //开启100ms定时器中断
HAL_TIM_PWM_Start(&PWM_TIM, TIM_CHANNEL_2); //开启PWM
HAL_TIM_PWM_Start(&PWM_TIM, TIM_CHANNEL_1); //开启PWM
__HAL_TIM_SET_COUNTER(&ENCODER_TIM, 10000); //编码器定时器初始值设定为10000
motor1.lastCount = 0; //结构体内容初始化
motor1.totalCount = 0;
motor1.overflowNum = 0;
motor1.speed = 0;
motor1.direct = 0;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//定时器回调函数,用于计算速度
{
if(htim- >Instance==ENCODER_TIM.Instance)//编码器输入定时器溢出中断,用于防溢出
{
if(COUNTERNUM < 10000) motor1.overflowNum++; //如果是向上溢出
else if(COUNTERNUM >= 10000) motor1.overflowNum--; //如果是向下溢出
__HAL_TIM_SetCounter(&ENCODER_TIM, 10000); //重新设定初始值
}
else if(htim- >Instance==GAP_TIM.Instance)//间隔定时器中断,是时候计算速度了
{
motor1.direct = __HAL_TIM_IS_TIM_COUNTING_DOWN(&ENCODER_TIM);//如果向上计数(正转),返回值为0,否则返回值为1
motor1.totalCount = COUNTERNUM + motor1.overflowNum * RELOADVALUE;//一个周期内的总计数值等于目前计数值加上溢出的计数值
motor1.speed = (float)(motor1.totalCount - motor1.totalCount) / (4 * MOTOR_SPEED_RERATIO * PULSE_PRE_ROUND) * 10;//算得每秒多少转
//motor1.speed = (float)(motor1.totalCount - motor1.totalCount) / (4 * MOTOR_SPEED_RERATIO * PULSE_PRE_ROUND) * 10 * LINE_SPEED_C//算得车轮线速度每秒多少毫米
motor1.lastCount = motor1.totalCount; //记录这一次的计数值
}
}
使用时需要在main.c的循环之前调用Motor_Init函数进行初始化。
如果发现无法进入编码器中断导致totalCount经常溢出归零,可以尝试换一种防溢出的方法,代码如下
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//定时器回调函数,用于计算速度
{
if(htim- >Instance==GAP_TIM.Instance)//间隔定时器中断,是时候计算速度了
{
motor1.direct = __HAL_TIM_IS_TIM_COUNTING_DOWN(&ENCODER_TIM);//如果向上计数(正转),返回值为0,否则返回值为1
motor1.totalCount = COUNTERNUM_1 + motor1.overflowNum * RELOADVALUE_1;//一个周期内的总计数值等于目前计数值加上溢出的计数值
if(motor1.lastCount - motor1.totalCount > 19000) // 在计数值溢出时进行防溢出处理
{
motor1.overflowNum++;
motor1.totalCount = COUNTERNUM_1 + motor1.overflowNum * RELOADVALUE_1;//一个周期内的总计数值等于目前计数值加上溢出的计数值
}
else if(motor1.totalCount - motor1.lastCount > 19000) // 在计数值溢出时进行防溢出处理
{
motor1.overflowNum--;
motor1.totalCount = COUNTERNUM_1 + motor1.overflowNum * RELOADVALUE_1;//一个周期内的总计数值等于目前计数值加上溢出的计数值
}
motor1.speed = (float)(motor1.totalCount - motor1.lastCount) / (4 * MOTOR_SPEED_RERATIO * PULSE_PRE_ROUND) * 3000;//算得每秒多少转,除以4是因为4倍频
motor1.lastCount = motor1.totalCount; //记录这一次的计数值
}
全部0条评论
快来发表一下你的评论吧 !