一、基础配置
首先完成cubemx的基础配置。如下图所示
二、定时器配置
这里采用定时器2通道1来产生PWM波,配置如下。
定时器PWM的计算方法如下。
为方便代码函数的封装先采用84-1的预分频,即84MHZ除以84得到1MHZ。自动重装载值先随便写一个20000-1后续代码会更改,然后占空比是不影响步进电机的速度的,我们默认百分之五十即可,即下方PWM选择自动重装载值的一半即可。我们还要打开定时器中断,方便后续计数控制圈数。
接着,步进电机需要一个使能引脚和一个方向引脚,这里选择两个GPIO口输出就行了。这里选择PA2和PC0,可以根据需要更改IO口,然后直接生成代码就行。
三、步进电机
步进电机需要驱动器来驱动,这里我选择的是ATK-2MD5050这种驱动器。这种驱动器右侧有拨码开关,我们可以通过拨码开关的不同来选择模式。上面的Microstep是细分步数,下面我将解释一下,我们的步进电机上面会有信息,我这里使用的1.8°四线两相的步进电机,电流为1.7A。1.8°的意思就是满足一些脉冲数其转动的角度,即步距角。
我们知道一圈的度数是360°,那么360°除以1.8°得到200,这个200就是我们转一圈所需要的脉冲数,就是需要200个高低电平的PWM。即200个周期的PWM。这里我选择了16细分,即200乘以16=3200,3200才是我所需要的脉冲个数,即3200个脉冲信号。后续代码我也是以16细分来编写的。即SW1 SW2 SW3 SW4 满足ON OFF ON ON
接着,电机额定电流是1.7A,将开关打成2A即可 就是SW5 SW6 SW7 SW8 满足ON OFF OFF OFF
然后是驱动器右侧一栏,我们看控制信号那一栏,其中ENA+ DIR+ PUL+我们接上5V的电压就行了,然后ENA-的意思就是使能引脚,我们选择上面配置的GPIO口,这里我选择的是PC0来控制,高电平使能,低电平失能。
那么同理,大家应该就知道DIR-就是控制方向的了,我选择的是PA2来控制,高电平和低电平分别控制正转和反转。
最下面的呢,A+ A- B+ B- 是接步进电机四根线的,其中一相就是两根线,如果电机上有信息直接接上就行了对应的线。如果没有,大家可以把其中的线两两接触,如果转不动,那么就是一相的,接上去就行了。
到这里驱动器和步进电机就介绍完了。
四、代码编写
代码这里只讲解主要部分。
如果我们想要写一个驱动去控制步进电机转动的速度,我们就要明白,控制步进电机速度的是PWM波形的频率,那么上面的公式我们已经知道如何计算频率和周期了,这里我写的是让步进电A机转一圈需要多少秒来控制步进电机的速度的。我们不改变预分频系数和驱动器的细分步长来控制变量,那么现在未知量就是用户输入的几秒钟,我们设为X变量,还有通过X得到需要改变的ARR即重装载值,设为Y,两个变量满足什么关系呢?不难得到PWM波形频率的倒数就是周期T,我们已知3200的脉冲数是固定的,那么就有以下的关系式,从而得到X与Y的关系,我们写成代码即可。其中的X是我们要输入的参数即多少秒转一圈,其中的Y就是我们需要更改的重装载值,从而去改变PWM输入的周期,从而改变转速。
上面,我们已经实现了如何控制速度,那么如何控制圈数呢?我们只需要在定时中断里面,进行计数就可以了,因为3200个脉冲转一圈是固定的数,我们只需要读取定时器中断里面的数值除以3200,就知道现在过去了几圈。再进行比较的if语句,就能实现控制了。这里我用KE1表示按键按下,大家知道即可。记得使能中断函数。
这里只介绍主要函数的由来,代码放在下面自取。
#ifndef __motor_H__
#define __motor_H__
#include "stm32f4xx_hal.h"
#include "tim.h"
#include "gpio.h"
extern int num;
extern float arr;
extern int key1;
void Motro1_PWM_Start(void);//初始化PWM
void Motor1_enable(void);//PC0使能
void Motor1_disable(void);//PC0失能
void Motor1_course(char course_mod);//PA2正转反转
void Motor1_Speed(float speed);//1圈所耗时间 使用16细分计算 占空比默认百分之五十
void Motro1_angle(int Angle,float TTIME); //参数1为圈数 参数2为速度
#endif
#include "motor.h"
#include "tim.h"
int num=0;
int key1=1;//按键按下给标志位1 先默认为0 后续更改
float arr=0;
TIM_OC_InitTypeDef Motor_PWM_sConfigOC = {0};
//TIM_HandleTypeDef htim2;
//初始化步进电机PWM
void Motro1_PWM_Start(void)
{
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1); //串口2通道1 可修改其他串口
}
//步进电机使能 PC0
void Motor1_enable(void)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET);
}
//步进电机失能 PC0
void Motor1_disable(void)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
}
//步进电机正转反转 PA2正转反转
void Motor1_course(char course_mod)
{
if(course_mod == 1){HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);} // 正转
else if(course_mod == 0){HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);} // 反转
}
//控制电机速度 1圈几秒
void Motor1_Speed(float time)
{
arr = 312.5f*time;
__HAL_TIM_SET_AUTORELOAD(&htim2, arr);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, arr/2);
}
//参数1圈数 参数2速度
void Motro1_angle(int Angle,float TTIME)
{
if(key1==1)
{
Motor1_Speed(TTIME);
if(Angle<=(num/3200))
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
num=0;
key1=0;
}
}
}
//定时器中断函数 用于计算圈数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim == (&htim2))
{
if(key1==1)
{
num ++;
}
}
}