CW32L011无感无刷驱动器代码详解 硬件平台: CW32L011 Cortex-M0 MCU (96MHz)驱动方式: 三相PWM驱动6步换向控制方式: 反电动势过零检测无传感器控制PWM频率: 15kHz项目结构:1 2 3 4 5 6 7 8 9 10 11 12bldc project/ ├── USER/ │ ├── src/main.c # 主程序入口 │ ├── src/interrupts_cw32l011.c # 中断处理 │ └── inc/main.h # 头文件 └── BLDC-MOTOR/ ├── init.C # 外设初始化 ├── global.c/global.h # 全局变量和宏定义 ├── motor.c/motor.h # 电机换向控制 ├── sensorless.c/sensorless.h # 无传感器控制过零检测 ├── control.c/control.h # 电机状态机控制 └── compu.c/compu.h # 采样计算函数第1部分外设初始化详解所有外设初始化在main()函数中按顺序调用位于init.C文件中。1.1 系统时钟配置 (RCC_Configuration)1 2 3 4void RCC_Configuration(void) { SYSCTRL_HSI_Enable(SYSCTRL_HSIOSC_DIV1); // 96MHz }功能: 启用内部高速时钟(HSI)并配置为96MHz主频时钟树分析:HSI OSC内部高速时钟SYSCTRL_HSIOSC_DIV11分频系统时钟 SYSCLK96MHzATIM高级定时器BTIM1/2/3基础定时器ADC模数转换器GPIO通用输入输出PWM输出15kHz三相定时中断1ms换向计时BTIM2延迟换向BTIM36通道采样BEMF/电压/电流说明: CW32L011使用内部RC振荡器通过分频器配置为96MHz为所有外设提供时钟源1.2 GPIO引脚配置代码中定义了以下引脚宏定义在global.h:1.2.1 控制引脚引脚端口编号功能模式LEDPC13Pin_13运行指示灯推挽输出DRPA9Pin_9方向控制输入上拉输入ENPC15Pin_15使能控制输入上拉输入FGPA12Pin_12转速反馈输出推挽输出控制逻辑:EN引脚: 外部开关控制电机使能EN 1: 电机可运行EN 0: 电机停止DR引脚: 外部开关控制旋转方向DR 1: 正转DR 0: 反转1.2.2 PWM输出引脚 (三相桥臂)引脚端口编号功能复用功能PWM_AHPB5Pin_5A相上桥臂ATIM_CH1PWM_ALPA15Pin_15A相下桥臂普通GPIOPWM_BHPB6Pin_6B相上桥臂ATIM_CH2PWM_BNPB3Pin_3B相下桥臂普通GPIOPWM_CHPB7Pin_7C相上桥臂ATIM_CH3PWM_CNPin_4Pin_4C相下桥臂普通GPIO1.2.3 GPIO操作宏定义1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19// LED控制 #define LEDON GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PIN, GPIO_Pin_RESET) // 低电平点亮 #define LEDOFF GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PIN, GPIO_Pin_SET) // 高电平熄灭 // 上桥臂控制通过ATIM PWM输出 #define PWM_AH_ON GPIO_WritePin(PWM_AP_PORT, PWM_AP_PIN, GPIO_Pin_SET) #define PWM_AH_OFF GPIO_WritePin(PWM_AP_PORT, PWM_AP_PIN, GPIO_Pin_RESET) #define PWM_BH_ON GPIO_WritePin(PWM_BP_PORT, PWM_BP_PIN, GPIO_Pin_SET) #define PWM_BH_OFF GPIO_WritePin(PWM_BP_PORT, PWM_BP_PIN, GPIO_Pin_RESET) #define PWM_CH_ON GPIO_WritePin(PWM_CP_PORT, PWM_CP_PIN, GPIO_Pin_SET) #define PWM_CH_OFF GPIO_WritePin(PWM_CP_PORT, PWM_CP_PIN, GPIO_Pin_RESET) // 下桥臂控制通过GPIO直接控制 #define PWM_AL_ON GPIO_WritePin(PWM_AN_PORT, PWM_AN_PIN, GPIO_Pin_SET) #define PWM_AL_OFF GPIO_WritePin(PWM_AN_PORT, PWM_AN_PIN, GPIO_Pin_RESET) #define PWM_BL_ON GPIO_WritePin(PWM_BN_PORT, PWM_BN_PIN, GPIO_Pin_SET) #define PWM_BL_OFF GPIO_WritePin(PWM_BN_PORT, PWM_BN_PIN, GPIO_Pin_RESET) #define PWM_CL_ON GPIO_WritePin(PWM_CN_PORT, PWM_CN_PIN, GPIO_Pin_SET) #define PWM_CL_OFF GPIO_WritePin(PWM_CN_PORT, PWM_CN_PIN, GPIO_Pin_RESET)1.2.4 初始化函数详解1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44void LEDConfiguration(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; __SYSCTRL_GPIOA_CLK_ENABLE(); __SYSCTRL_GPIOB_CLK_ENABLE(); __SYSCTRL_GPIOC_CLK_ENABLE(); GPIO_InitStruct.IT GPIO_IT_NONE; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; // 推挽输出 GPIO_InitStruct.Pins LED_GPIO_PIN; GPIO_Init(LED_GPIO_PORT, GPIO_InitStruct); LEDON; // 默认点亮LED表示上电 } void DR_Configuration(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; // ... 时钟使能 ... GPIO_InitStruct.IT GPIO_IT_NONE; GPIO_InitStruct.Mode GPIO_MODE_INPUT_PULLUP; // 上拉输入 GPIO_InitStruct.Pins DR_GPIO_PIN; GPIO_Init(DR_GPIO_PORT, GPIO_InitStruct); } void EN_Configuration(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; // ... 时钟使能 ... GPIO_InitStruct.IT GPIO_IT_NONE; GPIO_InitStruct.Mode GPIO_MODE_INPUT_PULLUP; // 上拉输入 GPIO_InitStruct.Pins EN_GPIO_PIN; GPIO_Init(EN_GPIO_PORT, GPIO_InitStruct); } void FG_Configuration(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; // ... 时钟使能 ... GPIO_InitStruct.IT GPIO_IT_NONE; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; // 推挽输出 GPIO_InitStruct.Pins FG_GPIO_PIN; GPIO_Init(FG_GPIO_PORT, GPIO_InitStruct); }1.3 ADC配置 (ADC_Configuration)功能: 配置6通道ADC用于采集模拟信号1.3.1 采样通道分配数组索引引脚ADC通道功能用途SampleData[0]PA06AIN6U相端电压BEMF检测SampleData[1]PA07AIN7V相端电压BEMF检测SampleData[2]PB00AIN8W相端电压BEMF检测SampleData[3]PA03AIN3反电动势过零检测SampleData[4]PB01AIN9电位器速度设定SampleData[5]PA08AIN10电源电压过压/欠压检测1.3.2 引脚配置1 2 3 4 5 6 7 8 9 10 11 12 13 14// 使能ADC和GPIO时钟 __SYSCTRL_ADC_CLK_ENABLE(); __SYSCTRL_GPIOA_CLK_ENABLE(); __SYSCTRL_GPIOB_CLK_ENABLE(); // 配置模拟输入引脚 PA06_ANALOG_ENABLE(); // AIN6 - U相电压 PA07_ANALOG_ENABLE(); // AIN7 - V相电压 PB00_ANALOG_ENABLE(); // AIN8 - W相电压 PB01_ANALOG_ENABLE(); // AIN9 - 电位器 PA08_ANALOG_ENABLE(); // AIN10 - 电源电压 PA03_ANALOG_ENABLE(); // AIN3 - BEMF PA04_ANALOG_ENABLE(); // AIN4 - 备用 PA05_ANALOG_ENABLE(); // AIN5 - 备用1.3.3 ADC初始化配置1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40ADC_InitTypeDef ADC_InitStructure {0}; // ADC时钟: 48MHz / (151) 2MHz (满足ADC最高14MHz要求) ADC_InitStructure.ADC_ClkDiv ADC_Clk_Div16; // 或者 ADC_Clk_Div2 配合其他分频 // 单次转换模式不是连续扫描 ADC_InitStructure.ADC_ConvertMode ADC_ConvertMode_OneShot; // 使能所有6个序列通道 ADC_InitStructure.ADC_SQREns ADC_SqrEns0to5; // 配置各通道 // 通道0: AIN6 (U相) - SampleData[0] ADC_InitStructure.ADC_IN0.ADC_InputChannel ADC_InputCH6; ADC_InitStructure.ADC_IN0.ADC_SampTime ADC_SampTime9Clk; // 通道1: AIN7 (V相) - SampleData[1] ADC_InitStructure.ADC_IN1.ADC_InputChannel ADC_InputCH7; ADC_InitStructure.ADC_IN1.ADC_SampTime ADC_SampTime9Clk; // 通道2: AIN8 (W相) - SampleData[2] ADC_InitStructure.ADC_IN2.ADC_InputChannel ADC_InputCH8; ADC_InitStructure.ADC_IN2.ADC_SampTime ADC_SampTime9Clk; // 通道3: AIN3 (BEMF) - SampleData[3] ADC_InitStructure.ADC_IN3.ADC_InputChannel ADC_InputCH3; ADC_InitStructure.ADC_IN3.ADC_SampTime ADC_SampTime9Clk; // 通道4: AIN9 (电位器) - SampleData[4] ADC_InitStructure.ADC_IN4.ADC_InputChannel ADC_InputCH9; ADC_InitStructure.ADC_IN4.ADC_SampTime ADC_SampTime9Clk; // 通道5: AIN10 (电源电压) - SampleData[5] ADC_InitStructure.ADC_IN5.ADC_InputChannel ADC_InputCH10; ADC_InitStructure.ADC_IN5.ADC_SampTime ADC_SampTime9Clk; ADC_Init(ADC_InitStructure); // 使能ADC ADC_Enable();1.3.4 ADC触发和中断配置1 2 3 4 5 6 7 8 9 10 11 12// 清除中断标志 ADC_ClearITPendingAll(); // 使能序列转换完成中断 (EOS End Of Sequence) ADC_ITConfig(ADC_IT_EOS, ENABLE); // 使能NVIC中的ADC中断 NVIC_EnableIRQ(ADC_IRQn); // 配置外部触发ATIM CC4事件触发ADC转换 // ATIM_CH4的比较事件触发ADC确保与PWM同步 ADC_ExtTrigCfg(ADC_TRIG_ATIMCC4, ENABLE);关键设计点:ADC由ATIM_CH4触发确保每次PWM周期中间采样采样时间9个ADC时钟在2MHz ADC时钟下约4.5μs6通道顺序采样总时间约27μs1.4 BLDC PWM配置 (BLDC_Configuration)功能: 配置高级定时器(ATIM)产生三相PWM波形1.4.1 PWM参数计算1 2 3 4 5 6#define PWM_PERIOD 6400 // PWM周期值 // PWM频率 96MHz / PWM_PERIOD 96MHz / 6400 15kHz // PWM分辨率 6400 2^12.65 ≈ 12.65位 #define OnepercentPWM (PWM_PERIOD) / 100 // 64 // 1%占空比对应的CCR值1.4.2 引脚复用配置1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34void BLDC_Configuration(void) { // 使能时钟 __SYSCTRL_ATIM_CLK_ENABLE(); __SYSCTRL_GPIOA_CLK_ENABLE(); __SYSCTRL_GPIOB_CLK_ENABLE(); // 配置上桥臂引脚为复用功能 GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.IT GPIO_IT_NONE; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pins PWM_AP_PIN | PWM_BP_PIN; GPIO_Init(CW_GPIOB, GPIO_InitStruct); GPIO_InitStruct.Pins PWM_CP_PIN; GPIO_Init(CW_GPIOB, GPIO_InitStruct); // 配置引脚复用为ATIM功能 PB05_AFx_ATIMCH1(); // PB5 → ATIM_CH1 (A相上桥) PB06_AFx_ATIMCH2(); // PB6 → ATIM_CH2 (B相上桥) PB07_AFx_ATIMCH3(); // PB7 → ATIM_CH3 (C相上桥) // 配置下桥臂引脚为普通GPIO GPIO_InitStruct.IT GPIO_IT_NONE; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pins PWM_AN_PIN; // PA15 GPIO_Init(CW_GPIOA, GPIO_InitStruct); GPIO_InitStruct.Pins PWM_BN_PIN | PWM_CN_PIN; // PB3, PB4 GPIO_Init(CW_GPIOB, GPIO_InitStruct); // 初始化下桥臂全部导通续流 PWM_AL_ON; PWM_BL_ON; PWM_CL_ON; }1.4.3 ATIM定时器初始化1 2 3 4 5 6 7 8 9 10 11 12ATIM_InitTypeDef ATIM_InitStruct; ATIM_OCInitTypeDef ATIM_OCInitStruct {0}; // 基础定时器配置 ATIM_InitStruct.BufferState ENABLE; // 使能影子寄存器 ATIM_InitStruct.CounterAlignedMode ATIM_COUNT_ALIGN_MODE_EDGE; // 边缘对齐 ATIM_InitStruct.CounterDirection ATIM_COUNTING_UP; // 向上计数 ATIM_InitStruct.CounterOPMode ATIM_OP_MODE_REPETITIVE; // 重复计数模式 ATIM_InitStruct.Prescaler 1 - 1; // 预分频 1, 时钟 96MHz ATIM_InitStruct.ReloadValue PWM_PERIOD - 1; // 自动重装载 6400-1 6399 ATIM_InitStruct.RepetitionCounter 0; // 重复计数器 0 ATIM_Init(ATIM_InitStruct);1.4.4 PWM输出通道配置1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31// 输出比较初始化 ATIM_OCInitStruct.BufferState ENABLE; // 使能CCR影子寄存器 ATIM_OCInitStruct.OCComplement DISABLE; // 不使用互补通道 ATIM_OCInitStruct.OCFastMode DISABLE; // 禁用快速模式 ATIM_OCInitStruct.OCInterruptState DISABLE; // 不使用输出比较中断 ATIM_OCInitStruct.OCMode ATIM_OCMODE_PWM1; // PWM1模式高电平有效 ATIM_OCInitStruct.OCPolarity ATIM_OCPOLARITY_NONINVERT; // 正极性 // 初始化4个通道 ATIM_OC1Init(ATIM_OCInitStruct); // A相 ATIM_OC2Init(ATIM_OCInitStruct); // B相 ATIM_OC3Init(ATIM_OCInitStruct); // C相 ATIM_OC4Init(ATIM_OCInitStruct); // ADC触发 // 设置初始占空比 ATIM_SetCompare1(0); // A相占空比 0% ATIM_SetCompare2(0); // B相占空比 0% ATIM_SetCompare3(0); // C相占空比 0% ATIM_SetCompare4(PWM_PERIOD / 2); // ADC触发点周期中部 // 使能各通道输出 ATIM_CH1Config(ENABLE); ATIM_CH2Config(ENABLE); ATIM_CH3Config(ENABLE); ATIM_CH4Config(ENABLE); // 使能PWM主输出 ATIM_CtrlPWMOutputs(ENABLE); // 使能定时器 ATIM_Cmd(ENABLE);PWM时序图:0900180027003600450054006300计数器 0→6399高电平 (占空比)低电平CCR4触发点计数器PWM输出ADC触发PWM周期时序图 (15kHz 66.67μs)1.5 基础定时器配置1.5.1 BTIM1 - 系统定时器 (1ms中断)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27void BTIM1_Configuration(void) { BTIM_TimeBaseInitTypeDef BTIM_TimeBaseInitStruct {0}; // 使能BTIM时钟 __SYSCTRL_BTIM123_CLK_ENABLE(); // 使能NVIC中断 __disable_irq(); NVIC_EnableIRQ(BTIM1_IRQn); __enable_irq(); // 定时器配置 BTIM_TimeBaseInitStruct.BTIM_Mode BTIM_MODE_TIMER; // 定时器模式 BTIM_TimeBaseInitStruct.BTIM_CountMode BTIM_COUNT_MODE_REPETITIVE; // 重复模式 BTIM_TimeBaseInitStruct.BTIM_Period 1000 - 1; // 1000计数 BTIM_TimeBaseInitStruct.BTIM_Prescaler 96 - 1; // 96分频 1MHz // 定时周期 1MHz / 1000 1kHz 1ms BTIM_TimeBaseInit(CW_BTIM1, BTIM_TimeBaseInitStruct); // 使能更新中断 BTIM_ITConfig(CW_BTIM1, BTIM_IT_UPDATE, ENABLE); // 使能定时器 BTIM_Cmd(CW_BTIM1, ENABLE); }1.5.2 SENSORLESS_TIM_Config - 换向定时器1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30void SENSORLESS_TIM_Config(void) { BTIM_TimeBaseInitTypeDef BTIM_InitStruct {0}; // 使能BTIM2和BTIM3时钟 __SYSCTRL_BTIM123_CLK_ENABLE(); // 使能BTIM3中断 __disable_irq(); NVIC_EnableIRQ(BTIM3_IRQn); __enable_irq(); // BTIM2和BTIM3配置相同 BTIM_InitStruct.BTIM_Mode BTIM_MODE_TIMER; BTIM_InitStruct.BTIM_CountMode BTIM_COUNT_MODE_REPETITIVE; BTIM_InitStruct.BTIM_Period 65530; // 最大周期 BTIM_InitStruct.BTIM_Prescaler 12 - 1; // 12分频 8MHz BTIM_TimeBaseInit(CW_BTIM2, BTIM_InitStruct); BTIM_TimeBaseInit(CW_BTIM3, BTIM_InitStruct); // BTIM2: 自由运行计数器用于测量换向间隔 BTIM_Cmd(CW_BTIM2, ENABLE); // BTIM3: 换向定时器初始禁用由软件触发 BTIM_Cmd(CW_BTIM3, DISABLE); // 使能BTIM3更新中断 BTIM_ITConfig(CW_BTIM3, BTIM_IT_UPDATE, ENABLE); }定时器用途:BTIM2: 自由运行计数器每次换向时读取计数值计算电机实际转速BTIM3: 延迟换向定时器过零检测后延迟固定时间触发换向第2部分各外设中断详解2.1 BTIM1_IRQHandler - 系统定时器中断位置:main.c:117-139触发频率: 1kHz (每1ms触发一次)中断处理流程:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48void BTIM1_IRQHandler(void) { // 检查是否为更新中断 if (BTIM_GetITStatus(CW_BTIM1, BTIM_IT_UPDATE)) { // 清除中断标志 BTIM_ClearITPendingBit(CW_BTIM1, BTIM_IT_UPDATE); // 1. ADC采样计数用于控制电流采样频率 Icount; // 2. 通用临时计时器用于软件延时 TimeCountTemp; // 3. 速度设定采样计时每20ms采样一次 TimeCountCompuSpeed; // 4. 启动延时计时 TimeCountSTDelay; // 5. 瞬时速度计时 TimeCountRealSpd; if(TimeCountRealSpd 20) // 20ms { HALLcountTemp HALLcount; // 保存瞬时计数值 HALLcount 0; // 清零重新计数 TimeCountRealSpd 0; } // 6. PID控制计时 TimeCountPID; // 7. 平均速度计时100ms TimeCountAvgSpd; if(TimeCountAvgSpd 100) { hte HALLcount1; // 保存100ms内的换向次数 HALLcount1 0; TimeCountAvgSpd 0; } // 8. 启动加速计时 TimeCountStartUP; // 9. 电压电流采样计时100ms TimeCountVI; } }时间参数汇总:变量周期用途Icount每2次(2ms)控制电流采样TimeCountCompuSpeed20ms速度设定采样TimeCountSTDelay可变启动延时TimeCountRealSpd20ms瞬时速度计算TimeCountPID可变PWM调节TimeCountAvgSpd100ms平均速度计算TimeCountVI100ms电压电流采样2.2 ADC_IRQHandler - ADC转换完成中断位置:sensorless.c:73-120触发条件: ADC序列转换完成EOS End Of Sequence执行流程:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80void ADC_IRQHandler(void) { // 检查序列结束标志 if (CW_ADC-ISR_f.EOS) { // 1. 清除中断标志 ADC_ClearITPendingAll(); // 2. 读取6通道转换结果 ADC_GetSqr3Result(SampleData[0]); // U相 - 通道3 ADC_GetSqr1Result(SampleData[1]); // V相 - 通道1 ADC_GetSqr2Result(SampleData[2]); // W相 - 通道2 ADC_GetSqr0Result(SampleData[3]); // BEMF - 通道0 ADC_GetSqr4Result(SampleData[4]); // 电位器 - 通道4 ADC_GetSqr5Result(SampleData[5]); // 电源电压 - 通道5 // 3. 电机运行时的电流采样用于过零检测 if(Motor_Start_F 1) { // 根据当前换向步骤选择对应的相进行采样 if(bHallStartStep1 0 || bHallStartStep1 5) // AB相通电 { if(SampleData[1] DIin) // V相 虚拟中性点 { bb DIin - SampleData[1]; bbc; if(bbc 30) { bbc 0; sumb bb; bb 0; } } } else if(bHallStartStep1 1 || bHallStartStep1 2) // AC相通电 { if(SampleData[2] DIin) // W相 虚拟中性点 { cc DIin - SampleData[2]; ccc; if(ccc 30) { ccc 0; sumc cc; cc 0; } } } else if(bHallStartStep1 3 || bHallStartStep1 4) // BA相通电 { if(SampleData[0] DIin) // U相 虚拟中性点 { aa DIin - SampleData[0]; aac; if(aac 30) { aac 0; suma aa; aa 0; } } } } // 4. 速度设定值滤波滑动平均 aavsp SampleData[4]; // 累加电位器ADC值 aacvsp; if(aacvsp 200) // 200 * 1ms 200ms 采样一次 { aacvsp 0; sumavsp aavsp; // 保存平均值 aavsp 0; } // 5. 过零检测处理仅在电机运行且无故障时 if(Motor_Start_F 0 || ErrorCode ! 0) return; if(Sta ! 2) return; ADCS_chuli(); // 处理反电动势 } }ADC采样时序图:ADC_IRQHandlerADC序列转换ATIM_CH4触发PWM周期ADC_IRQHandlerADC序列转换ATIM_CH4触发PWM周期CCR43200周期中部触发ADC转换CH0→CH1→CH2→CH3→CH4→CH5EOS中断标志置位读取6通道结果处理BEMF/速度/电压2.3 BTIM3_IRQHandler - 换向定时器中断位置:sensorless.c:41-70触发条件: BTIM3定时器溢出延迟换向时间到达处理流程:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36void BTIM3_IRQHandler(void) { if(BTIM_GetITStatus(CW_BTIM3, BTIM_IT_UPDATE)) { BTIM_ClearITPendingBit(CW_BTIM3, BTIM_IT_UPDATE); // 状态1: 首次换向启动阶段 if(Sta 1) { Sta 2; // 进入正常运行状态 BTIM_Cmd(CW_BTIM3, DISABLE); // 禁用定时器 } // 状态3: 正常运行中的延迟换向 else if(Sta 3 StOk 1) { // 禁用定时器 BTIM_Cmd(CW_BTIM3, DISABLE); // 计算下一步换向步骤 if(Dir 1) // 正转: 0→1→2→3→4→5→0 { bHallStartStep1; if(bHallStartStep1 6) bHallStartStep1 0; } else // 反转: 0→5→4→3→2→1→0 { if(bHallStartStep1 0) bHallStartStep1 5; else bHallStartStep1--; } // 执行换向 Commutation(bHallStartStep1, Motor_Start_F); } } }第3部分过零检测原理与实现3.1 反电动势(BEMF)原理3.1.1 物理原理无传感器BLDC电机控制的核心是利用反电动势Back Electromotive Force, BEMF检测转子位置。基本原理:当电机转子旋转时定子绕组切割磁力线产生感应电动势这个感应电动势的方向与供电电压相反故称反电动势BEMF的幅值与转子转速成正比E K_e × ωBEMF的过零点发生在转子磁极与定子绕组轴线垂直时重要特性:转子位置与BEMF关系60°60°60°60°BEMF波形BEMF波形N极过零点S极过零点N极上升下降3.1.2 过零检测与换向的关系过零时刻: 转子磁极与定子绕组轴线垂直换向时刻: 过零后延迟30°电角度原因: 等待转子到达下一个磁极位置后再换向3.2 BEMF检测电路3.2.1 端电压采样代码使用三个端电压采样U、V、W相通过ADC的SampleData[0-2]读取1 2 3 4 5// ADC通道配置init.C中 PA06_ANALOG_ENABLE(); // AIN6 → U相端电压 → SampleData[0] PA07_ANALOG_ENABLE(); // AIN7 → V相端电压 → SampleData[1] PB00_ANALOG_ENABLE(); // AIN8 → W相端电压 → SampleData[2] PA03_ANALOG_ENABLE(); // AIN3 → BEMF → SampleData[3]3.2.2 虚拟中性点代码使用DIin作为虚拟中性点电压center voltage在启动前采样1 2// main.c:47 DIin SampleData[0]; // 上电后采样U相电压作为虚拟中性点原理: 在星形连接的电机中虚拟中性点电压 (U V W) / 3但由于电机绕组对称性可以用一个相电压作为参考。3.3 过零检测实现3.3.1 换向表定义1 2 3 4 5 6 7 8 9 10 11 12 13// 不同方向下的过零边沿类型 // Dir0: 反转, Dir1: 正转 const unsigned char TAB_RFling[2][6] { {RISING, FALLING, RISING, FALLING, RISING, FALLING}, // 反转 {FALLING, RISING, FALLING, RISING, FALLING, RISING} // 正转 }; // BEMF采样通道选择根据步骤选择检测哪一相 // 实际使用中SampleData[3]固定为AIN3(BEMF) const unsigned char TAB_BEMFChannel[2][6] { {3, 2, 1, 3, 2, 1}, // 反转 {3, 2, 1, 3, 2, 1} // 正转 };3.3.2 换向表详解Step通电相正转Dir1反转Dir0检测边沿说明0ABFALLINGRISINGA相下降沿A相1ACRISINGFALLINGC相上升沿C相2BCFALLINGRISINGB相下降沿B相3BARISINGFALLINGA相上升沿A相4CAFALLINGRISINGC相下降沿C相5CBRISINGFALLINGB相上升沿B相注意: 代码中实际使用固定的SampleData[3]AIN3而不是根据步骤切换通道。3.3.3 过零检测处理函数1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96void ADCS_chuli(void) { unsigned char hx 0; // 过零检测标志 unsigned int thre 0; // 阈值 // 1. 获取当前BEMF值和边沿类型 BEMFConvertedValue SampleData[3]; // AIN3采样值 RisingFalling TAB_RFling[Dir][bHallStartStep1]; // 2. 计算动态阈值电源电压的一半 // 随电源电压变化自动调整检测阈值 thre SampleData[5] 1; // Vbus / 2 // 3. 检测下降沿过零 if(RisingFalling FALLING) { if(BEMFConvertedValue thre) // BEMF低于阈值 { // 连续检测2次确认消抖 static unsigned char cou 0; cou; if(cou 2) { cou 0; Sta 3; // 标记检测到过零 StCountComm; // 连续检测计数 FFlag 1; hx 1; // 触发换向 } } else { static unsigned char cou 0; cou 0; // 未检测到过零清除计数 } } // 4. 检测上升沿过零 else if(RisingFalling RISING) { if(BEMFConvertedValue thre) // BEMF高于阈值 { static unsigned char cou 0; cou; if(cou 2) { cou 0; Sta 3; StCountComm; FFlag 1; hx 1; } } else { static unsigned char cou 0; cou 0; } } // 5. 连续检测到20次有效过零后认为启动成功 #define STCount 20 if(StCountComm STCount StOk 0) { StOk 1; // 启动成功标志 } // 6. 执行换向 if(StOk 1 hx 1) { // 测量换向时间间隔 unsigned int StepTime BTIM_GetCounter(CW_BTIM2); if(StepTime 2000) // 低速时使用定时器延迟换向 { // 延迟时间为StepTime的1/8约30°电角度 BTIM_SetAutoreload(CW_BTIM3, StepTime 3); BTIM_SetCounter(CW_BTIM3, 0); BTIM_Cmd(CW_BTIM3, ENABLE); } else // 高速时直接换向 { if(Dir 1) // 正转 { bHallStartStep1; if(bHallStartStep1 6) bHallStartStep1 0; } else // 反转 { if(bHallStartStep1 0) bHallStartStep1 5; else bHallStartStep1--; } Commutation(bHallStartStep1, Motor_Start_F); } } }3.4 关键参数说明参数值说明STCount20启动成功所需连续过零检测次数threVbus/2动态阈值随电源电压变化换向延迟StepTime3过零后延迟1/8周期约30°电角度cou阈值2连续2次检测到过零才确认消抖3.5 过零检测时序图BTIM3延迟过零检测悬空相BEMF通电相换向步骤BTIM3延迟过零检测悬空相BEMF通电相换向步骤Step 0: AB通电A相PWM输出, B相接地W相悬空检测W相BEMF换向到Step1Step 1: AC通电A相PWM输出, C相接地B相悬空检测B相BEMF换向到Step2Step 2: BC通电B相PWM输出, C相接地A相悬空检测A相BEMF延迟时间 StepTime / 8监测W相BEMF检测过零触发延迟30°电角度监测B相BEMF触发延迟30°电角度第4部分电机启动流程4.1 启动流程概述无传感器BLDC电机无法在静止状态下获取转子位置因此采用预驱动Open Loop Start启动方法给定固定绕组通电按顺序强制换向逐步增加PWM占空比等待BEMF达到可检测水平连续20次过零切换到BEMF闭环控制进入正常运行Unsupported markdown: listUnsupported markdown: listUnsupported markdown: listUnsupported markdown: list4.2 启动函数实现1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90unsigned char Sensorless_START(void) { unsigned int Com_time 0; // 换向次数计数 // 1. 清零BTIM2计数器用于测量换向时间 BTIM_SetCounter(CW_BTIM2, 0); // 2. 初始化参数 Tonoroff 0; CW_ATIM-CCR4 PWM_PERIOD - 400; // ADC触发点调整 StOk 2; // 启动中标志2表示正在启动 Sta 0; // 3. 设置初始PWM占空比8% MINOUT PWM_PERIOD * QDPwm / 100; // QDPwm 8 OutPwmValue PWM_PERIOD * QDPwm / 100; // 4. 启动电机标志 Motor_Start_F 1; // 5. 初始BTIM2计数值 CW_BTIM2-CNT 20000; // 6. 更新PWM并执行首次换向 UPPWM(); Commutation(bHallStartStep1, Motor_Start_F); // 假设从Step 0开始 // 7. 等待20ms让电机稳定 TimeCountTemp 0; while(TimeCountTemp 20); TimeCountTemp 0; // 8. 预驱动循环最多60次换向 Com_time 0; StCountComm 0; FFlag 0; do { // 8.1 计算下一步换向 if(Dir 1) // 正转 { bHallStartStep1; if(bHallStartStep1 6) bHallStartStep1 0; } else // 反转 { if(bHallStartStep1 0) bHallStartStep1 5; else bHallStartStep1--; } // 8.2 检查是否检测到过零 if(FFlag 0) StCountComm 0; FFlag 0; // 8.3 如果未检测到过零执行强制换向 if(StOk 0) { Commutation(bHallStartStep1, Motor_Start_F); } // 8.4 等待10ms并检查是否检测到过零 TimeCountTemp 0; while(TimeCountTemp 10) { if((FFlag 1 || StOk 1) TimeCountTemp 1) break; } // 8.5 增加换向计数和PWM占空比 Com_time; OutPwmValue 5; // 每次增加约0.8%占空比 UPPWM();