一、新增文件对比
1. 核心控制库文件(闭环控制新增)
SimpleFOC/ 目录下的所有文件:
- MagneticSensor.c/h:磁性编码器接口
- FOCMotor.c/h:FOC 电机控制基类
- BLDCmotor.c/h:无刷电机控制实现
- pid.c/h:PID 控制器实现
- lowpass_filter.c/h:低通滤波器
- foc_utils.c/h:FOC 算法工具函数
2. 传感器驱动文件(闭环控制新增)
Hardware/ 目录下的编码器通信文件:
- iic.c/h:I2C 通信驱动(用于 AS5600 编码器)
- spi2.c/h:SPI 通信驱动(用于 TLE5012B 编码器)
3. 配置文件(闭环控制新增)
传感器配置相关代码:
- user/MyProject.h:编码器类型定义(M1_AS5600/M1_TLE5012B)
二、新增代码对比
| 开环控制 | 仅需初始化 GPIO 和 PWM |
| 闭环控制 | 新增传感器、FOC 和 PID 初始化 |
// 编码器初始化
#if M1_AS5600
I2C_Init_(); // AS5600 I2C初始化
printf("AS5600\\r\\n");
#elif M1_TLE5012B
SPI2_Init_(); // TLE5012B SPI初始化
printf("TLE5012B\\r\\n");
#endif
// 传感器初始化
MagneticSensor_Init(); // 初始化磁性编码器
// FOC和PID初始化
Motor_initFOC(); // 初始化FOC算法
PID_init(); // 初始化PID控制器
2. 主循环新增代码
表格
| 开环控制 | 仅需输出 PWM 信号 |
| 闭环控制 | 新增 FOC 算法执行和反馈处理 |
// 闭环控制核心流程
move(target); // 设置目标值(位置/速度)
loopFOC(); // 执行FOC算法,处理传感器反馈
3. 控制参数新增代码
| 开环控制 | 仅需设置电压或 PWM 占空比 |
| 闭环控制 | 新增控制模式和 PID 参数配置 |
// 闭环控制参数
voltage_power_supply=12; // 电源电压
pole_pairs=7; // 电机极对数
voltage_limit=6; // 电压限制
velocity_limit=20; // 速度限制
voltage_sensor_align=2.5; // 传感器对齐电压
torque_controller=Type_voltage; // 力矩控制器类型
controller=Type_velocity; // 控制模式(速度/位置/力矩)
4. 串口命令处理新增代码
| 开环控制 | 仅需处理电压或 PWM 命令 |
| 闭环控制 | 新增目标值设置和反馈处理 |
// 闭环控制命令处理
case 'T': // T6.28 设置目标值(位置/速度)
target=atof((const char *)(USART_RX_BUF+1));
printf("RX=%.4f\\r\\n", target);
break;
三、核心功能差异代码(闭环控制特有)
1. 传感器反馈处理
// MagneticSensor.c 中的位置读取函数
float getAngle() {
// 读取编码器原始值
// 转换为角度值
return angle;
}
// 计算速度
float getVelocity() {
// 根据位置变化计算速度
return velocity;
}
2. FOC 算法实现
// FOCMotor.c 中的FOC初始化
void Motor_initFOC() {
// 传感器零位校准
// 电流采样初始化
// FOC参数计算
}
// 执行FOC算法
void loopFOC() {
// 读取电机位置
// 计算电角度
// 电流采样和变换
// SVPWM计算和输出
}
3. PID 控制器
// pid.c 中的PID计算
float PIDoperator(PID_s *pid, float error) {
// 计算比例、积分、微分项
// 限幅处理
// 返回控制输出
return output;
}
四、核心差异总结
| 文件 | SimpleFOC 目录下的 FOC 算法文件 | 实现磁场定向控制和 PID 调节 |
| 文件 | Hardware 目录下的编码器驱动 | 实现传感器通信(I2C/SPI) |
| 代码 | 传感器初始化和配置 | 获取电机实际位置和速度 |
| 代码 | FOC 算法初始化和执行 | 计算最优电压矢量,提高控制效率 |
| 代码 | PID 控制器初始化和运算 | 实时校正控制误差,提高精度 |
| 代码 | 多模式控制逻辑 | 支持速度、位置、力矩模式切换 |
关键点回顾
SimpleFOC闭环控制的main.c
#include "stm32f10x.h" // 引入STM32F10x系列单片机底层驱动库
#include <stdlib.h> // 引入标准库,用于atof等函数
#include "MyProject.h" // 引入自定义工程头文件,包含外设和FOC相关声明
/************************************************
SimpleMotor开发板
闭环控制 演示
1、力矩模式
2、速度模式
3、位置模式
=================================================
本程序仅供学习,引用代码请标明出处
使用教程:https://blog.csdn.net/loop222/article/details/120471390
《SimpleFOC移植STM32(四) —— 闭环控制》
创建日期:20230208
作 者:loop222 @郑州
************************************************/
/******************************************************************************/
#define LED_blink GPIOC->ODR^=(1<<13) // 定义LED翻转宏,操作GPIOC的13引脚输出寄存器取反
/******************************************************************************/
float target; // 定义控制目标值(力矩/速度/位置)
/******************************************************************************/
void commander_run(void); // 声明串口指令处理函数
/******************************************************************************/
void GPIO_Config(void) // GPIO初始化配置函数
{
GPIO_InitTypeDef GPIO_InitStructure; // 定义GPIO初始化结构体变量
// 使能GPIOA、GPIOB、GPIOC时钟和AFIO复用功能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); // 禁用JTAG,释放相关引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; // 配置PC13引脚(LED)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; // 输出速度10MHz
GPIO_Init(GPIOC, &GPIO_InitStructure); // 初始化GPIOC13引脚
GPIO_ResetBits(GPIOC,GPIO_Pin_13); // PC13置低,上电点亮LED
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // 配置PB9引脚(电机1使能)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; // 输出速度10MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化GPIOB9引脚
GPIO_ResetBits(GPIOB,GPIO_Pin_9); // PB9置低解除使能(Motor_init中使能)
}
/******************************************************************************/
int main(void) // 主函数入口
{
unsigned int count_i=0; // 定义循环计数变量
GPIO_Config(); // 调用GPIO初始化函数
uart_init(115200); // 初始化串口,波特率115200
#if M1_AS5600 // 条件编译:如果使用AS5600编码器
I2C_Init_(); // 初始化I2C总线(AS5600通信)
printf("AS5600\\r\\n"); // 串口打印编码器类型
#elif M1_TLE5012B // 条件编译:如果使用TLE5012B编码器
SPI2_Init_(); // 初始化SPI2总线(TLE5012B通信)
printf("TLE5012B\\r\\n"); // 串口打印编码器类型
#endif
TIM2_PWM_Init(); // 初始化TIM2,生成PWM波驱动电机
TIM4_1ms_Init(); // 初始化TIM4,1ms中断(用于计时)
delay_ms(1000); // 延时1秒,等待系统稳定
MagneticSensor_Init(); // 初始化磁编码器(AS5600/TLE5012B)
voltage_power_supply=12; // 设置电源供电电压12V
pole_pairs=7; // 设置电机极对数为7(按实际电机配置)
voltage_limit=6; // 设置电压限制6V(<12/1.732=6.9)
velocity_limit=20; // 设置速度限制20rad/s(开环/位置环使用)
voltage_sensor_align=2.5; // 设置传感器对齐电压2.5V(云台电机2-3V)
torque_controller=Type_voltage; // 设置力矩控制模式为电压模式
controller=Type_velocity; // 设置闭环控制模式为速度模式(可改为位置/力矩)
target=0; // 初始化控制目标值为0
Motor_init(); // 初始化电机硬件和参数
Motor_initFOC(); // 初始化FOC算法相关配置
PID_init(); // 初始化PID控制器参数(内部已预设)
printf("Motor ready.\\r\\n"); // 串口打印电机就绪信息
systick_CountMode(); // 切换SysTick为计数模式(禁用delay_us/ms)
while(1) // 主循环
{
count_i++; // 计数变量自增
if(time1_cntr>=200) // 每200ms(1ms中断*200)执行一次
{
time1_cntr=0; // 重置计时变量
LED_blink; // 翻转LED状态(心跳灯)
}
if(time2_cntr>=1000) // 每1000ms执行一次
{
time2_cntr=0; // 重置计时变量
//printf("%d\\r\\n",count_i); // 调试用:打印计数(当前注释)
count_i=0; // 重置计数变量
}
move(target); // 执行目标值更新(位置/速度/力矩)
loopFOC(); // 执行FOC核心算法(电流采样/解耦/PWM输出)
commander_run(); // 检查串口指令并处理
}
}
/******************************************************************************/
void commander_run(void) // 串口指令处理函数
{
if((USART_RX_STA&0x8000)!=0) // 判断串口接收是否完成(最高位为1表示完成)
{
switch(USART_RX_BUF[0]) // 根据接收缓冲区第一个字符判断指令
{
case 'H': // 指令H:打印测试信息
printf("Hello World!\\r\\n"); // 串口打印Hello World
break; // 退出switch
case 'T': // 指令T+数值:设置目标值(如T6.28)
target=atof((const char *)(USART_RX_BUF+1)); // 转换字符串为浮点型目标值
printf("RX=%.4f\\r\\n", target); // 串口回显接收到的目标值
break; // 退出switch
case 'D': // 指令D:禁用电机
M1_Disable; // 执行电机禁用操作(宏定义)
printf("OK!\\r\\n"); // 串口打印确认信息
break; // 退出switch
case 'E': // 指令E:使能电机
M1_Enable; // 执行电机使能操作(宏定义)
printf("OK!\\r\\n"); // 串口打印确认信息
break; // 退出switch
}
USART_RX_STA=0; // 重置串口接收状态标志
}
}
/******************************************************************************/




