STM32CubeMX(6) —— STM32利用定时器编码器模式处理带编码器直流电机
STM32利用定时器编码器模式处理带编码器直流电机
文章目录
目录
STM32 Cubemax(五) —— STM32利用定时器编码器模式处理带编码器直流电机
文章目录
前言
一、硬件准备
二、接线
三、Cubemax配置
四、代码
总结
前言
电赛延期了,趁有时间再写点东西吧.
编码器电机配置较为繁琐,本文较长,耐心看下去,一定有收获.
本文适合已经对编码器有所了解的同学观看,如果对编码器原理还不太理解,可以看看CSDN中别人讲编码器的,个人觉得已经讲的十分清楚了,这里主要讲解怎么使用Cubemax去使用编码器
一、硬件准备
- 本次实验使用的是带增量式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); //编码器定时器初始值设定为10000motor.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,正溢出+1else 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控制带编码器的直流减速电机速度
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
