前言
最近在做一个单片机大作业,要用到直流有刷,在这里把学习编码器的知识记录一下,学习参考资料:
正点原子DMF407电机控制专题教程_V1.0
编码器测速原理
我所使用的编码器是市面上常见的磁电增量式编码器,其有AB两相,用于输出电机转动时的脉冲数,AB两相的先后顺序决定了电机的转动方向
这其实就是单片机的外部计数器模式,51中也带有同样的功能
信号从通道被采样后的处理过程如下
编码器的计数接口是利用脉冲的边沿来计数的,我们知道AB两相都有脉冲且相位差为90度,那么一次检测最多可以得到四个边沿,此时我们可以通过配置计数的方式来实现不同的边沿计数
由图可以看出,总共有三种计数方式供我们选择,不同的模式对应了不同的计数形式,这里我选用的是第三种,因此会产生四个边沿,相当于对信号进行了四倍频,即一个脉冲信号会计数4次,在计算时要注意
寄存器部分
在编码过程中有几个重要的寄存器要简单介绍一下
TIMx_CR1控制寄存器
我们要关注这里的DIR位,通过判断DIR来判断计数器所处的模式是递增还是递减,流程大致为:配置好定时器的装载值为65536,不分频,那么每一次接收到65536个脉冲后定时器就会溢出进入定时器中断,此时通过判断DIR是0还是1来判断是正转还是反转,进而将得到的脉冲数累积到总脉冲数中进行速度计算
同时还要注意 CEN位,该位用于使能计数器的工作,也就是相当于选择模式,对应硬件就是内部的开关,用于判断是外部定时器模式还是内部定时器模式,当该位置1为外部定时器模式
TIMx_CCMR1捕获/比较模式寄存器1
在这里IC1F为滤波器,其实现方法为通过配置寄存器来设定滤波系数,例如在一个采样周期下,当N=2时代表要两个相同的事件(比如两个相同电位的高电平信号)才能视为一个有效边沿,这个过程基于数字滤波器实现,寄存器配置如下
IC1PSC是输入捕获预分频器,和上述原理类似,这里我和教程一样,选择一个边沿就触发一次计数
CC1S用于配置定时器通道,这里不做多要求,IC1映射到TI1就可以了
TIMx_SMCR从模式控制器
SMS代表的三位用于配置编码器模式123,具体对应关系如下
至此要用到的所有寄存器就介绍完了,接下来我们来进行CUBEMX工程的创建
硬件信息
主控芯片我选择的是STM32F103C8T6,电机用的是常见的自带编码器的直流有刷减速电机,编码器线数为11,电机驱动选用L298N,同时用OLED屏幕显示电机转速信息
工程创建
首先配置时钟树,直接拉满,再初始化几个IO口用于驱动电机
剩下的流程就是选择对应的IDE生成工程即可
代码部分
初始化外设
/* USER CODE BEGIN 2 */
run_left_motor(50,1); //左轮电机启动
OLED_Init(); //OLED初始化
OLED_Clear();
HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL); //开启定时器编码器通道
HAL_TIM_Base_Start_IT(&htim4); //开启定时中断通道
/* USER CODE END 2 */
初始化电机以及编码器
#define ROTO_RATIO 44 //编码器线数11*分频系数4
#define REDUTATION_RATIO 30 //电机减速比30
//编码器结构体
typedef struct
{
int encode_old;
int encode_new;
float speed;
}ENCODE_TypeDef;
//电机结构体
typedef struct
{
float speed;
}Motor_TypeDef;
extern ENCODE_TypeDef g_encode_left;
extern Motor_TypeDef g_motor_left;
电机转动
void run_left_motor(uint8_t speed,unsigned char dir)
{
uint32_t arr;
HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);
if(dir == 1)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
}
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
arr = __HAL_TIM_GET_AUTORELOAD(&htim2);
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,(1.0*speed/100)*arr);
}
电机速度计算
//encoder_now为定时器编码器模式下的计数值,ms代表每隔多少ms进入一次计算公式
void left_speed_compute(int32_t encode_now,uint8_t ms)
{
uint8_t i=0,j=0;
float temp = 0.0; //用于后续冒泡排序
static uint8_t sp_count=0,k=0; //用于判断隔多长时间进一次计算,静态变量,不会随着函数调用被刷新
static float speed_array[10]={0.0}; //上面的k为数组的索引值
if(sp_count == ms) //当调用函数次数超过50次即每间隔50ms进入一次计数
{
g_encode_left.encode_new = encode_now; //编码器值更新
g_encode_left.speed = (g_encode_left.encode_new - g_encode_left.encode_old); //脉冲变化数计算
//通过脉冲计算速度,公式:(50ms内记录的脉冲数/50ms*60)/减速比/编码器线数/分频系数 = 每分钟的脉冲数/已知常量
speed_array[k++] = (float)(g_encode_left.speed*((1000/ms)*60.0)/(REDUTATION_RATIO*ROTO_RATIO));
g_encode_left.encode_old = g_encode_left.encode_new; //更新编码器计数值
//冒泡排序法
if(k==10)
{
for(i=10;i>=1;i--)
{
for(j=0;j<(i-1);j++) {
if (speed_array[j] > speed_array[j + 1]) {
temp = speed_array[j];
speed_array[j] = speed_array[j + 1];
speed_array[j + 1] = temp;
}
}
}
temp = 0.0; //初始化temp
//去除两边高低数据
for(i=2;i<8;i++)
{
temp += speed_array[i];
}
temp = (float)(temp/6);
/*
* 一阶低通滤波 Y(n)= qX(n) + (1-q)Y(n-1)
* 其中 X(n)为本次采样值;Y(n-1)为上次滤波输出值;Y(n)为本次滤波输出值,
* q 为滤波系数
*/
g_motor_left.speed = (float)((g_motor_left.speed)*(float)0.52)+((float)0.48*temp);
//显示当前速度
unsigned char Tx_Buf[20];
sprintf((char *)Tx_Buf,"Left: %.2f",g_motor_left.speed);
OLED_ShowString(1,2,Tx_Buf,5);
k = 0;
}
sp_count = 0;
}
sp_count++;
}
溢出计数统计以及调用计算
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//判断编码器的溢出方向
if(htim->Instance == TIM1)
{
if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim1))
{
g_tim1_encode_count--;
}
else
{
g_tim1_encode_count++;
}
}
//每间隔1ms更新一次脉冲数
if(htim->Instance == TIM4)
{
int Left_encode_now = gtim_get_encode();
left_speed_compute(Left_encode_now,50);
}
}
//更新脉冲数
int gtim_get_encode(void)
{
return ( int32_t )__HAL_TIM_GET_COUNTER(&htim1) + g_tim1_encode_count * 65536; /* 当前计数值+之前累计编码器的值=总的编码器值 */
}
实验现象验证
转动时转速为20r/min
不转动时转速为0文章来源:https://www.toymoban.com/news/detail-423297.html
文章来源地址https://www.toymoban.com/news/detail-423297.html
到了这里,关于STM32定时器编码器模式实现直流有刷电机测速(HAL库)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!