refactor(FOC): 重构齿槽转矩校准状态机为独立函数

- 将原本在 calibrate_cogging_tick 中的大函数拆分为多个职责单一的函数
- 新增 start_cogging_calibration、cogging_settling_tick、cogging_sampling_tick、
  cogging_stopping_tick、cogging_done_tick 等状态处理函数
- 添加 process_cogging_run_data、start_next_cogging_run、build_cogging_tables、
  print_cogging_table、print_cogging_c_array 等辅助函数
- 移动全局 FOC 控制器单例注释到更合适位置
- 添加齿槽转矩校准参数常量定义和详细注释
- 添加防御性编程处理默认状态分支,避免状态机卡死
- 提高代码可读性和维护性

feat(tasks): 添加任务头文件到项目配置

- 在 Robot_V2.cproject.yml 中添加 tasks.h 和 tasks.cpp 文件引用

docs(ADC): 添加ADC转换常量说明注释

- 在 ADC.cpp 中添加关于ADC换算常量的详细注释
- 说明全局采样器单例的初始化和使用方式
This commit is contained in:
cbb
2026-05-24 01:21:41 +08:00
parent 4c4e47e9e3
commit e646544f7f
23 changed files with 1705 additions and 647 deletions
@@ -0,0 +1,52 @@
# A solution is a collection of related projects that share same base configuration.
solution:
created-for: CMSIS-Toolbox@2.12.0
cdefault: # use CMSIS-Toolbox default Compiler options
# Compilers that can be selected
select-compiler:
- compiler: AC6
- compiler: GCC
- compiler: IAR
- compiler: CLANG
# List of miscellaneous tool-specific controls
misc:
- for-compiler: AC6 # GDB requires DWARF 5, remove when using uVision Debugger
C-CPP:
- -gdwarf-5
ASM:
- -gdwarf-5
# List the packs that define the device and/or board.
packs:
- pack: GigaDevice::GD32C10x_DFP
- pack: ARM::CMSIS
# List different hardware targets that are used to deploy the solution.
target-types:
- type: GD32C103CB
device: GD32C103CB
target-set:
- set:
images:
- project-context: Robot_V2.Release
debugger:
name: ST-Link@pyOCD
clock: 10000000
protocol: swd
# List of different build configurations.
build-types:
- type: Debug
debug: on
optimize: none
- type: Release
debug: off
optimize: balanced
# List related projects.
projects:
- project: Robot_V2/Robot_V2.cproject.yml
compiler: AC6
@@ -0,0 +1,182 @@
/**
* @file sys/initial.h
* @brief 系统服务与平台支持源文件
* @note 本文件仅补充 Doxygen 文档注释,不改变代码逻辑。
*/
#ifndef _INITIAL_H
#define _INITIAL_H
#ifdef __cplusplus
extern "C" {
#endif
#include "config.h"
#include "gd32c10x_eval.h"
#include <cstdint>
#include <cstdio>
// 任务标志定义
/**
* @brief 匿名枚举 枚举定义
*/
typedef enum {
TASK_MOTOR_CONTROL = 0,
TASK_CURRENT_UPDATE,
TASK_VELOCITY_UPDATE,
TASK_ANGLE_UPDATE,
TASK_MCU_TEMP_UPDATE,
TASK_DRV_TEMP_UPDATE,
TASK_VBUS_UPDATE,
TASK_THERMAL_CONTROL,
TASK_CAN_TRANSMIT,
TASK_MAGNETIC_CHECK,
TASK_COUNT
} SystemTask;
/**
* @brief rcu_config 函数
* @return void
*/
void rcu_config(void);
static volatile uint32_t timer_delay_count = 0; // volatile 很重要!
/**
* @brief fputc 函数
* @param[in] ch 参数
* @param[in] f 参数
* @return int 返回值
*/
int fputc(int ch, FILE *f); // 声明fputc函数以重载标准库实现
/**
* @brief 初始化 USART0 调试串口
* @return u8 返回值
*/
u8 USART0_init(void);
/**
* @brief 初始化独立看门狗
* @param[in] time 参数
* @return u8 返回值
*/
u8 watchdog_init(u32 time);
/**
* @brief 获取复位原因
* @return u16 返回值
*/
u16 get_reset_cause(void);
/**
* @brief 初始化未使用引脚状态
* @return void
*/
void unused_pin_init();
/**
* @brief 初始化 OTA 与 A/B 分区状态
* @return void
*/
void OTA_initial(void);
// 任务管理结构
typedef struct {
volatile u32 taskFlags; // 任务标志位(每个位代表一个任务)
} TaskScheduler;
// 版本管理类
/**
* @brief VersionManager 类或结构体
*/
class VersionManager {
public:
// 版本信息结构体
typedef struct {
u16 major;
u16 minor;
u16 patch;
u16 build;
} VersionInfo;
// 构造函数
VersionManager();
// 获取软件版本
/**
* @brief 获取 getSoftwareVersion 对应的数据或状态
* @return VersionInfo 返回值
*/
VersionInfo getSoftwareVersion() const;
// 获取硬件版本
/**
* @brief 获取 getHardwareVersion 对应的数据或状态
* @return VersionInfo 返回值
*/
VersionInfo getHardwareVersion() const;
// 获取BOOT版本
/**
* @brief 获取 getBootVersion 对应的数据或状态
* @return VersionInfo 返回值
*/
VersionInfo getBootVersion() const;
// 设置软件版本
/**
* @brief 设置 setSoftwareVersion 对应的参数或状态
* @param[in] major 参数
* @param[in] minor 参数
* @param[in] patch 参数
* @param[in] build 参数
* @return void
*/
void setSoftwareVersion(u16 major, u16 minor, u16 patch, u16 build);
// 设置硬件版本
/**
* @brief 设置 setHardwareVersion 对应的参数或状态
* @param[in] major 参数
* @param[in] minor 参数
* @param[in] patch 参数
* @param[in] build 参数
* @return void
*/
void setHardwareVersion(u16 major, u16 minor, u16 patch, u16 build);
// 设置BOOT版本
/**
* @brief 设置 setBootVersion 对应的参数或状态
* @param[in] major 参数
* @param[in] minor 参数
* @param[in] patch 参数
* @param[in] build 参数
* @return void
*/
void setBootVersion(u16 major, u16 minor, u16 patch, u16 build);
// 将版本信息转换为字符串
char *versionToString(const VersionInfo &version, char *buffer,
size_t bufSize) const;
// 打印所有版本信息
/**
* @brief printVersions 函数
* @return void
*/
void printVersions() const;
// 通过CAN发送版本信息
/**
* @brief sendVersionInfoViaCan 函数
* @return void
*/
void sendVersionInfoViaCan() const;
private:
VersionInfo softwareVersion;
VersionInfo hardwareVersion;
VersionInfo bootVersion;
};
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,252 @@
/**
* @file main.cpp
* @brief 应用程序主流程源文件
* @note 本文件仅补充 Doxygen 文档注释,不改变代码逻辑。
*/
#include "main.h"
#include "Can.h"
#include "FOC.h"
#include "Filter.h"
#include "Timer.h"
#include "adc.h"
#include "ang_sensor.h"
#include "flash.h"
#include "health.h"
#include "initial.h"
#include "systick.h"
// MAIN 调试宏定义
#if MAIN_DEBUG
/** @brief MAIN_DEBUG_PRINT 宏定义 */
#define MAIN_DEBUG_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
/** @brief MAIN_DEBUG_PRINT 宏定义 */
#define MAIN_DEBUG_PRINT(fmt, ...) ((void)0)
#endif
extern CAN_transmiter CAN0_transmiter; // CAN 初始化
extern sampler sampler; // 采样器
extern angle_sensor KTH7823; // 角度传感器
extern EncoderVelocityKalman Vel_kalman; // 速度滤波
extern EncoderAngleKalman Angle_kalman; // 角度滤波
extern ThermalController thermalController; // 热量控制器
extern FOC_Controller FOC; // FOC 控制
extern FlashEEPROM flashEEP; // EEPROM 类
extern VersionManager Version;
// 主任务调度共享位图:TIMER2 ISR 置位任务,main 循环短关中断后取快照并清位。
TaskScheduler scheduler = {0};
// 电机 50us 控制周期计数:主循环电机任务递增,观测器/计时逻辑读取。
u32 motor_runtime_50us = 0;
// 负载检测/通信心跳计数:主循环递增,CAN 周期发送任务清零。
u32 cnt_test = 0;
// 函数指针数组,包含各种控制模式对应的函数
static FOCFunctionPtr control_functions[] = {
&FOC_Controller::drv_hold, // 0: 占空比置
&FOC_Controller::angle_control, // 1: 位置闭环控制
&FOC_Controller::velocity_control, // 2: 速度闭环控制
&FOC_Controller::
angle_control_with_velocity_limit, // 3:
// 角度闭环控制,带速度限制
&FOC_Controller::MIT_Mode, // 4: MIT 模式
&FOC_Controller::current_control, // 5: 电流闭环控制
&FOC_Controller::velocity_open_loop, // 6: 速度开环控制
&FOC_Controller::PWM_out, // 0: 占空比置
};
/**
* @brief 判断任务标志中是否包含指定任务
* @param[in] currentTasks 当前任务位图快照
* @param[in] task 待检查任务枚举
* @return bool true 表示该任务需要执行
*/
static bool has_task(u32 currentTasks, SystemTask task) {
return (currentTasks & (1u << task)) != 0U;
}
/**
* @brief 控制模式变化时复位所有控制环,避免积分项跨模式继承
* @return void
*/
static void reset_control_loops_on_mode_change(void) {
static int last_control_mode = -1;
if (FOC.control_mode == last_control_mode) return;
FOC.vel_loop.reset();
FOC.angle_loop.reset();
FOC.current_loop.reset();
FOC.vel_inVelAngloop.reset();
FOC.ang_inVelAngloop.reset();
FOC.ang_inMITloop.reset();
FOC.vel_inMITloop.reset();
FOC.current_inMITloop.reset();
last_control_mode = FOC.control_mode;
}
/**
* @brief 执行 50us 电机控制任务,包含快速电压检测和控制函数派发
* @return void
*/
static void run_motor_control_task(void) {
motor_runtime_50us++;
static u8 vcheck_div = 0;
// 快速电压检测每 100us 执行一次,避免每 50us 都读取处理。
if (++vcheck_div >= 2u) {
vcheck_div = 0;
FOC.fast_voltage_check();
}
if (FOC.control_mode >= 8) return;
// 模式合法时再派发控制函数,防止数组越界。
reset_control_loops_on_mode_change();
if (!FOC.is_shut_down) {
(FOC.*control_functions[FOC.control_mode])();
} else {
FOC.drv_stop();
}
}
/**
* @brief 执行高频采样和电机控制相关任务
* @param[in] currentTasks 当前任务位图快照
* @return void
*/
static void run_fast_sample_tasks(u32 currentTasks) {
if (has_task(currentTasks, TASK_CURRENT_UPDATE)) {
sampler.update_current();
}
if (has_task(currentTasks, TASK_ANGLE_UPDATE)) {
KTH7823.update();
FOC.rt_angle = Angle_kalman.update(KTH7823.getAngle());
}
if (has_task(currentTasks, TASK_VELOCITY_UPDATE)) {
FOC.rt_velocity = Angle_kalman.getVelocity();
}
if (has_task(currentTasks, TASK_MOTOR_CONTROL)) {
run_motor_control_task();
}
}
/**
* @brief 执行温度、热管理、磁检测和母线电压等低频维护任务
* @param[in] currentTasks 当前任务位图快照
* @return void
*/
static void run_housekeeping_tasks(u32 currentTasks) {
if (has_task(currentTasks, TASK_MCU_TEMP_UPDATE)) {
sampler.update_mcu_temp();
}
if (has_task(currentTasks, TASK_DRV_TEMP_UPDATE)) {
sampler.update_drv_temp();
}
if (has_task(currentTasks, TASK_THERMAL_CONTROL)) {
thermalController.update();
}
if (has_task(currentTasks, TASK_MAGNETIC_CHECK)) {
angsens_MG_check();
}
if (has_task(currentTasks, TASK_VBUS_UPDATE)) {
power_manage();
}
}
/**
* @brief 执行 CAN 周期发送任务并喂狗
* @return void
*/
static void run_can_task(void) {
CAN0_transmiter.test_u16 = CAN0_transmiter.get_node_id();
cnt_test = 0;
CAN0_transmiter.can0_send_flag = SET;
CAN0_transmiter.communication_check();
fwdgt_counter_reload();
}
/**
* @brief 应用程序入口函数
* @return int 返回值
*/
int main(void) {
u8 init_status = hardware_init();
while (init_status) { // 初始化检测
MAIN_DEBUG_PRINT("初始化失败\r\n");
}
OTA_initial(); // OTA 初始化,A/B 分区处理
angsens_MG_check(); // 角度传感器磁感应强度测试
watchdog_init(50); // 看门狗初始化
while (1) {
__disable_irq();
u32 currentTasks =
scheduler.taskFlags; // 保存当前任务标志快照以提高效率并确保一致性
scheduler.taskFlags &= ~currentTasks; // 一次性清除所有已处理的任务标志
__enable_irq();
if (currentTasks == 0U) {
idle_task_count();
continue;
}
do_task(currentTasks);
}
return 0;
}
/**
* @brief 初始化应用层使用的硬件与软件模块
* @return u8 返回值
*/
u8 hardware_init(void) {
__enable_irq();
systick_config(); // 系统时钟初始化
unused_pin_init(); // 未使用引脚初始化
USART0_init(); // 调试串口初始化
User_timer_init(); // 任务 Timer 初始化
u8 init_status = 0;
init_status += KTH7823.init(); // 角度传感器初始化
init_status += sampler.init(); // 采样器初始化
// EEPROM 初始化 (必须在 CAN 初始化之前,因为 CAN 会从 Flash 读取节点 ID)
flashEEP.init(); // EEPROM 初始化
// CAN 初始化 (会先设置默认节点 ID,然后从 Flash 加载已保存的节点 ID)
init_status += CAN0_transmiter.init(); // CAN 初始化
init_status += Angle_kalman.init(KTH7823.getAngle()); // 角度滤波初始化
init_status += Vel_kalman.init(0.0f); // 速度滤波初始化
init_status += FOC.init(); // FOC 初始化
return init_status;
}
/**
* @brief 根据任务标志调度周期性业务任务
* @param[in] currentTasks 参数
* @return void
*/
void do_task(u32 currentTasks) {
busy_task_enter(); // DWT: 记录忙碌起始周期
cnt_test++;
// 高频任务先执行,保持电机控制优先级。
run_fast_sample_tasks(currentTasks);
// 齿槽转矩校准 tick(DEBUG,平时不启用)
#if FOC_DEBUG
FOC.calibrate_cogging_tick();
#endif
run_housekeeping_tasks(currentTasks);
// CAN 发送放在最后,避免通信处理影响前面的实时控制任务。
if (has_task(currentTasks, TASK_CAN_TRANSMIT)) {
run_can_task();
}
busy_task_exit(); // DWT: 累加忙碌周期
}
@@ -0,0 +1,52 @@
/*!
\file main.h
\brief the header file of main
\version 2025-06-20, V1.5.1, firmware for GD32C10x
*/
/*
Copyright (c) 2024, GigaDevice Semiconductor Inc.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MAIN_H
#define MAIN_H
#include <cstdint>
/**
* @brief 根据任务标志调度周期性业务任务
* @param[in] currentTasks 参数
* @return void
*/
void do_task(u32 currentTasks);
/**
* @brief 初始化应用层使用的硬件与软件模块
* @return u8 返回值
*/
u8 hardware_init(void);
#endif /* MAIN_H */