1. 初始化FOC控制核心
任务说明
本案例完成STM32平台上FOC控制核心的初始化:配置系统时钟、PWM输出引脚、定时器及相电流采样ADC,调用FOC库初始化函数,并实现电机的使能(Enable)与失能(Disable)控制。最终通过LED状态与ADC采样值验证初始化是否正确。
硬件资源
- MCU:STM32F103C8T6(72MHz主频)
- 电机驱动:三相全桥(如DRV8301或类似),PWM输入为6路互补带死区信号
- 采样电阻:下桥臂三电阻采样,经运放接入ADC通道
- 编码器:ABZ增量式(1000线),用于转子位置反馈
关键代码
// main.c — FOC核心初始化与使能/失能控制
#include "stm32f1xx_hal.h"
#include "foc.h"
// 定时器句柄(TIM1用于PWM输出,TIM3用于编码器)
TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim3;
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
// FOC库全局句柄
FOC_Handle hfoc;
// 相电流采样缓冲(三通道)
uint16_t adc_buf[3];
// 系统时钟配置:HSE 8MHz → PLL ×9 = 72MHz
void SystemClock_Config(void) {
RCC_OscInitTypeDef osc = {0};
RCC_ClkInitTypeDef clk = {0};
osc.OscillatorType = RCC_OSCILLATORTYPE_HSE;
osc.HSEState = RCC_HSE_ON;
osc.PLL.PLLState = RCC_PLL_ON;
osc.PLL.PLLSource = RCC_PLLSOURCE_HSE;
osc.PLL.PLLMUL = RCC_PLL_MUL9;
HAL_RCC_OscConfig(&osc);
clk.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK |
RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
clk.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clk.AHBCLKDivider = RCC_SYSCLK_DIV1;
clk.APB1CLKDivider = RCC_HCLK_DIV2; // 36MHz
clk.APB2CLKDivider = RCC_HCLK_DIV1; // 72MHz
HAL_RCC_ClockConfig(&clk, FLASH_LATENCY_2);
}
// TIM1 PWM初始化:6路互补输出,中心对齐模式,死区1μs
static void MX_TIM1_Init(void) {
TIM_OC_InitTypeDef oc = {0};
TIM_BreakDeadTimeConfigTypeDef bd = {0};
__HAL_RCC_TIM1_CLK_ENABLE();
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;
htim1.Init.Period = 7200 - 1; // 72MHz/7200 = 10kHz PWM
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_PWM_Init(&htim1);
oc.OCMode = TIM_OCMODE_PWM1;
oc.Pulse = 0;
oc.OCPolarity = TIM_OCPOLARITY_HIGH;
oc.OCNPolarity = TIM_OCNPOLARITY_HIGH;
oc.OCFastMode = TIM_OCFAST_DISABLE;
oc.OCIdleState = TIM_OCIDLESTATE_RESET;
oc.OCNIdleState = TIM_OCNIDLESTATE_RESET;
HAL_TIM_PWM_ConfigChannel(&htim1, &oc, TIM_CHANNEL_1);
HAL_TIM_PWM_ConfigChannel(&htim1, &oc, TIM_CHANNEL_2);
HAL_TIM_PWM_ConfigChannel(&htim1, &oc, TIM_CHANNEL_3);
bd.OffStateRunMode = TIM_OSSR_DISABLE;
bd.OffStateIDLEMode = TIM_OSSI_DISABLE;
bd.LockLevel = TIM_LOCKLEVEL_OFF;
bd.DeadTime = 72; // 1μs死区
bd.BreakState = TIM_BREAK_DISABLE;
bd.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
bd.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &bd);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);
}
// ADC1初始化:三通道扫描+DMA,采样相电流
static void MX_ADC1_Init(void) {
ADC_ChannelConfTypeTypeDef sConfig = {0};
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
HAL_DMA_Init(&hdma_adc1);
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_TRGO;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 3;
HAL_ADC_Init(&hadc1);
sConfig.Channel = ADC_CHANNEL_0; // IA
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_7CYCLES_5;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
sConfig.Channel = ADC_CHANNEL_1; // IB
sConfig.Rank = 2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
sConfig.Channel = ADC_CHANNEL_2; // IC
sConfig.Rank = 3;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buf, 3);
}
// GPIO初始化:使能引脚、LED指示、编码器输入
static void MX_GPIO_Init(void) {
GPIO_InitTypeDef gpio = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
// PC13 — LED(使能状态指示)
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
gpio.Pin = GPIO_PIN_13;
gpio.Mode = GPIO_MODE_OUTPUT_PP;
gpio.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &gpio);
// PA8 — 使能控制输入(高电平使能)
gpio.Pin = GPIO_PIN_8;
gpio.Mode = GPIO_MODE_INPUT;
gpio.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA, &gpio);
// PA6/PA7 — 编码器A/B相(TIM3通道1/2)
gpio.Pin = GPIO_PIN_6 | GPIO_PIN_7;
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Pull = GPIO_NOPULL;
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &gpio);
}
// 编码器接口初始化(TIM3)
static void MX_TIM3_Encoder_Init(void) {
TIM_Encoder_InitTypeDef enc = {0};
__HAL_RCC_TIM3_CLK_ENABLE();
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 0xFFFF;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
enc.EncoderMode = TIM_ENCODERMODE_TI12;
enc.IC1Polarity = TIM_ICPOLARITY_RISING;
enc.IC1Selection = TIM_ICSELECTION_DIRECTTI;
enc.IC1Prescaler = TIM_ICPSC_DIV1;
enc.IC1Filter = 0;
enc.IC2Polarity = TIM_ICPOLARITY_RISING;
enc.IC2Selection = TIM_ICSELECTION_DIRECTTI;
enc.IC2Prescaler = TIM_ICPSC_DIV1;
enc.IC2Filter = 0;
HAL_TIM_Encoder_Init(&htim3, &enc);
HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
}
// FOC库初始化与电机控制
void FOC_Motor_Init(void) {
FOC_InitTypeDef foc_cfg = {0};
foc_cfg.pwm_tim = &htim1;
foc_cfg.enc_tim = &htim3;
foc_cfg.adc_buf = adc_buf;
foc_cfg.pole_pairs = 4;
foc_cfg.phase_resistance = 0.5f; // 单位Ω
foc_cfg.phase_inductance = 0.0002f; // 单位H
foc_cfg.encoder_lines = 1000;
foc_cfg.pwm_freq = 10000;
foc_cfg.deadtime_us = 1.0f;
FOC_Init(&hfoc, &foc_cfg);
}
void FOC_Motor_Enable(void) {
FOC_Enable(&hfoc);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); // LED亮
}
void FOC_Motor_Disable(void) {
FOC_Disable(&hfoc);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); // LED灭
}
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM1_Init();
MX_ADC1_Init();
MX_TIM3_Encoder_Init();
FOC_Motor_Init();
while (1) {
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == GPIO_PIN_SET) {
FOC_Motor_Enable();
} else {
FOC_Motor_Disable();
}
HAL_Delay(10);
}
}
编译与烧录
# 使用STM32CubeIDE或arm-none-eabi工具链
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -DSTM32F103xB \
-I./Inc -I./Drivers/STM32F1xx_HAL_Driver/Inc \
main.c foc.c -o foc_init.elf
arm-none-eabi-objcopy -O binary foc_init.elf foc_init.bin
# 通过ST-Link烧录
st-flash write foc_init.bin 0x08000000
验证方法
- 时钟验证:在调试器中观察SystemCoreClock变量,应为72,000,000。
- PWM输出:用示波器测量TIM1_CH1(PA8)与TIM1_CH1N(PB13),应看到10kHz互补PWM波形,死区约1μs,占空比初始为0%。
- ADC采样:在调试器中查看adc_buf数组,三个通道应持续更新(数值随电机相电流变化)。
- 使能/失能控制:将PA8拉高,LED(PC13)点亮,PWM输出使能;拉低PA8,LED熄灭,PWM输出关闭。电机在使能状态下应能自由转动(无电流注入),失能后呈高阻状态。
通过条件:上述4项检查全部符合预期,且FOC库初始化函数返回无错误状态码。