#ifndef ENCODER_H
#define ENCODER_H
#include "stm32f1xx_hal.h"
#include <stdint.h>
#include <stdbool.h>
/**
* 机械旋转编码器(正交AB)→ “格”计数封装
* 典型用法:TI12(四倍频),每 4 计数 = 1 格
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
TIM_HandleTypeDef *htim; // 指向 CubeMX 生成的 TIM 句柄(如 &htim2)
int16_t last_cnt; // 上次读取的硬件 CNT(16位)
int32_t edge_acc; // 边沿累计(正/负),用于“每K计数=1格”的折算
int32_t notch_pos; // 以“格”为单位的累计位置(可多圈)
uint16_t ticks_per_notch; // 每“格”需要的硬件计数(TI12 通常是 4)
uint16_t notches_per_rev; // 一圈有多少“格”(如 20)
bool invert; // 方向取反(true 则翻转)
} Encoder_t;
/**
* @brief 初始化结构体(不启动定时器)
* @param enc 你的 Encoder 对象
* @param htim 绑定的 TIM 句柄(CubeMX 里配置好的 Encoder 模式)
* @param notches_per_rev 每圈“格”数(如 20)
* @param ticks_per_notch 每“格”对应的硬件计数(TI12 常用 4;TI1/TI2 可为 2 或 1)
*/
void Encoder_Init(Encoder_t *enc,
TIM_HandleTypeDef *htim,
uint16_t notches_per_rev,
uint16_t ticks_per_notch);
/**
* @brief 启动定时器编码器模式(等价 HAL_TIM_Encoder_Start)
*/
void Encoder_Start(Encoder_t *enc);
/**
* @brief 清零硬件 CNT 与软件累计(相当于“回零/标定当前为0格”)
*/
void Encoder_Reset(Encoder_t *enc);
/**
* @brief 周期调用,完成(硬件计数 → 边沿累计 → 折算为“格”)的更新
* 建议 1~10ms 调用一次(定时器中断、SysTick、或任务里都可以)
*/
void Encoder_Update(Encoder_t *enc);
/**
* @brief 读取“格”为单位的累计位置(多圈可正可负)
*/
static inline int32_t Encoder_GetNotchPos(const Encoder_t *enc)
{
return enc->notch_pos;
}
/**
* @brief 设置“格”为单位的当前位置(重定位)
*/
static inline void Encoder_SetNotchPos(Encoder_t *enc, int32_t pos)
{
enc->notch_pos = pos;
}
/**
* @brief 读取一圈内的“格”索引(0..notches_per_rev-1)
* 负数也会被正确映射到该范围
*/
int32_t Encoder_GetNotchMod(const Encoder_t *enc);
/**
* @brief 读取原始硬件 CNT(当前计数器值)
*/
static inline int16_t Encoder_GetRawCNT(const Encoder_t *enc)
{
return (int16_t)__HAL_TIM_GET_COUNTER(enc->htim);
}
/**
* @brief 设置方向是否取反(等价把A/B通道互换或极性反相)
*/
static inline void Encoder_SetInvert(Encoder_t *enc, bool inv)
{
enc->invert = inv;
}
#ifdef __cplusplus
}
#endif
#endif // ENCODER_H// main.c / app.c
#include "encoder.h"
extern TIM_HandleTypeDef htim2; // 由 CubeMX 生成
static Encoder_t gEnc;
void App_Init(void)
{
// CubeMX 已经初始化 TIM2 为 Encoder TI12; ARR=65535; PSC=0; 过滤器已设
Encoder_Init(&gEnc, &htim2, /*notches_per_rev=*/20, /*ticks_per_notch=*/4);
Encoder_Start(&gEnc);
// 如果方向反了,打开反向
// Encoder_SetInvert(&gEnc, true);
}
void App_Loop_1ms(void) // 每 1ms 调用一次(可放 SysTick 或定时器中断里)
{
Encoder_Update(&gEnc);
}
void Turn_Left_One_Notch(void)
{
int32_t target = Encoder_GetNotchPos(&gEnc) - 1;
// 启动电机左转...
// while(Encoder_GetNotchPos(&gEnc) > target) { /* 等到位或配合超时/陀螺 */ }
// 停止电机...
}
296

被折叠的 条评论
为什么被折叠?



