HAL库 STM32+DRV8825模块 驱动42步进电机 的3种方法超详细---定时器PWM(3)

记录一下学习使用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

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值