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