STM32 速度控制器:PWM + PID 无级调速实现

一、系统架构设计

复制代码
┌─────────────────────────────────────────────────────────────┐
│                    STM32 速度控制系统                       │
├─────────────────────────────────────────────────────────────┤
│  上位机/按键  │  目标速度设定  │  PID控制器  │  PWM输出    │
│  输入指令    │  (RPM/Hz)     │  算法处理    │  驱动电机    │
├─────────────┼──────────────┼────────────┼────────────┤
│  • 串口指令  │  • 速度设定   │  • 比例项    │  • TIMx     │
│  • 按键调整  │  • 加减速曲线 │  • 积分项    │  • 通道配置  │
│  • 旋钮输入  │  • 方向控制   │  • 微分项    │  • 死区补偿  │
└─────────────────────────────────────────────────────────────┘

二、代码

2.1 主程序:main.c

c 复制代码
/**
 * @file main.c
 * @brief STM32 速度控制器 - PWM + PID 无级调速
 * @platform STM32F103/F407 系列
 * @author AI Assistant
 * @date 2024
 */

#include "stm32f10x.h"
#include "pid.h"
#include "motor_control.h"
#include "encoder.h"
#include "usart.h"
#include "timer.h"

// 系统参数
#define SYSTEM_CLOCK     72000000    // 系统时钟 72MHz
#define PWM_FREQUENCY   20000       // PWM频率 20kHz
#define CONTROL_PERIOD  10          // 控制周期 10ms
#define MAX_SPEED       3000        // 最大速度 3000 RPM
#define MIN_SPEED       50          // 最小速度 50 RPM

// 全局变量
volatile uint16_t target_speed = 0;     // 目标速度 (RPM)
volatile uint16_t actual_speed = 0;     // 实际速度 (RPM)
volatile uint8_t system_status = 0;     // 系统状态
volatile uint8_t direction = 1;         // 方向:1正转,0反转

// PID控制器实例
PID_Controller speed_pid;

int main(void) {
    // 系统初始化
    System_Init();
    
    // PID参数初始化(根据实际电机调整)
    PID_Init(&speed_pid, 2.5f, 0.8f, 0.1f, 1000.0f, 0.0f, 1000.0f);
    
    // 启动系统
    Motor_Enable();
    
    while(1) {
        // 主循环处理
        System_Process();
        
        // 等待控制周期
        Delay_ms(CONTROL_PERIOD);
    }
}

/**
 * @brief 系统初始化
 */
void System_Init(void) {
    // 中断优先级分组
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    // 初始化各个模块
    USART_Init(115200);      // 串口初始化
    Encoder_Init();          // 编码器初始化
    Motor_Init();            // 电机驱动初始化
    Timer_Init(CONTROL_PERIOD); // 控制定时器初始化
    
    // 默认参数设置
    target_speed = 500;      // 默认500 RPM
    direction = 1;           // 正转
    
    printf("STM32 Speed Controller Initialized!\r\n");
    printf("Target Speed: %d RPM\r\n", target_speed);
}

/**
 * @brief 系统主处理逻辑
 */
void System_Process(void) {
    static uint8_t status_counter = 0;
    
    // 1. 读取实际速度(通过编码器)
    actual_speed = Encoder_GetSpeed();
    
    // 2. 执行PID控制
    float pid_output = PID_Calculate(&speed_pid, (float)target_speed, (float)actual_speed);
    
    // 3. 应用PID输出到PWM
    Motor_SetPWM(pid_output, direction);
    
    // 4. 状态上报(每秒一次)
    if(++status_counter >= (1000 / CONTROL_PERIOD)) {
        status_counter = 0;
        Report_Status();
    }
}

/**
 * @brief 上报系统状态
 */
void Report_Status(void) {
    printf("Status: Target=%d RPM, Actual=%d RPM, PWM=%.1f%%, Dir=%s\r\n",
           target_speed, actual_speed, 
           (speed_pid.output / 1000.0f) * 100.0f,
           direction ? "Forward" : "Reverse");
}

2.2 PID控制器:pid.h / pid.c

c 复制代码
/**
 * @file pid.h
 * @brief PID控制器头文件
 */

#ifndef __PID_H
#define __PID_H

#include "stm32f10x.h"

// PID控制器结构体
typedef struct {
    float kp;            // 比例系数
    float ki;            // 积分系数
    float kd;            // 微分系数
    float integral;      // 积分项
    float prev_error;    // 上一次误差
    float max_output;    // 最大输出限制
    float min_output;    // 最小输出限制
    float dead_zone;     // 死区
    float output;        // PID输出
    uint8_t enable;     // 使能标志
} PID_Controller;

// PID函数声明
void PID_Init(PID_Controller* pid, float kp, float ki, float kd, 
              float max_out, float min_out, float dead_zone);
float PID_Calculate(PID_Controller* pid, float target, float feedback);
void PID_Reset(PID_Controller* pid);
void PID_SetParameters(PID_Controller* pid, float kp, float ki, float kd);
void PID_SetOutputLimits(PID_Controller* pid, float max_out, float min_out);

#endif /* __PID_H */
c 复制代码
/**
 * @file pid.c
 * @brief PID控制器实现
 */

#include "pid.h"
#include "math.h"

/**
 * @brief PID控制器初始化
 * @param pid PID控制器指针
 * @param kp 比例系数
 * @param ki 积分系数
 * @param kd 微分系数
 * @param max_out 最大输出限制
 * @param min_out 最小输出限制
 * @param dead_zone 死区
 */
void PID_Init(PID_Controller* pid, float kp, float ki, float kd, 
              float max_out, float min_out, float dead_zone) {
    pid->kp = kp;
    pid->ki = ki;
    pid->kd = kd;
    pid->max_output = max_out;
    pid->min_output = min_out;
    pid->dead_zone = dead_zone;
    pid->integral = 0.0f;
    pid->prev_error = 0.0f;
    pid->output = 0.0f;
    pid->enable = 1;
}

/**
 * @brief PID计算函数
 * @param pid PID控制器指针
 * @param target 目标值
 * @param feedback 反馈值
 * @return PID输出值
 */
float PID_Calculate(PID_Controller* pid, float target, float feedback) {
    if(!pid->enable) {
        return 0.0f;
    }
    
    // 计算误差
    float error = target - feedback;
    
    // 死区处理
    if(fabs(error) < pid->dead_zone) {
        error = 0.0f;
    }
    
    // 比例项
    float proportional = pid->kp * error;
    
    // 积分项(带限幅)
    pid->integral += pid->ki * error;
    
    // 积分限幅(抗积分饱和)
    if(pid->integral > pid->max_output) {
        pid->integral = pid->max_output;
    } else if(pid->integral < pid->min_output) {
        pid->integral = pid->min_output;
    }
    
    // 微分项
    float derivative = pid->kd * (error - pid->prev_error);
    pid->prev_error = error;
    
    // PID输出
    pid->output = proportional + pid->integral + derivative;
    
    // 输出限幅
    if(pid->output > pid->max_output) {
        pid->output = pid->max_output;
    } else if(pid->output < pid->min_output) {
        pid->output = pid->min_output;
    }
    
    return pid->output;
}

/**
 * @brief 重置PID控制器
 * @param pid PID控制器指针
 */
void PID_Reset(PID_Controller* pid) {
    pid->integral = 0.0f;
    pid->prev_error = 0.0f;
    pid->output = 0.0f;
}

/**
 * @brief 设置PID参数
 * @param pid PID控制器指针
 * @param kp 比例系数
 * @param ki 积分系数
 * @param kd 微分系数
 */
void PID_SetParameters(PID_Controller* pid, float kp, float ki, float kd) {
    pid->kp = kp;
    pid->ki = ki;
    pid->kd = kd;
    PID_Reset(pid);
}

/**
 * @brief 设置输出限制
 * @param pid PID控制器指针
 * @param max_out 最大输出
 * @param min_out 最小输出
 */
void PID_SetOutputLimits(PID_Controller* pid, float max_out, float min_out) {
    pid->max_output = max_out;
    pid->min_output = min_out;
}

2.3 电机控制:motor_control.h / motor_control.c

c 复制代码
/**
 * @file motor_control.h
 * @brief 电机控制头文件
 */

#ifndef __MOTOR_CONTROL_H
#define __MOTOR_CONTROL_H

#include "stm32f10x.h"

// 电机控制引脚定义
#define MOTOR_PWM_PORT     GPIOA
#define MOTOR_PWM_PIN      GPIO_Pin_8      // TIM1_CH1
#define MOTOR_DIR_PORT     GPIOA
#define MOTOR_DIR_PIN      GPIO_Pin_0
#define MOTOR_EN_PORT      GPIOA
#define MOTOR_EN_PIN       GPIO_Pin_1

// 电机状态
#define MOTOR_FORWARD      1
#define MOTOR_REVERSE      0
#define MOTOR_ENABLE       1
#define MOTOR_DISABLE      0

// 函数声明
void Motor_Init(void);
void Motor_Enable(void);
void Motor_Disable(void);
void Motor_SetDirection(uint8_t dir);
void Motor_SetPWM(float duty_cycle, uint8_t dir);
void Motor_EmergencyStop(void);

#endif /* __MOTOR_CONTROL_H */
c 复制代码
/**
 * @file motor_control.c
 * @brief 电机控制实现
 */

#include "motor_control.h"
#include "timer.h"

// PWM参数
static uint16_t pwm_period = 0;
static uint16_t pwm_pulse = 0;

/**
 * @brief 电机控制初始化
 */
void Motor_Init(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    
    // 1. 使能时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE);
    
    // 2. 配置GPIO
    // PWM输出引脚
    GPIO_InitStructure.GPIO_Pin = MOTOR_PWM_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(MOTOR_PWM_PORT, &GPIO_InitStructure);
    
    // 方向和使能引脚
    GPIO_InitStructure.GPIO_Pin = MOTOR_DIR_PIN | MOTOR_EN_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(MOTOR_DIR_PORT, &GPIO_InitStructure);
    
    // 3. 配置定时器1(高级定时器)
    TIM_TimeBaseStructure.TIM_Period = 1000 - 1;  // 默认1kHz PWM
    TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; // 72MHz/72 = 1MHz
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
    
    // 4. 配置PWM输出
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
    TIM_OCInitStructure.TIM_Pulse = 0;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
    
    TIM_OC1Init(TIM1, &TIM_OCInitStructure);
    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
    
    // 5. 使能定时器
    TIM_Cmd(TIM1, ENABLE);
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
    
    // 6. 保存PWM周期
    pwm_period = 1000 - 1;
    
    // 7. 默认状态
    Motor_Disable();
    Motor_SetDirection(MOTOR_FORWARD);
    
    printf("Motor Control Initialized!\r\n");
}

/**
 * @brief 使能电机
 */
void Motor_Enable(void) {
    GPIO_SetBits(MOTOR_EN_PORT, MOTOR_EN_PIN);
}

/**
 * @brief 禁用电机
 */
void Motor_Disable(void) {
    GPIO_ResetBits(MOTOR_EN_PORT, MOTOR_EN_PIN);
}

/**
 * @brief 设置电机方向
 * @param dir 方向:MOTOR_FORWARD 或 MOTOR_REVERSE
 */
void Motor_SetDirection(uint8_t dir) {
    if(dir == MOTOR_FORWARD) {
        GPIO_SetBits(MOTOR_DIR_PORT, MOTOR_DIR_PIN);
    } else {
        GPIO_ResetBits(MOTOR_DIR_PORT, MOTOR_DIR_PIN);
    }
}

/**
 * @brief 设置电机PWM
 * @param duty_cycle PWM占空比 (0.0 - 100.0)
 * @param dir 方向
 */
void Motor_SetPWM(float duty_cycle, uint8_t dir) {
    // 限制占空比范围
    if(duty_cycle > 100.0f) duty_cycle = 100.0f;
    if(duty_cycle < 0.0f) duty_cycle = 0.0f;
    
    // 设置方向
    Motor_SetDirection(dir);
    
    // 计算PWM脉冲
    pwm_pulse = (uint16_t)((duty_cycle / 100.0f) * (pwm_period + 1));
    
    // 设置PWM
    TIM_SetCompare1(TIM1, pwm_pulse);
}

/**
 * @brief 紧急停止
 */
void Motor_EmergencyStop(void) {
    Motor_Disable();
    TIM_SetCompare1(TIM1, 0);
    printf("Emergency Stop Activated!\r\n");
}

2.4 编码器接口:encoder.h / encoder.c

c 复制代码
/**
 * @file encoder.h
 * @brief 编码器接口头文件
 */

#ifndef __ENCODER_H
#define __ENCODER_H

#include "stm32f10x.h"

// 编码器参数
#define ENCODER_PPR         1000        // 编码器每转脉冲数
#define ENCODER_TIMER       TIM2        // 使用TIM2作为编码器接口
#define ENCODER_SAMPLE_TIME 10          // 采样时间 10ms

// 函数声明
void Encoder_Init(void);
uint16_t Encoder_GetSpeed(void);
int32_t Encoder_GetPosition(void);
void Encoder_Reset(void);

#endif /* __ENCODER_H */
c 复制代码
/**
 * @file encoder.c
 * @brief 编码器接口实现
 */

#include "encoder.h"

static volatile int32_t encoder_count = 0;
static volatile uint16_t last_count = 0;
static volatile uint16_t current_count = 0;

/**
 * @brief 编码器初始化
 */
void Encoder_Init(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;
    
    // 1. 使能时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    // 2. 配置GPIO (PA0-TIM2_CH1, PA1-TIM2_CH2)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 3. 配置定时器基础
    TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(ENCODER_TIMER, &TIM_TimeBaseStructure);
    
    // 4. 配置编码器接口模式
    TIM_EncoderInterfaceConfig(ENCODER_TIMER, TIM_EncoderMode_TI12, 
                              TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
    
    // 5. 配置输入捕获
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.TIM_ICFilter = 0x06;  // 滤波
    TIM_ICInit(ENCODER_TIMER, &TIM_ICInitStructure);
    
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
    TIM_ICInit(ENCODER_TIMER, &TIM_ICInitStructure);
    
    // 6. 使能定时器
    TIM_Cmd(ENCODER_TIMER, ENABLE);
    
    printf("Encoder Initialized! PPR=%d\r\n", ENCODER_PPR);
}

/**
 * @brief 获取电机速度 (RPM)
 * @return 速度值 (RPM)
 */
uint16_t Encoder_GetSpeed(void) {
    static uint32_t last_time = 0;
    uint32_t current_time = Get_SystemTime();
    
    // 每10ms计算一次速度
    if(current_time - last_time >= ENCODER_SAMPLE_TIME) {
        last_time = current_time;
        
        // 读取当前计数值
        current_count = TIM_GetCounter(ENCODER_TIMER);
        
        // 计算脉冲差(考虑溢出)
        int16_t pulse_diff;
        if(current_count >= last_count) {
            pulse_diff = current_count - last_count;
        } else {
            pulse_diff = (0xFFFF - last_count) + current_count + 1;
        }
        
        // 更新上次计数值
        last_count = current_count;
        
        // 计算速度 (RPM)
        // 速度 = (脉冲差 / 采样时间) * 60秒 / 每转脉冲数
        float speed = ((float)pulse_diff / (ENCODER_SAMPLE_TIME / 1000.0f)) * 60.0f / ENCODER_PPR;
        
        return (uint16_t)speed;
    }
    
    return 0;
}

/**
 * @brief 获取编码器位置
 * @return 位置值
 */
int32_t Encoder_GetPosition(void) {
    return (int32_t)TIM_GetCounter(ENCODER_TIMER);
}

/**
 * @brief 重置编码器
 */
void Encoder_Reset(void) {
    TIM_SetCounter(ENCODER_TIMER, 0);
    encoder_count = 0;
    last_count = 0;
    current_count = 0;
}

2.5 定时器中断:timer.h / timer.c

c 复制代码
/**
 * @file timer.h
 * @brief 定时器中断头文件
 */

#ifndef __TIMER_H
#define __TIMER_H

#include "stm32f10x.h"

// 定时器定义
#define CONTROL_TIMER    TIM3
#define SYSTEM_TIMER     TIM4

// 函数声明
void Timer_Init(uint16_t period_ms);
void SysTick_Init(void);
uint32_t Get_SystemTime(void);
void Delay_ms(uint32_t ms);

#endif /* __TIMER_H */
c 复制代码
/**
 * @file timer.c
 * @brief 定时器中断实现
 */

#include "timer.h"

static volatile uint32_t system_time = 0;

/**
 * @brief 控制定时器初始化
 * @param period_ms 定时周期 (ms)
 */
void Timer_Init(uint16_t period_ms) {
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    // 1. 使能时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    
    // 2. 配置定时器
    TIM_TimeBaseStructure.TIM_Period = period_ms * 10 - 1;  // 10kHz计数
    TIM_TimeBaseStructure.TIM_Prescaler = 7200 - 1;         // 72MHz/7200 = 10kHz
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(CONTROL_TIMER, &TIM_TimeBaseStructure);
    
    // 3. 配置中断
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    // 4. 使能更新中断
    TIM_ITConfig(CONTROL_TIMER, TIM_IT_Update, ENABLE);
    
    // 5. 启动定时器
    TIM_Cmd(CONTROL_TIMER, ENABLE);
    
    printf("Control Timer Initialized! Period=%dms\r\n", period_ms);
}

/**
 * @brief SysTick初始化
 */
void SysTick_Init(void) {
    // 配置SysTick为1ms中断
    if(SysTick_Config(SystemCoreClock / 1000)) {
        while(1);  // 配置失败
    }
}

/**
 * @brief 获取系统时间
 * @return 系统时间 (ms)
 */
uint32_t Get_SystemTime(void) {
    return system_time;
}

/**
 * @brief 延时函数
 * @param ms 延时毫秒数
 */
void Delay_ms(uint32_t ms) {
    uint32_t start = system_time;
    while((system_time - start) < ms);
}

/**
 * @brief SysTick中断处理函数
 */
void SysTick_Handler(void) {
    system_time++;
}

/**
 * @brief 控制定时器中断处理函数
 */
void TIM3_IRQHandler(void) {
    if(TIM_GetITStatus(CONTROL_TIMER, TIM_IT_Update) != RESET) {
        TIM_ClearITPendingBit(CONTROL_TIMER, TIM_IT_Update);
        
        // 在这里可以添加周期性的控制逻辑
        // 注意:避免在中断中进行耗时操作
    }
}

2.6 串口通信:usart.h / usart.c

c 复制代码
/**
 * @file usart.h
 * @brief 串口通信头文件
 */

#ifndef __USART_H
#define __USART_H

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

// 串口定义
#define DEBUG_USART    USART1
#define BAUDRATE      115200

// 函数声明
void USART_Init(uint32_t baudrate);
void USART_SendChar(char ch);
void USART_SendString(char* str);
void USART_Printf(char* format, ...);

#endif /* __USART_H */
c 复制代码
/**
 * @file usart.c
 * @brief 串口通信实现
 */

#include "usart.h"
#include <stdarg.h>

/**
 * @brief 串口初始化
 * @param baudrate 波特率
 */
void USART_Init(uint32_t baudrate) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    
    // 1. 使能时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
    
    // 2. 配置GPIO
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  // TX
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // RX
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 3. 配置串口
    USART_InitStructure.USART_BaudRate = baudrate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(DEBUG_USART, &USART_InitStructure);
    
    // 4. 使能串口
    USART_Cmd(DEBUG_USART, ENABLE);
    
    printf("USART Initialized! Baudrate=%d\r\n", baudrate);
}

/**
 * @brief 发送单个字符
 * @param ch 字符
 */
void USART_SendChar(char ch) {
    USART_SendData(DEBUG_USART, (uint8_t)ch);
    while(USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET);
}

/**
 * @brief 发送字符串
 * @param str 字符串指针
 */
void USART_SendString(char* str) {
    while(*str) {
        USART_SendChar(*str++);
    }
}

/**
 * @brief 格式化输出
 * @param format 格式化字符串
 * @param ... 可变参数
 */
void USART_Printf(char* format, ...) {
    char buffer[256];
    va_list args;
    
    va_start(args, format);
    vsprintf(buffer, format, args);
    va_end(args);
    
    USART_SendString(buffer);
}

// 重定向printf到串口
int _write(int fd, char* ptr, int len) {
    for(int i = 0; i < len; i++) {
        USART_SendChar(ptr[i]);
    }
    return len;
}

三、高级功能扩展

3.1 速度斜坡控制

c 复制代码
/**
 * @file ramp_control.c
 * @brief 速度斜坡控制(S曲线)
 */

typedef struct {
    uint16_t target_speed;      // 目标速度
    uint16_t current_speed;     // 当前速度
    uint16_t acceleration;      // 加速度 (RPM/s)
    uint16_t deceleration;      // 减速度 (RPM/s)
    uint32_t last_update_time;  // 上次更新时间
    uint8_t ramp_enable;        // 斜坡使能
} Ramp_Controller;

/**
 * @brief 速度斜坡更新
 * @param ramp 斜坡控制器指针
 * @param target 目标速度
 * @return 斜坡调整后的速度
 */
uint16_t Ramp_Update(Ramp_Controller* ramp, uint16_t target) {
    uint32_t current_time = Get_SystemTime();
    uint32_t time_diff = current_time - ramp->last_update_time;
    
    if(!ramp->ramp_enable) {
        return target;
    }
    
    // 计算速度变化量
    float speed_change = (float)ramp->acceleration * (time_diff / 1000.0f);
    
    // 加速过程
    if(target > ramp->current_speed) {
        ramp->current_speed += (uint16_t)speed_change;
        if(ramp->current_speed > target) {
            ramp->current_speed = target;
        }
    }
    // 减速过程
    else if(target < ramp->current_speed) {
        speed_change = (float)ramp->deceleration * (time_diff / 1000.0f);
        ramp->current_speed -= (uint16_t)speed_change;
        if(ramp->current_speed < target) {
            ramp->current_speed = target;
        }
    }
    
    ramp->last_update_time = current_time;
    return ramp->current_speed;
}

3.2 看门狗保护

c 复制代码
/**
 * @file watchdog.c
 * @brief 独立看门狗保护
 */

void Watchdog_Init(void) {
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
    IWDG_SetPrescaler(IWDG_Prescaler_256);  // 32kHz/256 = 125Hz
    IWDG_SetReload(625);                    // 625/125 = 5秒超时
    IWDG_ReloadCounter();
    IWDG_Enable();
}

void Watchdog_Feed(void) {
    IWDG_ReloadCounter();
}

参考代码 stm32速度控制器 www.youwenfan.com/contentcsu/60235.html

四、调试与优化

4.1 PID参数整定步骤

  1. 先调比例(P)

    • 将Ki、Kd设为0
    • 逐渐增加Kp,直到系统出现轻微振荡
    • 将Kp减小到振荡值的60-70%
  2. 再调积分(I)

    • 保持Kp不变
    • 逐渐增加Ki,消除稳态误差
    • 注意不要引起积分饱和
  3. 最后调微分(D)

    • 保持Kp、Ki不变
    • 适当增加Kd,改善动态响应
    • 微分太大会放大噪声

4.2 性能优化

c 复制代码
// 1. 使用DMA传输PWM数据(减少CPU负载)
void PWM_DMA_Config(void) {
    // 配置DMA将PID计算结果直接传输到PWM寄存器
}

// 2. 使用硬件死区保护
void PWM_DeadZone_Config(void) {
    // 配置互补PWM的死区时间,防止上下桥臂直通
}

// 3. 速度前馈控制
float PID_WithFeedForward(PID_Controller* pid, float target, float feedback) {
    float pid_output = PID_Calculate(pid, target, feedback);
    float feedforward = target * 0.1f;  // 前馈系数
    return pid_output + feedforward;
}

4.3 故障保护机制

c 复制代码
// 过流保护
if(Get_MotorCurrent() > MAX_CURRENT) {
    Motor_EmergencyStop();
    printf("Over Current Protection Activated!\r\n");
}

// 堵转保护
if(actual_speed < 10 && target_speed > 100) {
    stall_counter++;
    if(stall_counter > 10) {
        Motor_EmergencyStop();
        printf("Stall Protection Activated!\r\n");
    }
}

五、实际应用示例

5.1 通过串口设置速度

c 复制代码
// 串口接收中断中解析速度指令
void USART1_IRQHandler(void) {
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        char ch = USART_ReceiveData(USART1);
        
        if(ch >= '0' && ch <= '9') {
            speed_input = speed_input * 10 + (ch - '0');
        }
        else if(ch == 's') {  // 设置速度命令
            target_speed = speed_input;
            speed_input = 0;
            printf("Set Target Speed: %d RPM\r\n", target_speed);
        }
        else if(ch == 'd') {  // 方向切换
            direction = !direction;
            printf("Direction Changed: %s\r\n", direction ? "Forward" : "Reverse");
        }
    }
}
相关推荐
czwxkn1 小时前
pcb设计-器件:稳压二极管
单片机·嵌入式硬件
刻BITTER2 小时前
W25Q32 SPI Flash 芯片读写速度测试 - 对比全片擦除和扇区擦除
嵌入式硬件
夜猫子ing2 小时前
《嵌入式 Linux 控制服务从零搭建(一):项目立意与架构总览》
linux·嵌入式硬件
灵哎惹,凌沃敏2 小时前
CM3/CM4内核总线知识总结
c语言·arm开发·单片机
森旺电子3 小时前
candence操作
单片机·嵌入式硬件·cadence
czwxkn3 小时前
pcb设计-电路:基准电压电路(TL431)
单片机·嵌入式硬件
三佛科技-134163842123 小时前
LED阅读灯方案开发,LED护眼读书灯单片机选择(FT60F010A,FT61F023,FT62F211,FT62F0MBA,FT32F103)
单片机·嵌入式硬件·智能家居·pcb工艺
上海合宙LuatOS3 小时前
合宙Air1601 MCU模组-硬件开发手册
单片机·嵌入式硬件·物联网·luatos