一,编码器原理详解:
参考:[野火]《电机应用开发实战指南》第13章
1,基本参数
(本次实验所用的增量式编码器查参数得为13ppr)
2,增量式编码器基本原理:
3,编码器的倍频
4,M法测速:
5,STM32的编码器接口实现原理(输入捕获定时器)
2倍频实现为例,其他的原理类同(一个通道的上升和下降沿都计数)
二,CUBEMX配置
1,定时器配置
需要注意的是:有些编码器输出是不带上拉电阻的,此时就需要将A,B通道的IO口成设置成上拉,本实验用的编码器查参数得知是带上拉输出(默认上拉到供电VCC引脚),故可用单片机直接采集。
关于几个成员的理解:
2,打开一个串口传数据
3,设置两个输出IO驱动电机
三,keil中代码
1,开启一系列
/* USER CODE BEGIN 2 */
//开启PWM输出
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);
//清零计数器
__HAL_TIM_SET_COUNTER(&htim3, 0);
//清零中断标志位
__HAL_TIM_CLEAR_IT(&htim3,TIM_IT_UPDATE);
// 使能定时器的更新事件中断
__HAL_TIM_ENABLE_IT(&htim3,TIM_IT_UPDATE);
//设置更新事件请求源为:计数器溢出(也就是只有计数溢出时触发更新中断)
__HAL_TIM_URS_ENABLE(&htim3);
//使能编码器接口(TIM_CHANNEL_ALL: TIM Channel 1 and TIM Channel 2 are selected)
HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
/* USER CODE END 2 */
2, 写更新中断回调函数(计在T0内有多少次溢出,用来计算T0内的总计数次数)
定义变量(关于__IO, 参考博客:(12条消息) 关于"__IO uint32_t" 中的__IO 表达的意思_znmdwahaha的专栏-优快云博客)
// 定时器溢出次数
__IO int16_t Encoder_Overflow_Count = 0;// 转向
__IO int8_t Motor_Direction = 0;
// 当前时刻总计数值
__IO int32_t Capture_Count = 0;
// 上一时刻总计数值
__IO int32_t Last_Count = 0;
// 转轴转速
__IO float Shaft_Speed = 0.0f;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* 判断当前计数器计数方向 */
if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3))
/* 下溢 */
Encoder_Overflow_Count--;
else
/* 上溢 */
Encoder_Overflow_Count++;
}
由上述STM32的编码器接口实现原理:每次捕获到输入沿(即编码器每产生一个脉冲)计数器就计数一次,因此可以通过T0内计数次数和编码器线数等算出转速(这里应该是忽略了在一个装载值内转向改变带来的影响)
3,计算转速,直接在void HAL_SYSTICK_Callback()里写了(1ms调用一次)
void HAL_SYSTICK_Callback(void)
{
static uint16_t i = 0;
i++;
if(i == 1000) //1s计算一次
{
//电机旋转方向 = 当前计数器计数方向
Motor_Direction = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3);
// 当前计数值 = 当前装载内计数器值 + 计数溢出次数 * 定时器装载值
Capture_Count =__HAL_TIM_GET_COUNTER(&htim3) + (Encoder_Overflow_Count * 65535);
// 转轴转速 = 单位时间内的计数值(当前计数值-上一次计数值) / 编码器总分辨率(ppr*倍频)*时间系数(进行单位转化的)
Shaft_Speed = (float)(Capture_Count - Last_Count) / (13*4) * 1;
printf("电机方向:%d\r\n", Motor_Direction);
printf("电机转轴处转速:%.2f 转/秒 \r\n", Shaft_Speed);
//注意输出的和转轴处转速不一样,还要除一个电机减速比
printf("电机输出轴转速:%.2f 转/秒 \r\n", Shaft_Speed/30);
// 记录当前总计数值,供下一时刻计算使用
Last_Count = Capture_Count;
i = 0;
}
}
由于手头的硬件无法进行实验,先挖个坑之后再调看是不是通的