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

验证方法

  1. 时钟验证:在调试器中观察SystemCoreClock变量,应为72,000,000。
  2. PWM输出:用示波器测量TIM1_CH1(PA8)与TIM1_CH1N(PB13),应看到10kHz互补PWM波形,死区约1μs,占空比初始为0%。
  3. ADC采样:在调试器中查看adc_buf数组,三个通道应持续更新(数值随电机相电流变化)。
  4. 使能/失能控制:将PA8拉高,LED(PC13)点亮,PWM输出使能;拉低PA8,LED熄灭,PWM输出关闭。电机在使能状态下应能自由转动(无电流注入),失能后呈高阻状态。

通过条件:上述4项检查全部符合预期,且FOC库初始化函数返回无错误状态码。