记录一下学习使用STM32+DRV8825模块驱动步进电机的3种方法。有需要可自取,有错误可留言或者私信我。
3种方法:
1.普通IO口+延迟函数。阻塞
2.普通IO口+定时器(定时器中断)。非阻塞
3.定时器PWM。非阻塞
DRV8825模块+硬件介绍请参考:https://blog.csdn.net/xiaokaidbb/article/details/160931219?spm=1001.2014.3001.5502
方法三:定时器PWM,非阻塞
一、代码介绍
建立hal库
1.设置debug为Serial Wire模式,必须设置,不然会锁芯片

2.设置时钟


3.配置定时器PWM
htim3.Instance = TIM3;
htim3.Init.Prescaler = 71;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 999;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 500;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;


设置nvic

配置gpio

生成工程文档


MDK5:代码编写
1.创建motor.c和motor.h文件
motor.h
#ifndef __MOTOR_H
#define __MOTOR_H
#include "main.h"
// 引脚定义
//电机EN使能引脚
#define MOTOR_nEN_Pin GPIO_PIN_6
#define MOTOR_nEN_Port GPIOA
//电机方向DIR引脚
#define MOTOR_DIR_Pin GPIO_PIN_7
#define MOTOR_DIR_Port GPIOA
// 加减速配置
#define ACCEL_STEPS 200 // 加速步数
#define DECEL_STEPS 200 // 减速步数
#define START_SPEED_ARR 3000 // 启动速度(越大越慢)
// 电机控制结构体
typedef struct
{
volatile uint32_t pulse_cnt; // 当前已发脉冲数
volatile uint32_t target_steps; // 目标步数
uint16_t current_speed_arr; // 当前速度ARR
uint16_t target_speed_arr; // 目标匀速速度ARR
uint32_t accel_step; // 加速阶段结束点
uint32_t decel_start_step; // 减速阶段开始点
} MotorCtrl_t;
// ======================
// 方向枚举(替换宏定义)
// ======================
typedef enum
{
MOTOR_DIR_CW = 0, // 顺时针
MOTOR_DIR_CCW // 逆时针(自动=1)
} MotorDir_t;
extern MotorCtrl_t motor_ctrl;
void MOTOR_Init(void);
void MOTOR_Enable(void);
void MOTOR_Disable(void);
void MOTOR_Dir(MotorDir_t dir);
void MOTOR_UpdateSpeed(void);
void MOTOR_RunSteps(uint32_t steps, MotorDir_t dir, uint16_t speed_arr);
void MOTOR_Stop(void);
uint8_t MOTOR_IsFinished(void);
#endif
motor.c
#include "motor.h"
#include "tim.h"
// 定义全局电机控制结构体
MotorCtrl_t motor_ctrl;
void MOTOR_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
// PA6 nEN 推挽输出
GPIO_InitStruct.Pin = MOTOR_nEN_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(MOTOR_nEN_Port, &GPIO_InitStruct);
HAL_GPIO_WritePin(MOTOR_nEN_Port, MOTOR_nEN_Pin, GPIO_PIN_SET);
// PA7 DIR 推挽输出
GPIO_InitStruct.Pin = MOTOR_DIR_Pin;
HAL_GPIO_Init(MOTOR_DIR_Port, &GPIO_InitStruct);
HAL_GPIO_WritePin(MOTOR_DIR_Port, MOTOR_DIR_Pin, GPIO_PIN_RESET);
// 初始化结构体
motor_ctrl.pulse_cnt = 0;
motor_ctrl.target_steps = 0;
}
//使能电机
void MOTOR_Enable(void)
{
HAL_GPIO_WritePin(MOTOR_nEN_Port, MOTOR_nEN_Pin, GPIO_PIN_RESET);
}
//失能电机
void MOTOR_Disable(void)
{
HAL_GPIO_WritePin(MOTOR_nEN_Port, MOTOR_nEN_Pin, GPIO_PIN_SET);
}
//设置方向
void MOTOR_Dir(MotorDir_t dir)
{
dir ? HAL_GPIO_WritePin(MOTOR_DIR_Port, MOTOR_DIR_Pin, GPIO_PIN_SET) : HAL_GPIO_WritePin(MOTOR_DIR_Port, MOTOR_DIR_Pin, GPIO_PIN_RESET);
}
// 更新速度(梯形加减速),启动和停止时候缓慢加速和缓慢减速
void MOTOR_UpdateSpeed(void)
{
if(motor_ctrl.pulse_cnt < motor_ctrl.accel_step)
{
// 加速阶段
uint32_t pos = motor_ctrl.pulse_cnt;
motor_ctrl.current_speed_arr = START_SPEED_ARR - ((START_SPEED_ARR - motor_ctrl.target_speed_arr) * pos / motor_ctrl.accel_step);
}
else if(motor_ctrl.pulse_cnt >= motor_ctrl.decel_start_step)
{
// 减速阶段
uint32_t pos = motor_ctrl.pulse_cnt - motor_ctrl.decel_start_step;
motor_ctrl.current_speed_arr = motor_ctrl.target_speed_arr + ((START_SPEED_ARR - motor_ctrl.target_speed_arr) * pos / DECEL_STEPS);
}
else
{
// 匀速阶段
motor_ctrl.current_speed_arr = motor_ctrl.target_speed_arr;
}
// // 防止速度过快失步,设置最小速度
// if(motor_ctrl.current_speed_arr < 400)
// motor_ctrl.current_speed_arr = 400;
__HAL_TIM_SET_AUTORELOAD(&htim3, motor_ctrl.current_speed_arr - 1);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, motor_ctrl.current_speed_arr / 2);
}
// 非阻塞运行指定步数,speed_arr最好设置在50-3000之间
//转速计算公式:一分钟转多少圈:RPM=9375/speed_arr;
//speed_arr=50-3000,所以RPM=187.5转/分钟----3.125转/分钟。即3.125转/秒--0.05转/秒
void MOTOR_RunSteps(uint32_t steps, MotorDir_t dir, uint16_t speed_arr)
{
motor_ctrl.target_steps = steps;
motor_ctrl.target_speed_arr = speed_arr;
motor_ctrl.pulse_cnt = 0;
// 加减速区间计算
motor_ctrl.accel_step = ACCEL_STEPS;
motor_ctrl.decel_start_step = motor_ctrl.target_steps - DECEL_STEPS;
// 保护:加速步数不超过总步数的一半
if(motor_ctrl.accel_step > motor_ctrl.target_steps / 2)
motor_ctrl.accel_step = motor_ctrl.target_steps / 2;
// 保护:减速开始点不能早于加速结束点
if(motor_ctrl.decel_start_step < motor_ctrl.accel_step)
motor_ctrl.decel_start_step = motor_ctrl.accel_step;
// 初始速度(启动速度)
motor_ctrl.current_speed_arr = START_SPEED_ARR;
__HAL_TIM_SET_AUTORELOAD(&htim3, START_SPEED_ARR - 1);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, START_SPEED_ARR / 2);
//设置方向
MOTOR_Dir(dir);
// 使能电机
HAL_GPIO_WritePin(MOTOR_nEN_Port, MOTOR_nEN_Pin, GPIO_PIN_RESET);
// 启动定时器中断 + PWM
__HAL_TIM_SET_COUNTER(&htim3, 0); //cnt清零
HAL_TIM_Base_Start_IT(&htim3); //开启定时器中断
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3); //开启PWM外设
}
// 判断是否运动完成
uint8_t MOTOR_IsFinished(void)
{
return (motor_ctrl.target_steps == 0);
}
//停止电机
void MOTOR_Stop(void)
{
HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_3); // 停止PWM脉冲
HAL_TIM_Base_Stop_IT(&htim3); // 关闭定时器中断
HAL_GPIO_WritePin(MOTOR_nEN_Port, MOTOR_nEN_Pin, GPIO_PIN_SET); // 失能电机
motor_ctrl.pulse_cnt = 0; //计数清零
motor_ctrl.target_steps = 0;
}
// 定时器更新中断回调:1次中断 = 1个STEP脉冲
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==&htim3)
{
if(motor_ctrl.target_steps == 0) //target_steps=0,退出
return;
motor_ctrl.pulse_cnt++; //记录中断溢出次数,完成一个脉冲周期,就会进入一次中断回调函数
MOTOR_UpdateSpeed(); //梯形调速
if(motor_ctrl.pulse_cnt >= motor_ctrl.target_steps) //判断有没有到达目标步数,到达关闭
{
MOTOR_Stop();
}
}
}
main函数
添加头文件
#include "motor.h"
功能实现
MOTOR_Init();
HAL_Delay(500);
// 等待电机空闲
while (!MOTOR_IsFinished());
// 1. 正转 1 圈(32细分 = 6400 步)
MOTOR_RunSteps(6400, MOTOR_DIR_CW, 500);
// 等待正转完成
while (!MOTOR_IsFinished());
// 等待 500ms
HAL_Delay(500);
// 2. 反转 1 圈
MOTOR_RunSteps(6400, MOTOR_DIR_CCW, 500);
实验现象:
上电初始化后,42步进电机,正转1圈,延迟500ms,反转1圈。启动和停止时候会有缓冲
代码核心:
1.运行MOTOR_RunSteps函数
2.初始化电机参数
3.设置方向
4.使能电机
5.启动定时器中断 + PWM
6.这时候定时器3通道3就会产生PWM波形
7.在定时器中断回调函数HAL_TIM_PeriodElapsedCallback中,进入1次中断 = 1个STEP脉冲
8.等pulse_cnt==target_steps时,表示已经走完我们设置的步数。
9.关闭PWM,关闭步进电机
工程文档下载链接:
通过网盘分享的文件:HAL STEPPER.7z
链接: https://pan.baidu.com/s/1BLXntDO1Cg6tmF6i-T_Tig?pwd=rdgc 提取码: rdgc
346

被折叠的 条评论
为什么被折叠?



