ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

基于Proteus的STM32 BLDC电机控制器设计与换相调试

基于Proteus的STM32 BLDC电机控制器设计与换相调试 简介面向有一定嵌入式开发经验的技术人员尤其适合STM32与BLDC电机控制方向的开发者可用于教学演示、课程设计或项目预研。文档围绕基于Proteus的STM32无刷直流电机控制器设计与实现展开覆盖STM32CubeMX资源初始化、HAL库程序设计、可调电阻配合ADC实现500-4596范围转速给定、定时器1六路PWM互补输出、定时器2输入捕获测速、外部中断换向与正反转切换以及LCD1602显示目标转速和实测转速等完整链路并针对Proteus中定时器计时不准、三路捕获无法同时工作、仿真速度缓慢等常见问题给出了时钟源调整、单通道测速等优化方案。资源包为单个docx文档756KB配有仿真过程截图和整体电路图便于对照复现。目前已有167人学习下载参照其中的配置与排错思路可显著减少在Proteus中搭建和调试BLDC电机控制系统的摸索时间。1. 基于Proteus的STM32 BLDC电机控制器难点不在PWM占空比而在换相时刻做BLDC控制的人大多一开始把注意力放在PWM占空比上实际上真正决定电机能不能转、电流平不平滑的是六个换相时刻是否落在正确转子位置。用Proteus做STM32的BLDC电机控制器仿真时这个问题会被放大看不到实际转轴只能靠端电压波形和换相点反推偏差稍微大一点电机就拖着噪声不转。下面这套基于Proteus的STM32 BLDC电机控制器设计路线会从换相原理、外设配置、仿真调试一直讲到用相位偏置角校准收尾覆盖从带霍尔六步换相到无感反电动势过零检测的完整闭环适合正在做毕业设计的学生也适合想先在仿真里验证换相算法的嵌入式工程师。2. BLDC控制原理与Proteus电机模型搭建2.1 六步换相状态机霍尔信号与导通相的一一对应BLDC的“直流无刷”并不意味着三相绕组始终通电而是每隔60°电角度切换一次通电组合定子磁场跳着往前走。霍尔传感器把转子位置编码成三路方波三个霍尔信号合起来只有6个有效组合每一种组合对应一个固定的通电状态这就是六步换相。家用电动工具、低压无人机电调里最常见的换相方式本质都是这张状态表。霍尔组合(C,B,A)上管PWM下管导通电流回路0b001A相B相下管A → B-0b011C相B相下管C → B-0b010C相A相下管C → A-0b110B相A相下管B → A-0b100B相C相下管B → C-0b101A相C相下管A → C-这张表假设电机相序和霍尔安装方向与模型默认一致。实际接线不一致时不需要重新推导把整个状态表循环平移一两个位置就能对上这也是后面查表换相代码能直接复用的原因。注意0b000和0b111是非法状态霍尔线断线或上电瞬间最容易出现这两个值代码里要把它们映射到关闭所有功率管而不是继续驱动。另一个容易被忽略的选型点是调制方式。上表采用“上管PWM、下管恒通”也就是常说的H_PWM-L_ON。相比上下管都做PWM的互补调制这种方式下续流路径固定经过半桥中点电流采样信号更干净换相逻辑也简单很多。代价是下管一直导通发热集中在下桥臂实际做硬件时要按下管持续通流的工况选型。2.2 反向电动势过零点检测原理与虚拟中性点无感方案不用霍尔依据是悬空相绕组的反向电动势过零。假设当前处于A→B-状态C相悬空C相端电压满足Uc Ec Un虚拟中性点电压Un近似等于母线电压的一半。Ec每个电气周期会从正到负穿过零点两次每次穿越点与理想换相点之间正好相隔30°电角度。所以只要检测到悬空相端电压与虚拟中性点电压相等就知道再过30°应该执行下一次换相。在Proteus里实现这个检测最直接的办法是把电机模型的中性点N引出来和三相端电压一起送进STM32的ADC。如果模型没有引出中性点就用三个相同阻值的电阻构成虚拟中性点三个电阻的一端分别接A、B、C相端电压另一端并在一起。这个并接点对地电压就是Un。这里有一个关键细节20kHz PWM斩波会在悬空相端电压上叠加强烈的开关纹波仿真里一样有所以过零比较不能盯着瞬时值要在PWM导通中段采样或者先做低通滤波后比较。// 虚拟中性点电压 三相端电压的等权平均 uint16_t virtual_neutral(uint16_t va, uint16_t vb, uint16_t vc) { return ((uint32_t)va vb vc) / 3u; }这段代码表达的是电阻网络的平均电位关系真正用来做控制时不会每周期都算三次ADC再取平均而是直接采电机模型N端电压或电阻网络中点。这里写出来是为了让原理和电路对应上避免在搭Proteus电路时把虚拟中性点接到电源地上去。2.3 在Proteus里搭逆变桥和BLDC电机模型的最小清单Proteus仿真BLDC不需要把功率电路画得像产品一样复杂但续流回路必须有否则换相瞬间感性电流没有通路SPICE仿真器会直接报收敛错误。我一般会用以下清单搭电路。元件数量作用STM32F103C8T61主控输出PWM和换相信号MOTOR-BLDC1Proteus电机模型搜索BLDC即可找到IR2101半桥驱动3高端MOS栅极驱动解决Vgs不够的问题IRFZ44N6三相全桥功率管1N58196续流二极管与MOS并联100uF电解电容1母线滤波抑制换相尖峰10kΩ电阻3构成虚拟中性点12V电源1母线电压连线顺序是12V正极接三个高端MOS漏极高端MOS源极分别接A/B/C绕组和对应低端MOS漏极低端MOS源极接GND。STM32的PA8/PA9/PA10接IR2101的HIN输入PB0/PB1/PB10接LIN输入霍尔信号A/B/C接PA0/PA1/PA2。如果Proteus版本里找不到MOTOR-BLDC也可以用三个受控电压源加R/L网络模拟反电动势但那样还要额外拟合转速与反电动势幅值的关系调试成本高一般不建议。提示仿真环境里栅极驱动可以简化但续流二极管不能省。缺少续流回路时换相瞬间绕组电流突变Proteus会提示SPICE仿真不收敛。3. STM32外设配置与Keil工程准备先把换相前线接通3.1 Proteus 8与Keil 5联调芯片包、晶振和.hex加载Keil与Proteus联调的关键不是插件而是两边对STM32型号和时钟的认识一致。首先在Keil的Pack Installer里安装STM32F1xx_DFP芯片包否则编译F103工程时会提示找不到Device。Proteus这边则要确认能搜到STM32F103C8T6老版本Proteus默认不带STM32库需要单独安装芯片库文件新版Proteus 8一般在Pick Devices里输入“STM32F103”就能看到。把代码编译成.hex之后在Proteus里双击STM32芯片在Program File一栏选择Keil生成的.hex然后重点检查Clock Frequency。我习惯在Keil工程里用8MHz外部晶振加PLL到72MHz所以Proteus里也要把晶振频率设为8MHz。如果两边不一致代码里的SystemInit会按错误时钟配置PLL现象是仿真能跑但PWM周期和定时器延时全部不对。联调时还有两个很容易踩的坑。第一个是Proteus默认的运行步长可能设在纳秒级配合20kHz PWM会让仿真慢得像是死机建议在仿真选项里把最大步长限制到微秒级比如2us对BLDC换相这种信号级验证完全够用。第二个是.hex加载后按运行没反应先别怀疑电机模型用虚拟示波器看PA8有没有PWM输出没有就回到工程检查高级定时器的MOE主输出使能位这一点在3.2代码里会专门说明。3.2 TIM1输出PWM与GPIO读取霍尔信号的最小配置STM32F103的高级定时器TIM1自带互补输出和刹车功能做BLDC全桥最合适。这里采用H_PWM-L_ON方式三个上管用TIM1的通道输出PWM三个下管用普通GPIO控制。void TIM1_PWM_Init(void) { GPIO_InitTypeDef gpio; TIM_TimeBaseInitTypeDef tim; TIM_OCInitTypeDef oc; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO | RCC_APB2Periph_TIM1, ENABLE); // PA8/PA9/PA10: TIM1_CH1/CH2/CH3上管PWM gpio.GPIO_Pin GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10; gpio.GPIO_Mode GPIO_Mode_AF_PP; gpio.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, gpio); // PB0/PB1/PB10: 下管控制 gpio.GPIO_Pin GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_10; gpio.GPIO_Mode GPIO_Mode_Out_PP; gpio.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, gpio); // 72MHz主频ARR3599PWM频率20kHz tim.TIM_Prescaler 0; tim.TIM_CounterMode TIM_CounterMode_Up; tim.TIM_Period 3599; tim.TIM_ClockDivision TIM_CKD_DIV1; TIM_TimeBaseInit(TIM1, tim); oc.TIM_OCMode TIM_OCMode_PWM1; oc.TIM_OutputState TIM_OutputState_Enable; oc.TIM_OCPolarity TIM_OCPolarity_High; oc.TIM_Pulse 0; TIM_OC1Init(TIM1, oc); TIM_OC2Init(TIM1, oc); TIM_OC3Init(TIM1, oc); TIM_CtrlPWMOutputs(TIM1, ENABLE); // MOE位高级定时器必须开 TIM_Cmd(TIM1, ENABLE); }代码里最需要记住的是最后两行中的TIM_CtrlPWMOutputs它会置位TIM1的主输出使能MOE位。F103普通定时器比如TIM2、TIM3没有这个位但TIM1和TIM8这两路高级定时器不开它PWM引脚永远输出不了波形这是很多Proteus仿真工程“不转”的直接原因。ARR3599、预分频为0时72MHz除以3600得到20kHz占空比则由CCR1到CCR3控制取值范围0到3599。霍尔引脚初始化的要点是不要配成浮空输入。Proteus里的BLDC模型输出霍尔信号是推挽源但实物电机霍尔大多是开集电极输出所以统一配成上拉输入更安全gpio.GPIO_Pin GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2; gpio.GPIO_Mode GPIO_Mode_IPU; GPIO_Init(GPIOA, gpio);霍尔三路信号读回来的是0到7的编码后续换相表直接拿这个数当下标查表不需要再单独判断每个引脚。3.3 ADC采样反电动势悬空相端电压与虚拟中性点比较无感过零检测在STM32侧可以用外部比较器也可以用ADC轮流采样悬空相和虚拟中性点。Proteus仿真阶段我推荐直接用ADC省去比较器建模和阈值调节等逻辑验证完再换成硬件比较器也不迟。void ADC1_Channels_Init(void) { GPIO_InitTypeDef gpio; ADC_InitTypeDef adc; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); // ADC时钟 72MHz / 6 12MHz // PA4为虚拟中性点PA5/PA6/PA7为A/B/C相端电压 gpio.GPIO_Pin GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; gpio.GPIO_Mode GPIO_Mode_AIN; GPIO_Init(GPIOA, gpio); adc.ADC_Mode ADC_Mode_Independent; adc.ADC_ScanConvMode DISABLE; adc.ADC_ContinuousConvMode ENABLE; adc.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; adc.ADC_DataAlign ADC_DataAlign_Right; adc.ADC_NbrOfChannel 1; ADC_Init(ADC1, adc); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while (ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1)); }这套配置没有启用扫描模式每次读哪一路就在转换前调用ADC_RegularChannelConfig切换通道。12MHz的ADC时钟配合28.5周期采样时间单次转换大约2usBLDC过零检测按20kHz到50kHz的采样频率跑完全来得及。霍尔信号放在PA0/PA1/PA2端电压采样放在PA4/PA5/PA6/PA7两组引脚分开能避免GPIO模拟输入和上拉输入互相覆盖。到这里“换相前线”已经接通定时器能出PWMGPIO能读霍尔ADC能采反电动势。接下来要解决的才是控制核心也就是换相状态机和过零检测的配合。4. 仿真调试从带霍尔六步换相切换到无感过零检测4.1 六步换相状态机的代码骨架与换相时序带霍尔换相的代码核心是一张查表即2.1节那六个状态的编码版本。Hall读进来的组合按0到7编号每一档对应一个上管通道号和一个下管引脚非法状态置0表示全关。static const uint8_t hi_pwm[8] {0,1,3,3,2,2,1,0}; static const uint16_t lo_on[8] {0,GPIO_Pin_1,GPIO_Pin_0,GPIO_Pin_1, GPIO_Pin_10,GPIO_Pin_10,GPIO_Pin_0,0}; void commutation_step(uint8_t hall) { uint8_t ch; // 1. 先清掉三个上管PWM避免换相瞬间直通 TIM1-CCR1 0; TIM1-CCR2 0; TIM1-CCR3 0; // 2. 关掉所有下管再按表打开目标下管 GPIOB-BRR GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_10; GPIOB-BSRR lo_on[hall]; // 3. 给目标上管写入当前占空比 ch hi_pwm[hall]; if (ch 1) TIM1-CCR1 duty; else if (ch 2) TIM1-CCR2 duty; else if (ch 3) TIM1-CCR3 duty; // 4. 等待功率管完全关断/开通再允许下一次换相 delay_us(3); }这里最忌讳的做法是“先开新的下管再关旧的下管”那会在几十纳秒内造成桥臂直通。代码里的顺序是先把PWM清掉再动下管最后才恢复PWM逻辑上保证任意时刻上下管不会同时导通。3us死区在Proteus仿真里只是为了贴近实际开关过程真要体现MOS管栅极充放电还需要在IGBT模型里设置开通/关断延时。霍尔换相调试时用一个大占空比比如30%慢慢推电机模型应该会跟着霍尔信号一步一步换相。如果电机反转把lo_on表的顺序倒过来即可不需要改霍尔接线。4.2 反电动势过零检测的开环启动参数表无感方案不能一上电就指望过零检测转速太低时反电动势幅值太小过零信号会被噪声淹没。常见做法是开环强制换相先按固定电频率输出六步等转速起来后再切换过零检测闭环。参数推荐起始值调整方向PWM频率20kHz仿真可降到4kHz仿真速度慢就降纹波会大开环起始占空比15%拖不动加5%不建议超过25%开环起始电频率50Hz电周期20ms每个扇区约3.3ms开环持续时间200ms负载惯量大时加到500ms过零滤波计数10转速升高后降到5过零后换相延时30°电角度高速带载时可提前到25°开环50Hz电频率时30°电角度对应1.67ms执行过零检测后第一次换相就按这个延时来。切换到闭环的判据不要用单一时间点而是连续检测到5次以上的反电动势过零后再切入避免开环末段偶发误判直接把换相打乱。过零比较的滤波策略也有讲究。10次滤波计数在低转速时好用到高转速时会因为相位滞后太多导致换相偏晚。我一般把采样点放在PWM导通中段再叠加一个窗口比较悬空相电压高于中性点加阈值时标记一个过零低于中性点减阈值时再确认另一个过零。阈值大小和母线电压成比例12V母线时取0.1V左右折合到12位ADC大约几十个LSB。4.3 在虚拟示波器上判断过零点是否提前或滞后Proteus的虚拟示波器至少需要同时看三路信号悬空相端电压、虚拟中性点电压、过零比较输出。判断换相点对不对最直观的方法是量“电压交叉点”到“PWM切换点”的时间差。电气周期T_e是固定的30°电角度对应的理论延时是T_e/12。若测出来的时间差明显大于T_e/12说明换相滞后小于则说明换相提前。// 电气周期us / 12 30°电角度对应延时 uint16_t delay_30deg_us electrical_period_us / 12u;这个公式简单但实际操作时要注意悬空相端电压波形上混杂PWM纹波直接找交叉点会有抖动。我习惯在Proteus里给虚拟中性点信号加一个低通滤波器时间常数取PWM周期的三到五倍虽然会引入一点相位滞后但观察交叉趋势比看毛刺靠谱得多。母线电流波形同样能反映问题换相瞬间电流出现明显台阶基本可以断定是换相点偏差不是在占空比或PID上找原因。5. 进阶验证技巧用相位偏置角校准霍尔安装误差5.1 测量偏置角从霍尔边沿到反电动势过零的时间差霍尔传感器和反电动势过零点的相位关系在Proteus模型里是固定的但实物的霍尔贴装位置、磁钢极弧和端盖公差都会造成偏差。拿到一个电机后直接套用30°换相角往往不是磁场最优换相点。更稳的做法是先测出偏置角再把偏置合并到过零后延时里。用虚拟示波器接Hall_A和A相端电压对虚拟中性点的信号找一个稳定的转速读出电气周期T_e以及Hall_A上升沿到A相过零点的时间差dt。偏置角按以下公式换算offset_deg (uint16_t)((uint32_t)dt_us * 360u / period_us);offset_deg可能是正值也可能是负值。正值说明霍尔跳变沿滞后于反电动势过零点补偿时要把这个角度从换相延时里减掉负值则反向处理。实际补偿时不需要直接改延时角而是把最终目标延时角度换算成定时器计数值uint16_t angle_to_us(uint16_t angle_deg, uint16_t period_us) { return (uint16_t)(((uint32_t)period_us * angle_deg) / 360u); }比如理论换相角30°测出偏置角为8°目标角度就写成22°。调用angle_to_us(22, period_us)得到定时器初值在过零中断里装载后就开始倒计时换相。5.2 正反转两次测量取平均消除系统延时误差霍尔信号本身经过光耦或比较器会有传输延迟这部分延迟和安装偏置叠加在同一个测量值里无法直接区分。我的做法是让电机正转测一次偏置角再反转测一次两个方向各多测几个电周期取平均。真实安装偏置在正反转下会保留相同幅值而比较器、滤波电路造成的固定延时在方向切换后符号相反取平均后能抵消掉。在校准代码里我会把每一路霍尔边沿对应的偏置角存成一张表而不是只存一个平均角度。因为霍尔贴装是三颗独立的传感器每颗的位置偏差可能都不一样单独校准每一路换相点比全局统一补一个角度更精确。把这张表维护好之后再回头调4.2节的开环启动参数你会看到母线电流波形上的台阶明显变小这一步做完整个基于Proteus的STM32 BLDC电机控制器仿真流程才算真正闭环。本文还有配套的精品资源点击获取
返回列表