STM32 TIM8 两路互补PWM带死区控制程序

1. 系统配置和头文件

1.1 主程序头文件 (main.h)

c 复制代码
#ifndef __MAIN_H
#define __MAIN_H

#include "stm32f1xx_hal.h"
#include <stdio.h>

// PWM通道定义
#define PWM_CHANNEL_1  TIM_CHANNEL_1
#define PWM_CHANNEL_1N TIM_CHANNEL_1
#define PWM_CHANNEL_2  TIM_CHANNEL_2
#define PWM_CHANNEL_2N TIM_CHANNEL_2
#define PWM_CHANNEL_3  TIM_CHANNEL_3
#define PWM_CHANNEL_3N TIM_CHANNEL_3

// 死区时间定义 (单位: ns)
#define DEAD_TIME_NS   1000  // 1us死区时间

// 引脚定义
// TIM8 CH1/CH1N: PC6/PA7
// TIM8 CH2/CH2N: PC7/PB0
// TIM8 CH3/CH3N: PC8/PB1
#define TIM8_CH1_PIN  GPIO_PIN_6
#define TIM8_CH1_PORT GPIOC
#define TIM8_CH1N_PIN GPIO_PIN_7
#define TIM8_CH1N_PORT GPIOA

#define TIM8_CH2_PIN  GPIO_PIN_7
#define TIM8_CH2_PORT GPIOC
#define TIM8_CH2N_PIN GPIO_PIN_0
#define TIM8_CH2N_PORT GPIOB

#define TIM8_CH3_PIN  GPIO_PIN_8
#define TIM8_CH3_PORT GPIOC
#define TIM8_CH3N_PIN GPIO_PIN_1
#define TIM8_CH3N_PORT GPIOB

// 函数声明
void SystemClock_Config(void);
void MX_GPIO_Init(void);
void MX_TIM8_Init(void);
void PWM_SetDutyCycle(uint8_t channel, float duty_cycle);
void PWM_SetFrequency(uint32_t frequency_hz);
void PWM_EnableOutputs(void);
void PWM_DisableOutputs(void);
void PWM_BreakEnable(void);
void PWM_BreakDisable(void);
void PWM_SetDeadTime(uint16_t dead_time_ns);
void Error_Handler(void);

#endif /* __MAIN_H */

2. 主程序实现

2.1 主程序 (main.c)

c 复制代码
#include "main.h"

TIM_HandleTypeDef htim8;
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};

// 全局变量
uint32_t pwm_frequency = 20000;  // 默认20kHz
uint32_t timer_clock = 72000000; // TIM8时钟频率
uint16_t pwm_period = 0;         // 自动重载值

int main(void)
{
    // HAL库初始化
    HAL_Init();
    
    // 系统时钟配置
    SystemClock_Config();
    
    // 外设初始化
    MX_GPIO_Init();
    MX_TIM8_Init();
    
    // 设置PWM频率为20kHz
    PWM_SetFrequency(20000);
    
    // 设置死区时间为1us
    PWM_SetDeadTime(DEAD_TIME_NS);
    
    // 设置初始占空比
    PWM_SetDutyCycle(PWM_CHANNEL_1, 0.5f);  // 50%占空比
    PWM_SetDutyCycle(PWM_CHANNEL_2, 0.5f);
    
    // 使能PWM输出
    PWM_EnableOutputs();
    
    // 主循环
    while (1)
    {
        // 可以在这里添加占空比调节逻辑
        // 例如:按键控制、ADC反馈、通信控制等
        
        // 模拟呼吸灯效果
        static float duty = 0.0f;
        static int8_t dir = 1;
        
        duty += 0.01f * dir;
        if(duty > 0.9f) {
            duty = 0.9f;
            dir = -1;
        } else if(duty < 0.1f) {
            duty = 0.1f;
            dir = 1;
        }
        
        PWM_SetDutyCycle(PWM_CHANNEL_1, duty);
        HAL_Delay(10);
    }
}

/**
  * @brief 系统时钟配置
  */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    // 配置HSE
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);
    
    // 配置系统时钟
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                  |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
    
    // 更新系统时钟变量
    SystemCoreClockUpdate();
    
    // 获取TIM8时钟频率
    // TIM8在APB2总线上,如果APB2分频为1,则时钟为系统时钟
    if(RCC_ClkInitStruct.APB2CLKDivider == RCC_HCLK_DIV1) {
        timer_clock = SystemCoreClock;
    } else {
        timer_clock = SystemCoreClock * 2;
    }
}

/**
  * @brief GPIO初始化
  */
void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // 使能GPIO时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    
    // 配置TIM8通道1引脚
    GPIO_InitStruct.Pin = TIM8_CH1_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;  // 复用推挽输出
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(TIM8_CH1_PORT, &GPIO_InitStruct);
    
    // 配置TIM8通道1N引脚
    GPIO_InitStruct.Pin = TIM8_CH1N_PIN;
    HAL_GPIO_Init(TIM8_CH1N_PORT, &GPIO_InitStruct);
    
    // 配置TIM8通道2引脚
    GPIO_InitStruct.Pin = TIM8_CH2_PIN;
    HAL_GPIO_Init(TIM8_CH2_PORT, &GPIO_InitStruct);
    
    // 配置TIM8通道2N引脚
    GPIO_InitStruct.Pin = TIM8_CH2N_PIN;
    HAL_GPIO_Init(TIM8_CH2N_PORT, &GPIO_InitStruct);
    
    // 配置TIM8通道3引脚
    GPIO_InitStruct.Pin = TIM8_CH3_PIN;
    HAL_GPIO_Init(TIM8_CH3_PORT, &GPIO_InitStruct);
    
    // 配置TIM8通道3N引脚
    GPIO_InitStruct.Pin = TIM8_CH3N_PIN;
    HAL_GPIO_Init(TIM8_CH3N_PORT, &GPIO_InitStruct);
}

3. TIM8 PWM配置

3.1 TIM8初始化 (tim8_pwm.c)

c 复制代码
#include "main.h"

extern TIM_HandleTypeDef htim8;
extern TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
extern TIM_OC_InitTypeDef sConfigOC;

/**
  * @brief TIM8 PWM初始化
  */
void MX_TIM8_Init(void)
{
    TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    TIM_MasterConfigTypeDef sMasterConfig = {0};
    TIM_OC_InitTypeDef sConfigOC = {0};
    TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
    
    // 使能TIM8时钟
    __HAL_RCC_TIM8_CLK_ENABLE();
    
    // 配置TIM8
    htim8.Instance = TIM8;
    htim8.Init.Prescaler = 0;  // 不分频
    htim8.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;  // 中心对齐模式1
    htim8.Init.Period = 3599;  // 默认20kHz (72MHz / 3600 = 20kHz)
    htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim8.Init.RepetitionCounter = 0;
    htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    
    if (HAL_TIM_PWM_Init(&htim8) != HAL_OK)
    {
        Error_Handler();
    }
    
    // 配置时钟源
    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig);
    
    // 配置PWM模式
    sConfigOC.OCMode = TIM_OCMODE_PWM1;  // PWM模式1
    sConfigOC.Pulse = 1800;              // 默认50%占空比
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;  // 有效电平为高
    sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; // 互补通道有效电平为高
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
    sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    
    // 配置通道1
    if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
    {
        Error_Handler();
    }
    
    // 配置通道2
    if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
    {
        Error_Handler();
    }
    
    // 配置通道3
    if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
    {
        Error_Handler();
    }
    
    // 配置主模式
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig);
    
    // 配置断路和死区时间
    sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
    sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
    sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
    sBreakDeadTimeConfig.DeadTime = 72;  // 1us死区时间 (72MHz时钟)
    sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
    sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
    sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
    
    HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig);
}

/**
  * @brief 设置PWM占空比
  * @param channel: PWM通道
  * @param duty_cycle: 占空比 (0.0 - 1.0)
  */
void PWM_SetDutyCycle(uint8_t channel, float duty_cycle)
{
    uint32_t pulse = 0;
    
    // 限制占空比范围
    if(duty_cycle < 0.0f) duty_cycle = 0.0f;
    if(duty_cycle > 1.0f) duty_cycle = 1.0f;
    
    // 计算比较值
    // 注意:在中心对齐模式下,比较值应该是周期值的一半
    pulse = (uint32_t)(duty_cycle * htim8.Init.Period);
    
    // 设置比较值
    __HAL_TIM_SET_COMPARE(&htim8, channel, pulse);
}

/**
  * @brief 设置PWM频率
  * @param frequency_hz: 频率值 (Hz)
  */
void PWM_SetFrequency(uint32_t frequency_hz)
{
    TIM_Base_InitTypeDef TIM_BaseStruct = {0};
    uint32_t prescaler = 0;
    uint32_t period = 0;
    
    // 计算预分频和自动重载值
    if(frequency_hz > 0)
    {
        // 计算最小预分频值
        prescaler = (timer_clock / (frequency_hz * 65536)) - 1;
        if(prescaler < 0) prescaler = 0;
        
        // 计算周期值
        period = (timer_clock / ((prescaler + 1) * frequency_hz)) - 1;
        
        // 如果周期值太大,增加预分频
        if(period > 65535)
        {
            prescaler = (timer_clock / (frequency_hz * 65536)) - 1;
            period = (timer_clock / ((prescaler + 1) * frequency_hz)) - 1;
        }
        
        pwm_frequency = frequency_hz;
        pwm_period = period;
        
        // 停止定时器
        HAL_TIM_PWM_Stop(&htim8, TIM_CHANNEL_1);
        HAL_TIM_PWM_Stop(&htim8, TIM_CHANNEL_2);
        HAL_TIM_PWM_Stop(&htim8, TIM_CHANNEL_3);
        
        // 更新定时器参数
        TIM_BaseStruct.Prescaler = prescaler;
        TIM_BaseStruct.Period = period;
        TIM_BaseStruct.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;
        TIM_BaseStruct.ClockDivision = TIM_CLOCKDIVISION_DIV1;
        TIM_BaseStruct.RepetitionCounter = 0;
        TIM_BaseStruct.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
        
        if(HAL_TIM_Base_Init(&htim8) != HAL_OK)
        {
            Error_Handler();
        }
        
        // 重新启动PWM
        HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);
        HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_2);
        HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_3);
    }
}

/**
  * @brief 设置死区时间
  * @param dead_time_ns: 死区时间 (纳秒)
  */
void PWM_SetDeadTime(uint16_t dead_time_ns)
{
    // 计算死区时间寄存器值
    // DT = DTG[7:0] * Tdtg
    // 其中Tdtg是定时器时钟周期
    
    float timer_period_ns = 1e9f / timer_clock;  // 定时器时钟周期(纳秒)
    uint16_t dead_time_ticks = (uint16_t)(dead_time_ns / timer_period_ns);
    
    // 限制死区时间最大值
    if(dead_time_ticks > 0xFF)  // DTG寄存器只有8位
    {
        dead_time_ticks = 0xFF;
    }
    
    // 停止PWM输出
    PWM_DisableOutputs();
    
    // 重新配置死区时间
    sBreakDeadTimeConfig.DeadTime = dead_time_ticks;
    
    if(HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK)
    {
        Error_Handler();
    }
    
    // 重新使能PWM输出
    PWM_EnableOutputs();
}

/**
  * @brief 使能PWM输出
  */
void PWM_EnableOutputs(void)
{
    // 使能通道1和互补通道1
    HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);
    HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_1);
    
    // 使能通道2和互补通道2
    HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_2);
    HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_2);
    
    // 使能通道3和互补通道3
    HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_3);
    HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_3);
    
    // 使能主输出
    __HAL_TIM_MOE_ENABLE(&htim8);
}

/**
  * @brief 禁用PWM输出
  */
void PWM_DisableOutputs(void)
{
    // 禁用主输出
    __HAL_TIM_MOE_DISABLE(&htim8);
    
    // 停止通道1和互补通道1
    HAL_TIM_PWM_Stop(&htim8, TIM_CHANNEL_1);
    HAL_TIMEx_PWMN_Stop(&htim8, TIM_CHANNEL_1);
    
    // 停止通道2和互补通道2
    HAL_TIM_PWM_Stop(&htim8, TIM_CHANNEL_2);
    HAL_TIMEx_PWMN_Stop(&htim8, TIM_CHANNEL_2);
    
    // 停止通道3和互补通道3
    HAL_TIM_PWM_Stop(&htim8, TIM_CHANNEL_3);
    HAL_TIMEx_PWMN_Stop(&htim8, TIM_CHANNEL_3);
}

/**
  * @brief 使能断路功能
  */
void PWM_BreakEnable(void)
{
    sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
    
    if(HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK)
    {
        Error_Handler();
    }
}

/**
  * @brief 禁用断路功能
  */
void PWM_BreakDisable(void)
{
    sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
    
    if(HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK)
    {
        Error_Handler();
    }
}

/**
  * @brief 错误处理
  */
void Error_Handler(void)
{
    // 可以在这里添加错误处理代码
    // 例如:闪烁LED、重启系统等
    while(1)
    {
        // 死循环
    }
}

4. PWM控制高级功能

4.1 同步触发和刹车控制 (pwm_control.c)

c 复制代码
#include "main.h"

/**
  * @brief 配置PWM同步触发
  * @param master_mode: 主模式选择
  * @param slave_mode: 从模式选择
  */
void PWM_ConfigSync(uint32_t master_mode, uint32_t slave_mode)
{
    TIM_MasterConfigTypeDef sMasterConfig = {0};
    TIM_SlaveConfigTypeDef sSlaveConfig = {0};
    
    // 配置主模式
    sMasterConfig.MasterOutputTrigger = master_mode;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
    HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig);
    
    // 配置从模式
    sSlaveConfig.SlaveMode = slave_mode;
    sSlaveConfig.InputTrigger = TIM_TS_ITR0;  // 内部触发0
    sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING;
    sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;
    sSlaveConfig.TriggerFilter = 0;
    HAL_TIM_SlaveConfigSynchronization(&htim8, &sSlaveConfig);
}

/**
  * @brief 配置互补输出极性
  * @param channel: 通道
  * @param polarity: 主通道极性
  * @param npolarity: 互补通道极性
  */
void PWM_ConfigPolarity(uint32_t channel, uint32_t polarity, uint32_t npolarity)
{
    TIM_OC_InitTypeDef sConfigOC = {0};
    
    // 获取当前配置
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = __HAL_TIM_GET_COMPARE(&htim8, channel);
    sConfigOC.OCPolarity = polarity;
    sConfigOC.OCNPolarity = npolarity;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
    sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    
    // 重新配置通道
    if(HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, channel) != HAL_OK)
    {
        Error_Handler();
    }
}

/**
  * @brief 配置输出比较空闲状态
  * @param channel: 通道
  * @param idle_state: 空闲状态
  * @param nidle_state: 互补通道空闲状态
  */
void PWM_ConfigIdleState(uint32_t channel, uint32_t idle_state, uint32_t nidle_state)
{
    TIM_OC_InitTypeDef sConfigOC = {0};
    
    // 获取当前配置
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = __HAL_TIM_GET_COMPARE(&htim8, channel);
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    sConfigOC.OCIdleState = idle_state;
    sConfigOC.OCNIdleState = nidle_state;
    
    // 重新配置通道
    if(HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, channel) != HAL_OK)
    {
        Error_Handler();
    }
}

/**
  * @brief 设置PWM对齐模式
  * @param mode: 对齐模式
  * 可选值:
  *   TIM_COUNTERMODE_UP - 边沿对齐模式(向上计数)
  *   TIM_COUNTERMODE_DOWN - 边沿对齐模式(向下计数)
  *   TIM_COUNTERMODE_CENTERALIGNED1 - 中心对齐模式1
  *   TIM_COUNTERMODE_CENTERALIGNED2 - 中心对齐模式2
  *   TIM_COUNTERMODE_CENTERALIGNED3 - 中心对齐模式3
  */
void PWM_SetAlignmentMode(uint32_t mode)
{
    // 停止PWM输出
    PWM_DisableOutputs();
    
    // 更新对齐模式
    htim8.Init.CounterMode = mode;
    
    if(HAL_TIM_PWM_Init(&htim8) != HAL_OK)
    {
        Error_Handler();
    }
    
    // 重新使能PWM输出
    PWM_EnableOutputs();
}

5. 死区时间计算模块

5.1 死区时间计算 (deadtime_calc.c)

c 复制代码
#include "main.h"
#include <math.h>

/**
  * @brief 计算死区时间寄存器值
  * @param dead_time_ns: 死区时间(纳秒)
  * @param timer_freq: 定时器时钟频率(Hz)
  * @return 死区时间寄存器值
  * 
  * 死区时间计算公式:
  * DT = (DTG[7:0] + 1) * Tdtg
  * 其中Tdtg是定时器时钟周期
  * 
  * 根据DTG[7:5]的值,公式不同:
  * 000: DT = DTG[7:0] * Tdtg
  * 001: DT = (64 + DTG[5:0]) * 2 * Tdtg
  * 010: DT = (32 + DTG[4:0]) * 8 * Tdtg
  * 011: DT = (32 + DTG[4:0]) * 16 * Tdtg
  * 1xx: DT = (32 + DTG[4:0]) * 32 * Tdtg
  */
uint32_t CalculateDeadTimeReg(uint32_t dead_time_ns, uint32_t timer_freq)
{
    float timer_period_ns = 1e9f / timer_freq;  // 定时器时钟周期(纳秒)
    uint32_t dtg_value = 0;
    
    // 计算需要的时钟周期数
    float required_cycles = dead_time_ns / timer_period_ns;
    
    if(required_cycles <= 127.0f)
    {
        // 模式0: DT = DTG[7:0] * Tdtg
        dtg_value = (uint32_t)required_cycles;
    }
    else if(required_cycles <= 254.0f)
    {
        // 模式1: DT = (64 + DTG[5:0]) * 2 * Tdtg
        uint32_t cycles = (uint32_t)(required_cycles / 2.0f);
        if(cycles < 64) cycles = 64;
        if(cycles > 127) cycles = 127;
        dtg_value = ((cycles - 64) & 0x3F) | 0x40;  // 设置DTG[6]=1
    }
    else if(required_cycles <= 1016.0f)
    {
        // 模式2: DT = (32 + DTG[4:0]) * 8 * Tdtg
        uint32_t cycles = (uint32_t)(required_cycles / 8.0f);
        if(cycles < 32) cycles = 32;
        if(cycles > 63) cycles = 63;
        dtg_value = ((cycles - 32) & 0x1F) | 0x80;  // 设置DTG[7]=1
    }
    else if(required_cycles <= 2032.0f)
    {
        // 模式3: DT = (32 + DTG[4:0]) * 16 * Tdtg
        uint32_t cycles = (uint32_t)(required_cycles / 16.0f);
        if(cycles < 32) cycles = 32;
        if(cycles > 63) cycles = 63;
        dtg_value = ((cycles - 32) & 0x1F) | 0xC0;  // 设置DTG[7:6]=11
    }
    else
    {
        // 模式4: DT = (32 + DTG[4:0]) * 32 * Tdtg
        uint32_t cycles = (uint32_t)(required_cycles / 32.0f);
        if(cycles < 32) cycles = 32;
        if(cycles > 63) cycles = 63;
        dtg_value = ((cycles - 32) & 0x1F) | 0xE0;  // 设置DTG[7:5]=111
    }
    
    return dtg_value;
}

/**
  * @brief 验证死区时间设置
  * @param dtg_value: 死区时间寄存器值
  * @param timer_freq: 定时器时钟频率(Hz)
  * @return 实际死区时间(纳秒)
  */
float VerifyDeadTime(uint32_t dtg_value, uint32_t timer_freq)
{
    float timer_period_ns = 1e9f / timer_freq;
    float dead_time_ns = 0.0f;
    
    if((dtg_value & 0x80) == 0)
    {
        // 模式0
        if((dtg_value & 0x40) == 0)
        {
            dead_time_ns = dtg_value * timer_period_ns;
        }
        // 模式1
        else
        {
            uint32_t dtg_low = dtg_value & 0x3F;
            dead_time_ns = (64 + dtg_low) * 2 * timer_period_ns;
        }
    }
    else
    {
        uint32_t dtg_low = dtg_value & 0x1F;
        
        if((dtg_value & 0xC0) == 0x80)
        {
            // 模式2
            dead_time_ns = (32 + dtg_low) * 8 * timer_period_ns;
        }
        else if((dtg_value & 0xE0) == 0xC0)
        {
            // 模式3
            dead_time_ns = (32 + dtg_low) * 16 * timer_period_ns;
        }
        else
        {
            // 模式4
            dead_time_ns = (32 + dtg_low) * 32 * timer_period_ns;
        }
    }
    
    return dead_time_ns;
}

6. 中断处理

6.1 中断配置 (tim8_it.c)

c 复制代码
#include "main.h"

// 中断回调变量
volatile uint8_t pwm_update_flag = 0;
volatile uint8_t break_event_flag = 0;

/**
  * @brief 配置TIM8中断
  */
void PWM_ConfigInterrupts(void)
{
    // 使能TIM8中断
    HAL_NVIC_SetPriority(TIM8_UP_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM8_UP_IRQn);
    
    HAL_NVIC_SetPriority(TIM8_BRK_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(TIM8_BRK_IRQn);
    
    HAL_NVIC_SetPriority(TIM8_TRG_COM_IRQn, 0, 2);
    HAL_NVIC_EnableIRQ(TIM8_TRG_COM_IRQn);
    
    HAL_NVIC_SetPriority(TIM8_CC_IRQn, 0, 3);
    HAL_NVIC_EnableIRQ(TIM8_CC_IRQn);
    
    // 使能更新中断
    __HAL_TIM_ENABLE_IT(&htim8, TIM_IT_UPDATE);
    
    // 使能断路中断
    __HAL_TIM_ENABLE_IT(&htim8, TIM_IT_BREAK);
    
    // 使能比较中断
    __HAL_TIM_ENABLE_IT(&htim8, TIM_IT_CC1);
    __HAL_TIM_ENABLE_IT(&htim8, TIM_IT_CC2);
    __HAL_TIM_ENABLE_IT(&htim8, TIM_IT_CC3);
}

/**
  * @brief TIM8更新中断处理
  */
void TIM8_UP_IRQHandler(void)
{
    if(__HAL_TIM_GET_FLAG(&htim8, TIM_FLAG_UPDATE) != RESET)
    {
        if(__HAL_TIM_GET_IT_SOURCE(&htim8, TIM_IT_UPDATE) != RESET)
        {
            __HAL_TIM_CLEAR_IT(&htim8, TIM_IT_UPDATE);
            pwm_update_flag = 1;
            
            // 可以在这里添加周期更新处理代码
        }
    }
}

/**
  * @brief TIM8断路中断处理
  */
void TIM8_BRK_IRQHandler(void)
{
    if(__HAL_TIM_GET_FLAG(&htim8, TIM_FLAG_BREAK) != RESET)
    {
        if(__HAL_TIM_GET_IT_SOURCE(&htim8, TIM_IT_BREAK) != RESET)
        {
            __HAL_TIM_CLEAR_IT(&htim8, TIM_IT_BREAK);
            break_event_flag = 1;
            
            // 处理断路事件
            // 可以在这里添加紧急停机、故障记录等代码
        }
    }
}

/**
  * @brief TIM8比较中断处理
  */
void TIM8_CC_IRQHandler(void)
{
    // 处理比较中断
    if(__HAL_TIM_GET_FLAG(&htim8, TIM_FLAG_CC1) != RESET)
    {
        if(__HAL_TIM_GET_IT_SOURCE(&htim8, TIM_IT_CC1) != RESET)
        {
            __HAL_TIM_CLEAR_IT(&htim8, TIM_IT_CC1);
            // 处理通道1比较事件
        }
    }
    
    if(__HAL_TIM_GET_FLAG(&htim8, TIM_FLAG_CC2) != RESET)
    {
        if(__HAL_TIM_GET_IT_SOURCE(&htim8, TIM_IT_CC2) != RESET)
        {
            __HAL_TIM_CLEAR_IT(&htim8, TIM_IT_CC2);
            // 处理通道2比较事件
        }
    }
    
    if(__HAL_TIM_GET_FLAG(&htim8, TIM_FLAG_CC3) != RESET)
    {
        if(__HAL_TIM_GET_IT_SOURCE(&htim8, TIM_IT_CC3) != RESET)
        {
            __HAL_TIM_CLEAR_IT(&htim8, TIM_IT_CC3);
            // 处理通道3比较事件
        }
    }
}

7. PWM控制应用示例

7.1 电机控制应用 (motor_control.c)

c 复制代码
#include "main.h"
#include <math.h>

// 电机控制结构体
typedef struct {
    float duty_a;     // A相占空比
    float duty_b;     // B相占空比
    float duty_c;     // C相占空比
    float frequency;  // PWM频率
    float deadtime;   // 死区时间
    uint8_t enabled;  // 使能状态
} MotorControl_t;

MotorControl_t motor = {0};

/**
  * @brief 初始化电机控制
  */
void Motor_Init(void)
{
    motor.frequency = 20000.0f;  // 20kHz
    motor.deadtime = 1000.0f;    // 1us
    motor.enabled = 0;
    
    // 初始化PWM
    PWM_SetFrequency((uint32_t)motor.frequency);
    PWM_SetDeadTime((uint16_t)motor.deadtime);
    
    // 设置初始占空比
    motor.duty_a = 0.0f;
    motor.duty_b = 0.0f;
    motor.duty_c = 0.0f;
    
    PWM_SetDutyCycle(PWM_CHANNEL_1, motor.duty_a);
    PWM_SetDutyCycle(PWM_CHANNEL_2, motor.duty_b);
    PWM_SetDutyCycle(PWM_CHANNEL_3, motor.duty_c);
}

/**
  * @brief 设置三相PWM
  * @param u: U相电压 (-1.0 到 1.0)
  * @param v: V相电压 (-1.0 到 1.0)
  * @param w: W相电压 (-1.0 到 1.0)
  */
void Motor_SetThreePhase(float u, float v, float w)
{
    // 限制输入范围
    if(u < -1.0f) u = -1.0f;
    if(u > 1.0f)  u = 1.0f;
    if(v < -1.0f) v = -1.0f;
    if(v > 1.0f)  v = 1.0f;
    if(w < -1.0f) w = -1.0f;
    if(w > 1.0f)  w = 1.0f;
    
    // 转换为占空比 (0.0 到 1.0)
    motor.duty_a = (u + 1.0f) * 0.5f;
    motor.duty_b = (v + 1.0f) * 0.5f;
    motor.duty_c = (w + 1.0f) * 0.5f;
    
    // 设置PWM占空比
    PWM_SetDutyCycle(PWM_CHANNEL_1, motor.duty_a);
    PWM_SetDutyCycle(PWM_CHANNEL_2, motor.duty_b);
    PWM_SetDutyCycle(PWM_CHANNEL_3, motor.duty_c);
}

/**
  * @brief 生成SVPWM波形
  * @param angle: 电角度 (弧度)
  * @param magnitude: 调制深度 (0.0 到 1.0)
  */
void Motor_SVPWM(float angle, float magnitude)
{
    // 限制调制深度
    if(magnitude < 0.0f) magnitude = 0.0f;
    if(magnitude > 1.0f) magnitude = 1.0f;
    
    // 三相正弦波
    float u = magnitude * sinf(angle);
    float v = magnitude * sinf(angle + 2.0f * 3.1415926f / 3.0f);
    float w = magnitude * sinf(angle - 2.0f * 3.1415926f / 3.0f);
    
    // 设置三相PWM
    Motor_SetThreePhase(u, v, w);
}

/**
  * @brief 使能电机驱动
  */
void Motor_Enable(void)
{
    if(!motor.enabled)
    {
        motor.enabled = 1;
        PWM_EnableOutputs();
    }
}

/**
  * @brief 禁用电机驱动
  */
void Motor_Disable(void)
{
    if(motor.enabled)
    {
        motor.enabled = 0;
        PWM_DisableOutputs();
        
        // 设置占空比为0
        motor.duty_a = 0.0f;
        motor.duty_b = 0.0f;
        motor.duty_c = 0.0f;
        
        PWM_SetDutyCycle(PWM_CHANNEL_1, 0.0f);
        PWM_SetDutyCycle(PWM_CHANNEL_2, 0.0f);
        PWM_SetDutyCycle(PWM_CHANNEL_3, 0.0f);
    }
}

/**
  * @brief 紧急停止
  */
void Motor_EmergencyStop(void)
{
    // 使能断路功能
    PWM_BreakEnable();
    
    // 禁用输出
    Motor_Disable();
    
    // 可以添加故障记录等其他处理
}

参考代码 STM32的TIM8的PWM两路带死区的程序 www.youwenfan.com/contentcsv/71035.html

8. Keil工程配置

8.1 工程配置要点

  1. Device: STM32F103ZE (或其他支持TIM8的型号)

  2. Target: 设置晶振频率为8MHz

  3. C/C++: 添加包含路径和预定义符号

    复制代码
    Define: USE_HAL_DRIVER, STM32F103xE
    Include Paths: 添加所有必要的HAL库路径
  4. Debug: 配置ST-Link调试器

  5. Utilities: 配置Flash烧录算法

8.2 链接脚本

scatter 复制代码
LR_IROM1 0x08000000 0x00080000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00010000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

9. 调试和测试

9.1 测试程序

c 复制代码
// 测试PWM输出的主循环
void Test_PWM_Output(void)
{
    // 测试不同频率
    uint32_t test_frequencies[] = {10000, 15000, 20000, 25000, 30000};
    uint8_t freq_index = 0;
    
    // 测试不同死区时间
    uint16_t test_deadtimes[] = {500, 1000, 1500, 2000};  // ns
    uint8_t deadtime_index = 0;
    
    while(1)
    {
        // 测试频率切换
        PWM_SetFrequency(test_frequencies[freq_index]);
        freq_index = (freq_index + 1) % 5;
        
        // 测试死区时间切换
        PWM_SetDeadTime(test_deadtimes[deadtime_index]);
        deadtime_index = (deadtime_index + 1) % 4;
        
        // 测试占空比扫频
        for(float duty = 0.0f; duty <= 1.0f; duty += 0.01f)
        {
            PWM_SetDutyCycle(PWM_CHANNEL_1, duty);
            PWM_SetDutyCycle(PWM_CHANNEL_2, 1.0f - duty);
            HAL_Delay(10);
        }
        
        for(float duty = 1.0f; duty >= 0.0f; duty -= 0.01f)
        {
            PWM_SetDutyCycle(PWM_CHANNEL_1, duty);
            PWM_SetDutyCycle(PWM_CHANNEL_2, 1.0f - duty);
            HAL_Delay(10);
        }
        
        HAL_Delay(1000);
    }
}

10. 注意事项

  1. 硬件连接:

    • 确保TIM8的互补输出引脚正确连接
    • 注意引脚的最大驱动电流
    • 添加必要的保护电路(如TVS、RC缓冲)
  2. 死区时间设置:

    • 死区时间必须大于MOSFET/IGBT的开关时间
    • 考虑温度对开关时间的影响
    • 死区时间过大会导致输出失真
  3. EMC考虑:

    • 使用屏蔽电缆连接功率器件
    • 添加RC缓冲电路减少开关噪声
    • 合理布局PCB,减少辐射
  4. 安全保护:

    • 实现过流、过压、过热保护
    • 添加硬件断路输入
    • 实现软件看门狗
  5. 调试技巧:

    • 使用示波器观察PWM波形
    • 验证死区时间是否准确
    • 检查互补信号是否有重叠
相关推荐
傻啦嘿哟13 小时前
指纹伪装:除了换IP,OpenClaw的浏览器指纹该如何配置
网络·网络协议·tcp/ip
米高梅狮子1 天前
03.网络类服务实践
linux·运维·服务器·网络·kubernetes·centos·openstack
June`1 天前
网络编程时内核究竟做了什么???
linux·服务器·网络
原来是猿1 天前
腾讯云服务器端口开放完全指南
服务器·网络·腾讯云
你的保护色1 天前
【无标题】
java·服务器·网络
楼兰公子1 天前
RK3588 + Linux7.0.3 网络工程调试错误速查手册
linux·网络·3588
IpdataCloud1 天前
稳定的企业级IP数据接口怎么选?可用性指标+离线库高可用方案
运维·网络·tcp/ip
HMS工业网络1 天前
如何解决使用TwinCAT时EtherCAT网络出现“Sync Manager Watchdog”报错
网络·网络协议·网络安全
Jason_zhao_MR1 天前
RK3576 MIPI Camera ISP调试:主观调优与工程实战(下)
stm32·嵌入式硬件·安全·系统架构·嵌入式