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

相关推荐
soulermax6 小时前
数字ic后端设计从入门到精通11(含fusion compiler, tcl教学)全定制设计入门
嵌入式硬件·fpga开发·硬件架构
weixin_1122337 小时前
基于STM32单片机车牌识别系统摄像头图像处理设计的论文
图像处理·stm32·单片机
国科安芯8 小时前
抗辐照与国产替代:ASM1042在卫星光纤放大器(EDFA)中的应用探索
网络·单片机·嵌入式硬件·安全·硬件架构
TESmart碲视9 小时前
一台显示器上如何快速切换两台电脑主机?
单片机·计算机外设·电脑·显示器·智能硬件
DIY机器人工房9 小时前
关于字符编辑器vi、vim版本的安装过程及其常用命令:
linux·stm32·单片机·嵌入式硬件·编辑器·vim·diy机器人工房
风之子npu11 小时前
后仿之debug记录
单片机·嵌入式硬件
芯巧电子12 小时前
PSpice软件快速入门系列--11.如何进行PSpice AA电应力(Smoke)分析
单片机·嵌入式硬件
景彡先生12 小时前
STM32 RTOS 开发基础:从任务管理到同步机制的全面解析
stm32·单片机·嵌入式硬件
GalaxySinCos12 小时前
03 51单片机之独立按键控制LED状态
单片机·嵌入式硬件·51单片机