stm32驱动无刷电调控制无刷电机原理及代码(按键启停与调速)

2025-10-05 11:57:50

能看到这篇文章的说明对无刷电机也有过一定了解了,所以我就简单介绍一下无刷电机然后就介绍驱动,已经了解无刷电机的可直接翻到下面观看驱动部分。

“无刷”的本质: 去除了有刷电机的机械换向器(电刷和换向片),改用电子换向。

换向: 根据转子位置信息,按特定顺序给电机的定子绕组通电,产生旋转磁场,吸引或推动永磁体转子持续旋转。

定子: 铁芯上绕有绕组(通常是三相:U, V, W)。

转子: 装有永磁体(通常是钕铁硼或铁氧体)。

转子位置传感器: (可选但常用)如霍尔效应传感器、编码器(增量式/绝对式)或无传感器电路。

电子控制器 (ESC - Electronic Speed Controller): 包含功率开关器件(通常是 MOSFET 或 IGBT)、驱动电路、控制逻辑(微控制器)和电源管理。它根据控制指令和转子位置信息,精确控制流经各相绕组的电流。

1.无刷电机主要分为两类

一类是无刷直流电机(BLDC)- 控制方式为梯形波/方波驱动 - 又称六步换向 (如下图所示)

控制器根据转子位置信息(来自霍尔传感器或无传感器算法),将直流母线电压通过逆变桥(由6个功率开关管组成,如MOSFET)以方波电压的形式依次施加到电机的两相通电绕组上(第三相悬空)。每个电气周期(360°电角度)内,有6个特定的开关状态组合(故称“六步”)。通过改变施加电压的占空比(PWM控制),可以调节平均电压,从而控制电机转速和转矩。

一类是永磁同步电机(PMSM)- 控制方式为正弦波驱动 / 磁场定向控制 (FOC),关键步骤如下图所示。

核心思想是将定子电流矢量分解为两个相互垂直的分量: 产生磁场的分量(直轴电流 Id)和产生转矩的分量(交轴电流 Iq)。通过独立控制 Id 和 Iq,就像控制直流电机一样(励磁电流和电枢电流),实现对转矩和磁场的精确、解耦控制。

2.stm32f103c8t6驱动电调控制A2212无刷电机

有了电调以后我们便帮我们省略了上述复杂的控制过程,我们只需最简单的pwm即可控制无刷电机,首先说一下硬件接线, 下图为30A无刷电调(不支持双向),左边三根蓝线接无刷电机三相,因不支持双向所以这三根线可随便接,右边T字头接12V电源,剩下三根信号线分别接pwm,电源和gnd,详情可看下图标注。

接下来就是软件代码,电调通常通过PWM信号控制,具体来说是周期为20ms(50Hz)的PWM脉冲,其中高电平的宽度在1.5ms到2ms之间对应电机的停止到全速。但请注意,不同电调可能有不同的校准范围,通常需要先进行校准。(校准的通常步骤是:发送最大值(2ms)信号,听到提示音后发送最小值(1.5ms)信号,再听到提示音后完成校准。 )

下面给出核心代码,电调校准后可通过按键控制无刷电机加减速以及启停控制(若是双向电调则1ms到1.5ms对应的是反转,1.5ms到2ms对应的是正转,对应修改代码即可)

motor.c

#include "stm32f10x.h"

#include "PWM.h"

#include "delay.h"

void Motor_PWM_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_OCInitTypeDef TIM_OCInitStructure;

// 1. 使能时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

// 2. 配置PA7为复用推挽输出

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

// 3. 定时器基础设置

TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD - 1; // 自动重装载值

TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; // 72MHz/72=1MHz

TIM_TimeBaseStructure.TIM_ClockDivision = 0;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

// 4. PWM通道配置

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_Pulse = PWM_MIN; // 初始脉宽

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

TIM_OC2Init(TIM3, &TIM_OCInitStructure);

// 5. 启动定时器

TIM_Cmd(TIM3, ENABLE);

TIM_CtrlPWMOutputs(TIM3, ENABLE);

}

// 设置PWM脉宽(范围:1000-2000)

void Set_PWM_Pulse(uint16_t pulse) {

if(pulse < PWM_MIN) pulse = PWM_MIN;

if(pulse > PWM_MAX) pulse = PWM_MAX;

TIM3->CCR2 = pulse;

}

// 电机控制函数

void Motor_Control(int16_t speed) {

// 将速度(0~1000)转换为PWM脉宽(1500-2000)

uint16_t pulse = PWM_MIN + speed / 2;

Set_PWM_Pulse(pulse);

}

pwm.h

#ifndef __PWM_H

#define __PWM_H

void Motor_PWM_Init(void);

void Set_PWM_Pulse(uint16_t pulse) ;

void Motor_Control(int16_t speed);

#define PWM_PERIOD 20000 // 20ms周期(50Hz)

#define PWM_MIN 1500 // 1.5ms脉宽(停止)

#define PWM_MAX 2000 // 2ms脉宽(全速)

#endif

main.c

uint8_t KeyNum;

uint8_t flag = 0;

u8 RxData;

char t;

extern Results results[];

int Speed=0;

extern nt_calendar_obj nwt; //定义结构体变量

int main(void)

{

delay_init(); //延时函数初始化

KEY_Init(); //按键初始化

EXTIX_Init(); //外部中断初始化

Motor_PWM_Init();

// 电调校准(首次使用需要)

Set_PWM_Pulse(PWM_MAX); // 发送最大信号

delay_ms(3000); // 等待3秒

Set_PWM_Pulse(PWM_MIN); // 发送最小信号

delay_ms(3000); // 等待3秒

while (1)

{

KeyNum = Key_GetNum();

if(KeyNum == 1)

{

Speed+=100;//加速

}

else if(KeyNum == 2)

{

Speed-=100;//减速

}

else if(KeyNum == 3)

{

Speed=0; //停止

}

if(Speed >= 1000)

{

Speed = 1000;

}

else if(Speed <= 0)

{

Speed = 0;

}

Motor_Control(Speed);

}

}

key.c

#include "key.h"

#include "delay.h"

//按键初始化函数

void KEY_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOB,ENABLE);//使能PORTA,PORTC时钟

GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//关闭jtag,使能SWD,可以用SWD模式调试

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//PA15

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入

GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA15

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//PC5

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入

GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC5

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//PA0

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //PA0设置成输入,默认下拉

GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3| GPIO_Pin_4| GPIO_Pin_5;;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOB, &GPIO_InitStructure);

}

uint8_t Key_GetNum(void)//四个按键B3 B4 B5 A0

{

uint8_t KeyNum = 0;

if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3) == 0)

{

delay_ms(20);

while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3) == 0);

delay_ms(20);

KeyNum = 1;

}

if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4) == 0)

{

delay_ms(20);

while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4) == 0);

delay_ms(20);

KeyNum = 2;

}

if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5) == 0)

{

delay_ms(20);

while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5) == 0);

delay_ms(20);

KeyNum = 3;

}

if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0)

{

delay_ms(20);

while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0);

delay_ms(20);

KeyNum = 4;

}

return KeyNum;

}

key.h

#ifndef __KEY_H

#define __KEY_H

#include "sys.h"

uint8_t Key_GetNum(void);

void KEY_Init(void);//IO初始化

u8 KEY_Scan(u8 mode); //按键扫描函数

#endif

虽然用电调来控制无刷电机并不难,但我一开始发现网上的资料还是对初学者来说不够细致,故希望这篇文章能够帮助大家,创作不易,若想要完整源码的,可一键三连后私聊获取,若您能看到这里,也感谢您的支持!!!

[分享]【攻略:装备搭配】套装到底怎么选?重力之泉版本套装梯度表
最好玩的免费 PS4 ▷➡️