HAL库 STM32+DRV8825模块 驱动42步进电机 的3种方法超详细---普通IO口+定时器中断(二)

记录一下学习使用STM32+DRV8825模块驱动步进电机的3种方法。有需要可自取,有错误可留言或者私信我。

3种方法:

1.普通IO口+延迟函数。堵塞

2.普通IO口+定时器(定时器中断)。非堵塞

3.定时器PWM。非堵塞

DRV8825模块+硬件介绍请参考:https://blog.csdn.net/xiaokaidbb/article/details/160931219?spm=1001.2014.3001.5502

方法二:

普通IO口+定时器(定时器中断)。非堵塞版

一、代码介绍

1.建立hal工程

2.设置时钟

3.定时器中断设置

定时器参数设置

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 72-1;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 100-1;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;

4 使能GPIO

PA6--nEN,推挽模式,初始化高电平

PA7--DIR,推挽模式,初始化低电平

PB0--STEP,推挽模式,初始化低电平

GPIO不需要在这里配置,稍后会在motor.c中配置。

5.使能定时器中断

生成工程

代码编写

1.创建motor.c和motor.h文件

2. motor.h

#ifndef __MOTOR_H
#define __MOTOR_H

#include "stm32f1xx_hal.h"

// 引脚定义
#define MOTOR_EN_Pin        GPIO_PIN_6
#define MOTOR_EN_GPIO_Port  GPIOA

#define MOTOR_DIR_Pin       GPIO_PIN_7
#define MOTOR_DIR_GPIO_Port GPIOA

#define MOTOR_STEP_Pin      GPIO_PIN_0
#define MOTOR_STEP_GPIO_Port GPIOB

extern uint32_t motor_current_steps;
// 电机方向
typedef enum
{
    CW  = 1,   // 正转
    CCW = 0    // 反转
} Motor_DirTypeDef;

// 对外函数
void Motor_Init(void);
void Motor_Start(Motor_DirTypeDef dir, uint32_t total_steps, uint16_t normal_speed);
void Motor_Stop(void);
uint8_t Motor_IsBusy(void);

#endif

motor.c

#include "motor.h"



extern TIM_HandleTypeDef htim2;

uint32_t motor_target_steps = 0;		//目标步数
uint32_t motor_current_steps = 0;	//当前步数
uint8_t  motor_running_flag = 0;			//	0为空闲,1为电机正在运行,只有电机处于空闲状态,才能执行下一次电机指令

// ===================== 平滑启停参数 =====================
#define ACCEL_STEPS  100      // 启动加速步数
#define DECEL_STEPS  100      // 停止减速步数
#define START_SPEED  4000     // 启动最慢速度
// ========================================================

uint16_t user_normal_speed;  // 你设定的正常速度

void Motor_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();

    // PA6 PA7
    GPIO_InitStruct.Pin = MOTOR_EN_Pin | MOTOR_DIR_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // PB0
    GPIO_InitStruct.Pin = MOTOR_STEP_Pin;
    HAL_GPIO_Init(MOTOR_STEP_GPIO_Port, &GPIO_InitStruct);

    HAL_GPIO_WritePin(MOTOR_EN_GPIO_Port, MOTOR_EN_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(MOTOR_DIR_GPIO_Port, MOTOR_DIR_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(MOTOR_STEP_GPIO_Port, MOTOR_STEP_Pin, GPIO_PIN_RESET);
}

// 启动电机(非阻塞)(设置半周期最好在100-3000之间)
void Motor_Start(Motor_DirTypeDef dir, uint32_t steps, uint16_t half_period_us)
{
    if(steps == 0 || motor_running_flag) return;

    // 使能 + 方向
    HAL_GPIO_WritePin(MOTOR_EN_GPIO_Port, MOTOR_EN_Pin, GPIO_PIN_RESET);
	
	dir ? HAL_GPIO_WritePin(MOTOR_DIR_GPIO_Port, MOTOR_DIR_Pin, GPIO_PIN_SET) :     
    HAL_GPIO_WritePin(MOTOR_DIR_GPIO_Port, MOTOR_DIR_Pin, GPIO_PIN_RESET);

    HAL_Delay(1);

    motor_target_steps = steps;
    motor_current_steps = 0;
    motor_running_flag = 1;

	// 保存用户设定的正常速度
    user_normal_speed = half_period_us;
	
	
    // 设置 TIM2 中断速度
    __HAL_TIM_SET_AUTORELOAD(&htim2, START_SPEED);
	
	 // 【可选】立即生效,不等待当前计数结束(强制更新)
    __HAL_TIM_SET_COUNTER(&htim2, 0);  // 清零计数器
    __HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE); // 清除更新标志

    // 关键!!!启动中断
    HAL_TIM_Base_Start_IT(&htim2);
}

void Motor_Stop(void)
{
	motor_target_steps = 0;
    motor_current_steps = 0;
    motor_running_flag = 0;
    HAL_GPIO_WritePin(MOTOR_EN_GPIO_Port, MOTOR_EN_Pin, GPIO_PIN_SET);
}

uint8_t Motor_IsBusy(void)
{
    return motor_running_flag;
}

//// ==============================
//// 定时器中断:匀速
//// ==============================
//void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
//{
//	if(htim==&htim2)
//	{
//		if(!motor_running_flag) return;
//		
//		// 只做引脚翻转,不做任何延时
//		HAL_GPIO_TogglePin(MOTOR_STEP_GPIO_Port, MOTOR_STEP_Pin);

//		// 只有当引脚拉低时,才算完成一个脉冲
//		if(HAL_GPIO_ReadPin(MOTOR_STEP_GPIO_Port, MOTOR_STEP_Pin) == 0)
//		{
//			motor_current_steps++;

//			if(motor_current_steps >= motor_target_steps)
//			{
//				Motor_Stop();
//				HAL_TIM_Base_Stop_IT(&htim2); // 停止定时器中断,防止一直触发
//			}
//		}
//		
//	}
//	
//}

// ==============================
// 定时器中断 + 平滑加减速(你要的功能在这里!)
// ==============================
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim == &htim2)
    {
        if(!motor_running_flag) return;

        // 发脉冲
        HAL_GPIO_TogglePin(MOTOR_STEP_GPIO_Port, MOTOR_STEP_Pin);

        if(HAL_GPIO_ReadPin(MOTOR_STEP_GPIO_Port, MOTOR_STEP_Pin) == 0)
        {
            motor_current_steps++;

            // ===================== 【平滑加减速核心】 =====================
            uint16_t current_period = __HAL_TIM_GET_AUTORELOAD(&htim2);

            // 1. 启动加速:从慢 → 正常速度
            if(motor_current_steps <= ACCEL_STEPS)
            {
                if(current_period > user_normal_speed)
                {
                    current_period -= 20;  // 数值越小加速越柔
                }
            }
            // 2. 停止减速:正常 → 慢
            else if(motor_current_steps >= motor_target_steps - DECEL_STEPS)
            {
                if(current_period < START_SPEED)
                {
                    current_period += 20;
                }
            }
            // 3. 中间保持正常速度
            else
            {
                current_period = user_normal_speed;
            }

            // 更新速度
            __HAL_TIM_SET_AUTORELOAD(&htim2, current_period);
            // ==============================================================

            // 到达终点停止
            if(motor_current_steps >= motor_target_steps)
            {
                Motor_Stop();
                HAL_TIM_Base_Stop_IT(&htim2);
            }
        }
    }
}




main.c

添加头文件

#include "motor.h"

在main()函数里面,while(1)函数之前添加

    Motor_Init();    //初始化
	HAL_Delay(1000);
	
	if(!Motor_IsBusy())
        {
            Motor_Start(CCW, 6400, 600);
		    //反转1圈,600us半周期,想要加速,减小半周期值
        }
	
	HAL_Delay(1000);

	if(!Motor_IsBusy())
        {
            Motor_Start(CW, 6400, 600);
		    //正转1圈,600us半周期
        }

实验现象

        上电后,反转1圈,延迟1秒,正转1圈。

速度说明:

运行Motor_Start(CW, 6400, 600);函数后,前100step,速度会从0逐步加速到设定的速度,然后按照规定速度匀速行驶,快到终点的前100步,速度会从设定速度逐步减小到0.

核心:

运行Motor_Start函数后

1.        使能电机

2.        设置方向

3.        设置定时器的ARR,(ARR可以控制转速),清空cnt,清除更新标志,开启定时器中断。

4.        在中断回调函数HAL_TIM_PeriodElapsedCallback中,翻转STEP引脚,motor_current_steps计数+1,motor_current_steps等于我们设置的步数后,当motor_current_steps==motor_target_steps后,停止中断。失能电机

工程文件下载链接:
链接: 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、付费专栏及课程。

余额充值