STM32 Cubemax(六) —— STM32利用定时器编码器模式处理带编码器直流电机

STM32 Cubemax(六) —— STM32利用定时器编码器模式处理带编码器直流电机


前言

电赛延期了,趁有时间再写点东西吧.

编码器电机配置较为繁琐,本文较长,耐心看下去,一定有收获.

本文适合已经对编码器有所了解的同学观看,如果对编码器原理还不太理解,可以看看CSDN中别人讲编码器的,个人觉得已经讲的十分清楚了,这里主要讲解怎么使用Cubemax去使用编码器


一、硬件准备

  1.         本次实验使用的是带增量式AB相霍尔编码器的直流减速电机

 简单介绍一下这款电机,减速比为1:30,即输出轴转一圈,电机内部实际转30圈,霍尔编码器为13位编码器,即电机每转,对于编码器有2的13次方的增量.(简单的说,上面那个霍尔编码器检测的圆盘,转一圈,检测13个脉冲)

 2.        电机所使用的电机驱动为应该大家都十分熟悉的L298N

                                 

这里就不过多介绍了,CSDN上也有很多对此介绍十分详细的.

3.        合适的8-12V的电源

                                           

电机额定电压为12V,可以选择串联3节锂电池12V,或者两节锂电池8V来进行实验.

二、接线 !!!

电机 L298N STM32
M- OUT1 /
5V 5V /
A / 编码器模式定时器IO
B        / 编码器模式定时器IO

GND

GND GND
M+ OUT2 /
/ ENA PWM输出IO
/ M1 输出IO
/ M2 输出IO

        其中,这里要说明几点.

        1.L298N,单片机和电机需要共地

        2.我这里使用的是单PWM输出IO来控制ENA,而不是和其他博主一样使用两路PWM输出去控制M1,M2,然后一直使能的方法,这样可以节约一个定时器产生PWM.

三、Cubemax配置

1.首先是接线中用来控制M1和M2的两个IO口的输出配置,这里我使用的是PC4和PC5

 2.开启定时器一的编码器模式

这里面修改Counter Period为20000,即代表,编码器计数器范围为0~20000.其他默认即可,这里的分配系数表示的对计数值分频,如果你这里写了3=4-1,那后面speed算的时候就不用除以4了。

 对应的IO口为PE9,PE11.

 3.开启用于控制ENA的PWM输出

这里采用的是定时器5的PWM输出.

本实验使用的是F103的板子,PWM输出频率为100hz

 4.开启每隔10ms对编码器定时器中值的读取的定时器

5.最后配置中断 

这里注意一下,最好编码器的更新中断定时器,要比10ms定时器的优先级高,可以防止在更新中打被打断.

四、代码

首先创建一个文件Motor.c和Motor.h,在此文件中来编写我们有关电机的代码.

首先在Motor.h中来定义一些我们常用的东西

1.Motor.h中定义Motor相关参数

#define RR 30u    //电机减速比
#define RELOADVALUE __HAL_TIM_GetAutoreload(&htim1)    //获取自动装载值,本例中为20000
#define COUNTERNUM __HAL_TIM_GetCounter(&htim1)        //获取编码器定时器中的计数值
#define IN1(state) HAL_GPIO_WritePin(GPIOC,GPIO_PIN_4,(GPIO_PinState)(state))    //M1
#define IN2(state) HAL_GPIO_WritePin(GPIOC,GPIO_PIN_5,(GPIO_PinState)(state))    //M2

//电机结构体
typedef struct _Motor
{
	int32_t lastAngle;        //上10ms转过的角度
	int32_t totalAngle;       //总的角度
	int16_t loopNum;          //溢出次数计数值
	float speed;              //电机输出轴目前转速,单位为RPM
}Motor;

2.Motor初始化

void Motor_Init()
{
	HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);      //开启编码器定时器
    __HAL_TIM_ENABLE_IT(&htim1,TIM_IT_UPDATE);           //开启编码器定时器更新中断,防溢出处理
	HAL_TIM_Base_Start_IT(&htim6);                       //开启10ms定时器中断
	HAL_TIM_PWM_Start(&htim5, TIM_CHANNEL_2);            //开启PWM
	__HAL_TIM_SET_COUNTER(&htim1, 10000);                //编码器定时器初始值设定为10000
	motor.loopNum = 0;                                   //溢出计数
}

此函数在main中使用即可.

 3.中断处理函数重写

我们需要重写HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)来处理中断

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==htim6.Instance)		              //10ms中断
	{
		
		int16_t pluse = COUNTERNUM - RELOADVALUE/2;
        //从开始到现在当前10ms的总脉冲数							               									
		motor.totalAngle = pluse + motor.loopNum * RELOADVALUE/2;  
        //进行速度计算,根据前文所说的,4倍频,编码器13位,减速比30,再乘以6000即为每分钟输出轴多少转
        //motor.totalAngle - motor.lastAngle为当前10ms内的增量,即脉冲数
		motor.speed = (float)(motor.totalAngle - motor.lastAngle)/(4*13*RR)*6000;			
		motor.lastAngle = motor.totalAngle;              //更新转过的圈数
	}

    //如果是编码器更新中断,即10ms内,脉冲数超过了计数范围,需要进行处理
	else if(htim->Instance == htim1.Instance)            
	{
		if(COUNTERNUM < 10000)	motor.loopNum++;         //向上计数超过10000,正溢出+1
		else if(COUNTERNUM > 10000)	motor.loopNum--;     //向下计数小于0,负溢出+1
		__HAL_TIM_SetCounter(&htim1, 10000);             //重新设定初始值			
	}
}

这里注意,本文采用了编码器更新中断的方法,防止出现10ms内出现电机转速过快,脉冲计数超过设定值的情况出现,跟其他博主不同,主流在编码器计数时都采用限定值为65535,并没有考虑这个情况,不过多数电机不是转太快的情景,主流的方法都可行.

之后我们可以通过,对IN1,IN2写值,来控制电机正转,反转,然后对PWM写值,来控制电机运动来观察结构体中Motor中speed值的变化.

如果懒的写,就用手去选择一下输出轴或者上面的编码器盘,在debug中观察一下现象.

总结

本文介绍了编码器电机数据的读取,当我们可以读取到编码器电机中的值后,我们就可以在后续进行PID速度和串级PID角度的控制.

STM32 Cubemax(七) —— 单级PID控制带编码器的直流减速电机速度

版权声明:本文为CSDN博主「lzzzzzzm」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lzzzzzzm/article/details/119416134

生成海报
点赞 0

lzzzzzzm

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

辉光管升压电路理论,让USB升压170V

前言 辉光管是一种早期的字符显示元件,在数码管没有被开发,半导体没那么高级的情况下,是除了钨丝灯和氖泡外最主要的数显方式。 辉光管的驱动条件以现在眼光来看可能有点苛刻,并且非常危险&#x

【史上最全】常用USB转串口芯片特性比较

学电子设计少不了使用串口通信,但是现在的笔记本电脑基本上不带串口了,好在现在有USB转串口可以使用。市场上常见的USB转串口芯片主要有4个系列:CP2102、CH340、FT232、PL2303。 本文