stm32驱动双步进电机

连线看我上一个文章,这里只是补充上一个文章的代码部分,上一个是单步进电机的,这个是双步进电机。

这里外加一个32的引脚定义表:

具体接线看我上一个文章。

PWM.C文件:

#include "stm32f10x.h"

#include "math.h"

// 步进电机参数配置

#define STEPS_PER_REVOLUTION 200 // 每转步数 (1.8°/步)

#define MICROSTEPS 16 // 微步细分

#define STEPS_PER_REVOLUTION2 200 // 每转步数 (1.8°/步)

#define MICROSTEPS2 16 // 微步细分

// 全局变量

volatile uint32_t step_count = 0; // 电机1当前步数

float current_angle = 0.0f; // 电机1当前角度(支持累积,如720°表示2圈)

volatile uint8_t motor1_running = 0; // 电机1运行标志

uint32_t motor1_target_steps = 0; // 电机1目标步数

float motor1_target_angle;

volatile uint32_t step_count2 = 0; // 电机2当前步数

float current_angle2 = 0.0f; // 电机2当前角度(支持累积)

volatile uint8_t motor2_running = 0; // 电机2运行标志

uint32_t motor2_target_steps = 0; // 电机2目标步数

float motor2_target_angle;

// 电机1初始化

void Stepper_Init(void) {

GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_OCInitTypeDef TIM_OCInitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

// 使能时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

// 配置PWM输出引脚 (PA1 - TIM2_CH2)

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

// 配置方向控制引脚 (PA2)

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

// 配置定时器时基

TIM_TimeBaseStructure.TIM_Period = 7200 - 1; // 初始频率约10Hz @72MHz

TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

// PWM 输出配置

TIM_OCStructInit(&TIM_OCInitStructure);

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

TIM_OCInitStructure.TIM_Pulse = 3600; // 50% 占空比

TIM_OC2Init(TIM2, &TIM_OCInitStructure);

// 配置更新中断

NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

}

// 电机2初始化

void Stepper_Init2(void) {

GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_OCInitTypeDef TIM_OCInitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

// 使能时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

// 配置PWM输出引脚 (PA6 - TIM3_CH1)

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

// 配置方向控制引脚 (PA3)

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

// 配置定时器时基

TIM_TimeBaseStructure.TIM_Period = 7200 - 1; // 初始频率约10Hz @72MHz

TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

// PWM 输出配置

TIM_OCStructInit(&TIM_OCInitStructure);

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

TIM_OCInitStructure.TIM_Pulse = 3600; // 50% 占空比

TIM_OC1Init(TIM3, &TIM_OCInitStructure);

// 配置更新中断

NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

}

// 电机1速度设置(RPM)

void Set_Motor_Speed(float rpm) {

if (rpm <= 0) return;

uint32_t freq = (uint32_t)(rpm * STEPS_PER_REVOLUTION * MICROSTEPS / 60.0f);

if (freq == 0) return;

uint32_t arr = (72000000UL / (72UL * freq)) - 1;

if (arr < 10) arr = 10; // 避免溢出

TIM_SetAutoreload(TIM2, arr);

TIM_SetCompare2(TIM2, arr / 2); // 50%占空比

}

// 电机2速度设置(RPM)

void Set_Motor_Speed2(float rpm) {

if (rpm <= 0) return;

uint32_t freq = (uint32_t)(rpm * STEPS_PER_REVOLUTION2 * MICROSTEPS2 / 60.0f);

if (freq == 0) return;

uint32_t arr = (72000000UL / (72UL * freq)) - 1;

if (arr < 10) arr = 10; // 避免溢出

TIM_SetAutoreload(TIM3, arr);

TIM_SetCompare1(TIM3, arr / 2); // 50%占空比

}

// 启动电机1

void Start_Motor(void) {

step_count = 0;

TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

TIM_Cmd(TIM2, ENABLE);

}

// 启动电机2

void Start_Motor2(void) {

step_count2 = 0;

TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

TIM_Cmd(TIM3, ENABLE);

}

// 停止电机1

void Stop_Motor(void) {

TIM_Cmd(TIM2, DISABLE);

TIM_SetCompare2(TIM2, 0);

TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

}

// 停止电机2

void Stop_Motor2(void) {

TIM_Cmd(TIM3, DISABLE);

TIM_SetCompare1(TIM3, 0);

TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

}

// 电机1转动到目标角度(支持任意角度,包括多圈)

void Rotate_To_Angle(float target_angle, float speed_rpm) {

// 计算原始角度差(保留多圈信息,不做规范化)

float angle_diff = target_angle - current_angle;

// 忽略微小角度(<0.5°),避免误触发

if (fabs(angle_diff) < 0.5f) {

current_angle = target_angle; // 同步角度,消除累积误差

return;

}

// 计算所需总步数(含多圈,四舍五入提高精度)

int32_t required_steps = (int32_t)round(

angle_diff * STEPS_PER_REVOLUTION * MICROSTEPS / 360.0f

);

// 处理步数为0的极端情况(理论上不会触发)

if (required_steps == 0) return;

// 根据角度差判断转动方向

if (angle_diff > 0) {

GPIO_SetBits(GPIOA, GPIO_Pin_2); // 正转

} else {

GPIO_ResetBits(GPIOA, GPIO_Pin_2); // 反转

required_steps = -required_steps; // 步数取绝对值

}

// 配置目标参数并启动电机

motor1_target_angle = target_angle; // 保存目标角度(支持多圈)

motor1_target_steps = required_steps; // 总步数(含多圈)

motor1_running = 1;

Set_Motor_Speed(speed_rpm); // 设置转速

Start_Motor(); // 启动电机

}

// 电机2转动到目标角度(支持任意角度,包括多圈)

void Rotate_To_Angle2(float target_angle, float speed_rpm) {

// 计算原始角度差(保留多圈信息,不做规范化)

float angle_diff2 = target_angle - current_angle2;

// 忽略微小角度(<0.5°),避免误触发

if (fabs(angle_diff2) < 0.5f) {

current_angle2 = target_angle; // 同步角度,消除累积误差

return;

}

// 计算所需总步数(含多圈,四舍五入提高精度)

int32_t required_steps = (int32_t)round(

angle_diff2 * STEPS_PER_REVOLUTION2 * MICROSTEPS2 / 360.0f

);

// 处理步数为0的极端情况(理论上不会触发)

if (required_steps == 0) return;

// 根据角度差判断转动方向

if (angle_diff2 > 0) {

GPIO_SetBits(GPIOA, GPIO_Pin_3); // 正转

} else {

GPIO_ResetBits(GPIOA, GPIO_Pin_3); // 反转

required_steps = -required_steps; // 步数取绝对值

}

// 配置目标参数并启动电机

motor2_target_angle = target_angle; // 保存目标角度(支持多圈)

motor2_target_steps = required_steps; // 总步数(含多圈)

motor2_running = 1;

Set_Motor_Speed2(speed_rpm); // 设置转速

Start_Motor2(); // 启动电机

}

// 电机1按相对角度转动(+正转,-反转,支持多圈)

void Rotate_Relative(float angle, float speed_rpm) {

if (fabs(angle) < 0.5f) return; // 忽略微小角度

Rotate_To_Angle(current_angle + angle, speed_rpm); // 目标角度 = 当前角度 + 相对角度

}

// 电机2按相对角度转动(+正转,-反转,支持多圈)

void Rotate_Relative2(float angle, float speed_rpm) {

if (fabs(angle) < 0.5f) return; // 忽略微小角度

Rotate_To_Angle2(current_angle2 + angle, speed_rpm); // 目标角度 = 当前角度 + 相对角度

}

// 电机1中断服务函数(TIM2)

void TIM2_IRQHandler(void) {

if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {

step_count++;

if (step_count >= motor1_target_steps) {

motor1_running = 0;

Stop_Motor();

current_angle = motor1_target_angle; // 直接更新为目标角度(无累积误差)

}

TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

}

}

// 电机2中断服务函数(TIM3)

void TIM3_IRQHandler(void) {

if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {

step_count2++;

if (step_count2 >= motor2_target_steps) {

motor2_running = 0;

Stop_Motor2();

current_angle2 = motor2_target_angle; // 直接更新为目标角度(无累积误差)

}

TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

}

}

PWM.H文件:

#ifndef __PWM2_H

#define __PWM2_H

void Stepper_Init(void);

void Stepper_Init2(void);

void Start_Motor(void);

void Stop_Motor(void);

void Set_Motor_Speed(float rpm);

void Rotate_To_Angle(float target_angle, float speed_rpm);

void Start_Motor2(void);

void Stop_Motor2(void);

void Set_Motor_Speed2(float rpm);

void Rotate_To_Angle2(float target_angle, float speed_rpm);

void Rotate_Relative(float angle, float speed_rpm);

void Rotate_Relative2(float angle, float speed_rpm);

void TIM2_IRQHandler(void);

void TIM3_IRQHandler(void);

#endif

可以看到有两个功能

1 Rotate_To_Angle(角度,速度);到达指定角度;

2 Rotate_Relative(角度,速度);旋转角度不计数;

注意:步长已经是设置好的,如果你输入的角度和旋转的角度等比例不一样说明你设置的和我不一样,我这里脉冲量是3200,自己在.c文件设置。

相关推荐
CODECOLLECT1 小时前
京元 I62D Windows PDA 技术拆解:Windows 10 IoT 兼容 + 硬解码模块,如何降低工业软件迁移成本?
stm32·单片机·嵌入式硬件
BackCatK Chen1 小时前
STM32+FreeRTOS:嵌入式开发的黄金搭档,未来十年就靠它了!
stm32·单片机·嵌入式硬件·freertos·低功耗·rtdbs·工业控制
全栈游侠4 小时前
STM32F103XX 02-电源与备份寄存器
stm32·单片机·嵌入式硬件
Lsir10110_4 小时前
【Linux】中断 —— 操作系统的运行基石
linux·运维·嵌入式硬件
深圳市九鼎创展科技6 小时前
瑞芯微 RK3399 开发板 X3399 评测:高性能 ARM 平台的多面手
linux·arm开发·人工智能·单片机·嵌入式硬件·边缘计算
辰哥单片机设计6 小时前
STM32项目分享:车辆防盗报警系统
stm32·单片机·嵌入式硬件
風清掦8 小时前
【江科大STM32学习笔记-05】EXTI外部中断11
笔记·stm32·学习
小龙报8 小时前
【51单片机】从 0 到 1 玩转 51 蜂鸣器:分清有源无源,轻松驱动它奏响新年旋律
c语言·数据结构·c++·stm32·单片机·嵌入式硬件·51单片机
范纹杉想快点毕业8 小时前
嵌入式与单片机开发核心学习指南——从思维转变到第一性原理的深度实践
单片机·嵌入式硬件
Industio_触觉智能8 小时前
瑞芯微RK3566开发板规格书,详细参数配置,型号EVB3566-V1,基于RK3566核心板SOM3566邮票孔封装
嵌入式硬件·开发板·rk3568·rk3566·核心板·瑞芯微