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文件设置。

相关推荐
传感器与混合集成电路20 小时前
210℃与175℃高温存储器选型研究:LHM256MB与LDMF4GA-H架构与可靠性对比(上)
嵌入式硬件·能源
时光找茬20 小时前
【瑞萨AI挑战赛-FPB-RA6E2】+ 从零开始:FPB-RA6E2 开箱测评与 e2 studio 环境配置
c++·单片机·边缘计算
17(无规则自律)21 小时前
【CSAPP 读书笔记】第二章:信息的表示和处理
linux·嵌入式硬件·考研·高考
@good_good_study21 小时前
FreeRTOS内存管理
单片机
Hello_Embed1 天前
libmodbus 移植 STM32(基础篇)
笔记·stm32·单片机·学习·modbus
qq_397562311 天前
QT工程 , 生成别的电脑运行的exe程序
嵌入式硬件·qt
qqssss121dfd1 天前
STM32H750XBH6的ETH模块移植LWIP
网络·stm32·嵌入式硬件
想放学的刺客1 天前
单片机嵌入式试题(第27期)设计可移植、可配置的外设驱动框架的关键要点
c语言·stm32·单片机·嵌入式硬件·物联网
天昊吖1 天前
stc8H启用DMA发送后 卡住【踩坑日志】
单片机
李永奉1 天前
杰理芯片SDK开发-ENC双麦降噪配置/调试教程
人工智能·单片机·嵌入式硬件·物联网·语音识别