接线
编码器电机、电机驱动(这里用的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; //记录这一次的计数值
}
设计资源 培训 开发板 精华推荐
- MIC2026-1YM双通道热插拔配电开关典型应用
- LTM4650IY-1A 50A、1V 输出 DC/DC 降压稳压器的典型应用电路
- LTC2945IMS 在 -48V 恶劣环境中使用 INTVCC 并联稳压器进行电源监控以耐受 200V 瞬变的典型应用
- 采用 AD5541A 精密、16 位、电压电平设置且总功耗小于 5mW 的应用电路
- 使用 ON Semiconductor 的 LV8760T 的参考设计
- 使用 AD7393 传输具有输出电池短路保护的复合视频的稳健解决方案
- 【训练营】dogdogdog
- MIC2025-2YM单通道配电开关MM8典型应用USB总线供电集线器应用
- ADL5545-EVALZ,基于 ADL5545 30 MHz 至 6 GHz RF/IF 增益模块的评估板
- 使用 Richtek Technology Corporation 的 RT7257J 的参考设计