Merge pull request 'DRV8313兼容性合并' (#1) from DRV8323 into master

Reviewed-on: http://192.168.31.10:8418/cbb/Robot_v2/pulls/1
This commit is contained in:
cbb
2026-01-24 01:55:30 +08:00
38 changed files with 2731 additions and 1445 deletions
+2 -3
View File
@@ -30,12 +30,11 @@ solution:
target-set:
- set:
images:
- project-context: Robot_V2.Debug
- project-context: Robot_V2.Release
debugger:
name: ST-Link@pyOCD
port: 3333
protocol: swd
clock: 10000000
protocol: swd
# List of different build configurations.
build-types:
-227
View File
@@ -1,227 +0,0 @@
#include "DengFOC.h"
#include "Can.h"
#include "Filter.h"
#include "Timer.h"
#include "adc.h"
#include "ang_sensor.h"
#include "initial.h"
#include "pid.h"
#include <cmath>
#include <gd32c10x.h>
#include <stdint.h>
constexpr double PI = 3.1415926535897932384626433832795f;
constexpr float ANGLE_FACTOR = 25.0f / 360.0f * 2.0f * 3.14159265358979323846f;
constexpr float _1_SQRT3 = 0.57735026919f;
constexpr float _2_SQRT3 = 1.15470053838f;
constexpr float _3PI_2 = 4.71238898038f;
constexpr u8 PP = 11;
constexpr float DIR = 1.0;
constexpr float sqrt3 = 1.73205080757f; // sqrt(3)的预计算值
constexpr float sqrt3dv2 = 0.86602540378f; // sqrt(3)/2的预计算值
constexpr float zero_electric_angle = 0.0f;
constexpr u16 LUT_SCALE = (LUT_SIZE / (2.0f * PI));
FOC_Controlroller FOC; // FOC控制初始化
extern sampler sampler;
extern angle_sensor KTH7823;
extern CAN_transmiter CAN0_transmiter;
CurrentKalman curU_kalman(0.0f, 0.0026f, 4.8f, 0.0001f, 1e-6f, 0.02f);
CurrentKalman curV_kalman(0.0f, 0.0026f, 4.8f, 0.0001f, 1e-6f, 0.02f);
CurrentKalman curW_kalman(0.0f, 0.0026f, 4.8f, 0.0001f, 1e-6f, 0.02f);
// 初始变量及函数定义
#define _constrain(amt, low, high) \
((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
#define constrain(value, min, max, target_min, target_max) \
((value - min) / (max - min) * (target_max - target_min))
/**
* @brief 归一化角度
*
* @param angle
* @return float
*/
inline float _normalizeAngle(float angle) {
float a = fmod(angle, 2 * PI);
// 取余运算可以用于归一化,列出特殊值例子算便知
return a >= 0 ? a : (a + 2 * PI);
}
/**
* @brief 电机控制类构造函数
*
*/
FOC_Controlroller::FOC_Controlroller() { ; }
/**
* @brief 设置电机输出,使用优化的SVPWM算法
*
* @param Uq: q轴电压
* @param Ud: d轴电压
* @param angle_el: 电机轴角度
*/
inline void FOC_Controlroller::setPhaseVoltage(float Uq, float Ud) {
// 计算电气角度
float angle_el = _normalizeAngle(shaft_angle * PP);
// 帕克逆变换 (直接计算,避免函数调用开销)
float sin_el, cos_el;
sin_el = sin_lut[(u16)(angle_el * LUT_SCALE) & LUT_MASK];
cos_el = cos_lut[(u16)(angle_el * LUT_SCALE) & LUT_MASK];
float Ualpha = Ud * cos_el - Uq * sin_el;
float Ubeta = Ud * sin_el + Uq * cos_el;
// 克拉克逆变换 (使用预计算常量优化)
Ua = Ualpha + v_half;
Ub = sqrt3dv2 * Ubeta - 0.5f * Ualpha + v_half;
Uc = -0.5f * Ualpha - sqrt3dv2 * Ubeta + v_half;
// 计算占空比并限制范围
float dc_a = _constrain(Ua / v_safe, 0.0f, 1.0f);
float dc_b = _constrain(Ub / v_safe, 0.0f, 1.0f);
float dc_c = _constrain(Uc / v_safe, 0.0f, 1.0f);
// 设置PWM输出
float voltage_exchange = limit_voltage / v_safe;
dc_a = dc_a * voltage_exchange;
dc_b = dc_b * voltage_exchange;
dc_c = dc_c * voltage_exchange;
Set_3Pwm(dc_a, dc_b, dc_c);
// std::printf("PWM:%f,%f,%f\n", dc_a, dc_b, dc_c);
}
/**
* @brief 电机关机
*
*/
void FOC_Controlroller::shut_down() {
thermal_uncontrol = 0;
is_shut_down = 1;
gpio_bit_reset(GPIOB, GPIO_PIN_12);
}
/**
* @brief 占空比置0
*
*/
void FOC_Controlroller::drv_stop() { Set_3Pwm(0.0f, 0.0f, 0.0f); }
/**
* @brief 电机锁止
*/
void FOC_Controlroller::drv_hold(float duty) {
if (duty > 0.95f) {
duty = 0.95f;
} else if (duty < 0.0f) {
duty = 0.0f;
}
Set_3Pwm(duty, duty, duty);
}
/**
* @brief 电机恢复
*
*/
void FOC_Controlroller::resume() {
thermal_uncontrol = false;
voltage_error = false;
is_shut_down = false;
gpio_bit_set(GPIOB, GPIO_PIN_12);
}
/**
* @brief 更新电源电压
*
*/
void FOC_Controlroller::update_power(void) {
voltage_power_supply = sampler.get_vbus_voltage();
if (voltage_power_supply < 36.0f and voltage_power_supply > 8.0f) {
voltage_error = false;
v_half = voltage_power_supply * 0.5f;
v_safe = voltage_power_supply * 0.95f;
} else {
voltage_error = true;
}
}
/**
* @brief 速度开环控制
*
* @param target_velocity: 目标速度
* @return float: q轴电压
*/
float FOC_Controlroller::velocity_open_loop() {
// 通过时间间隔和目标速度计算需要转动的机械角度,存储在shaft_angle中,在此之前,还需要对轴角度归一化
// 预计算常量 1e-4 = 100微秒控制周期
shaft_angle =
_normalizeAngle(shaft_angle + target_velocity * ANGLE_FACTOR * 1e-4f);
// 因为在开环控制中,Ud始终为0,只控制Uq
const float Uq = voltage_power_supply / 2.0f;
setPhaseVoltage(Uq, 0.0f);
return limit_voltage;
}
/**
* @brief 电机初始化
*
* @param _PP: 电机极队数
*/
// void FOC_Controlroller::DFOC_alignSensor(int _PP) {
// u8 PP = _PP;
// setPhaseVoltage(3, 0, _3PI_2);
// delay_1ms(3000);
// zero_electric_angle = _electricalAngle();
// setPhaseVoltage(0, 0, _3PI_2);
// std::printf("0电角度:%f", zero_electric_angle);
// }
/**
* @brief 角度闭环控制
*
* @param target_angle: 目标角度
* @return float: 当前角度
*/
float FOC_Controlroller::angle_control(float target_angle) {
// PID 控制计算
float Uq = angle_loop(target_angle - rt_angle);
// 获取电机轴角度
shaft_angle = KTH7823.getcurrent_sensorangle() * DEG2RAD;
// 设置相电压
setPhaseVoltage(Uq, 0.0f);
return shaft_angle;
}
/**
* @brief 角度闭环控制
*
* @param target_angle: 目标角度
* @return float: 当前角度
*/
float FOC_Controlroller::angle_control_NPID(float target_angle) {
static float Kp = 20.0f;
// 控制力矩计算
float Uq = _constrain(Kp * (target_angle - rt_angle), -voltage_power_supply,
voltage_power_supply);
// 获取电机轴角度
shaft_angle = KTH7823.getcurrent_sensorangle() * DEG2RAD;
// 设置相电压
setPhaseVoltage(Uq, 0.0f);
return shaft_angle;
}
/**
* @brief 速度闭环控制
*
* @param target_velocity: 目标速度
* @return float: 当前速度
*/
float FOC_Controlroller::velocity_control(float target_velocity) {
// PID 控制计算
float Uq = vel_loop(target_velocity - rt_velocity);
// 获取电机轴角度
shaft_angle = KTH7823.getcurrent_sensorangle() * DEG2RAD;
// 设置相电压
setPhaseVoltage(Uq, 0.0f);
return rt_velocity;
}
-410
View File
@@ -1,410 +0,0 @@
// 函数声明
#ifndef _DENGFOC_H
#define _DENGFOC_H
#include "pid.h"
#include <stdint.h>
class FOC_Controlroller {
public:
FOC_Controlroller();
u8 control_mode = 0;
float limit_voltage = 0.0f;
float limit_velocity = 0.0f;
float target_angle = 0.0f;
float target_velocity = 0.0f;
float rt_angle = 0.0f;
float rt_velocity = 0.0f;
bool thermal_uncontrol = false;
bool voltage_error = false;
bool is_shut_down = false;
float voltage_power_supply = 24.0f; // 电源电压
float velocity_open_loop();
float angle_control(float target_angle);
float velocity_control(float target_velocity);
float angle_control_NPID(float target_angle);
void update_power(void);
void DFOC_alignSensor(int _PP);
void shut_down(void);
void resume(void);
void drv_stop(void);
void drv_hold(float duty = 0.5f);
protected:
std::u64 last_time_us = 0;
std::u64 now_us = 0;
float shaft_angle = 0;
float Ualpha, Ubeta = 0, Ua = 0, Ub = 0, Uc = 0;
float zero_electric_angle = 0;
float v_half = voltage_power_supply * 0.5f; // 电源电压的一半
float v_safe = voltage_power_supply * 0.95f;
// PIDController vel_loop =PIDController{1.8f, 1.2f, 0.0002f, 1000000,
// voltage_power_supply};//8V
// PIDController angle_loop = PIDController{140.0f, 80.0f, 0.005f, 10000000,
// voltage_power_supply}; // 8V
PIDController vel_loop = PIDController{0.7f, 0.45f, 0.001f, 1000000,
voltage_power_supply}; // 12V
PIDController angle_loop = PIDController{25.0f, 30.0f, 0.15f, 10000000,
voltage_power_supply}; // 12V
void setPhaseVoltage(float Uq, float Ud);
};
float _normalizeAngle(float angle);
void DFOC_Vbus(float power_supply);
inline float _electricalAngle();
float DFOC_M0_Angle(void);
constexpr u16 LUT_SIZE = 1024;
constexpr u16 LUT_MASK = (LUT_SIZE - 1);
__attribute__((aligned(4))) const float sin_lut[LUT_SIZE] = {
0.000000f, 0.006136f, 0.012272f, 0.018407f, 0.024541f, 0.030675f,
0.036807f, 0.042938f, 0.049068f, 0.055195f, 0.061321f, 0.067444f,
0.073565f, 0.079682f, 0.085797f, 0.091909f, 0.098017f, 0.104122f,
0.110222f, 0.116319f, 0.122411f, 0.128498f, 0.134581f, 0.140658f,
0.146730f, 0.152797f, 0.158858f, 0.164913f, 0.170962f, 0.177004f,
0.183040f, 0.189069f, 0.195090f, 0.201105f, 0.207111f, 0.213110f,
0.219101f, 0.225084f, 0.231058f, 0.237024f, 0.242980f, 0.248928f,
0.254866f, 0.260794f, 0.266713f, 0.272621f, 0.278520f, 0.284408f,
0.290285f, 0.296151f, 0.302006f, 0.307850f, 0.313682f, 0.319502f,
0.325310f, 0.331106f, 0.336890f, 0.342661f, 0.348419f, 0.354164f,
0.359895f, 0.365613f, 0.371317f, 0.377007f, 0.382683f, 0.388345f,
0.393992f, 0.399624f, 0.405241f, 0.410843f, 0.416430f, 0.422000f,
0.427555f, 0.433094f, 0.438616f, 0.444122f, 0.449611f, 0.455084f,
0.460539f, 0.465976f, 0.471397f, 0.476799f, 0.482184f, 0.487550f,
0.492898f, 0.498228f, 0.503538f, 0.508830f, 0.514103f, 0.519356f,
0.524590f, 0.529804f, 0.534998f, 0.540171f, 0.545325f, 0.550458f,
0.555570f, 0.560662f, 0.565732f, 0.570781f, 0.575808f, 0.580814f,
0.585798f, 0.590760f, 0.595699f, 0.600616f, 0.605511f, 0.610383f,
0.615232f, 0.620057f, 0.624859f, 0.629638f, 0.634393f, 0.639124f,
0.643832f, 0.648514f, 0.653173f, 0.657807f, 0.662416f, 0.667000f,
0.671559f, 0.676093f, 0.680601f, 0.685084f, 0.689541f, 0.693971f,
0.698376f, 0.702755f, 0.707107f, 0.711432f, 0.715731f, 0.720003f,
0.724247f, 0.728464f, 0.732654f, 0.736817f, 0.740951f, 0.745058f,
0.749136f, 0.753187f, 0.757209f, 0.761202f, 0.765167f, 0.769103f,
0.773010f, 0.776888f, 0.780737f, 0.784557f, 0.788346f, 0.792107f,
0.795837f, 0.799537f, 0.803208f, 0.806848f, 0.810457f, 0.814036f,
0.817585f, 0.821103f, 0.824589f, 0.828045f, 0.831470f, 0.834863f,
0.838225f, 0.841555f, 0.844854f, 0.848120f, 0.851355f, 0.854558f,
0.857729f, 0.860867f, 0.863973f, 0.867046f, 0.870087f, 0.873095f,
0.876070f, 0.879012f, 0.881921f, 0.884797f, 0.887640f, 0.890449f,
0.893224f, 0.895966f, 0.898674f, 0.901349f, 0.903989f, 0.906596f,
0.909168f, 0.911706f, 0.914210f, 0.916679f, 0.919114f, 0.921514f,
0.923880f, 0.926210f, 0.928506f, 0.930767f, 0.932993f, 0.935184f,
0.937339f, 0.939459f, 0.941544f, 0.943593f, 0.945607f, 0.947586f,
0.949528f, 0.951435f, 0.953306f, 0.955141f, 0.956940f, 0.958703f,
0.960431f, 0.962121f, 0.963776f, 0.965394f, 0.966976f, 0.968522f,
0.970031f, 0.971504f, 0.972940f, 0.974339f, 0.975702f, 0.977028f,
0.978317f, 0.979570f, 0.980785f, 0.981964f, 0.983105f, 0.984210f,
0.985278f, 0.986308f, 0.987301f, 0.988258f, 0.989177f, 0.990058f,
0.990903f, 0.991710f, 0.992480f, 0.993212f, 0.993907f, 0.994565f,
0.995185f, 0.995767f, 0.996313f, 0.996820f, 0.997290f, 0.997723f,
0.998118f, 0.998476f, 0.998795f, 0.999078f, 0.999322f, 0.999529f,
0.999699f, 0.999831f, 0.999925f, 0.999981f, 1.000000f, 0.999981f,
0.999925f, 0.999831f, 0.999699f, 0.999529f, 0.999322f, 0.999078f,
0.998795f, 0.998476f, 0.998118f, 0.997723f, 0.997290f, 0.996820f,
0.996313f, 0.995767f, 0.995185f, 0.994565f, 0.993907f, 0.993212f,
0.992480f, 0.991710f, 0.990903f, 0.990058f, 0.989177f, 0.988258f,
0.987301f, 0.986308f, 0.985278f, 0.984210f, 0.983105f, 0.981964f,
0.980785f, 0.979570f, 0.978317f, 0.977028f, 0.975702f, 0.974339f,
0.972940f, 0.971504f, 0.970031f, 0.968522f, 0.966976f, 0.965394f,
0.963776f, 0.962121f, 0.960431f, 0.958703f, 0.956940f, 0.955141f,
0.953306f, 0.951435f, 0.949528f, 0.947586f, 0.945607f, 0.943593f,
0.941544f, 0.939459f, 0.937339f, 0.935184f, 0.932993f, 0.930767f,
0.928506f, 0.926210f, 0.923880f, 0.921514f, 0.919114f, 0.916679f,
0.914210f, 0.911706f, 0.909168f, 0.906596f, 0.903989f, 0.901349f,
0.898674f, 0.895966f, 0.893224f, 0.890449f, 0.887640f, 0.884797f,
0.881921f, 0.879012f, 0.876070f, 0.873095f, 0.870087f, 0.867046f,
0.863973f, 0.860867f, 0.857729f, 0.854558f, 0.851355f, 0.848120f,
0.844854f, 0.841555f, 0.838225f, 0.834863f, 0.831470f, 0.828045f,
0.824589f, 0.821103f, 0.817585f, 0.814036f, 0.810457f, 0.806848f,
0.803208f, 0.799537f, 0.795837f, 0.792107f, 0.788346f, 0.784557f,
0.780737f, 0.776888f, 0.773010f, 0.769103f, 0.765167f, 0.761202f,
0.757209f, 0.753187f, 0.749136f, 0.745058f, 0.740951f, 0.736817f,
0.732654f, 0.728464f, 0.724247f, 0.720003f, 0.715731f, 0.711432f,
0.707107f, 0.702755f, 0.698376f, 0.693971f, 0.689541f, 0.685084f,
0.680601f, 0.676093f, 0.671559f, 0.667000f, 0.662416f, 0.657807f,
0.653173f, 0.648514f, 0.643832f, 0.639124f, 0.634393f, 0.629638f,
0.624859f, 0.620057f, 0.615232f, 0.610383f, 0.605511f, 0.600616f,
0.595699f, 0.590760f, 0.585798f, 0.580814f, 0.575808f, 0.570781f,
0.565732f, 0.560662f, 0.555570f, 0.550458f, 0.545325f, 0.540171f,
0.534998f, 0.529804f, 0.524590f, 0.519356f, 0.514103f, 0.508830f,
0.503538f, 0.498228f, 0.492898f, 0.487550f, 0.482184f, 0.476799f,
0.471397f, 0.465976f, 0.460539f, 0.455084f, 0.449611f, 0.444122f,
0.438616f, 0.433094f, 0.427555f, 0.422000f, 0.416430f, 0.410843f,
0.405241f, 0.399624f, 0.393992f, 0.388345f, 0.382683f, 0.377007f,
0.371317f, 0.365613f, 0.359895f, 0.354164f, 0.348419f, 0.342661f,
0.336890f, 0.331106f, 0.325310f, 0.319502f, 0.313682f, 0.307850f,
0.302006f, 0.296151f, 0.290285f, 0.284408f, 0.278520f, 0.272621f,
0.266713f, 0.260794f, 0.254866f, 0.248928f, 0.242980f, 0.237024f,
0.231058f, 0.225084f, 0.219101f, 0.213110f, 0.207111f, 0.201105f,
0.195090f, 0.189069f, 0.183040f, 0.177004f, 0.170962f, 0.164913f,
0.158858f, 0.152797f, 0.146730f, 0.140658f, 0.134581f, 0.128498f,
0.122411f, 0.116319f, 0.110222f, 0.104122f, 0.098017f, 0.091909f,
0.085797f, 0.079682f, 0.073565f, 0.067444f, 0.061321f, 0.055195f,
0.049068f, 0.042938f, 0.036807f, 0.030675f, 0.024541f, 0.018407f,
0.012272f, 0.006136f, 0.000000f, -0.006136f, -0.012272f, -0.018407f,
-0.024541f, -0.030675f, -0.036807f, -0.042938f, -0.049068f, -0.055195f,
-0.061321f, -0.067444f, -0.073565f, -0.079682f, -0.085797f, -0.091909f,
-0.098017f, -0.104122f, -0.110222f, -0.116319f, -0.122411f, -0.128498f,
-0.134581f, -0.140658f, -0.146730f, -0.152797f, -0.158858f, -0.164913f,
-0.170962f, -0.177004f, -0.183040f, -0.189069f, -0.195090f, -0.201105f,
-0.207111f, -0.213110f, -0.219101f, -0.225084f, -0.231058f, -0.237024f,
-0.242980f, -0.248928f, -0.254866f, -0.260794f, -0.266713f, -0.272621f,
-0.278520f, -0.284408f, -0.290285f, -0.296151f, -0.302006f, -0.307850f,
-0.313682f, -0.319502f, -0.325310f, -0.331106f, -0.336890f, -0.342661f,
-0.348419f, -0.354164f, -0.359895f, -0.365613f, -0.371317f, -0.377007f,
-0.382683f, -0.388345f, -0.393992f, -0.399624f, -0.405241f, -0.410843f,
-0.416430f, -0.422000f, -0.427555f, -0.433094f, -0.438616f, -0.444122f,
-0.449611f, -0.455084f, -0.460539f, -0.465976f, -0.471397f, -0.476799f,
-0.482184f, -0.487550f, -0.492898f, -0.498228f, -0.503538f, -0.508830f,
-0.514103f, -0.519356f, -0.524590f, -0.529804f, -0.534998f, -0.540171f,
-0.545325f, -0.550458f, -0.555570f, -0.560662f, -0.565732f, -0.570781f,
-0.575808f, -0.580814f, -0.585798f, -0.590760f, -0.595699f, -0.600616f,
-0.605511f, -0.610383f, -0.615232f, -0.620057f, -0.624859f, -0.629638f,
-0.634393f, -0.639124f, -0.643832f, -0.648514f, -0.653173f, -0.657807f,
-0.662416f, -0.667000f, -0.671559f, -0.676093f, -0.680601f, -0.685084f,
-0.689541f, -0.693971f, -0.698376f, -0.702755f, -0.707107f, -0.711432f,
-0.715731f, -0.720003f, -0.724247f, -0.728464f, -0.732654f, -0.736817f,
-0.740951f, -0.745058f, -0.749136f, -0.753187f, -0.757209f, -0.761202f,
-0.765167f, -0.769103f, -0.773010f, -0.776888f, -0.780737f, -0.784557f,
-0.788346f, -0.792107f, -0.795837f, -0.799537f, -0.803208f, -0.806848f,
-0.810457f, -0.814036f, -0.817585f, -0.821103f, -0.824589f, -0.828045f,
-0.831470f, -0.834863f, -0.838225f, -0.841555f, -0.844854f, -0.848120f,
-0.851355f, -0.854558f, -0.857729f, -0.860867f, -0.863973f, -0.867046f,
-0.870087f, -0.873095f, -0.876070f, -0.879012f, -0.881921f, -0.884797f,
-0.887640f, -0.890449f, -0.893224f, -0.895966f, -0.898674f, -0.901349f,
-0.903989f, -0.906596f, -0.909168f, -0.911706f, -0.914210f, -0.916679f,
-0.919114f, -0.921514f, -0.923880f, -0.926210f, -0.928506f, -0.930767f,
-0.932993f, -0.935184f, -0.937339f, -0.939459f, -0.941544f, -0.943593f,
-0.945607f, -0.947586f, -0.949528f, -0.951435f, -0.953306f, -0.955141f,
-0.956940f, -0.958703f, -0.960431f, -0.962121f, -0.963776f, -0.965394f,
-0.966976f, -0.968522f, -0.970031f, -0.971504f, -0.972940f, -0.974339f,
-0.975702f, -0.977028f, -0.978317f, -0.979570f, -0.980785f, -0.981964f,
-0.983105f, -0.984210f, -0.985278f, -0.986308f, -0.987301f, -0.988258f,
-0.989177f, -0.990058f, -0.990903f, -0.991710f, -0.992480f, -0.993212f,
-0.993907f, -0.994565f, -0.995185f, -0.995767f, -0.996313f, -0.996820f,
-0.997290f, -0.997723f, -0.998118f, -0.998476f, -0.998795f, -0.999078f,
-0.999322f, -0.999529f, -0.999699f, -0.999831f, -0.999925f, -0.999981f,
-1.000000f, -0.999981f, -0.999925f, -0.999831f, -0.999699f, -0.999529f,
-0.999322f, -0.999078f, -0.998795f, -0.998476f, -0.998118f, -0.997723f,
-0.997290f, -0.996820f, -0.996313f, -0.995767f, -0.995185f, -0.994565f,
-0.993907f, -0.993212f, -0.992480f, -0.991710f, -0.990903f, -0.990058f,
-0.989177f, -0.988258f, -0.987301f, -0.986308f, -0.985278f, -0.984210f,
-0.983105f, -0.981964f, -0.980785f, -0.979570f, -0.978317f, -0.977028f,
-0.975702f, -0.974339f, -0.972940f, -0.971504f, -0.970031f, -0.968522f,
-0.966976f, -0.965394f, -0.963776f, -0.962121f, -0.960431f, -0.958703f,
-0.956940f, -0.955141f, -0.953306f, -0.951435f, -0.949528f, -0.947586f,
-0.945607f, -0.943593f, -0.941544f, -0.939459f, -0.937339f, -0.935184f,
-0.932993f, -0.930767f, -0.928506f, -0.926210f, -0.923880f, -0.921514f,
-0.919114f, -0.916679f, -0.914210f, -0.911706f, -0.909168f, -0.906596f,
-0.903989f, -0.901349f, -0.898674f, -0.895966f, -0.893224f, -0.890449f,
-0.887640f, -0.884797f, -0.881921f, -0.879012f, -0.876070f, -0.873095f,
-0.870087f, -0.867046f, -0.863973f, -0.860867f, -0.857729f, -0.854558f,
-0.851355f, -0.848120f, -0.844854f, -0.841555f, -0.838225f, -0.834863f,
-0.831470f, -0.828045f, -0.824589f, -0.821103f, -0.817585f, -0.814036f,
-0.810457f, -0.806848f, -0.803208f, -0.799537f, -0.795837f, -0.792107f,
-0.788346f, -0.784557f, -0.780737f, -0.776888f, -0.773010f, -0.769103f,
-0.765167f, -0.761202f, -0.757209f, -0.753187f, -0.749136f, -0.745058f,
-0.740951f, -0.736817f, -0.732654f, -0.728464f, -0.724247f, -0.720003f,
-0.715731f, -0.711432f, -0.707107f, -0.702755f, -0.698376f, -0.693971f,
-0.689541f, -0.685084f, -0.680601f, -0.676093f, -0.671559f, -0.667000f,
-0.662416f, -0.657807f, -0.653173f, -0.648514f, -0.643832f, -0.639124f,
-0.634393f, -0.629638f, -0.624859f, -0.620057f, -0.615232f, -0.610383f,
-0.605511f, -0.600616f, -0.595699f, -0.590760f, -0.585798f, -0.580814f,
-0.575808f, -0.570781f, -0.565732f, -0.560662f, -0.555570f, -0.550458f,
-0.545325f, -0.540171f, -0.534998f, -0.529804f, -0.524590f, -0.519356f,
-0.514103f, -0.508830f, -0.503538f, -0.498228f, -0.492898f, -0.487550f,
-0.482184f, -0.476799f, -0.471397f, -0.465976f, -0.460539f, -0.455084f,
-0.449611f, -0.444122f, -0.438616f, -0.433094f, -0.427555f, -0.422000f,
-0.416430f, -0.410843f, -0.405241f, -0.399624f, -0.393992f, -0.388345f,
-0.382683f, -0.377007f, -0.371317f, -0.365613f, -0.359895f, -0.354164f,
-0.348419f, -0.342661f, -0.336890f, -0.331106f, -0.325310f, -0.319502f,
-0.313682f, -0.307850f, -0.302006f, -0.296151f, -0.290285f, -0.284408f,
-0.278520f, -0.272621f, -0.266713f, -0.260794f, -0.254866f, -0.248928f,
-0.242980f, -0.237024f, -0.231058f, -0.225084f, -0.219101f, -0.213110f,
-0.207111f, -0.201105f, -0.195090f, -0.189069f, -0.183040f, -0.177004f,
-0.170962f, -0.164913f, -0.158858f, -0.152797f, -0.146730f, -0.140658f,
-0.134581f, -0.128498f, -0.122411f, -0.116319f, -0.110222f, -0.104122f,
-0.098017f, -0.091909f, -0.085797f, -0.079682f, -0.073565f, -0.067444f,
-0.061321f, -0.055195f, -0.049068f, -0.042938f, -0.036807f, -0.030675f,
-0.024541f, -0.018407f, -0.012272f, -0.006136f};
__attribute__((aligned(4))) const float cos_lut[LUT_SIZE] = {
1.000000f, 0.999981f, 0.999925f, 0.999831f, 0.999699f, 0.999529f,
0.999322f, 0.999078f, 0.998795f, 0.998476f, 0.998118f, 0.997723f,
0.997290f, 0.996820f, 0.996313f, 0.995767f, 0.995185f, 0.994565f,
0.993907f, 0.993212f, 0.992480f, 0.991710f, 0.990903f, 0.990058f,
0.989177f, 0.988258f, 0.987301f, 0.986308f, 0.985278f, 0.984210f,
0.983105f, 0.981964f, 0.980785f, 0.979570f, 0.978317f, 0.977028f,
0.975702f, 0.974339f, 0.972940f, 0.971504f, 0.970031f, 0.968522f,
0.966976f, 0.965394f, 0.963776f, 0.962121f, 0.960431f, 0.958703f,
0.956940f, 0.955141f, 0.953306f, 0.951435f, 0.949528f, 0.947586f,
0.945607f, 0.943593f, 0.941544f, 0.939459f, 0.937339f, 0.935184f,
0.932993f, 0.930767f, 0.928506f, 0.926210f, 0.923880f, 0.921514f,
0.919114f, 0.916679f, 0.914210f, 0.911706f, 0.909168f, 0.906596f,
0.903989f, 0.901349f, 0.898674f, 0.895966f, 0.893224f, 0.890449f,
0.887640f, 0.884797f, 0.881921f, 0.879012f, 0.876070f, 0.873095f,
0.870087f, 0.867046f, 0.863973f, 0.860867f, 0.857729f, 0.854558f,
0.851355f, 0.848120f, 0.844854f, 0.841555f, 0.838225f, 0.834863f,
0.831470f, 0.828045f, 0.824589f, 0.821103f, 0.817585f, 0.814036f,
0.810457f, 0.806848f, 0.803208f, 0.799537f, 0.795837f, 0.792107f,
0.788346f, 0.784557f, 0.780737f, 0.776888f, 0.773010f, 0.769103f,
0.765167f, 0.761202f, 0.757209f, 0.753187f, 0.749136f, 0.745058f,
0.740951f, 0.736817f, 0.732654f, 0.728464f, 0.724247f, 0.720003f,
0.715731f, 0.711432f, 0.707107f, 0.702755f, 0.698376f, 0.693971f,
0.689541f, 0.685084f, 0.680601f, 0.676093f, 0.671559f, 0.667000f,
0.662416f, 0.657807f, 0.653173f, 0.648514f, 0.643832f, 0.639124f,
0.634393f, 0.629638f, 0.624859f, 0.620057f, 0.615232f, 0.610383f,
0.605511f, 0.600616f, 0.595699f, 0.590760f, 0.585798f, 0.580814f,
0.575808f, 0.570781f, 0.565732f, 0.560662f, 0.555570f, 0.550458f,
0.545325f, 0.540171f, 0.534998f, 0.529804f, 0.524590f, 0.519356f,
0.514103f, 0.508830f, 0.503538f, 0.498228f, 0.492898f, 0.487550f,
0.482184f, 0.476799f, 0.471397f, 0.465976f, 0.460539f, 0.455084f,
0.449611f, 0.444122f, 0.438616f, 0.433094f, 0.427555f, 0.422000f,
0.416430f, 0.410843f, 0.405241f, 0.399624f, 0.393992f, 0.388345f,
0.382683f, 0.377007f, 0.371317f, 0.365613f, 0.359895f, 0.354164f,
0.348419f, 0.342661f, 0.336890f, 0.331106f, 0.325310f, 0.319502f,
0.313682f, 0.307850f, 0.302006f, 0.296151f, 0.290285f, 0.284408f,
0.278520f, 0.272621f, 0.266713f, 0.260794f, 0.254866f, 0.248928f,
0.242980f, 0.237024f, 0.231058f, 0.225084f, 0.219101f, 0.213110f,
0.207111f, 0.201105f, 0.195090f, 0.189069f, 0.183040f, 0.177004f,
0.170962f, 0.164913f, 0.158858f, 0.152797f, 0.146730f, 0.140658f,
0.134581f, 0.128498f, 0.122411f, 0.116319f, 0.110222f, 0.104122f,
0.098017f, 0.091909f, 0.085797f, 0.079682f, 0.073565f, 0.067444f,
0.061321f, 0.055195f, 0.049068f, 0.042938f, 0.036807f, 0.030675f,
0.024541f, 0.018407f, 0.012272f, 0.006136f, 0.000000f, -0.006136f,
-0.012272f, -0.018407f, -0.024541f, -0.030675f, -0.036807f, -0.042938f,
-0.049068f, -0.055195f, -0.061321f, -0.067444f, -0.073565f, -0.079682f,
-0.085797f, -0.091909f, -0.098017f, -0.104122f, -0.110222f, -0.116319f,
-0.122411f, -0.128498f, -0.134581f, -0.140658f, -0.146730f, -0.152797f,
-0.158858f, -0.164913f, -0.170962f, -0.177004f, -0.183040f, -0.189069f,
-0.195090f, -0.201105f, -0.207111f, -0.213110f, -0.219101f, -0.225084f,
-0.231058f, -0.237024f, -0.242980f, -0.248928f, -0.254866f, -0.260794f,
-0.266713f, -0.272621f, -0.278520f, -0.284408f, -0.290285f, -0.296151f,
-0.302006f, -0.307850f, -0.313682f, -0.319502f, -0.325310f, -0.331106f,
-0.336890f, -0.342661f, -0.348419f, -0.354164f, -0.359895f, -0.365613f,
-0.371317f, -0.377007f, -0.382683f, -0.388345f, -0.393992f, -0.399624f,
-0.405241f, -0.410843f, -0.416430f, -0.422000f, -0.427555f, -0.433094f,
-0.438616f, -0.444122f, -0.449611f, -0.455084f, -0.460539f, -0.465976f,
-0.471397f, -0.476799f, -0.482184f, -0.487550f, -0.492898f, -0.498228f,
-0.503538f, -0.508830f, -0.514103f, -0.519356f, -0.524590f, -0.529804f,
-0.534998f, -0.540171f, -0.545325f, -0.550458f, -0.555570f, -0.560662f,
-0.565732f, -0.570781f, -0.575808f, -0.580814f, -0.585798f, -0.590760f,
-0.595699f, -0.600616f, -0.605511f, -0.610383f, -0.615232f, -0.620057f,
-0.624859f, -0.629638f, -0.634393f, -0.639124f, -0.643832f, -0.648514f,
-0.653173f, -0.657807f, -0.662416f, -0.667000f, -0.671559f, -0.676093f,
-0.680601f, -0.685084f, -0.689541f, -0.693971f, -0.698376f, -0.702755f,
-0.707107f, -0.711432f, -0.715731f, -0.720003f, -0.724247f, -0.728464f,
-0.732654f, -0.736817f, -0.740951f, -0.745058f, -0.749136f, -0.753187f,
-0.757209f, -0.761202f, -0.765167f, -0.769103f, -0.773010f, -0.776888f,
-0.780737f, -0.784557f, -0.788346f, -0.792107f, -0.795837f, -0.799537f,
-0.803208f, -0.806848f, -0.810457f, -0.814036f, -0.817585f, -0.821103f,
-0.824589f, -0.828045f, -0.831470f, -0.834863f, -0.838225f, -0.841555f,
-0.844854f, -0.848120f, -0.851355f, -0.854558f, -0.857729f, -0.860867f,
-0.863973f, -0.867046f, -0.870087f, -0.873095f, -0.876070f, -0.879012f,
-0.881921f, -0.884797f, -0.887640f, -0.890449f, -0.893224f, -0.895966f,
-0.898674f, -0.901349f, -0.903989f, -0.906596f, -0.909168f, -0.911706f,
-0.914210f, -0.916679f, -0.919114f, -0.921514f, -0.923880f, -0.926210f,
-0.928506f, -0.930767f, -0.932993f, -0.935184f, -0.937339f, -0.939459f,
-0.941544f, -0.943593f, -0.945607f, -0.947586f, -0.949528f, -0.951435f,
-0.953306f, -0.955141f, -0.956940f, -0.958703f, -0.960431f, -0.962121f,
-0.963776f, -0.965394f, -0.966976f, -0.968522f, -0.970031f, -0.971504f,
-0.972940f, -0.974339f, -0.975702f, -0.977028f, -0.978317f, -0.979570f,
-0.980785f, -0.981964f, -0.983105f, -0.984210f, -0.985278f, -0.986308f,
-0.987301f, -0.988258f, -0.989177f, -0.990058f, -0.990903f, -0.991710f,
-0.992480f, -0.993212f, -0.993907f, -0.994565f, -0.995185f, -0.995767f,
-0.996313f, -0.996820f, -0.997290f, -0.997723f, -0.998118f, -0.998476f,
-0.998795f, -0.999078f, -0.999322f, -0.999529f, -0.999699f, -0.999831f,
-0.999925f, -0.999981f, -1.000000f, -0.999981f, -0.999925f, -0.999831f,
-0.999699f, -0.999529f, -0.999322f, -0.999078f, -0.998795f, -0.998476f,
-0.998118f, -0.997723f, -0.997290f, -0.996820f, -0.996313f, -0.995767f,
-0.995185f, -0.994565f, -0.993907f, -0.993212f, -0.992480f, -0.991710f,
-0.990903f, -0.990058f, -0.989177f, -0.988258f, -0.987301f, -0.986308f,
-0.985278f, -0.984210f, -0.983105f, -0.981964f, -0.980785f, -0.979570f,
-0.978317f, -0.977028f, -0.975702f, -0.974339f, -0.972940f, -0.971504f,
-0.970031f, -0.968522f, -0.966976f, -0.965394f, -0.963776f, -0.962121f,
-0.960431f, -0.958703f, -0.956940f, -0.955141f, -0.953306f, -0.951435f,
-0.949528f, -0.947586f, -0.945607f, -0.943593f, -0.941544f, -0.939459f,
-0.937339f, -0.935184f, -0.932993f, -0.930767f, -0.928506f, -0.926210f,
-0.923880f, -0.921514f, -0.919114f, -0.916679f, -0.914210f, -0.911706f,
-0.909168f, -0.906596f, -0.903989f, -0.901349f, -0.898674f, -0.895966f,
-0.893224f, -0.890449f, -0.887640f, -0.884797f, -0.881921f, -0.879012f,
-0.876070f, -0.873095f, -0.870087f, -0.867046f, -0.863973f, -0.860867f,
-0.857729f, -0.854558f, -0.851355f, -0.848120f, -0.844854f, -0.841555f,
-0.838225f, -0.834863f, -0.831470f, -0.828045f, -0.824589f, -0.821103f,
-0.817585f, -0.814036f, -0.810457f, -0.806848f, -0.803208f, -0.799537f,
-0.795837f, -0.792107f, -0.788346f, -0.784557f, -0.780737f, -0.776888f,
-0.773010f, -0.769103f, -0.765167f, -0.761202f, -0.757209f, -0.753187f,
-0.749136f, -0.745058f, -0.740951f, -0.736817f, -0.732654f, -0.728464f,
-0.724247f, -0.720003f, -0.715731f, -0.711432f, -0.707107f, -0.702755f,
-0.698376f, -0.693971f, -0.689541f, -0.685084f, -0.680601f, -0.676093f,
-0.671559f, -0.667000f, -0.662416f, -0.657807f, -0.653173f, -0.648514f,
-0.643832f, -0.639124f, -0.634393f, -0.629638f, -0.624859f, -0.620057f,
-0.615232f, -0.610383f, -0.605511f, -0.600616f, -0.595699f, -0.590760f,
-0.585798f, -0.580814f, -0.575808f, -0.570781f, -0.565732f, -0.560662f,
-0.555570f, -0.550458f, -0.545325f, -0.540171f, -0.534998f, -0.529804f,
-0.524590f, -0.519356f, -0.514103f, -0.508830f, -0.503538f, -0.498228f,
-0.492898f, -0.487550f, -0.482184f, -0.476799f, -0.471397f, -0.465976f,
-0.460539f, -0.455084f, -0.449611f, -0.444122f, -0.438616f, -0.433094f,
-0.427555f, -0.422000f, -0.416430f, -0.410843f, -0.405241f, -0.399624f,
-0.393992f, -0.388345f, -0.382683f, -0.377007f, -0.371317f, -0.365613f,
-0.359895f, -0.354164f, -0.348419f, -0.342661f, -0.336890f, -0.331106f,
-0.325310f, -0.319502f, -0.313682f, -0.307850f, -0.302006f, -0.296151f,
-0.290285f, -0.284408f, -0.278520f, -0.272621f, -0.266713f, -0.260794f,
-0.254866f, -0.248928f, -0.242980f, -0.237024f, -0.231058f, -0.225084f,
-0.219101f, -0.213110f, -0.207111f, -0.201105f, -0.195090f, -0.189069f,
-0.183040f, -0.177004f, -0.170962f, -0.164913f, -0.158858f, -0.152797f,
-0.146730f, -0.140658f, -0.134581f, -0.128498f, -0.122411f, -0.116319f,
-0.110222f, -0.104122f, -0.098017f, -0.091909f, -0.085797f, -0.079682f,
-0.073565f, -0.067444f, -0.061321f, -0.055195f, -0.049068f, -0.042938f,
-0.036807f, -0.030675f, -0.024541f, -0.018407f, -0.012272f, -0.006136f,
-0.000000f, 0.006136f, 0.012272f, 0.018407f, 0.024541f, 0.030675f,
0.036807f, 0.042938f, 0.049068f, 0.055195f, 0.061321f, 0.067444f,
0.073565f, 0.079682f, 0.085797f, 0.091909f, 0.098017f, 0.104122f,
0.110222f, 0.116319f, 0.122411f, 0.128498f, 0.134581f, 0.140658f,
0.146730f, 0.152797f, 0.158858f, 0.164913f, 0.170962f, 0.177004f,
0.183040f, 0.189069f, 0.195090f, 0.201105f, 0.207111f, 0.213110f,
0.219101f, 0.225084f, 0.231058f, 0.237024f, 0.242980f, 0.248928f,
0.254866f, 0.260794f, 0.266713f, 0.272621f, 0.278520f, 0.284408f,
0.290285f, 0.296151f, 0.302006f, 0.307850f, 0.313682f, 0.319502f,
0.325310f, 0.331106f, 0.336890f, 0.342661f, 0.348419f, 0.354164f,
0.359895f, 0.365613f, 0.371317f, 0.377007f, 0.382683f, 0.388345f,
0.393992f, 0.399624f, 0.405241f, 0.410843f, 0.416430f, 0.422000f,
0.427555f, 0.433094f, 0.438616f, 0.444122f, 0.449611f, 0.455084f,
0.460539f, 0.465976f, 0.471397f, 0.476799f, 0.482184f, 0.487550f,
0.492898f, 0.498228f, 0.503538f, 0.508830f, 0.514103f, 0.519356f,
0.524590f, 0.529804f, 0.534998f, 0.540171f, 0.545325f, 0.550458f,
0.555570f, 0.560662f, 0.565732f, 0.570781f, 0.575808f, 0.580814f,
0.585798f, 0.590760f, 0.595699f, 0.600616f, 0.605511f, 0.610383f,
0.615232f, 0.620057f, 0.624859f, 0.629638f, 0.634393f, 0.639124f,
0.643832f, 0.648514f, 0.653173f, 0.657807f, 0.662416f, 0.667000f,
0.671559f, 0.676093f, 0.680601f, 0.685084f, 0.689541f, 0.693971f,
0.698376f, 0.702755f, 0.707107f, 0.711432f, 0.715731f, 0.720003f,
0.724247f, 0.728464f, 0.732654f, 0.736817f, 0.740951f, 0.745058f,
0.749136f, 0.753187f, 0.757209f, 0.761202f, 0.765167f, 0.769103f,
0.773010f, 0.776888f, 0.780737f, 0.784557f, 0.788346f, 0.792107f,
0.795837f, 0.799537f, 0.803208f, 0.806848f, 0.810457f, 0.814036f,
0.817585f, 0.821103f, 0.824589f, 0.828045f, 0.831470f, 0.834863f,
0.838225f, 0.841555f, 0.844854f, 0.848120f, 0.851355f, 0.854558f,
0.857729f, 0.860867f, 0.863973f, 0.867046f, 0.870087f, 0.873095f,
0.876070f, 0.879012f, 0.881921f, 0.884797f, 0.887640f, 0.890449f,
0.893224f, 0.895966f, 0.898674f, 0.901349f, 0.903989f, 0.906596f,
0.909168f, 0.911706f, 0.914210f, 0.916679f, 0.919114f, 0.921514f,
0.923880f, 0.926210f, 0.928506f, 0.930767f, 0.932993f, 0.935184f,
0.937339f, 0.939459f, 0.941544f, 0.943593f, 0.945607f, 0.947586f,
0.949528f, 0.951435f, 0.953306f, 0.955141f, 0.956940f, 0.958703f,
0.960431f, 0.962121f, 0.963776f, 0.965394f, 0.966976f, 0.968522f,
0.970031f, 0.971504f, 0.972940f, 0.974339f, 0.975702f, 0.977028f,
0.978317f, 0.979570f, 0.980785f, 0.981964f, 0.983105f, 0.984210f,
0.985278f, 0.986308f, 0.987301f, 0.988258f, 0.989177f, 0.990058f,
0.990903f, 0.991710f, 0.992480f, 0.993212f, 0.993907f, 0.994565f,
0.995185f, 0.995767f, 0.996313f, 0.996820f, 0.997290f, 0.997723f,
0.998118f, 0.998476f, 0.998795f, 0.999078f, 0.999322f, 0.999529f,
0.999699f, 0.999831f, 0.999925f, 0.999981f};
#endif
+293
View File
@@ -0,0 +1,293 @@
#include "FOC.h"
#include "Can.h"
#include "Filter.h"
#include "Timer.h"
#include "adc.h"
#include "ang_sensor.h"
#include "config.h"
#include "motor.h"
#include "pid.h"
#include <arm_math.h>
#include <cmath>
#include <gd32c10x.h>
FOC_Controlroller FOC; // FOC控制初始化
extern sampler sampler;
extern angle_sensor KTH7823;
extern CAN_transmiter CAN0_transmiter;
extern EncoderVelocityKalman Vel_kalman; // 速度滤波
// 初始变量及函数定义
#define _constrain(amt, low, high) \
((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
#define constrain(value, min, max, target_min, target_max) \
((value - min) / (max - min) * (target_max - target_min))
/**@
* @brief 归一化角度
*
* @param angle
* @return float
*/
inline float _normalizeAngle(float angle) {
float a = fmod(angle, 360.0f);
// 取余运算可以用于归一化,列出特殊值例子算便知
return a >= 0 ? a : (a + 360.0f);
}
// 通过Ia,Ib,Ic计算Iq,Id(目前仅输出Iq)
inline float FOC_Controlroller::cal_Iq_Id(float current_a, float current_b,
float current_c) {
// 计算电气角度
float angle_el = _normalizeAngle(shaft_angle * PP);
float I_alpha, I_beta;
// Clarke变换 (使用三相电流)
// arm_clarke_f32(current_a, current_b, &I_alpha, &I_beta);
I_alpha = (2.0f / 3.0f) * current_a - (1.0f / 3.0f) * current_b -
(1.0f / 3.0f) * current_c;
I_beta = _1_SQRT3 * current_b - _1_SQRT3 * current_c;
// Park变换
float sin_el, cos_el;
arm_sin_cos_f32(angle_el, &sin_el, &cos_el);
float I_q, I_d;
I_q = I_beta * cos_el - I_alpha * sin_el;
// arm_park_f32(I_alpha, I_beta, &I_d, &I_q, sin_el, cos_el);
return I_q * 1000.0f -
KE_FACTOR * rt_velocity; // 返回Iq值,乘以100以转换为mA
}
/**
* @brief 电机控制类初始化函数
*
* @return u8 0表示初始化成功,1表示初始化失败
*/
u8 FOC_Controlroller::init() {
motor_init(); // 电机驱动初始化
vel_loop.set_PID(vel_loop_p * 100 / limit_voltage, 0.20f, 5e-5); // 设置电机速度控制参数
angle_loop.set_PID(angle_loop_p * 100 / limit_voltage, 100.0f,
0.2f); // 设置电机角度控制参数
current_loop.set_PID(current_loop_p * 100 / limit_voltage, 5e-7f,
7e-8); // 设置电机电流控制参数
vel_inVelAngloop.set_PID(vel_angloop_p * 100 / limit_voltage, 3.0f,
5e-4); // 设置电机速度控制参数
ang_inVelAngloop.set_PID(ang_angloop_p * 100 / limit_voltage, 0.0f,
5e-4); // 设置电机角度控制参数
return 0;
}
/**
* @brief 电机控制类构造函数
*
*/
FOC_Controlroller::FOC_Controlroller() { ; }
/**
* @brief 设置电机输出,使用优化的SVPWM算法
*
* @param Uq: q轴电压
* @param Ud: d轴电压
* @param angle_el: 电机轴角度
*/
inline void FOC_Controlroller::setPhaseVoltage(float Uq, float Ud) {
// 计算电气角度
float angle_el = _normalizeAngle(shaft_angle * PP);
// 帕克逆变换 (直接计算,避免函数调用开销)
float sin_el, cos_el;
arm_sin_cos_f32(angle_el, &sin_el, &cos_el);
float Ualpha = Ud * cos_el - Uq * sin_el;
float Ubeta = Ud * sin_el + Uq * cos_el;
// 克拉克逆变换 (使用预计算常量优化)
Ua = Ualpha + v_half;
Ub = sqrt3dv2 * Ubeta - 0.5f * Ualpha + v_half;
Uc = -0.5f * Ualpha - sqrt3dv2 * Ubeta + v_half;
// 计算占空比并限制范围
duty_a = _constrain(Ua / v_safe, 0.0f, 1.0f);
duty_b = _constrain(Ub / v_safe, 0.0f, 1.0f);
duty_c = _constrain(Uc / v_safe, 0.0f, 1.0f);
// 设置PWM输出
float voltage_exchange = limit_voltage / v_safe;
duty_a = duty_a * voltage_exchange;
duty_b = duty_b * voltage_exchange;
duty_c = duty_c * voltage_exchange;
Set_3Pwm(duty_a, duty_b, duty_c);
}
/**
* @brief 电机关机
*
*/
void FOC_Controlroller::shut_down() {
is_shut_down = 1;
motor_sleep();
}
/**
* @brief 占空比置0
*
*/
void FOC_Controlroller::drv_stop() { Set_3Pwm(0.0f, 0.0f, 0.0f); }
/**
* @brief 电机锁止
*/
float FOC_Controlroller::drv_hold() {
float hold_pwm_duty = HOLD_PWM_DUTY;
if (HOLD_PWM_DUTY > 0.95f) {
hold_pwm_duty = 0.95f;
} else if (HOLD_PWM_DUTY < 0.0f) {
hold_pwm_duty = 0.0f;
}
Set_3Pwm(hold_pwm_duty, hold_pwm_duty, hold_pwm_duty);
return hold_pwm_duty;
}
/**
* @brief 电机恢复
*
*/
void FOC_Controlroller::resume() {
over_current = false;
voltage_error = false;
is_shut_down = false;
motor_resume();
}
/**
* @brief 更新电源电压
*
*/
void FOC_Controlroller::update_power(void) {
voltage_power_supply = sampler.get_vbus_voltage();
if (voltage_power_supply < 36.0f and voltage_power_supply > 8.0f) {
voltage_error = false;
v_half = voltage_power_supply * 0.5f;
v_safe = voltage_power_supply * 0.95f;
} else {
voltage_error = true;
}
}
/**
* @brief 速度开环控制
*
* @param target_velocity: 目标速度
* @return float: q轴电压
*/
float FOC_Controlroller::velocity_open_loop() {
// 通过时间间隔和目标速度计算需要转动的机械角度,存储在shaft_angle中,在此之前,还需要对轴角度归一化
shaft_angle = _normalizeAngle(shaft_angle + target_velocity * ANGLE_FACTOR *
REDUCTION_RATIO * 1.0 /
TIMER2_FREQUENCY);
// 因为在开环控制中,Ud始终为0,只控制Uq
const float Uq = voltage_power_supply / 2.0f;
setPhaseVoltage(Uq, 0.0f);
CAN0_transmiter.testfloat_union.f = shaft_angle;
// cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
// sampler.get_current('W'));
return limit_voltage;
}
/**
* @brief 电机初始化
*
* @param _PP: 电机极队数
*/
// void FOC_Controlroller::DFOC_alignSensor(int _PP) {
// u8 PP = _PP;
// setPhaseVoltage(3, 0, _3PI_2);
// delay_1ms(3000);
// zero_electric_angle = _electricalAngle();
// setPhaseVoltage(0, 0, _3PI_2);
// std::printf("0电角度:%f", zero_electric_angle);
// }
/**
* @brief 角度闭环控制
*
* @param target_angle: 目标角度
* @return float: 当前角度
*/
float FOC_Controlroller::angle_control() {
// PID 控制计算
float Uq = angle_loop(target_angle - rt_angle);
// 获取电机轴角度
shaft_angle = KTH7823.getcurrent_sensorangle();
// 设置相电压
setPhaseVoltage(Uq, 0.0f);
return shaft_angle;
}
/**
* @brief 带速度限制的角度闭环控制
*
* @param target_angle: 目标角度
* @param max_velocity: 最大速度限制 (单位: rad/s)
* @return float: 当前角度
*/
float FOC_Controlroller::angle_control_with_velocity_limit() {
// 计算角度误差
float angle_error = target_angle - rt_angle;
// 使用角度PID控制器计算目标速度
float target_velocity = ang_inVelAngloop(angle_error);
// 对目标速度进行限幅
target_velocity =
_constrain(target_velocity, -limit_velocity, limit_velocity);
// 使用速度PID控制器计算最终输出电压
float Uq = vel_inVelAngloop(rt_velocity - target_velocity);
CAN0_transmiter.testfloat_union.f = shaft_angle;
// 获取电机轴角度
shaft_angle = KTH7823.getcurrent_sensorangle();
// 设置相电压
setPhaseVoltage(Uq, 0.0f);
return shaft_angle;
}
/**
* @brief 速度闭环控制
*
* @param target_velocity: 目标速度
* @return float: 当前速度
*/
float FOC_Controlroller::velocity_control() {
// PID 控制计算
float Uq = vel_loop((rt_velocity - target_velocity) * 25);
// 获取电机轴角度
shaft_angle = KTH7823.getcurrent_sensorangle();
// 设置相电压
setPhaseVoltage(Uq, 0.0f);
CAN0_transmiter.testfloat_union.f =
cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
sampler.get_current('W'));
return rt_velocity;
}
float FOC_Controlroller::current_control() {
// PID 控制计算
float Iq = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
sampler.get_current('W'));
float Uq = current_loop(target_current - Iq);
CAN0_transmiter.testfloat_union.f = Iq;
// 获取电机轴角度
shaft_angle = KTH7823.getcurrent_sensorangle();
// 设置相电压
setPhaseVoltage(Uq, 0.0f);
return 1;
}
+77
View File
@@ -0,0 +1,77 @@
// 函数声明
#ifndef _FOC_H
#define _FOC_H
#include "config.h"
#include "pid.h"
#include <cstdint>
class FOC_Controlroller {
public:
FOC_Controlroller();
// 初始化函数
u8 init();
u8 control_mode = 0;
float limit_voltage = 0.0f;
float limit_velocity = 0.0f;
float target_angle = 0.0f;
float target_velocity = 0.0f;
float target_current = 0.0f;
float rt_angle = 0.0f;
float rt_velocity = 0.0f;
bool over_current = false;
bool voltage_error = false;
bool is_shut_down = false;
float voltage_power_supply = 24.0f; // 电源电压
float v_safe = voltage_power_supply * 0.95f;
float duty_a = 0, duty_b = 0, duty_c = 0;
float Ua = 0, Ub = 0, Uc = 0;
float velocity_open_loop(void);
float angle_control(void);
float angle_control_with_velocity_limit(void);
float velocity_control(void);
float current_control(void);
void update_power(void);
void DFOC_alignSensor(int _PP);
void shut_down(void);
void resume(void);
void drv_stop(void);
float drv_hold(void);
PIDController vel_loop = PIDController{
vel_loop_p * 100, 0.20f, 5e-5, 1000000, voltage_power_supply}; // 12V
PIDController angle_loop =
PIDController{angle_loop_p * 100, 100.0f, 0.2f, 10000000,
voltage_power_supply}; // 12V
PIDController current_loop = PIDController{
current_loop_p * 100, 5e-7f, 7e-8, 500, 24}; // 12V
PIDController vel_inVelAngloop = PIDController{
vel_angloop_p * 100, 3.0f, 5e-4, 1000000, voltage_power_supply};
PIDController ang_inVelAngloop =
PIDController{ang_angloop_p * 100, 0.0f, 5e-4, 1000000, 999};
void update_pid_limits() {
vel_loop.limit = voltage_power_supply;
angle_loop.limit = voltage_power_supply;
current_loop.limit = voltage_power_supply;
vel_inVelAngloop.limit = voltage_power_supply;
}
protected:
float shaft_angle = 0;
float Ualpha, Ubeta = 0;
float zero_electric_angle = 0;
float v_half = voltage_power_supply * 0.5f; // 电源电压的一半
void setPhaseVoltage(float Uq, float Ud);
float cal_Iq_Id(float current_a, float current_b, float current_c);
};
// 定义函数指针类型
typedef float (FOC_Controlroller::*FOCFunctionPtr)(void);
inline float _normalizeAngle(float angle);
inline float _electricalAngle();
#endif
+17 -72
View File
@@ -1,14 +1,15 @@
#include "Filter.h"
#include "Can.h"
#include "ang_sensor.h"
#include "gd32c10x_can.h"
#include "config.h"
#include <algorithm>
#include <cstring>
#include <stdint.h>
extern angle_sensor KTH7823;
extern CAN_transmiter CAN0_transmiter;
constexpr u8 SIZE_FLOAT = sizeof(float);
extern u32 motor_runtime_50us;
EncoderAngleKalman Angle_kalman(0, 1.0f, 1e-4f, 0.25f);
EncoderVelocityKalman Vel_kalman(0, 1e-5f, 1e-6f, 0.02f);
/*!
\brief 中值滤波器函数
@@ -28,57 +29,6 @@ float medium_filter(float values[], u8 size) {
return sorted[size / 2]; // 返回中值
}
// CurrentKalman类的实现
/*!
\brief 构造函数,初始化卡尔曼滤波器参数
\param[in] initial_current 初始电流值
\param[in] L 电机电感(H) 0.0026H
\param[in] R 电机电阻(Ω) 4.8 Ω
\param[in] T 控制周期(s) 1e -4
\param[in] Q 过程噪声协方差(典型值: 1e-6 ~ 1e-4)
\param[in] R_noise 测量噪声协方差(典型值: 电流范围的0.5%~2%)
\retval none
*/
CurrentKalman::CurrentKalman(float initial_current, float L, float R, float T,
float Q, float R_noise)
: kalman(initial_current, 1.0f, Q, R_noise), L(L), R_m(R), T(T) {}
/*!
\brief 更新卡尔曼滤波器状态
\param[in] measured_value 测量值
\param[in] applied_voltage 应用电压值
\retval 估计的电流值
\note 实现卡尔曼滤波的预测和更新步骤
*/
float CurrentKalman::update(float measured_value, float applied_voltage) {
// 1. 预测步骤 - 基于电机模型
float predicted_current = kalman.getState() + T * (applied_voltage - R_m * kalman.getState()) / L;
// 2. 预测误差协方差已经在kalman.predict中处理
// 3. 执行预测
kalman.predict(predicted_current);
// 4. 更新步骤 - 直接使用测量值更新
return kalman.update(measured_value);
}
/*!
\brief 获取当前电流估计值
\retval 当前电流估计值
*/
float CurrentKalman::getCurrent() const { return kalman.getState(); }
/*!
\brief 设置过程噪声协方差
\param[in] q 过程噪声协方差值
\retval none
*/
void CurrentKalman::setProcessNoise(float q) { kalman.setProcessNoise(q); }
/*!
\brief 设置测量噪声协方差
\param[in] r 测量噪声协方差值
\retval none
*/
void CurrentKalman::setMeasurementNoise(float r) { kalman.setMeasurementNoise(r); }
// EncoderVelocityKalman类的实现
/*!
\brief 构造函数,初始化编码器速度卡尔曼滤波器参数
@@ -109,7 +59,7 @@ float EncoderVelocityKalman::update(float measured_velocity) {
/*!
\brief 获取当前速度估计值
\retval 当前速度估计值 (rad/s)
\retval 当前速度估计值 (deg/s)
*/
float EncoderVelocityKalman::getVelocity() const { return kalman.getState(); }
@@ -148,24 +98,20 @@ EncoderAngleKalman::EncoderAngleKalman(float initial_angle,
measurement_noise),
last_angle(initial_angle), initialized(true) {}
/*!
\brief 更新卡尔曼滤波器状态
\param[in] measured_angle 测量的角度值 (degree)
\retval 估计的角度值 (degree)
\note 实现卡尔曼滤波的预测和更新步骤,处理角度环绕问题
\note 实现卡尔曼滤波的预测和更新步骤
*/
float EncoderAngleKalman::update(float measured_angle) {
// 更新last_angle以保持同步
// 更新last_angle以支持速度计算
last_angle = kalman.getState();
// 1. 预测步骤 - 假设角度符合随机游走模型(角速度为0)
// 由于角度变化相对缓慢,我们可以简单预测角度保持不变
kalman.predict(kalman.getState());
// 1. 预测步骤 - 速度估计
kalman.predict(last_angle);
// 2. 更新步骤 - 使用处理后的角度值更新
float filtered_angle = kalman.update(measured_angle);
return filtered_angle;
}
@@ -178,21 +124,20 @@ float EncoderAngleKalman::getAngle() const { return kalman.getState(); }
\brief 获取当前角度估计值
\retval 当前角度估计值 (degree)
*/
float EncoderAngleKalman::getVelocity() const { return (kalman.getState()-last_angle)*1e4; }
/*!
\brief 获取前一个角度估计值
\retval 前一个角度估计值 (degree)
*/
float EncoderAngleKalman::getlastAngle() const { return last_angle; }
float EncoderAngleKalman::getVelocity() const {
static u32 last_us50_counter = motor_runtime_50us;
float vel = (kalman.getState() - last_angle) * TIMER2_FREQUENCY *
(motor_runtime_50us - last_us50_counter);
last_us50_counter = motor_runtime_50us;
return vel;
}
/*!
\brief 设置过程噪声协方差
\param[in] q 过程噪声协方差值
\retval none
*/
void EncoderAngleKalman::setProcessNoise(float q) {
kalman.setProcessNoise(q);
}
void EncoderAngleKalman::setProcessNoise(float q) { kalman.setProcessNoise(q); }
/*!
\brief 设置测量噪声协方差
+15 -38
View File
@@ -1,7 +1,6 @@
#ifndef _FILTER_H
#define _FILTER_H
#include <cstdio>
#ifdef __cplusplus
extern "C" {
#endif
@@ -14,9 +13,8 @@ extern "C" {
#endif
#ifdef __cplusplus
#include <array>
#include <cstring>
#include <stdint.h>
#include <cstdint>
float medium_filter(float values[], u8 size);
@@ -26,12 +24,12 @@ float medium_filter(float values[], u8 size);
*/
template <typename T> class KalmanFilter {
private:
T x; // 状态估计
T P; // 估计误差协方差
T Q; // 过程噪声协方差
T R; // 测量噪声协方差
public:
T x; // 状态估计
/*!
\brief 构造函数
\param[in] initial_state 初始状态值
@@ -105,35 +103,6 @@ template <typename T> class KalmanFilter {
void setMeasurementNoise(T measurement_noise) { R = measurement_noise; }
};
/*!
\brief 电流卡尔曼滤波器类
\note 基于电机模型的卡尔曼滤波器实现,用于电流状态估计
\note
// 创建卡尔曼滤波器实例
CurrentKalman kalman(0.0f, 0.0026f, 4.8f, 0.02f, 1e-6f, 0.02f);
// 更新滤波器状态并获取估计值
float estimatedCurrent = kalman.update(measuredCurrent, appliedVoltage);
*/
class CurrentKalman {
private:
KalmanFilter<float> kalman;
float L; // 电机电感(H)
float R_m; // 电机电阻(Ω)
float T; // 控制周期(s)
public:
CurrentKalman(float initial_current, float L, float R, float T, float Q,
float R_noise);
float update(float measured_current, float applied_voltage);
float getCurrent() const;
void setProcessNoise(float q);
void setMeasurementNoise(float r);
};
/*!
\brief 编码器速度卡尔曼滤波器类
\note 用于滤除编码器速度测量噪声的卡尔曼滤波器实现
@@ -154,6 +123,11 @@ class EncoderVelocityKalman {
void setProcessNoise(float q);
void setMeasurementNoise(float r);
u8 init(float init_velocity) {
kalman.x = init_velocity;
return 0;
}
};
/*!
@@ -161,25 +135,28 @@ class EncoderVelocityKalman {
\note 用于滤除编码器角度测量噪声的卡尔曼滤波器实现
*/
class EncoderAngleKalman {
private:
private:
KalmanFilter<float> kalman;
float last_angle;
bool initialized;
float last_angle;
public:
public:
EncoderAngleKalman(float initial_angle, float initial_error_covariance,
float process_noise, float measurement_noise);
float update(float measured_angle);
float getAngle() const;
float getlastAngle() const;
float getVelocity() const;
void setProcessNoise(float q);
float getstate() const { return kalman.getState(); };
void setMeasurementNoise(float r);
u8 init(float init_angle) {
kalman.x = init_angle;
return 0;
}
};
#endif // __cplusplus
+22 -11
View File
@@ -2,7 +2,8 @@
#define _constrain(amt, low, high) \
((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
#include "Can.h"
#include "math.h"
#include <algorithm>
#include <cmath>
extern CAN_transmiter CAN0_transmiter;
constexpr float TIME_SLICE = 1e-4;
@@ -18,25 +19,27 @@ PIDController::PIDController(float P, float I, float D, float ramp, float limit)
float PIDController::operator()(float error) {
// P环
float proportional = P * error;
// Tustin 散点积分(I环)
// 添加积分限幅,防止积分饱和
float integral = integral_prev + I * TIME_SLICE * 0.5f * (error + error_prev);
float integral =
integral_prev + I * TIME_SLICE * 0.5f * (error + error_prev);
integral = _constrain(integral, -limit, limit);
// D环(微分环节)
float derivative = D * (error - error_prev) / TIME_SLICE;
// 将P,I,D三环的计算值加起来
float output = proportional + integral + derivative;
output = _constrain(output, -limit, limit);
// 输出斜坡限制
// 简化的斜坡限制(单行逻辑)
if (output_ramp > 0) {
float max_delta = output_ramp * TIME_SLICE;
output = output_prev + fmaxf(-max_delta, fminf(max_delta, output - output_prev));
}
// 简化的斜坡限制(单行逻辑)
if (output_ramp > 0) {
float max_delta = output_ramp * TIME_SLICE;
output = output_prev +
fmaxf(-max_delta, fminf(max_delta, output - output_prev));
}
// 保存值(为了下一次循环)
integral_prev = integral;
output_prev = output;
@@ -57,4 +60,12 @@ void PIDController::set_PID(float P, float I, float D) {
this->P = P;
this->I = I;
this->D = D;
}
}
/**
* @brief 设置P参数
*
* @param P: P参数
* @return void
*/
void PIDController::set_P_percent(float pp) { this->P = pp; }
+25
View File
@@ -0,0 +1,25 @@
#ifndef PID_H
#define PID_H
class PIDController {
public:
PIDController(float P, float I, float D, float ramp, float limit);
~PIDController() = default;
float operator()(float error);
void set_PID(float P, float I, float D);
void set_P_percent(float pp);
float P; //!< 比例增益(P环增益)
float I; //!< 积分增益(I环增益)
float D; //!< 微分增益(D环增益)
float output_ramp;
float limit;
protected:
float error_prev; //!< 最后的跟踪误差值
float output_prev; //!< 最后一个 pid 输出值
float integral_prev; //!< 最后一个积分分量值
unsigned long timestamp_prev; //!< 上次执行时间戳
};
#endif
@@ -32,7 +32,8 @@
LR_ROM0 __ROM0_BASE __ROM0_SIZE {
ER_ROM0 __ROM0_BASE __ROM0_SIZE {
*.o (RESET, +First)
*.o (RESET, +First) /* 向量表和复位处理程序 */
*(.text.init) /* 确保系统初始化代码在最前面 */
*(InRoot$$Sections)
*(+RO +XO)
}
@@ -33,6 +33,7 @@ OF SUCH DAMAGE.
*/
#include "gd32c10x_fmc.h"
#include "stdio.h"
/* FMC mask */
#define LOW_8BITS_MASK ((uint32_t)0x000000FFU)
@@ -988,7 +989,7 @@ void fmc_interrupt_flag_clear(uint32_t flag)
static fmc_state_enum fmc_state_get(void)
{
fmc_state_enum fmc_state = FMC_READY;
if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_BUSY)){
fmc_state = FMC_BUSY;
}else{
@@ -14,10 +14,10 @@
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region. Default: 0x08000000
// <i> Contains Startup and Vector Table
#define __ROM0_BASE 0x08000000
#define __ROM0_BASE 0x08012000
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region. Default: 0x00020000
#define __ROM0_SIZE 0x00020000
#define __ROM0_SIZE 0x0000C000
// </h>
// <h> __ROM1 (unused)
@@ -42,7 +42,8 @@
#define __SYS_OSC_CLK (__IRC8M) /* main oscillator frequency */
/* Vector Table base offset */
#define VECT_TAB_OFFSET 0x00 /* This value must be a multiple of 0x200. */
#define APP_BASE ((uint32_t)0x08012000U) /*!< main FLASH base address */
#define VECT_TAB_OFFSET (uint32_t)APP_BASE-FLASH_BASE /* This value must be a multiple of 0x200. */
/* select a system clock by uncommenting the following line */
/* use IRC8M */
@@ -1,6 +1,6 @@
/*
* CSOLUTION generated file: DO NOT EDIT!
* Generated by: csolution version 2.11.0
* Generated by: csolution version 2.12.0+p41-gfeadfc5e
*
* Project: 'Robot_V2.Debug+GD32C103CB'
* Target: 'Debug+GD32C103CB'
@@ -17,8 +17,12 @@
/* GigaDevice::Device:GD32C10x_StdPeripherals:ADC@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_ADC
/* GigaDevice::Device:GD32C10x_StdPeripherals:BKP@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_BKP
/* GigaDevice::Device:GD32C10x_StdPeripherals:CAN@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_CAN
/* GigaDevice::Device:GD32C10x_StdPeripherals:CRC@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_CRC
/* GigaDevice::Device:GD32C10x_StdPeripherals:DBG@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_DBG
/* GigaDevice::Device:GD32C10x_StdPeripherals:DMA@1.0.0 */
@@ -37,6 +41,8 @@
#define RTE_DEVICE_STDPERIPHERALS_PMU
/* GigaDevice::Device:GD32C10x_StdPeripherals:RCU@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_RCU
/* GigaDevice::Device:GD32C10x_StdPeripherals:RTC@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_RTC
/* GigaDevice::Device:GD32C10x_StdPeripherals:SPI_I2S@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_SPI
/* GigaDevice::Device:GD32C10x_StdPeripherals:TIMER@1.0.0 */
@@ -1,6 +1,6 @@
/*
* CSOLUTION generated file: DO NOT EDIT!
* Generated by: csolution version 2.11.0
* Generated by: csolution version 2.12.0+p41-gfeadfc5e
*
* Project: 'Robot_V2.Release+GD32C103CB'
* Target: 'Release+GD32C103CB'
@@ -17,8 +17,12 @@
/* GigaDevice::Device:GD32C10x_StdPeripherals:ADC@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_ADC
/* GigaDevice::Device:GD32C10x_StdPeripherals:BKP@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_BKP
/* GigaDevice::Device:GD32C10x_StdPeripherals:CAN@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_CAN
/* GigaDevice::Device:GD32C10x_StdPeripherals:CRC@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_CRC
/* GigaDevice::Device:GD32C10x_StdPeripherals:DBG@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_DBG
/* GigaDevice::Device:GD32C10x_StdPeripherals:DMA@1.0.0 */
@@ -37,6 +41,8 @@
#define RTE_DEVICE_STDPERIPHERALS_PMU
/* GigaDevice::Device:GD32C10x_StdPeripherals:RCU@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_RCU
/* GigaDevice::Device:GD32C10x_StdPeripherals:RTC@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_RTC
/* GigaDevice::Device:GD32C10x_StdPeripherals:SPI_I2S@1.0.0 */
#define RTE_DEVICE_STDPERIPHERALS_SPI
/* GigaDevice::Device:GD32C10x_StdPeripherals:TIMER@1.0.0 */
+23 -8
View File
@@ -12,6 +12,9 @@ project:
- file: sys/initial.h
- file: sys/health.h
- file: sys/health.cpp
- file: sys/flash.h
- file: sys/flash.cpp
- file: sys/config.h
- group: device
files:
- file: device/Can.cpp
@@ -23,22 +26,26 @@ project:
- file: device/Timer.cpp
- file: device/Timer.h
- file: device/test.cpp
- file: device/motor.cpp
- file: device/motor.h
- group: Algorithm
files:
- file: Algorithm/Filter.cpp
- file: Algorithm/Filter.h
- file: Algorithm/DengFOC.cpp
- file: Algorithm/DengFOC.h
- file: Algorithm/FOC.cpp
- file: Algorithm/FOC.h
- file: Algorithm/pid.cpp
- file: pid.h
- file: Algorithm/pid.h
components:
- component: ARM::CMSIS:CORE
- component: Device:Startup
- component: Device:EVAL:GD32C10x
- component: Device:GD32C10x_libopt
- component: Device:GD32C10x_StdPeripherals:FMC
- component: Device:GD32C10x_StdPeripherals:ADC
- component: Device:GD32C10x_StdPeripherals:CAN
- component: Device:GD32C10x_StdPeripherals:DMA
- component: Device:GD32C10x_StdPeripherals:EXTI
- component: Device:GD32C10x_StdPeripherals:FMC
- component: Device:GD32C10x_StdPeripherals:GPIO
- component: Device:GD32C10x_StdPeripherals:MISC
- component: Device:GD32C10x_StdPeripherals:PMU
@@ -46,15 +53,18 @@ project:
- component: Device:GD32C10x_StdPeripherals:SPI_I2S
- component: Device:GD32C10x_StdPeripherals:TIMER
- component: Device:GD32C10x_StdPeripherals:USART
- component: Device:GD32C10x_libopt
- component: Device:GD32C10x_StdPeripherals:DBG
- component: Device:EVAL:GD32C10x
- component: Device:GD32C10x_StdPeripherals:FWDGT
- component: Device:GD32C10x_StdPeripherals:WWDGT
- component: Device:GD32C10x_StdPeripherals:BKP
- component: Device:GD32C10x_StdPeripherals:CRC
- component: Device:GD32C10x_StdPeripherals:RTC
- component: CMSIS:DSP
output:
type:
- elf
- hex
- bin
- map
packs:
- pack: ARM::CMSIS
@@ -66,11 +76,16 @@ project:
- -fshort-wchar
- -D__MICROLIB
- -Wno-register
- -O3 # 添加优化级别
- -DARM_MATH_CM4 # Cortex-M4核心定义
C:
- -D__packed=packed
- -D__packed=__attribute__((packed))
ASM:
- -D__packed=packed
- -D__packed=__attribute__((packed))
- -D__MICROLIB
Link:
- --library_type=microlib
- --entry=Reset_Handler
- --remove # 移除未使用的代码段
- --diag_suppress=L6207,L6210,L6218,L6220,L6222,L6224,L6226,L6228,L6230,L6232,L6234,L6236,L6238,L6240,L6242,L6244,L6246,L6248,L6308,L6329,L6310,L6312,L6314,L6316,L6318,L6320,L6322,L6324,L6326,L6328,L6330,L6332,L6334,L6336,L6338,L6340,L6342,L6344,L6346,L6348,L6350,L6352,L6354,L6311,L6313,L6315,L6317,L6319,L6321,L6323,L6325,L6327,L6329,L6331,L6333,L6335,L6337,L6339,L6341,L6343,L6345,L6347,L6349,L6351,L6353
# 移除了 __TARGET_FPU_VFP,因为它不是链接器参数
+33 -28
View File
@@ -1,27 +1,22 @@
#include "adc.h"
#include "Can.h"
#include "FOC.h"
#include "Filter.h"
#include "config.h"
#include "math.h"
#include "systick.h"
#include <cstring>
#include <gd32c10x_dma.h>
#include <stdint.h>
#include <cstdint>
constexpr float ERROR_ADC_VAL = 255.0f;
constexpr float ADC_SCALE = 3.3f / 4096.0f;
constexpr float TEMP_FACTOR = 1000.0f / 4.3f;
constexpr float VCC_FACTOR = 11.0f;
constexpr float CURRENT_OFFSET = -1.60f;
constexpr float CURRENT_FACTOR =
1.0f / 50.0f * 100.0f; // 50倍放大,100倍电流采样电阻, 单位mA
constexpr float MAX_TEMP = 150.0f;
constexpr float MIN_TEMP = -40.0f;
constexpr float MAX_CURRENT = 40.0f;
constexpr float MIN_CURRENT = -40.0f;
constexpr float MAX_VCC = 65.0f;
constexpr float MIN_VCC = -0.1f;
extern CAN_transmiter CAN0_transmiter;
sampler sampler; // 采样器初始化
extern FOC_Controlroller FOC;
sampler sampler; // 采样器初始化
u16 adc_value[6] = {0}; // 显式初始化数组元素为0
/*!
\brief configure the DMA peripheral
@@ -109,11 +104,12 @@ void adc_config(void) {
/**
* @brief 采样类初始化
*/
sampler::sampler() {
u8 sampler::init() {
dma_config(); // DMA采样ADC初始化
adc_config(); // ADC初始化
delay_1ms(1);
// 初始采样
for (int i = 0; i < FILTER_SIZE + 1; i++) {
for (int i = 0; i < ADC_FILTER_SIZE + 1; i++) {
mcu_temp_samples[i] =
(1.43f - adc_value[0] * ADC_SCALE) * TEMP_FACTOR + 35.0f;
@@ -129,7 +125,9 @@ sampler::sampler() {
float R_now = (float)adc_value[1] / (4096 - (float)adc_value[1]) * 4700;
drv_temp_samples[i] =
1.0f / (0.00335f + 0.00025f * log(R_now / 10000.0f)) - 273.15f;
delay_1ms(1);
}
return 0;
}
/**
* @brief 获取MCU温度
@@ -137,7 +135,7 @@ sampler::sampler() {
* 温度值,单位为摄氏度,范围应在-40到145之间,如果读取失败则返回0.0f
*/
float sampler::get_mcu_temp() {
tempora_sample = medium_filter(mcu_temp_samples, FILTER_SIZE + 1);
tempora_sample = medium_filter(mcu_temp_samples, ADC_FILTER_SIZE + 1);
// 检查温度读数是否在有效范围内
if (tempora_sample < MIN_TEMP or tempora_sample > MAX_TEMP) {
return ERROR_ADC_VAL;
@@ -153,7 +151,7 @@ float sampler::get_mcu_temp() {
* 如果计算结果超出有效范围(-40到255摄氏度),则重新采样计算。
*/
float sampler::get_drv_temp() {
tempora_sample = medium_filter(drv_temp_samples, FILTER_SIZE + 1);
tempora_sample = medium_filter(drv_temp_samples, ADC_FILTER_SIZE + 1);
// 检查温度读数是否在有效范围内
if (tempora_sample < MIN_TEMP || tempora_sample > MAX_TEMP) {
return ERROR_ADC_VAL;
@@ -171,15 +169,18 @@ float sampler::get_drv_temp() {
float sampler::get_current(char type) {
switch (type) {
case 'U': {
tempora_sample = medium_filter(currU_samples, FILTER_SIZE + 1);
// return currU_samples[current_sample_index];
tempora_sample = medium_filter(currU_samples, ADC_FILTER_SIZE + 1);
break;
}
case 'V': {
tempora_sample = medium_filter(currV_samples, FILTER_SIZE + 1);
// return currV_samples[current_sample_index];
tempora_sample = medium_filter(currV_samples, ADC_FILTER_SIZE + 1);
break;
}
case 'W': {
tempora_sample = medium_filter(currW_samples, FILTER_SIZE + 1);
// return currW_samples[current_sample_index];
tempora_sample = medium_filter(currW_samples, ADC_FILTER_SIZE + 1);
break;
}
default: {
@@ -189,6 +190,7 @@ float sampler::get_current(char type) {
if (tempora_sample < MIN_CURRENT or tempora_sample > MAX_CURRENT) {
return ERROR_ADC_VAL;
}
return tempora_sample;
}
@@ -200,10 +202,10 @@ float sampler::get_current(char type) {
* 如果计算结果超出有效范围(-40到255伏特),则重新采样计算。
*/
float sampler::get_vbus_voltage() {
tempora_sample = medium_filter(vbus_samples, FILTER_SIZE + 1);
tempora_sample = medium_filter(vbus_samples, ADC_FILTER_SIZE + 1);
// 检查电压读数是否在有效范围内
if (vbus_samples[FILTER_SIZE / 2] > MAX_VCC or
vbus_samples[FILTER_SIZE / 2] < MIN_VCC) {
if (vbus_samples[ADC_FILTER_SIZE / 2] > MAX_VCC or
vbus_samples[ADC_FILTER_SIZE / 2] < MIN_VCC) {
return ERROR_ADC_VAL;
}
return tempora_sample;
@@ -217,8 +219,8 @@ float sampler::get_vbus_voltage() {
*/
void sampler::update_mcu_temp() {
memmove(mcu_temp_samples, mcu_temp_samples + 1,
FILTER_SIZE * sizeof(float));
mcu_temp_samples[FILTER_SIZE] =
ADC_FILTER_SIZE * sizeof(float));
mcu_temp_samples[ADC_FILTER_SIZE] =
(1.43f - adc_value[0] * ADC_SCALE) * TEMP_FACTOR + 35.0f;
}
@@ -227,9 +229,9 @@ void sampler::update_mcu_temp() {
*/
void sampler::update_drv_temp() {
memmove(drv_temp_samples, drv_temp_samples + 1,
FILTER_SIZE * sizeof(float));
ADC_FILTER_SIZE * sizeof(float));
float R_now = (float)adc_value[1] / (4096 - (float)adc_value[1]) * 4700;
drv_temp_samples[FILTER_SIZE] =
drv_temp_samples[ADC_FILTER_SIZE] =
1.0f / (0.00335f + 0.00025f * log(R_now / 10000.0f)) - 273.15f;
}
@@ -238,6 +240,7 @@ void sampler::update_drv_temp() {
*/
void sampler::update_current() {
u8 idx = current_sample_index;
extern FOC_Controlroller FOC;
// 优化计算
const float scale = ADC_SCALE * CURRENT_FACTOR;
const float offset = CURRENT_OFFSET * CURRENT_FACTOR;
@@ -248,15 +251,17 @@ void sampler::update_current() {
// 更新索引
current_sample_index++;
if (current_sample_index >= FILTER_SIZE - 1) {
if (current_sample_index >= ADC_FILTER_SIZE - 1) {
current_sample_index = 0;
}
// 卡尔曼滤波更新
float voltage = FOC.voltage_power_supply;
}
/**
* @brief 更新供电电压
*/
void sampler::update_vbus_voltage() {
memmove(vbus_samples, vbus_samples + 1, FILTER_SIZE * sizeof(float));
vbus_samples[FILTER_SIZE] = adc_value[5] * ADC_SCALE * VCC_FACTOR;
memmove(vbus_samples, vbus_samples + 1, ADC_FILTER_SIZE * sizeof(float));
vbus_samples[ADC_FILTER_SIZE] = adc_value[5] * ADC_SCALE * VCC_FACTOR;
}
+302 -174
View File
@@ -1,31 +1,33 @@
#include "Can.h"
#include "DengFOC.h"
#include "FOC.h"
#include "Filter.h"
#include "adc.h"
#include "ang_sensor.h"
#include "config.h"
#include "flash.h"
#include "gd32c10x.h"
#include "gd32c10x_can.h"
#include "gd32c10x_dma.h"
#include "gd32c10x_fmc.h"
#include "gd32c10x_gpio.h"
#include "initial.h"
#include "motor.h"
#include "systick.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <random>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
constexpr u16 CANX = CAN0;
constexpr u16 DEV_CAN0_ID = 0x0000;
constexpr u16 DEV_CAN0_MASK = 0x0000;
constexpr u16 DEV_CAN_LOOPBACK_ID = 0x0000;
constexpr float ANGLE_FACTOR = 25.0f / 360.0f * 2.0f * 3.14159265358979323846f;
CAN_transmiter CAN0_transmiter; // CAN初始化
CAN_transmiter CAN0_transmiter; // CAN初始化
extern FOC_Controlroller FOC;
extern sampler sampler;
extern angle_sensor KTH7823;
extern EncoderVelocityKalman Vel_kalman;
extern EncoderAngleKalman Angle_kalman; // 角度滤波
extern EncoderVelocityKalman Vel_kalman; // 速度滤波
extern FlashEEPROM flashEEP;
extern VersionManager Version; // 声明外部版本管理器实例
// 添加DMA相关变量
dma_parameter_struct dma_rx_parameter;
@@ -50,8 +52,10 @@ u8 can_gpio_init() {
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); // tx
gpio_pin_remap_config(GPIO_CAN0_PARTIAL_REMAP, ENABLE);
/* enable the EN GPIO clock */
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ,
GPIO_PIN_13 | GPIO_PIN_14);
gpio_bit_reset(GPIOB, GPIO_PIN_13);
gpio_bit_reset(GPIOB, GPIO_PIN_14);
return 0;
}
@@ -152,8 +156,11 @@ void can_config(void) {
/* configure CAN0 NVIC */
nvic_irq_enable(CAN0_RX0_IRQn, 1, 0);
nvic_irq_enable(CAN0_TX_IRQn, 1, 1); // 添加发送中断
/* enable can receive FIFO0 not empty interrupt */
can_interrupt_enable(CAN0, CAN_INTEN_RFNEIE0);
/* enable can transmit mailbox empty interrupt */
can_interrupt_enable(CAN0, CAN_INTEN_TMEIE);
// 使能DMA中断
nvic_irq_enable(DMA0_Channel4_IRQn, 1, 1);
@@ -168,6 +175,7 @@ void can_config(void) {
*/
void canfd_config(void) {
can_gpio_init();
can_dma_init(); // 初始化DMA
can_parameter_struct can_parameter;
can_fdframe_struct can_fd_parameter;
can_fd_tdc_struct can_fd_tdc_parameter;
@@ -230,6 +238,9 @@ void canfd_config(void) {
nvic_irq_enable(CAN0_RX0_IRQn, 1, 0);
/* enable can receive FIFO0 not empty interrupt */
can_interrupt_enable(CAN0, CAN_INTEN_RFNEIE0);
// 使能DMA中断
nvic_irq_enable(DMA0_Channel4_IRQn, 1, 1);
dma_interrupt_enable(DMA0, DMA_CH4, DMA_INT_FTF);
}
/*!
@@ -260,7 +271,7 @@ void can_loopback_init(void) {
can_parameter.prescaler = 6;
if (can_init(CANX, &can_parameter) != SUCCESS) {
u16 i = 200;
while (--i>0){
while (--i > 0) {
delay_1ms(10);
printf("can init error \r\n");
}
@@ -413,7 +424,7 @@ void can_loopback_test(void) {
\brief CAN_transmiter构造函数
\note 初始化CAN通信相关参数和硬件配置
*/
CAN_transmiter::CAN_transmiter() {
u8 CAN_transmiter::init() {
// 初始化CAN硬件
// can_config();
canfd_config();
@@ -426,145 +437,32 @@ CAN_transmiter::CAN_transmiter() {
// 初始化DMA缓冲区
memset(can_rx_buffer, 0, sizeof(can_rx_buffer));
memset(can_tx_buffer, 0, sizeof(can_tx_buffer));
return 0;
}
/*!
\brief CAN 数据更新
*/
void CAN_transmiter::update(void) {
target_angle_union.f = FOC.target_angle;
target_velocity_union.f = FOC.target_velocity;
target_current_union.f = FOC.target_current;
limit_velocity_union.f = FOC.limit_velocity;
limit_voltage = FOC.limit_voltage * 1000;
mcu_temp = sampler.get_mcu_temp() * 100;
motor_temp = sampler.get_drv_temp() * 100;
Power_Voltage = sampler.get_vbus_voltage() * 1000;
rt_angle_union.f = FOC.rt_angle;
// rt_velocity_union.f = KTH7823.getVelocity();
rt_velocity_union.f = FOC.rt_velocity;
MotorStatus = (gpio_input_bit_get(GPIOB, GPIO_PIN_2) == SET) ? 0 : 1;
MotorStatus = gpio_input_bit_get(GPIOB, GPIO_PIN_2) == RESET;
EEPROMStatus = flashEEP.EEPROMStatus;
Target_Control_Mode = FOC.control_mode;
controller_Mode = FOC.control_mode;
// 使用简单平均滤波的电流值
u_current_union.f = sampler.get_current('U') * 1000;
w_current_union.f = sampler.get_current('W') * 1000;
v_current_union.f = sampler.get_current('V') * 1000;
// testfloat_union.f = KTH7823.getVelocity();
}
/*!
\brief CAN 数据发送
\param id CAN ID
\param length 数据长度
\param data 数据
*/
u8 CAN_transmiter::CAN_Send(u32 id, u8 length, u8 *data) {
// 检查数据长度是否符合CAN规范
if (length > 8) {
printf("CAN data length exceeds maximum of 8 bytes\r\n");
return 0;
}
// 检查数据指针是否有效
if (data == nullptr) {
printf("Invalid data pointer\r\n");
return 0;
}
/* 配置发送消息参数 */
transmit_message.tx_ft = CAN_FT_DATA; // 数据帧
transmit_message.tx_ff = CAN_FF_STANDARD; // 标准帧格式
transmit_message.tx_sfid = id; // 设置帧ID
transmit_message.tx_dlen = length; // 设置数据长度
// 复制数据到发送缓冲区
for (int i = 0; i < length && i < 8; i++) {
transmit_message.tx_data[i] = *(data + i);
}
// 将数据复制到DMA缓冲区
memcpy(can_tx_buffer, data, length);
// 配置DMA发送参数
dma_tx_parameter.number = length;
dma_init(DMA0, DMA_CH5, &dma_tx_parameter);
// 启动DMA传输
dma_channel_enable(DMA0, DMA_CH5);
// 自动选择空闲mailbox发送消息,不需要人为指定
transmit_mailbox = can_message_transmit(CAN0, &transmit_message);
// 检查是否成功获取mailbox
if (CAN_NOMAILBOX == transmit_mailbox) {
// 没有可用的mailbox,可能所有mailbox都在使用中
printf("No available mailbox for CAN transmission\r\n");
return 0;
}
return 1;
}
/*!
\brief CANFD 数据发送
\param id CAN消息ID
\param length CAN消息长度
\param data CAN消息数据
*/
u8 CAN_transmiter::CANFD_Send(u32 id, u8 length, u8 *data) {
// 检查CANFD模式是否启用
if (!(CAN_CTL(CAN0) & CAN_CTL_DFZ)) {
printf("CANFD mode not enabled\r\n");
return 0;
}
// 检查数据指针是否有效
if (data == nullptr) {
printf("Invalid data pointer\r\n");
return 0;
}
// 检查数据长度是否符合CANFD规范
if (length > 64) {
printf("CANFD data length exceeds maximum of 64 bytes\r\n");
return 0;
}
/* 配置发送消息参数 */
transmit_message.tx_ft = CAN_FT_DATA; // 数据帧
transmit_message.tx_ff = CAN_FF_EXTENDED; // 扩展帧格式
// transmit_message.tx_sfid = id; // 设置帧ID
transmit_message.tx_efid = id; // 扩展帧ID
transmit_message.tx_dlen = length; // 设置数据长度
// 设置CANFD特定参数
transmit_message.fd_flag = CAN_FDF_FDFRAME; // CANFD帧格式
transmit_message.fd_brs = ENABLE; // 使能比特率切换
transmit_message.fd_esi = DISABLE; // 错误状态指示
// 复制数据到发送缓冲区
for (int i = 0; i < length && i < 64; i++) {
transmit_message.tx_data[i] = *(data + i);
}
// 将数据复制到DMA缓冲区
memcpy(can_tx_buffer, data, length);
// 配置DMA发送参数
dma_tx_parameter.number = length;
dma_init(DMA0, DMA_CH5, &dma_tx_parameter);
// 启动DMA传输
dma_channel_enable(DMA0, DMA_CH5);
// 自动选择空闲mailbox发送消息,不需要人为指定
transmit_mailbox = can_message_transmit(CAN0, &transmit_message);
// 检查是否成功获取mailbox
if (CAN_NOMAILBOX == transmit_mailbox) {
// 没有可用的mailbox,可能所有mailbox都在使用中
printf("No available mailbox for CANFD transmission\r\n");
return 0;
}
return 1;
}
/**
@@ -581,31 +479,39 @@ u8 CAN_transmiter::CAN_all_Send() {
constexpr u32 Status_FEED = 0x118;
constexpr u32 Limit_Vel_Vol_FEED = 0x119;
// 打包RT_Vel_Ang_FEED
// 打包RT_Vel_Ang_FEED - 只清零实际使用的8字节
memset(transmit_data, 0, 8);
pack_float_to_bytes(transmit_data, 0, rt_angle_union);
pack_float_to_bytes(transmit_data, 4, rt_velocity_union);
success_flag += CAN_Send(RT_Vel_Ang_FEED, 8, transmit_data);
// 打包SET_Vel_Ang_FEED
success_flag += CAN_AsyncSend(RT_Vel_Ang_FEED, 8, transmit_data);
// 打包SET_Vel_Ang_FEED - 只清零实际使用的8字节
memset(transmit_data, 0, 8);
pack_float_to_bytes(transmit_data, 0, target_angle_union);
pack_float_to_bytes(transmit_data, 4, target_velocity_union);
success_flag += CAN_Send(SET_Vel_Ang_FEED, 8, transmit_data);
// 打包Current_FEED
success_flag += CAN_AsyncSend(SET_Vel_Ang_FEED, 8, transmit_data);
// 打包Current_FEED - 只清零实际使用的6字节
memset(transmit_data, 0, 6);
pack_u16_to_bytes(transmit_data, 0, u16(u_current_union.f));
pack_u16_to_bytes(transmit_data, 2, u16(w_current_union.f));
pack_u16_to_bytes(transmit_data, 4, u16(v_current_union.f));
success_flag += CAN_Send(Current_FEED, 6, transmit_data);
success_flag += CAN_AsyncSend(Current_FEED, 6, transmit_data);
// 打包Status_FEED
// 打包Status_FEED - 只清零实际使用的8字节
memset(transmit_data, 0, 8);
transmit_data[0] = MotorStatus;
transmit_data[1] = controller_Mode;
pack_u16_to_bytes(transmit_data, 2, motor_temp);
pack_u16_to_bytes(transmit_data, 4, mcu_temp);
pack_u16_to_bytes(transmit_data, 6, Power_Voltage);
success_flag += CAN_Send(Status_FEED, 8, transmit_data);
// 打包Limit_Vel_Vol_FEED
success_flag += CAN_AsyncSend(Status_FEED, 8, transmit_data);
// 打包Limit_Vel_Vol_FEED - 只清零实际使用的6字节
memset(transmit_data, 0, 6);
pack_float_to_bytes(transmit_data, 0, limit_velocity_union);
pack_u16_to_bytes(transmit_data, 4, limit_voltage);
success_flag += CAN_Send(Limit_Vel_Vol_FEED, 6, transmit_data);
success_flag += CAN_AsyncSend(Limit_Vel_Vol_FEED, 6, transmit_data);
return success_flag;
}
@@ -618,32 +524,31 @@ u8 CAN_transmiter::CAN_all_Send() {
u8 CAN_transmiter::CANFD_all_Send() {
u32 success_flag = 0;
constexpr u32 STATUS_ID = 0x18FF0100;
constexpr u32 CONFIG_ID = 0x18FF0101;
// 打包status数据
// 打包status数据 - 只清零实际使用的32字节
memset(transmit_data, 0, 32);
pack_u16_to_bytes(transmit_data, 0, mcu_temp);
pack_u16_to_bytes(transmit_data, 2, motor_temp);
pack_u16_to_bytes(transmit_data, 4, u16(u_current_union.f));
pack_u16_to_bytes(transmit_data, 6, u16(w_current_union.f));
pack_u16_to_bytes(transmit_data, 8, u16(v_current_union.f));
transmit_data[10] = (transmit_data[10] & ~0x07) |
((MotorStatus & 0x01) |
((MagStatus & 0x01) << 1) |
((ThermalStatus & 0x01) << 2));
pack_u16_to_bytes(transmit_data, 6, u16(v_current_union.f));
pack_u16_to_bytes(transmit_data, 8, u16(w_current_union.f));
transmit_data[10] =
(transmit_data[10] & ~0x07) |
((MotorStatus & 0x01) | ((MagStatus & 0x01) << 1) |
((ThermalStatus & 0x01) << 2) | ((EEPROMStatus & 0x07) << 3));
pack_u16_to_bytes(transmit_data, 11, Power_Voltage);
pack_float_to_bytes(transmit_data, 13, rt_angle_union);
pack_float_to_bytes(transmit_data, 17, rt_velocity_union);
pack_float_to_bytes(transmit_data, 21, testfloat_union);
success_flag += CANFD_Send(STATUS_ID, 32, transmit_data);
success_flag += CANFD_AsyncSend(CANFD_STATUS_ID, 32, transmit_data);
// 打包config数据
// 打包config数据 - 只清零实际使用的16字节
memset(transmit_data, 0, 16);
transmit_data[0] = controller_Mode;
pack_u16_to_bytes(transmit_data, 1, limit_voltage);
pack_float_to_bytes(transmit_data, 3, limit_velocity_union);
pack_float_to_bytes(transmit_data, 7, target_angle_union);
pack_float_to_bytes(transmit_data, 11, target_velocity_union);
success_flag += CANFD_Send(CONFIG_ID, 16, transmit_data);
success_flag += CANFD_AsyncSend(CANFD_CONFIG_ID, 16, transmit_data);
return success_flag;
}
@@ -657,9 +562,9 @@ void CAN_transmiter::communication_check() {
// CAN0 发送数据标志
if (SET == can0_send_flag) {
// printf("\r\n can0 %X receive data:", receive_message.rx_efid);
CAN0_transmiter.update();
update();
// CAN0_transmiter.CAN_all_Send();
CAN0_transmiter.CANFD_all_Send();
CANFD_all_Send();
can0_send_flag = RESET;
}
@@ -669,32 +574,114 @@ void CAN_transmiter::communication_check() {
// for (i = 0; i < receive_message.rx_dlen; i++) {
// printf(" %02x", receive_message.rx_data[i]);
// }
if (receive_message.rx_efid == 0x18ff0200) {
if (receive_message.rx_efid == CANFD_CMD_ID) {
// 控制模式
FOC.control_mode = receive_message.rx_data[0];
if (float(unpack_bytes_to_u16(receive_message.rx_data, 1)) / 1000 !=
FOC.limit_voltage) {
FOC.limit_voltage =
float(unpack_bytes_to_u16(receive_message.rx_data, 1)) /
1000;
}
if (unpack_bytes_to_float(receive_message.rx_data, 3).f !=
FOC.limit_velocity) {
FOC.limit_velocity =
unpack_bytes_to_float(receive_message.rx_data, 3).f;
}
// 目标角度
FOC.limit_voltage =
float(unpack_bytes_to_u16(receive_message.rx_data, 1)) / 1000;
// 目标电流&目标速度
FOC.limit_velocity =
unpack_bytes_to_float(receive_message.rx_data, 3).f;
FOC.target_current = FOC.limit_velocity;
// 目标角度
target_angle_union.f =
unpack_bytes_to_float(receive_message.rx_data, 7).f;
FOC.target_angle = target_angle_union.f;
// 目标速度
target_velocity_union.f =
unpack_bytes_to_float(receive_message.rx_data, 11).f;
FOC.target_velocity = target_velocity_union.f;
FOC.target_current = FOC.target_velocity * 10.0f;
can0_receive_flag = RESET;
// 解析PID参数
u16 P_config = unpack_bytes_to_u16(receive_message.rx_data, 15);
float voltage = FOC.limit_voltage;
FOC.current_loop.set_P_percent(current_loop_p * P_config / voltage);
P_config = unpack_bytes_to_u16(receive_message.rx_data, 17);
FOC.vel_loop.set_P_percent(vel_loop_p * P_config / voltage);
P_config = unpack_bytes_to_u16(receive_message.rx_data, 19);
FOC.angle_loop.set_P_percent(angle_loop_p * P_config / voltage);
P_config = unpack_bytes_to_u16(receive_message.rx_data, 21);
FOC.vel_inVelAngloop.set_P_percent(vel_angloop_p * P_config /
voltage);
} else if (receive_message.rx_efid == CANFD_RESET_ID) {
u8 first_byte = receive_message.rx_data[0];
u8 eigth_byte = receive_message.rx_data[7];
// 电机重置
if (first_byte & 0x01) {
motor_reset();
}
// EEPROM重置
if (first_byte >> 1 & 0x01) {
// flashEEP.format();
}
// 系统参数保存
if (first_byte >> 2 & 0x01) {
flashEEP.save_system_config(false);
}
// 角度传感器重置
if (first_byte >> 3 & 0x01) {
KTH7823.angle_set(0);
Angle_kalman.init(0); // 角度滤波
Vel_kalman.init(0); // 角度滤波
}
// 休眠
if (eigth_byte & 0x80 >> 7) {
app_prepare_deep_sleep(true);
// CAN_Sleep();
}
} else if (receive_message.rx_efid == CANFD_VERSION_ID) {
// 处理版本号请求,发送当前系统版本信息
Version.sendVersionInfoViaCan();
} else if (receive_message.rx_efid == CANFD_BOOT_ID) {
flashEEP.save_system_config(false);
fmc_unlock();
OTA_SET(n_APP_LATEST_EN_ADDR, OTA_NOT_AVAL); // 设置APP为不激活
fmc_lock();
jumpToBOOT();
} else if (receive_message.rx_efid == 0x00000102) {
volatile u32 *flash_ptr = (volatile u32 *)n_APP_LATEST_EN_ADDR;
u32 app_enable = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_LATEST_CHECK_ADDR;
u32 app_check = *flash_ptr;
transmit_data[0] = 0x0A;
transmit_data[1] = 0xAC;
delay_1ms(1);
if (app_enable == OTA_AVAL && app_check == OTA_AVAL) {
CANFD_AsyncSend(CANFD_OTA_ACK_ID, 2, transmit_data);
}
} else {
printf("Unknown CAN ID: %X\n", receive_message.rx_efid);
}
can0_receive_flag = RESET;
}
}
/**
* @brief CAN睡眠
* @param None
* @retval None
*/
u8 CAN_transmiter::CAN_Sleep() {
gpio_bit_set(GPIOB, GPIO_PIN_13);
is_sleep = true;
return 0;
}
/**
* @brief CAN唤醒
* @param None
* @retval None
*/
u8 CAN_transmiter::CAN_Wakeup() {
printf("can wake\r\n");
is_sleep = false;
canfd_config();
return 0;
}
/**
* @brief CAN0中断服务程序
* @retval 无
@@ -741,7 +728,6 @@ void DMA0_Channel4_IRQHandler(void) {
if (dma_interrupt_flag_get(DMA0, DMA_CH4, DMA_INT_FLAG_FTF)) {
// 清除DMA传输完成中断标志
dma_interrupt_flag_clear(DMA0, DMA_CH4, DMA_INT_FLAG_G);
// 将DMA缓冲区的数据复制到接收消息结构体
for (int i = 0; i < CAN0_transmiter.receive_message.rx_dlen && i < 8;
i++) {
@@ -756,7 +742,149 @@ void DMA0_Channel4_IRQHandler(void) {
*/
void DMA0_Channel5_IRQHandler(void) {
if (dma_interrupt_flag_get(DMA0, DMA_CH5, DMA_INT_FLAG_FTF)) {
// DMA传输完成,可以在此处执行后续处理
// 清除DMA传输完成中断标志
dma_interrupt_flag_clear(DMA0, DMA_CH5, DMA_INT_FLAG_G);
dma_interrupt_flag_clear(DMA0, DMA_CH5, DMA_INT_FLAG_FTF);
// 可以在此添加后续处理逻辑,如发送下一个数据包等
}
}
/**
* @brief 异步CAN数据发送(使用DMA和中断机制)
* @param id CAN消息ID
* @param length CAN消息长度
* @param data CAN消息数据
*/
u8 CAN_transmiter::CAN_AsyncSend(u32 id, u8 length, u8 *data) {
// 检查数据长度是否符合CAN规范
if (length > 8) {
printf("CAN data length exceeds maximum of 8 bytes\r\n");
return 0;
}
// 检查数据指针是否有效
if (data == nullptr) {
printf("Invalid data pointer\r\n");
return 0;
}
/* 配置发送消息参数 */
transmit_message.tx_ft = CAN_FT_DATA; // 数据帧
transmit_message.tx_ff = CAN_FF_STANDARD; // 标准帧格式
transmit_message.tx_sfid = id; // 设置帧ID
transmit_message.tx_dlen = length; // 设置数据长度
// 复制数据到发送缓冲区
for (int i = 0; i < length && i < 8; i++) {
transmit_message.tx_data[i] = *(data + i);
}
// 自动选择空闲mailbox发送消息
transmit_mailbox = can_message_transmit(CAN0, &transmit_message);
// 检查是否成功获取mailbox
if (transmit_mailbox == CAN_NOMAILBOX) {
// 没有可用的mailbox,启用发送中断以便在邮箱可用时重试
printf("No available mailbox for CAN transmission, enabling TX "
"interrupt\r\n");
// 可以设置一个标志位,当邮箱可用时发送
// 在实际应用中,可以维护一个待发送队列
return 0;
}
// 启用CAN发送中断以检测传输完成
can_interrupt_enable(CAN0, CAN_INTEN_TMEIE);
return 1;
}
/**
* @brief 异步CANFD数据发送(使用DMA和中断机制)
* @param id CAN消息ID
* @param length CAN消息长度
* @param data CAN消息数据
*/
u8 CAN_transmiter::CANFD_AsyncSend(u32 id, u8 length, u8 *data) {
u8 valid_length = length;
// 检查CANFD模式是否启用
if (!(CAN_CTL(CAN0) & CAN_CTL_DFZ)) {
printf("CANFD mode not enabled\r\n");
return 0;
}
// 检查数据指针是否有效
if (data == nullptr) {
printf("Invalid data pointer\r\n");
return 0;
}
// 检查数据长度是否符合CANFD规范
if (length > 8) {
if (length > 8 and length < 13) {
valid_length = 12;
} else if (length > 12 and length < 17) {
valid_length = 16;
} else if (length > 16 and length < 21) {
valid_length = 20;
} else if (length > 20 and length < 25) {
valid_length = 24;
} else if (length > 24 and length < 33) {
valid_length = 32;
} else if (length > 32 and length < 49) {
valid_length = 48;
} else if (length > 48 and length < 65) {
valid_length = 64;
} else {
printf("CANFD data length error\r\n");
return 0;
}
}
/* 配置发送消息参数 */
transmit_message.tx_ft = CAN_FT_DATA; // 数据帧
transmit_message.tx_ff = CAN_FF_EXTENDED; // 扩展帧格式
transmit_message.tx_efid = id; // 扩展帧ID
transmit_message.tx_dlen = valid_length; // 设置数据长度
// 设置CANFD特定参数
transmit_message.fd_flag = CAN_FDF_FDFRAME; // CANFD帧格式
transmit_message.fd_brs = ENABLE; // 使能比特率切换
transmit_message.fd_esi = DISABLE; // 错误状态指示
// 复制数据到发送缓冲区
for (int i = 0; i < valid_length; i++) {
if (i < length) {
transmit_message.tx_data[i] = *(data + i);
} else {
transmit_message.tx_data[i] = 0;
}
}
// 自动选择空闲mailbox发送消息
transmit_mailbox = can_message_transmit(CAN0, &transmit_message);
// 检查是否成功获取mailbox
if (transmit_mailbox == CAN_NOMAILBOX) {
// 没有可用的mailbox,启用发送中断以便在邮箱可用时重试
printf("No available mailbox for CANFD transmission, enabling TX "
"interrupt\r\n");
return 0;
}
// 启用CAN发送中断以检测传输完成
can_interrupt_enable(CAN0, CAN_INTEN_TMEIE);
return 1;
}
// 添加CAN传输中断处理函数
void CAN0_TX_IRQHandler(void) {
// 检查是否有发送邮箱空闲
if (can_flag_get(CAN0, CAN_FLAG_TME0) != RESET ||
can_flag_get(CAN0, CAN_FLAG_TME1) != RESET ||
can_flag_get(CAN0, CAN_FLAG_TME2) != RESET) {
// 邮箱已空闲,可以发送新消息
// 可以在这里处理待发送队列中的消息
// 清除发送中断标志
can_flag_clear(CAN0, CAN_FLAG_TME0);
can_flag_clear(CAN0, CAN_FLAG_TME1);
can_flag_clear(CAN0, CAN_FLAG_TME2);
}
}
+42 -37
View File
@@ -7,8 +7,6 @@ extern "C" {
#endif
#include "gd32c10x_can.h"
#include "stdint.h"
#include <stdio.h>
// 定义一个联合体类型用于float和byte数组之间的转换
typedef union {
@@ -53,13 +51,14 @@ static inline float_union_t unpack_bytes_to_float(u8 *buffer, u16 offset) {
return float_union;
}
u8 can_gpio_init(void); // CAN引脚初始化
void can_config(void); // CAN初始化
void canfd_config(void);// CANFD初始化
void can_dma_init(void); // CAN DMA初始化
void CAN0_RX0_IRQHandler(void);// CAN接收中断处理函数
u8 can_gpio_init(void); // CAN引脚初始化
void can_config(void); // CAN初始化
void canfd_config(void); // CANFD初始化
void can_dma_init(void); // CAN DMA初始化
void CAN0_RX0_IRQHandler(void); // CAN接收中断处理函数
void DMA0_Channel4_IRQHandler(void); // DMA通道4中断处理函数(CAN接收)
void DMA0_Channel5_IRQHandler(void); // DMA通道5中断处理函数(CAN发送)
void jumpToBOOT();
void can_loopback_init(void);
void can_loopback_test(void);
@@ -71,46 +70,52 @@ void can_loopback_test(void);
class CAN_transmiter {
private:
u8 controller_Mode = 0; // 电机模式
float_union_t limit_velocity_union = {0}; // 限制速度
u16 limit_voltage = 0; // 限制电压
short mcu_temp = 0; // MCU温度
short motor_temp = 0; // 电机温度
u16 Power_Voltage = 0; // 电源电压
float_union_t rt_angle_union = {0}; // 实时角度
float_union_t rt_velocity_union = {0}; // 实时速度
bool MotorStatus = 0; // 电机状态码
float_union_t target_angle_union = {0}; // 目标角度
u8 Target_Control_Mode = 0; // 目标控制模式
float_union_t target_velocity_union = {0}; // 目标速度
float_union_t u_current_union = {0}; // U相电流
float_union_t w_current_union = {0}; // W相电流
float_union_t v_current_union = {0}; // V相电流
bool is_sleep = false; // 是否休眠
u8 controller_Mode = 0; // 电机模式
float_union_t limit_velocity_union = {0}; // 限制速度
u16 limit_voltage = 0; // 限制电压
short mcu_temp = 0; // MCU温度
short motor_temp = 0; // 电机温度
u16 Power_Voltage = 0; // 电源电压
float_union_t rt_angle_union = {0}; // 实时角度
float_union_t rt_velocity_union = {0}; // 实时速度
bool MotorStatus = 0; // 电机状态码
float_union_t target_angle_union = {0}; // 目标角度
u8 Target_Control_Mode = 0; // 目标控制模式
u8 EEPROMStatus = 0; // EEPROM状态码
float_union_t target_velocity_union = {0}; // 目标速度
float_union_t target_current_union = {0};
float_union_t u_current_union = {0}; // U相电流
float_union_t w_current_union = {0}; // W相电流
float_union_t v_current_union = {0}; // V相电流
can_trasnmit_message_struct transmit_message; // 发送消息结构体
u8 transmit_mailbox = CAN_NOMAILBOX; // 初始化为无mailbox状态
u8 transmit_data[64]; // CANFD最大64字节
void update(); // 更新数据
u8 CAN_Receive(); // CAN接收
u8 CANFD_Receive(); // CANFD接收
u8 CAN_Send(u32 ID, u8 length, u8 *data); // CAN发送
u8 CANFD_Send(u32 ID, u8 length, u8 *data); // CANFD发送
u8 CAN_all_Send(); // CAN发送
u8 CANFD_all_Send(); // CANFD发送
void update(); // 更新数据
u8 CAN_Receive(); // CAN接收
u8 CANFD_Receive(); // CANFD接收
public:
// 添加构造函数声明
CAN_transmiter();
u8 init(void);
can_receive_message_struct receive_message; // 接收消息结构体
FlagStatus can0_receive_flag; // CAN0接收标志
FlagStatus can0_send_flag; // CAN0发送标志
float_union_t testfloat_union = {0}; // 测试用
can_receive_message_struct receive_message; // 接收消息结构体
FlagStatus can0_receive_flag; // CAN0接收标志
FlagStatus can0_send_flag; // CAN0发送标志
float_union_t testfloat_union = {0}; // 测试用
bool MagStatus = 0; // 磁状态码
bool ThermalStatus = 0; // 热能状态码
void communication_check(); // 通信检查
bool MagStatus = 0; // 磁状态码
bool ThermalStatus = 0; // 热能状态码
void communication_check(); // 通信检查
u8 CAN_Sleep(); // CAN进入睡眠
u8 CAN_Wakeup(); // CAN进入睡眠
u8 CAN_AsyncSend(u32 ID, u8 length, u8 *data); // CAN异步发送(使用DMA)
u8 CANFD_AsyncSend(u32 ID, u8 length, u8 *data); // CANFD异步发送(使用DMA)
u8 CAN_all_Send(); // CAN发送
u8 CANFD_all_Send(); // CANFD发送
};
#ifdef __cplusplus
+70 -87
View File
@@ -1,6 +1,6 @@
#include "Timer.h"
#include "Can.h"
#include "DengFOC.h"
#include "FOC.h"
#include "Timer.h"
#include "gd32c10x.h"
#include "gd32c10x_gpio.h"
@@ -8,31 +8,14 @@
#include "gd32c10x_rcu.h"
#include "gd32c10x_timer.h"
#include "initial.h"
#include <cstdio>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
constexpr int TIMER2_PRESCALER = 119; // 120MHz / 120 = 1MHz
constexpr int TIMER2_PERIOD = 99; // 1MHz / 100 = 100us
constexpr int TIMER3_PRESCALER = 119; // 120MHz / 120 = 1MHz
constexpr int TIMER3_PERIOD = 9999; // 1MHz / 10000 = 100Hz = 10ms
constexpr int TIMER1_PRESCALER = 0; // 不分频,计数器时钟为120MHz
constexpr int TIMER1_PERIOD = 5999; // 120MHz / (0+1) / (5999+1) = 20kHz
constexpr int TIMER1_CH0_PULSE = 0;
constexpr int TIMER1_CH1_PULSE = 0;
constexpr int TIMER1_CH2_PULSE = 0;
constexpr int TIMER1_CH3_COMPARE_VALUE =
(TIMER1_PERIOD + 1) * 0.5 - 1; // PWM周期50%位置触发中断
static u32 total_us100_counter = 0; // 总计数器,每100微秒增加1
volatile u32 total_us100_counter = 0; // 总计数器,每100微秒增加1
extern u16 adc_value[7];
extern FOC_Controlroller FOC;
extern TaskScheduler scheduler;
extern CAN_transmiter CAN0_transmiter;
// 添加系统运行时间计数器
static volatile std::u64 system_runtime_us = 0;
extern u32 cnt_test;
/**
* @brief 设置引脚中断优先级
@@ -45,11 +28,11 @@ void nvic_config(void) {
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
/* 使能TIMER2中断,设置抢占优先级为1,子优先级为1 */
nvic_irq_enable(TIMER2_IRQn, 0, 1);
nvic_irq_enable(TIMER1_IRQn, 0, 1);
nvic_irq_enable(TIMER1_IRQn, 0, 2);
}
/**
* @brief 配置定时器2
* @brief 配置定时器2-任务管理
* @return void
*
*配置定时器2,用于定时执行FOC控制、采样、CAN发送等任务
@@ -90,7 +73,7 @@ void TIMER2_config(void) {
}
/**
* @brief 配置TIMER2中断
* @brief 配置TIMER2-任务管理中断
* @return void
*/
void User_timer_init(void) {
@@ -100,16 +83,8 @@ void User_timer_init(void) {
nvic_config();
}
/*!
\brief 获取系统运行时间(毫秒)
\param[in] none
\param[out] none
\retval 系统运行时间,单位为毫秒
*/
uint64_t get_system_runtime_us(void) { return system_runtime_us; }
/**
* @brief TIMER2中断处理函数
* @brief TIMER2-任务管理中断处理函数
* @return void
*/
void TIMER2_IRQHandler(void) {
@@ -117,67 +92,75 @@ void TIMER2_IRQHandler(void) {
if (timer_interrupt_flag_get(TIMER2, TIMER_INT_UP) != RESET) {
// 清除更新中断标志
timer_interrupt_flag_clear(TIMER2, TIMER_INT_UP);
// 每100us执行一次的操作
scheduler.taskFlags |= (1 << TASK_ANGLE_UPDATE) |
(1 << TASK_VELOCITY_UPDATE) |
(1 << TASK_MOTOR_CONTROL);
switch (total_us100_counter) { // 每1ms执行的代码,负载均衡
case 0: {
scheduler.taskFlags |= (1 << TASK_MCU_TEMP_UPDATE);
break;
}
case 1: {
scheduler.taskFlags |= (1 << TASK_DRV_TEMP_UPDATE);
break;
}
case 2: {
scheduler.taskFlags |= (1 << TASK_VBUS_UPDATE);
break;
}
case 3: {
break;
}
case 9: {
CAN0_transmiter.can0_send_flag = SET;
scheduler.taskFlags |= (1 << TASK_CAN_TRANSMIT);
break;
}
}
// 每50us执行一次的操作 - 电机控制
scheduler.taskFlags |= (1 << TASK_MOTOR_CONTROL);
scheduler.taskFlags |=
(1 << TASK_ANGLE_UPDATE) | (1 << TASK_VELOCITY_UPDATE);
total_us100_counter++;
if (total_us100_counter > 9) {
total_us100_counter = 0;
// 可以添加每1ms执行的代码,无负载均衡
static u8 ms1_counter = 0;
// 使用标志位控制,每100us执行一次其他任务
static bool isEvenCall = false;
isEvenCall = !isEvenCall;
switch (ms1_counter) { // 每10ms执行的代码,负载均衡
if (isEvenCall) {
// 每100us执行一次的操作 - 保持原有频率
switch (total_us100_counter) { // 每1ms执行的代码,负载均衡
case 0: {
scheduler.taskFlags |= (1 << TASK_THERMAL_CONTROL);
scheduler.taskFlags |= (1 << TASK_MCU_TEMP_UPDATE);
break;
}
case 1: {
scheduler.taskFlags |= (1 << TASK_MAGNETIC_CHECK);
scheduler.taskFlags |= (1 << TASK_DRV_TEMP_UPDATE);
break;
}
case 2: {
scheduler.taskFlags |= (1 << TASK_VBUS_UPDATE);
break;
}
case 3: {
break;
}
case 9: {
scheduler.taskFlags |= (1 << TASK_CAN_TRANSMIT);
break;
}
}
ms1_counter++;
if (ms1_counter > 9) {
ms1_counter = 0;
// 可以添加每10ms执行的代码,无负载均衡
static u8 ms10_counter = 0;
ms10_counter++;
if (ms10_counter > 9) {
ms10_counter = 0;
// 可以添加每100ms执行的代码
static u8 sec_counter = 0;
sec_counter++;
if (sec_counter > 9) {
sec_counter = 0;
// 可以添加每1s执行的代码
total_us100_counter++;
if (total_us100_counter > 9) {
total_us100_counter = 0;
// 可以添加每1ms执行的代码,无负载均衡
static u8 ms1_counter = 0;
switch (ms1_counter) { // 每10ms执行的代码,负载均衡
case 0: {
scheduler.taskFlags |= (1 << TASK_THERMAL_CONTROL);
break;
}
case 1: {
scheduler.taskFlags |= (1 << TASK_MAGNETIC_CHECK);
break;
}
case 2: {
break;
}
}
ms1_counter++;
if (ms1_counter > 9) {
ms1_counter = 0;
// 可以添加每10ms执行的代码,无负载均衡
static u8 ms10_counter = 0;
ms10_counter++;
if (ms10_counter > 9) {
ms10_counter = 0;
// 可以添加每100ms执行的代码
static u8 sec_counter = 0;
sec_counter++;
if (sec_counter > 9) {
sec_counter = 0;
// 可以添加每1s执行的代码
}
}
}
}
@@ -186,7 +169,7 @@ void TIMER2_IRQHandler(void) {
}
/**
* @brief TIMER1 GPIO配置函数
* @brief TIMER1-PWM GPIO配置函数
*/
void timer1_gpio_config(void) {
// 时钟使能
@@ -210,7 +193,7 @@ void timer1_gpio_config(void) {
}
/**
* @brief TIMER1 配置函数
* @brief TIMER1-PWM 配置函数
*/
void timer1_pwm_config(void) {
timer_parameter_struct timer_initpara;
@@ -254,11 +237,11 @@ void timer1_pwm_config(void) {
TIMER_OC_MODE_PWM0); // CH3也设为PWM模式
timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_0,
TIMER1_CH0_PULSE);
TIMER1_DEFAULT_PULSE);
timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_1,
TIMER1_CH1_PULSE);
TIMER1_DEFAULT_PULSE);
timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_2,
TIMER1_CH2_PULSE);
TIMER1_DEFAULT_PULSE);
// 设置CH3比较值为PWM周期x%位置
timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_3,
TIMER1_CH3_COMPARE_VALUE);
@@ -274,12 +257,12 @@ void timer1_pwm_config(void) {
timer_enable(TIMER1);
}
// 添加TIMER1中断处理函数
// 添加TIMER1-PWM中断处理函数
/**
* @brief TIMER1中断处理函数
* @return void
*/
extern "C" void TIMER1_IRQHandler(void) {
void TIMER1_IRQHandler(void) {
// 检查CH3比较中断标志并处理
if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH3) != RESET) {
// 清除CH3比较中断标志
+2 -6
View File
@@ -5,10 +5,10 @@
extern "C" {
#endif
#include <stdint.h>
#include <cstdint>
void User_timer_init(void);
void Set_Pwm(uint16_t channel, float duty_cycle);
void Set_Pwm(u16 channel, float duty_cycle);
void Set_3Pwm(float duty_cycle0, float duty_cycle1,float duty_cycle2);
void TIMER2_IRQHandler(void);
@@ -16,10 +16,6 @@ void timer1_pwm_config(void);
void timer1_gpio_config(void);
void TIMER1_IRQHandler(void); // 添加TIMER1中断处理函数声明
/* 获取系统运行时间 */
uint64_t get_system_runtime_us(void);
#ifdef __cplusplus
}
#endif
+9 -10
View File
@@ -5,23 +5,22 @@
extern "C" {
#endif
#include "stdint.h"
constexpr u8 FILTER_SIZE = 6;
constexpr u8 BLOCK_SIZE = FILTER_SIZE * sizeof(float);
#include "config.h"
class sampler {
private:
float vbus_samples[FILTER_SIZE + 1];
float currU_samples[FILTER_SIZE + 1];
float currV_samples[FILTER_SIZE + 1];
float currW_samples[FILTER_SIZE + 1];
float mcu_temp_samples[FILTER_SIZE + 1];
float drv_temp_samples[FILTER_SIZE + 1];
float vbus_samples[ADC_FILTER_SIZE + 1];
float currU_samples[ADC_FILTER_SIZE + 1];
float currV_samples[ADC_FILTER_SIZE + 1];
float currW_samples[ADC_FILTER_SIZE + 1];
float mcu_temp_samples[ADC_FILTER_SIZE + 1];
float drv_temp_samples[ADC_FILTER_SIZE + 1];
u8 current_sample_index;
float tempora_sample;
public:
sampler();
u8 init(void);
void update_mcu_temp(void);
void update_drv_temp(void);
void update_vbus_voltage(void);
+44 -74
View File
@@ -1,34 +1,30 @@
#include "ang_sensor.h"
#include "Can.h"
#include "Filter.h"
#include "core_cmFunc.h"
#include "config.h"
#include "flash.h"
#include "gd32c10x_dma.h"
#include "gd32c10x_gpio.h"
#include "gd32c10x_spi.h"
#include "initial.h"
#include <cstdio>
#include <cstring>
#include <stdint.h>
#define ANG_SENS_DEBUG 1
#define SPI_CS_ENABLE() gpio_bit_reset(GPIOA, GPIO_PIN_15)
#define SPI_CS_DISABLE() gpio_bit_set(GPIOA, GPIO_PIN_15)
constexpr float ANGLE_FACTOR = 1.0f / 65536.0f * 360.0f;
constexpr float RAD_FACTOR = 1.0f / 65536.0f * 2.0f * 3.14159265358979323846f;
constexpr u16 DEFAULT_COMMAND = 0x0000;
constexpr u16 FAULT_RECEIVE = 0xFFFF;
constexpr float VELOCITY_SCALE = 1e4f;
constexpr float ANGLE_WRAP_THRESHOLD = 300.0f;
constexpr float ANGLE_WRAP_VALUE = 360.0f;
constexpr u8 SIZE_FLOAT = sizeof(float);
#define ANG_SPI_CS_ENABLE() gpio_bit_reset(GPIOA, GPIO_PIN_15)
#define ANG_SPI_CS_DISABLE() gpio_bit_set(GPIOA, GPIO_PIN_15)
#define DRV_SPI_CS_ENABLE() gpio_bit_reset(GPIOB, GPIO_PIN_14)
#define DRV_SPI_CS_DISABLE() gpio_bit_set(GPIOB, GPIO_PIN_14)
// DMA传输完成标志
volatile bool spi_dma_tx_complete = false;
volatile bool spi_dma_rx_complete = false;
angle_sensor KTH7823; // 角度传感器初始化
EncoderAngleKalman Angle_kalman(KTH7823.getAngle(), 1.0f, 1e-4f, 0.25f);
EncoderVelocityKalman Vel_kalman(Angle_kalman.getAngle(), 1e-5f, 1e-6f, 0.02f);
extern FlashEEPROM flashEEP;
extern EncoderAngleKalman Angle_kalman;
extern EncoderVelocityKalman Vel_kalman;
extern CAN_transmiter CAN0_transmiter; // CAN初始化
/**
* @brief SPI DMA initialization
@@ -194,47 +190,52 @@ void KTH7823_spi_init(void) {
}
/**
* @brief KTH7823 初始化
* @ 角度传感器类 初始化
* @return 0:初始化成功 1:初始化失败
*/
void angle_sensor::KTH7823_init(void) {
u8 angle_sensor::init(void) {
KTH7823_gpio_init(); // GPIO初始化
KTH7823_spi_init(); // SPI初始化
spi_dma_init(); // DMA初始化
return 0;
}
/**
* @brief 角度传感器构造函数
* @ 角度传感器类 设置当前角度
* @param angle 输出级角度值
* @return 0成功/1失败
*/
angle_sensor::angle_sensor(void) { KTH7823_init(); }
u8 angle_sensor::angle_set(float angle) {
m_cumulativeAngle = angle * REDUCTION_RATIO; // 从Flash读取上次保存的角度
m_firstUpdate = true;
return 0;
}
/**
* @brief 读取传感器数据
* @return 传感器数据
*/
inline float angle_sensor::read_sensorAngle(void) {
uint16_t raw_data;
uint16_t raw_data;
SPI_CS_ENABLE();
u8 result = spi_rw_half_word_dma(SPI0, DEFAULT_COMMAND, &raw_data);
SPI_CS_DISABLE();
if (result == 0) {
// 单次浮点乘法优化:只计算一次度数,然后转换为弧度
float angle_deg = (float)raw_data * ANGLE_FACTOR;
current_angle_deg = angle_deg;
current_angle_rad = angle_deg * DEG2RAD; // M_PI/180.0f
return angle_deg;
}
#ifdef DEBUG
// 仅在调试模式下输出错误,避免发布版本中的I/O开销
if (result != 0) {
// 使用更高效的串口输出替代printf(如果可用)
ANG_SPI_CS_ENABLE();
u8 result = spi_rw_half_word_dma(SPI0, DEFAULT_COMMAND, &raw_data);
ANG_SPI_CS_DISABLE();
if (result == 0) {
// 单次浮点乘法优化:只计算一次度数,然后转换为弧度
float angle_deg = -(float)raw_data * ANGLESENS_FACTOR + ANGLESENS_OFFSET;
current_angle_deg = angle_deg;
current_angle_rad = angle_deg * DEG2RAD; // M_PI/180.0f
return angle_deg;
}
// 仅在调试模式下输出错误,避免发布版本中的I/O开销
if (result != 0) {
// 使用更高效的串口输出替代printf(如果可用)
printf("Error reading angle from sensor.\n");
}
#endif
return (float)FAULT_RECEIVE;
}
return (float)FAULT_RECEIVE;
}
/**
* @brief 更新传感器角度(输出级)
@@ -253,7 +254,7 @@ float angle_sensor::update(void) {
float delta = current_angle_deg - m_lastAngle;
// 处理角度绕回情况(0度和360度之间的跳变)
// 如果变化超过180度,说明发生了绕回
// 如果变化超过300度,说明发生了绕回
if (delta > ANGLE_WRAP_THRESHOLD) {
// 从接近360度绕回到接近0度
delta -= ANGLE_WRAP_VALUE;
@@ -262,9 +263,6 @@ float angle_sensor::update(void) {
delta += ANGLE_WRAP_VALUE;
}
std::memmove(velocity, velocity + 1, SIZE_FLOAT * (VEL_FILTER_SIZE - 1));
velocity[VEL_FILTER_SIZE - 1] = delta * VELOCITY_SCALE;
m_cumulativeAngle += delta;
m_lastAngle = current_angle_deg;
@@ -285,26 +283,6 @@ float angle_sensor::getAngle(void) const {
*/
float angle_sensor::getRawAngle(void) const { return m_cumulativeAngle; }
/**
* @brief 获取速度值(输出级)
* @return 速度值(输出级)
*/
float angle_sensor::getVelocity(void) const {
return getRawVelocity() / REDUCTION_RATIO;
}
/**
* @brief 获取速度值(原始级)
* @return 速度值(原始级)
*/
float angle_sensor::getRawVelocity(void) const {
float velocity_filted = 0;
for (int i = 0; i < VEL_FILTER_SIZE - 1; i++) {
velocity_filted += velocity[i];
}
return velocity_filted / (VEL_FILTER_SIZE - 1);
// return velocity[VEL_FILTER_SIZE - 1];
}
/**
* @brief 获取角度值(原始级)
* @return 角度值(原始级)
@@ -312,11 +290,3 @@ float angle_sensor::getRawVelocity(void) const {
float angle_sensor::getcurrent_sensorangle(void) const {
return current_angle_deg;
}
/**
* @brief 重置累积角度值
*/
void angle_sensor::reset(void) {
m_cumulativeAngle = 0.0f;
m_firstUpdate = true;
}
+4 -6
View File
@@ -4,28 +4,26 @@
extern "C" {
#endif
#include "gd32c10x_eval.h"
#include "stdio.h"
#include <cstring>
#include "config.h"
u16 spi_rw_half_word(u32 spi_periph, const u16 i_HalfWord);
int spi_rw_half_word_dma(uint32_t spi_periph, uint16_t tx_data,
uint16_t *rx_data);
constexpr u16 VEL_FILTER_SIZE = 4;
class angle_sensor {
public:
angle_sensor();
u8 init(void);
float read_sensorAngle(void);
float update(void);
void reset(void);
float getAngle(void) const;
float getRawAngle(void) const;
float getVelocity(void) const;
float getRawVelocity(void) const;
float getcurrent_sensorangle(void) const;
u8 angle_set(float angle);
protected:
void KTH7823_init(void);
float m_cumulativeAngle;
float current_angle_deg;
float current_angle_rad;
+52
View File
@@ -0,0 +1,52 @@
#include "motor.h"
#include "Timer.h"
#include "gd32c10x_eval.h"
#include "gd32c10x_gpio.h"
#include <cstdio>
/**
* @brief driver输出初始化
*/
void motor_init(void) {
timer1_gpio_config();
timer1_pwm_config();
// 使能GPIOB时钟
rcu_periph_clock_enable(RCU_GPIOB);
// 配置PB2为输入引脚,用于读取电机状态
gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
/* 配置GPIOB的PB14为推挽输出 SPICS */
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ,
GPIO_PIN_14 | GPIO_PIN_12);
// 使能GPIOC时钟,用于电机驱动使能引脚
rcu_periph_clock_enable(RCU_MOTOR_EN_GPIO);
// 配置PC13为推挽输出,用于控制电机驱动器使能
gpio_init(MOTOR_EN_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, MOTOR_EN_GPIO_PIN);
}
/**
* @brief 电机复位
*/
void motor_reset(void) {
motor_sleep();
printf("motor reseting...\r\n");
motor_resume();
}
/**
* @brief 电机休眠
*/
void motor_sleep(void) {
gpio_bit_reset(GPIOB, GPIO_PIN_12);
// 同时禁用电机驱动器
gpio_bit_reset(MOTOR_EN_GPIO_PORT, MOTOR_EN_GPIO_PIN);
}
/**
* @brief 电机启动
*/
void motor_resume(void) {
gpio_bit_set(GPIOB, GPIO_PIN_12);
// 同时启用电机驱动器
gpio_bit_set(MOTOR_EN_GPIO_PORT, MOTOR_EN_GPIO_PIN);
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef _MOTOR_H
#define _MOTOR_H
// 定义电机驱动使能引脚
#define MOTOR_EN_GPIO_PORT GPIOC
#define MOTOR_EN_GPIO_PIN GPIO_PIN_13
#define RCU_MOTOR_EN_GPIO RCU_GPIOC
void motor_init(void);
void motor_reset(void);
void motor_resume(void);
void motor_sleep(void);
#endif
+105 -80
View File
@@ -1,100 +1,125 @@
#include "main.h"
#include "Can.h"
#include "DengFOC.h"
#include "FOC.h"
#include "Filter.h"
#include "Timer.h"
#include "adc.h"
#include "ang_sensor.h"
#include "core_cm4.h"
#include "core_cmFunc.h"
#include "flash.h"
#include "health.h"
#include "initial.h"
#include "sys/health.h"
#include "sys/systick.h"
#include "motor.h"
#include "systick.h"
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_Controlroller FOC; // FOC控制
extern FlashEEPROM flashEEP; // EEPROM类
extern VersionManager Version;
// 全局版本管理器实例
TaskScheduler scheduler = {0};
volatile u32 motor_runtime_50us = 0; // 电机驱动计算轮次
volatile u32 cnt_test = 0; // 负载检测
int main(void) {
systick_config(); // 系统时钟初始化
USART0_init(); // 调试串口初始化
User_timer_init(); // Timer初始化
driver_init(); // 电机驱动初始化
extern FOC_Controlroller FOC; // FOC控制
extern sampler sampler; // 采样器
extern EncoderVelocityKalman Vel_kalman; // 速度滤波
extern EncoderAngleKalman Angle_kalman; // 角度滤波
extern angle_sensor KTH7823; // 角度传感器
extern CAN_transmiter CAN0_transmiter; // CAN
extern ThermalController thermalController; // 热量控制器
u8 init_status = hardware_init();
while (init_status) { // 初始化检测
std::printf("初始化失败\r\n");
}
OTA_initial(); // OTA初始化,A/B分区处理
angsens_MG_check(); // 角度传感器磁感应强度测试
watchdog_init(50); // 看门狗初始化
delay_1ms(5);
angsens_MG_check(); // 角度传感器磁感应强度测试
watchdog_init(5000); // 看门狗初始化
while (1) {
__disable_irq();
// 保存当前任务标志快照以提高效率并确保一致性
u32 currentTasks = scheduler.taskFlags;
// 一次性清除所有已处理的任务标志
scheduler.taskFlags &= ~currentTasks;
u32 currentTasks =
scheduler.taskFlags; // 保存当前任务标志快照以提高效率并确保一致性
scheduler.taskFlags &= ~currentTasks; // 一次性清除所有已处理的任务标志
__enable_irq();
// 按照优先级和重要性处理任务
if (currentTasks & (1 << TASK_CURRENT_UPDATE)) { // 更新电流采样值
sampler.update_current();
}
if (currentTasks & (1 << TASK_ANGLE_UPDATE)) { // 更新角度传感器值
KTH7823.update();
FOC.rt_angle = Angle_kalman.update(KTH7823.getAngle());
}
if (currentTasks & (1 << TASK_VELOCITY_UPDATE)) { // 更新速度传感器值
FOC.rt_velocity = Vel_kalman.update(Angle_kalman.getVelocity());
}
if (currentTasks &
(1 << TASK_MOTOR_CONTROL)) { // 电机控制任务(最高优先级)
switch (FOC.control_mode) {
case 0: {
FOC.drv_hold(0.95); // 占空比置0
break;
}
case 1: {
FOC.angle_control(FOC.target_angle); // 角度闭环控制
break;
}
case 2: {
FOC.velocity_control(FOC.target_velocity); // 速度闭环控制
break;
}
case 3: {
FOC.angle_control_NPID(FOC.target_angle); // 角度闭环控制
break;
}
case 4: {
FOC.velocity_open_loop(); // 速度开环控制
break;
}
}
}
if (currentTasks & (1 << TASK_MCU_TEMP_UPDATE)) { // 更新mcu温度传感器值
sampler.update_mcu_temp();
}
if (currentTasks &
(1 << TASK_DRV_TEMP_UPDATE)) { // 更新电机温度传感器值
sampler.update_drv_temp();
}
if (currentTasks & (1 << TASK_THERMAL_CONTROL)) { // 热量控制
thermalController.update();
}
if (currentTasks & (1 << TASK_MAGNETIC_CHECK)) { // 磁感应强度检测
angsens_MG_check();
}
if (currentTasks & (1 << TASK_VBUS_UPDATE)) { // 更新vbus电压值
sampler.update_vbus_voltage();
FOC.update_power();
}
if (currentTasks & (1 << TASK_CAN_TRANSMIT)) { // CAN通信
CAN0_transmiter.communication_check();
fwdgt_counter_reload(); // 看门狗复位
do_task(currentTasks);
}
return 0;
}
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(); // 采样器初始化
flashEEP.init(); // EEPROM初始化,必须放在角度卡尔曼之前,角度传感器之后
init_status += Angle_kalman.init(KTH7823.getAngle()); // 角度滤波初始化
init_status += Vel_kalman.init(0.0f); // 速度滤波初始化
init_status += CAN0_transmiter.init(); // CAN初始化
init_status += FOC.init(); // FOC初始化
return init_status;
}
void do_task(u32 currentTasks) {
cnt_test++;
// 按照优先级和重要性处理任务
if (currentTasks & (1 << TASK_CURRENT_UPDATE)) { // 更新电流采样值
sampler.update_current();
}
if (currentTasks & (1 << TASK_ANGLE_UPDATE)) { // 更新角度传感器值
KTH7823.update();
FOC.rt_angle = Angle_kalman.update(KTH7823.getAngle());
}
if (currentTasks & (1 << TASK_VELOCITY_UPDATE)) { // 更新速度传感器值
FOC.rt_velocity = Vel_kalman.update(Angle_kalman.getVelocity());
}
if (currentTasks & (1 << TASK_MOTOR_CONTROL)) { // 电机控制任务(最高优先级)
motor_runtime_50us++;
// 函数指针数组,包含各种控制模式对应的函数
static FOCFunctionPtr control_functions[] = {
&FOC_Controlroller::drv_hold, // 0: 占空比置
&FOC_Controlroller::
angle_control_with_velocity_limit, // 1:
// 角度闭环控制,带速度限制
&FOC_Controlroller::velocity_control, // 2: 速度闭环控制
&FOC_Controlroller::current_control, // 3: 电流闭环控制
&FOC_Controlroller::velocity_open_loop, // 4: 速度开环控制
};
// 边界检查,防止数组越界
if (FOC.control_mode >= 0 && FOC.control_mode < 5) { // 更新为7个控制模式
// 调用对应的控制函数
(FOC.*control_functions[FOC.control_mode])();
}
}
if (currentTasks & (1 << TASK_MCU_TEMP_UPDATE)) { // 更新mcu温度传感器值
sampler.update_mcu_temp();
}
if (currentTasks & (1 << TASK_DRV_TEMP_UPDATE)) { // 更新电机温度传感器值
sampler.update_drv_temp();
}
if (currentTasks & (1 << TASK_THERMAL_CONTROL)) { // 热量控制
thermalController.update();
}
if (currentTasks & (1 << TASK_MAGNETIC_CHECK)) { // 磁感应强度检测
angsens_MG_check();
}
if (currentTasks & (1 << TASK_VBUS_UPDATE)) { // 更新vbus电压值
power_manage();
}
if (currentTasks & (1 << TASK_CAN_TRANSMIT)) { // CAN通信
// CAN0_transmiter.testfloat_union.f = cnt_test; // 负载检测
cnt_test = 0;
CAN0_transmiter.can0_send_flag = SET;
CAN0_transmiter.communication_check();
fwdgt_counter_reload(); // 看门狗复位
}
}
+3
View File
@@ -34,6 +34,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef MAIN_H
#define MAIN_H
#include <cstdint>
void do_task(u32 currentTasks);
u8 hardware_init(void);
#endif /* MAIN_H */
-25
View File
@@ -1,25 +0,0 @@
#ifndef PID_H
#define PID_H
class PIDController
{
public:
PIDController(float P, float I, float D, float ramp, float limit);
~PIDController() = default;
float operator() (float error);
void set_PID(float P, float I, float D);
float P; //!< 比例增益(P环增益)
float I; //!< 积分增益(I环增益)
float D; //!< 微分增益(D环增益)
float output_ramp;
float limit;
protected:
float error_prev; //!< 最后的跟踪误差值
float output_prev; //!< 最后一个 pid 输出值
float integral_prev; //!< 最后一个积分分量值
unsigned long timestamp_prev; //!< 上次执行时间戳
};
#endif
+135
View File
@@ -0,0 +1,135 @@
#ifndef __CONFIG_H
#define __CONFIG_H
#include <cstdint>
// 如果使用CMSIS DSP库,需要定义ARM_MATH_CM4
#define ARM_MATH_CM4
#define EEP_DEBUG 1
#define OTA_DEBUG 1
#define SLEEP_DEBUG 1
// 版本号定义 - 可根据实际项目进行调整
constexpr u16 SOFTWARE_VERSION_MAJOR = 26;
constexpr u16 SOFTWARE_VERSION_MINOR = 1;
constexpr u16 SOFTWARE_VERSION_PATCH = 24;
constexpr u16 SOFTWARE_VERSION_BUILD = 1;
constexpr u16 HARDWARE_VERSION_MAJOR = 25;
constexpr u16 HARDWARE_VERSION_MINOR = 12;
constexpr u16 HARDWARE_VERSION_PATCH = 01;
constexpr u16 HARDWARE_VERSION_BUILD = 0;
constexpr u16 BOOT_VERSION_MAJOR = 26;
constexpr u16 BOOT_VERSION_MINOR = 1;
constexpr u16 BOOT_VERSION_PATCH = 12;
constexpr u16 BOOT_VERSION_BUILD = 0;
// Flash分区配置
constexpr u32 BOOTLOADER_SIZE = 0x6000; // 24KB
constexpr u32 BOOTLOADER_START_ADDR = 0x08000000; // BOOT起始地址
constexpr u32 APPLATEST_START_ADDR = 0x08012000; // APP起始地址
constexpr u32 APPBACK_START_ADDR = 0x08006000; // APPBACK起始地址
constexpr u32 APP_MAX_SIZE = 0xC000; // 48KB
constexpr u32 FMC_PAGE_SIZE = 0x400; // 1KB
constexpr u32 SLEEP_CONFIG_START = 0x0801E400; // 睡眠配置起始地址
constexpr u32 SLEEP_CONFIG_END = 0x0801E800; // 睡眠配置结束地址
constexpr u32 FLASH_EMPTY = 0xFFFFFFFF; // 空数据
constexpr u32 SLEEP_ENABLE = 0x11111111; // 睡眠使能
constexpr u32 SLEEP_DISABLE = 0x00000000; // 睡眠禁止
// BOOT 相关
constexpr u32 OTA_CONFIG_NUM = 6;
constexpr u32 n_APP_LATEST_AVAL_ADDR = 0x0801E000; // 最新APP可用地址
constexpr u32 n_APP_BACKUP_AVAL_ADDR = 0x0801E004; // 备份APP可用地址
constexpr u32 n_APP_LATEST_EN_ADDR = 0x0801E008; // 最新APP激活
constexpr u32 n_APP_BACKUP_EN_ADDR = 0x0801E00C; // 备份APP激活
constexpr u32 n_APP_LATEST_CHECK_ADDR = 0x0801E010; // 最新APP校验
constexpr u32 n_APP_BACKUP_CHECK_ADDR = 0x0801E014; // 备份APP校验
constexpr u32 OTA_NOT_AVAL = 0xFFFFFFFF;
constexpr u32 OTA_AVAL = 0x00000000; // 全零表示可用
// 参数配置
constexpr u8 PP = 11;
constexpr float DIR = -1.0f;
constexpr u16 REDUCTION_RATIO = 25;
constexpr float CURRENT_OFFSET = -1.62f; // 当前电流传感器的零点偏移
constexpr float HOLD_PWM_DUTY = 0.95f;
constexpr u16 ANGLESENS_OFFSET = +0;
constexpr float KE_FACTOR = 14.0f;
// PID配置
constexpr float current_loop_p = 6e-2f / 100 * 12; // 电流P
constexpr float vel_loop_p = 0.01f / 100 * 12; // 速度P
constexpr float angle_loop_p = 20.0f / 100 * 12; // 角度P
constexpr float vel_angloop_p = 0.12f / 100 * 12; // 速度 速度-角度P
constexpr float ang_angloop_p = 100.0f / 100 * 12; // 角度 速度-角度P
// 常量定义
constexpr u8 SIZE_FLOAT = sizeof(float);
constexpr u8 SIZE_U32 = sizeof(uint32_t);
constexpr float ADC_MAX = 65536.0f;
constexpr float PI = 3.14159265358979323846f;
constexpr float ANGLE_FACTOR = 25.0f / 180.0f * PI;
constexpr float DEG2RAD = 1.0f / 180.0f * PI;
constexpr float RAD2DEG = 180.0f / PI; // 修正RAD2DEG定义,应该是180/π
constexpr float _1_SQRT3 = 0.57735026919f; // 1/sqrt(3)
constexpr float sqrt3dv2 = 0.86602540378f; // sqrt(3)/2的预计算值
constexpr u8 DEFAULT_VALUE = 0;
constexpr u8 CONFIG_SAVED_NUM = 6;
// 三角函数快速计算LUT
constexpr u16 LUT_SIZE = 1024;
constexpr u16 LUT_MASK = (LUT_SIZE - 1);
constexpr u16 LUT_SCALE = (LUT_SIZE / (2.0f * PI));
// CAN相关
constexpr u16 DEV_CAN0_ID = 0x0000;
constexpr u16 DEV_CAN0_MASK = 0x0000;
constexpr u16 DEV_CAN_LOOPBACK_ID = 0x0000;
// 反馈ID
constexpr u32 CANFD_STATUS_ID = 0x00010100;
constexpr u32 CANFD_CONFIG_ID = 0x00010101;
constexpr u32 CANFD_VERSION_ID = 0x00010000;
// 命令ID
constexpr u32 CANFD_CMD_ID = 0x00010200;
constexpr u32 CANFD_RESET_ID = 0x00010301;
// OTA相关ID
constexpr u32 CANFD_BOOT_ID = 0x00000000;
constexpr u32 CANFD_OTA_REQ_ID = 0x00000100;
constexpr u32 CANFD_OTA_DATA_ID = 0x00000101;
constexpr u32 CANFD_OTA_ACK_ID = 0x00000102;
constexpr u32 CANFD_OTA_WAIT_ID = 0x00000103;
// ADC
constexpr u8 ADC_FILTER_SIZE = 6;
constexpr u8 BLOCK_SIZE = ADC_FILTER_SIZE * SIZE_FLOAT;
constexpr float ERROR_ADC_VAL = 255.0f;
constexpr float MAX_TEMP = 150.0f;
constexpr float MIN_TEMP = -40.0f;
constexpr float MAX_CURRENT = 40.0f;
constexpr float MIN_CURRENT = -40.0f;
constexpr float MAX_VCC = 65.0f;
constexpr float MIN_VCC = -0.1f;
// ang_sensor
constexpr u16 VEL_FILTER_SIZE = 4;
constexpr u16 DEFAULT_COMMAND = 0x0000;
constexpr u16 FAULT_RECEIVE = 0xFFFF;
constexpr float ANGLE_WRAP_THRESHOLD = 300.0f;
constexpr float ANGLE_WRAP_VALUE = 360.0f;
constexpr float RAD_FACTOR = 1.0f / ADC_MAX * 2.0f * PI;
constexpr float ANGLESENS_FACTOR = 1.0f / ADC_MAX * 360.0f;
// TIMER2-任务调度
constexpr int TIMER2_PRESCALER = 119; // 120MHz / 120 = 1MHz
constexpr int TIMER2_PERIOD = 49; // 1MHz / 50 = 50us
constexpr float TIMER2_FREQUENCY = 1 / 5e-5;
// TIMER1-PWM
constexpr int TIMER1_PRESCALER = 0; // 不分频,计数器时钟为120MHz
constexpr int TIMER1_PERIOD = 5999; // 120MHz / (0+1) / (5999+1) = 20kHz
constexpr int TIMER1_DEFAULT_PULSE = 0;
constexpr int TIMER1_CH3_COMPARE_VALUE =
(TIMER1_PERIOD + 1) * 0.5 - 1; // PWM周期50%位置触发中断
#endif
+795
View File
@@ -0,0 +1,795 @@
#include "flash.h"
#include "FOC.h"
#include "ang_sensor.h"
#include "config.h"
#include "gd32c10x.h" // GD32主头文件,确保外设函数声明可用
#include "gd32c10x_crc.h"
#include "gd32c10x_fmc.h"
#include "systick.h"
#include <Can.h>
#include <cstdio>
#include <cstring>
FlashEEPROM flashEEP = FlashEEPROM();
extern angle_sensor KTH7823;
extern CAN_transmiter CAN0_transmiter;
extern FOC_Controlroller FOC; // FOC控制
fmc_state_enum write_ADDRESS(u32 address, u32 data) {
fmc_unlock();
fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_PGAERR | FMC_FLAG_WPERR);
// 确保使用对齐地址
fmc_state_enum fmc_status = fmc_word_program(address, data);
fmc_lock();
return fmc_status;
}
// FlashEEPROM类实现
FlashEEPROM::FlashEEPROM() {
// 构造函数可以为空,或者做一些初始化工作
}
/**
* @brief 初始化Flash EEPROM模拟
* @param None
* @retval None
*/
u8 FlashEEPROM::init() {
rcu_periph_clock_enable(RCU_CRC);
crc_deinit(); // 初始化CRC模块
FlashEepromStatus status = FLASH_EEPROM_OK;
// 读取系统配置
read_saved_system_config();
if (EEPROMStatus == FLASH_EEPROM_OK) {
return FLASH_EEPROM_OK;
} else {
return FLASH_EEPROM_READ_ERROR;
}
return 1; // 正常不会返回这个,未预料的异常情况返回
}
/**
* @brief 读取EEPROM数据
* @param virtualAddr: 虚拟地址
* @param data: 存储读取数据的指针
* @retval EEPROMStatus: 是否成功
*/
u8 FlashEEPROM::read_saved_system_config(void) {
// 读取保存的参数
u32 CRC_NUM = 0x0000;
FlashEepromStatus status_read[CONFIG_SAVED_NUM + 1] = {FLASH_EEPROM_OK};
float data[CONFIG_SAVED_NUM] = {0.0f};
// 尝试从Flash读取参数,如果不存在则使用默认值
status_read[1] = readFloat(ADDR_CONTROL_MODE, &data[0]);
status_read[2] = readFloat(ADDR_VOLTAGE_LIMIT, &data[1]);
status_read[3] = readFloat(ADDR_VEL_LIMIT, &data[2]);
status_read[4] = readFloat(ADDR_ANGLE, &data[3]);
status_read[5] = readFloat(ADDR_TARGET_ANGLE, &data[4]);
status_read[6] = readFloat(ADDR_TARGET_VEL, &data[5]);
// 读取失败则使用默认值
for (u8 i = 1; i < CONFIG_SAVED_NUM + 1; i++) {
if (status_read[i] ==
FLASH_EEPROM_DATA_NOT_FOUND) { // 首次读取,不保存报错
data[i - 1] = DEFAULT_VALUE;
} else if (status_read[i] != FLASH_EEPROM_OK) { // 其余错误,保存报错
data[i - 1] = DEFAULT_VALUE;
status_read[0] = status_read[i];
}
}
// 读取到全部数据
if (status_read[0] == FLASH_EEPROM_OK) {
u32 next_address = EEPROM_END_ADDRESS;
// 遍历Flash页面寻找下一个可写入位置
for (u32 address = EEPROM_DATA_START_ADDRESS - SIZE_U32;
address > EEPROM_START_ADDRESS; address -= SIZE_U32) {
// 安全读取Flash数据
volatile u32 *flash_ptr = (volatile u32 *)address;
u32 data_word = *flash_ptr;
// 找到空位置
if (data_word == 0xFFFFFFFF) {
next_address = address + SIZE_U32; // 上一个位置为有效存储的数据
break;
}
// 更新下一个可能的写入位置(如果需要格式化)
next_address = address - SIZE_U32;
}
if (next_address == EEPROM_DATA_START_ADDRESS) {
// 从来没有存储过,直接返回
return FLASH_EEPROM_OK;
}
crc_data_register_reset(); // 确保CRC计算从初始状态开始
CRC_NUM = crc_block_data_calculate((uint32_t *)data, CONFIG_SAVED_NUM);
#if EEP_DEBUG
printf("CRC cmp1,0x%X_0x%x \r\n", CRC_NUM, *((u32 *)next_address));
#endif
if (CRC_NUM != *((u32 *)next_address)) { // CRC错误
for (u8 i = 0; i < CONFIG_SAVED_NUM; i++) {
data[i] = DEFAULT_VALUE;
}
EEPROMStatus = FLASH_EEPROM_CRC_ERROR;
} else { // CRC正确
EEPROMStatus = FLASH_EEPROM_OK;
}
} else {
// 读取失败,报错
EEPROMStatus = status_read[0];
}
KTH7823.angle_set(0);
FOC.control_mode = (u8)data[0];
FOC.limit_voltage = data[1];
FOC.limit_velocity = data[2];
KTH7823.angle_set(data[3]);
FOC.target_angle = data[4];
FOC.target_velocity = data[5];
return EEPROMStatus;
}
/**
* @brief 从Flash EEPROM读取数据
* @param virtualAddr: 虚拟地址
* @param data: 指向存储读取数据的指针
* @retval FlashEepromStatus: 操作状态
*/
FlashEepromStatus FlashEEPROM::read(u8 virtualAddr, u16 *data) const {
// 参数检查
if (data == nullptr) {
return FLASH_EEPROM_INVALID_ADDR;
}
// 从Flash末尾开始向前搜索,找到最新的数据
for (u32 address = EEPROM_END_ADDRESS - SIZE_U32;
address >= EEPROM_START_ADDRESS; address -= SIZE_U32) {
u32 data_word = *((u32 *)address);
// 检查是否是有效数据(非擦除状态)
if (data_word != 0xFFFFFFFF) {
u8 addr = (u8)(data_word & DATA_ADDR_MASK);
// 找到匹配的虚拟地址
if (addr == virtualAddr) {
*data = (u16)(data_word & DATA_U16_MASK);
return FLASH_EEPROM_OK;
}
}
}
return FLASH_EEPROM_DATA_NOT_FOUND;
}
/**
* @brief 从Flash EEPROM读取float数据
* @param virtualAddr: 虚拟地址
* @param data: 指向存储读取数据的指针
* @retval FlashEepromStatus: 操作状态
*/
FlashEepromStatus FlashEEPROM::readFloat(u8 virtualAddr, float *data) const {
// 检查参数有效性
if (data == nullptr) {
return FLASH_EEPROM_INVALID_ADDR;
}
// 从Flash末尾开始向前搜索,找到最新的数据
for (u32 address = EEPROM_END_ADDRESS - SIZE_U32;
address >= EEPROM_START_ADDRESS; address -= SIZE_U32) {
// 使用volatile确保每次都从内存读取,防止编译器优化
volatile u32 *flash_ptr = (volatile u32 *)address;
u32 data_word = *flash_ptr;
// 检查是否是有效数据(非擦除状态)
if (data_word != 0xFFFFFFFF) {
u8 addr = (u8)(data_word & DATA_ADDR_MASK);
// 找到匹配的虚拟地址
if (addr == virtualAddr) {
// 清除最低的8位地址信息,保留高24位数据
u32 float_data = data_word & DATA_FLOAT_MASK;
// 使用内存拷贝将处理后的数据解释为float
memcpy(data, &float_data, SIZE_FLOAT);
#if EEP_DEBUG
printf("read:0x%x=%f\r\n", address, *data);
#endif
return FLASH_EEPROM_OK;
}
}
}
// 未找到指定虚拟地址的数据
return FLASH_EEPROM_DATA_NOT_FOUND;
}
/**
* @brief 向Flash EEPROM写入数据
* @param virtualAddr: 虚拟地址
* @param data: 要写入的数据
* @retval FlashEepromStatus: 操作状态
*/
FlashEepromStatus FlashEEPROM::write(u8 virtualAddr, u16 data) {
// 查找下一个可写入的位置
u32 next_address = EEPROM_START_ADDRESS;
u32 data_read;
// 插入虚拟地址到低8位 格式: [data:16bit][reserved:8bit][addr:8bit]
data = (data & DATA_U16_MASK) | (u32)virtualAddr;
for (u32 address = EEPROM_END_ADDRESS - SIZE_U32;
address >= EEPROM_DATA_START_ADDRESS; address -= SIZE_U32) {
// 安全读取Flash数据
volatile u32 *flash_ptr = (volatile u32 *)address;
data_read = *flash_ptr;
if ((data_read & DATA_ADDR_MASK) == (u32)virtualAddr) { // 虚拟地址相同
if ((data_read & DATA_U16_MASK) ==
(data & DATA_U16_MASK)) { // 数据相同
#if EEP_DEBUG
data_read = data_read & DATA_U16_MASK;
u16 float_data_read = *((u16 *)&data_read);
printf("Found data in:0x%x=%u\r\n", address, data_read);
#endif
return FLASH_EEPROM_OK;
} else {
break;
}
}
}
// 遍历Flash页面寻找下一个可写入位置
for (u32 address = EEPROM_DATA_START_ADDRESS; address < EEPROM_END_ADDRESS;
address += SIZE_U32) {
// 安全读取Flash数据
volatile u32 *flash_ptr = (volatile u32 *)address;
u32 data_word = *flash_ptr;
// 找到空位置
if (data_word == 0xFFFFFFFF) {
next_address = address;
break;
}
// 更新下一个可能的写入位置(如果需要格式化)
next_address = address + SIZE_U32;
}
// 如果有足够空间,直接写入
if (next_address < EEPROM_END_ADDRESS) {
u32 data_word = ((u32)data << 16) | (u32)virtualAddr;
fmc_state_enum fmc_status = write_ADDRESS(next_address, data_word);
if (fmc_status != FMC_READY) {
return FLASH_EEPROM_WRITE_ERROR;
}
return FLASH_EEPROM_OK;
} else { // 空间不足,需要格式化页面
#if EEP_DEBUG
printf("no enough space\r\n");
#endif
FlashEepromStatus status = format();
if (status == FLASH_EEPROM_OK) {
status = save_system_config(false);
return status;
} else {
return FLASH_EEPROM_ERASE_ERROR;
}
}
}
/**
* @brief 向Flash EEPROM写入float数据
* @param virtualAddr: 虚拟地址
* @param data: 要写入的数据
* @retval FlashEepromStatus: 操作状态
*/
FlashEepromStatus FlashEEPROM::writeFloat(u8 virtualAddr, float data) {
// 查找下一个可写入的位置
u32 next_address = EEPROM_START_ADDRESS;
u32 data_word;
// 将完整的float数据复制到32位变量中
memcpy(&data_word, &data, SIZE_FLOAT);
// 插入虚拟地址到低8位 格式: [data:24bit][addr:8bit]
data_word = (data_word & DATA_FLOAT_MASK) | (u32)virtualAddr;
// 从Flash末尾开始向前搜索,找到最新的数据
for (u32 address = EEPROM_END_ADDRESS - SIZE_U32;
address >= EEPROM_DATA_START_ADDRESS; address -= SIZE_U32) {
// 安全读取Flash数据
volatile u32 *flash_ptr = (volatile u32 *)address;
u32 data_word_read = *flash_ptr;
if ((data_word_read & DATA_ADDR_MASK) ==
(u32)virtualAddr) { // 虚拟地址相同
if ((data_word_read & DATA_FLOAT_MASK) ==
(data_word & DATA_FLOAT_MASK)) { // 数据相同
#if EEP_DEBUG
data_word_read = data_word_read & DATA_FLOAT_MASK;
float float_data_read = *((float *)&data_word_read);
printf("Found data in:0x%x=%f\r\n", address, float_data_read);
#endif
return FLASH_EEPROM_OK;
} else {
break; // 找到相同地址但数据不同,需要更新
}
}
}
// 遍历Flash页面寻找下一个可写入位置
for (u32 address = EEPROM_DATA_START_ADDRESS; address < EEPROM_END_ADDRESS;
address += SIZE_U32) {
// 安全读取Flash数据
volatile u32 *flash_ptr = (volatile u32 *)address;
u32 data_word_read = *flash_ptr;
// 找到空位置
if (data_word_read == 0xFFFFFFFF) {
next_address = address;
break;
}
// 更新下一个可能的写入位置(如果需要格式化)
next_address = address + SIZE_U32;
}
// 如果有足够空间,直接写入
if (next_address < EEPROM_END_ADDRESS) {
fmc_state_enum fmc_status = write_ADDRESS(next_address, data_word);
#if EEP_DEBUG
u32 data_word_c = *((u32 *)next_address);
data_word_c = data_word_c & DATA_FLOAT_MASK;
float float_data = *((float *)&data_word_c);
printf("save:0x%x=%f\r\n", next_address, float_data);
#endif
if (fmc_status != FMC_READY) {
return FLASH_EEPROM_WRITE_ERROR;
}
return FLASH_EEPROM_OK;
} else {
// 空间不足,需要格式化页面
#if EEP_DEBUG
printf("no enough space\r\n");
#endif
FlashEepromStatus status = format();
if (status == FLASH_EEPROM_OK) {
status = save_system_config(false);
return status;
} else {
return FLASH_EEPROM_ERASE_ERROR;
}
}
}
/**
* @brief 格式化Flash EEPROM页面
* @param None
* @retval FlashEepromStatus: 操作状态
*/
FlashEepromStatus FlashEEPROM::format() {
fmc_state_enum fmc_status;
#if EEP_DEBUG
printf("擦除页面\r\n");
#endif
fmc_unlock();
fmc_status = fmc_page_erase(EEPROM_START_ADDRESS); // 擦除第一页
if (fmc_status != FMC_READY) {
fmc_lock();
return FLASH_EEPROM_ERASE_ERROR;
}
fmc_status = fmc_page_erase(EEPROM_DATA_PAGE2_ADDRESS); // 擦除第二页
if (fmc_status != FMC_READY) {
fmc_lock();
return FLASH_EEPROM_ERASE_ERROR;
}
fmc_lock();
return FLASH_EEPROM_OK;
}
/**
* @brief 更新系统配置并保存到Flash
* @param config 新的系统配置值
*/
FlashEepromStatus FlashEEPROM::save_system_config(bool saved) {
u32 CRC_NUM = 0x0000;
float data[CONFIG_SAVED_NUM] = {
(float)FOC.control_mode, FOC.limit_voltage,
FOC.limit_velocity, FOC.rt_angle,
FOC.target_angle, FOC.target_velocity};
// 如果系统配置标记已保存,则无需再次保存
if (system_config_saved) {
EEPROMStatus = FLASH_EEPROM_OK;
return FLASH_EEPROM_OK;
}
// 写入参数并检查错误
FlashEepromStatus status;
status = writeFloat(ADDR_CONTROL_MODE, data[0]);
if (status != FLASH_EEPROM_OK) {
EEPROMStatus = status;
return status;
}
status = writeFloat(ADDR_VOLTAGE_LIMIT, data[1]);
if (status != FLASH_EEPROM_OK) {
EEPROMStatus = status;
return status;
}
status = writeFloat(ADDR_VEL_LIMIT, data[2]);
if (status != FLASH_EEPROM_OK) {
EEPROMStatus = status;
return status;
}
status = writeFloat(ADDR_ANGLE, data[3]);
if (status != FLASH_EEPROM_OK) {
EEPROMStatus = status;
return status;
}
status = writeFloat(ADDR_TARGET_ANGLE, data[4]);
if (status != FLASH_EEPROM_OK) {
EEPROMStatus = status;
return status;
}
status = writeFloat(ADDR_TARGET_VEL, data[5]);
if (status != FLASH_EEPROM_OK) {
EEPROMStatus = status;
return status;
}
// 创建用于CRC计算的模拟数据数组,模拟实际存储到Flash中的数据格式
u32 crc_data_words[CONFIG_SAVED_NUM];
// 按照writeFloat函数的方式处理数据
for (u8 i = 0; i < CONFIG_SAVED_NUM; i++) {
// 将完整的float数据复制到32位变量中
memcpy(&crc_data_words[i], &data[i], SIZE_FLOAT);
// 去除最后2位精度
crc_data_words[i] = crc_data_words[i] & DATA_FLOAT_MASK;
}
crc_data_register_reset(); // 确保CRC计算从初始状态开始
CRC_NUM = crc_block_data_calculate(crc_data_words, CONFIG_SAVED_NUM);
writeCRC(CRC_NUM, saved);
EEPROMStatus = FLASH_EEPROM_OK;
return FLASH_EEPROM_OK;
}
/**
* @brief 读取角度数据从Flash
* @return float: 角度数据
*/
float FlashEEPROM::read_angle() {
float angle = DEFAULT_VALUE;
if (readFloat(ADDR_ANGLE, &angle) != FLASH_EEPROM_OK) {
angle = DEFAULT_VALUE;
}
return angle;
}
/**
* @brief 保存CRC数据到Flash
* @param saved: 是否一次性保存
* @return FlashEepromStatus: 状态
*/
FlashEepromStatus FlashEEPROM::writeCRC(u32 CRC_NUM, bool saved) {
static u32 next_address;
// 遍历Flash页面寻找下一个可写入crc的位置
for (u32 address = EEPROM_DATA_START_ADDRESS - SIZE_U32;
address > EEPROM_START_ADDRESS; address -= SIZE_U32) {
// 安全读取Flash数据
volatile u32 *flash_ptr = (volatile u32 *)address;
u32 data_word = *flash_ptr;
// 找到空位置
if (data_word == 0xFFFFFFFF) {
next_address = address;
break;
}
// 更新下一个可能的写入位置(如果需要格式化)
next_address = address - SIZE_U32;
}
// 如果当前CRC与现在的crc值不同,则写入
if (*((u32 *)next_address) != CRC_NUM) {
// 如果有足够空间,直接写入crc值
if (next_address > EEPROM_START_ADDRESS) {
fmc_state_enum fmc_status = write_ADDRESS(next_address, CRC_NUM);
#if EEP_DEBUG
printf("CRC cmp1,0x%X_0x%x \r\n", CRC_NUM, *((u32 *)next_address));
#endif
// 检查写入是否成功
if (fmc_status != FMC_READY) {
EEPROMStatus = fmc_status;
return FLASH_EEPROM_WRITE_ERROR;
}
} else {
// 空间不足,需要格式化页面
#if EEP_DEBUG
printf("no enough space\r\n");
#endif
FlashEepromStatus status = format();
if (status == FLASH_EEPROM_OK) {
status = save_system_config(false);
return status;
} else {
EEPROMStatus = FLASH_EEPROM_ERASE_ERROR;
return FLASH_EEPROM_ERASE_ERROR;
}
}
}
// 重新读取CRC校验
if (CRC_NUM == *((u32 *)next_address)) {
system_config_saved = saved; // 标记已保存过
EEPROMStatus = FLASH_EEPROM_OK; // 设置EEPROM状态
return FLASH_EEPROM_OK;
} else {
EEPROMStatus = FLASH_EEPROM_CRC_ERROR; // 设置EEPROM错误状态
return FLASH_EEPROM_CRC_ERROR;
}
}
/**
* @brief 设置OTA配置参数到Flash
*
* 此函数用于更新存储在Flash中的OTA相关标志位(如APP可用、启用、校验等)。
* GD32的Flash特性是:只能将1写为0,不能将0写为1。若要将0变为1,必须先擦除整个页面。
* 因此,本函数通过读取同一页内的所有参数,擦除该页,然后重新写入有效的参数来实现“写1”操作。
*
* @param addr: 要设置的Flash地址
* @param data: 要写入的数据 (通常为OTA_AVAL=0x00000000 或
* OTA_NOT_AVAL=0xFFFFFFFF)
* @retval FLASH_EEPROM_OK (0) 表示成功, 其他值表示失败
*/
u8 OTA_SET(u32 addr, u32 data) {
#if EEP_DEBUG
printf("OTA_prepare write%08x at %08x\r\n", data, addr);
#endif
fmc_state_enum fmc_status;
u32 temp_val[OTA_CONFIG_NUM]; // 临时数组,用于存储当前所有配置参数的值
volatile u32 *flash_ptr = (volatile u32 *)addr;
// 1. 检查目标地址的值是否已与期望值相同,如果相同则无需操作
temp_val[0] = *flash_ptr;
if (temp_val[0] == data) {
return FLASH_EEPROM_OK; // 值已正确,直接返回成功
}
// 2. 尝试直接写入数据。这适用于将1修改为0的情况(因为Flash允许1->0)
if (data == OTA_AVAL) {
fmc_status = write_ADDRESS(addr, data);
// 如果写入成功,则返回成功
if (fmc_status == FMC_READY) {
return FLASH_EEPROM_OK;
}
// 如果写入失败(例如地址已被写为0),则继续执行后续的擦除-重写流程
}
// 3. 对于需要将0改回1的操作,必须先擦除整个Flash页
flash_ptr = (volatile u32 *)n_APP_LATEST_AVAL_ADDR;
temp_val[0] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_AVAL_ADDR;
temp_val[1] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_LATEST_EN_ADDR;
temp_val[2] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_EN_ADDR;
temp_val[3] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_LATEST_CHECK_ADDR;
temp_val[4] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_CHECK_ADDR;
temp_val[5] = *flash_ptr;
#if EEP_DEBUG
printf("OTA_prepare write%08x at %08x\r\n", data, addr);
// 修复:完整输出所有6个配置项的值,便于调试
printf("LatestAval:0x%x, BackupAval:0x%x, LatestEn:0x%x, "
"BackupEn:0x%x, LatestCheck:0x%x, BackupCheck:0x%x\r\n",
temp_val[0], temp_val[1], temp_val[2], temp_val[3], temp_val[4],
temp_val[5]);
#endif
// 4. 擦除包含所有配置参数的Flash页
fmc_status = fmc_page_erase(n_APP_LATEST_AVAL_ADDR);
if (fmc_status != FMC_READY) {
#if EEP_DEBUG
printf("OTA_SET - Page erase failed! Status: %d\r\n", fmc_status);
#endif
return FLASH_EEPROM_ERASE_ERROR;
}
// 5. 重新写入所有之前读取的配置项值(恢复原始状态)
// 注意:不包括当前正在设置的地址,因为它将在最后单独处理
for (int i = 0; i < OTA_CONFIG_NUM; i++) {
u32 current_addr = n_APP_LATEST_AVAL_ADDR + 4 * i;
if (current_addr != addr and temp_val[i] != OTA_NOT_AVAL) {
fmc_status = write_ADDRESS(current_addr, temp_val[i]);
if (fmc_status != FMC_READY) {
#if EEP_DEBUG
printf("OTA_SET - Write backup value %08X failed at "
"0x%08X!status:%d\r\n",
temp_val[i], current_addr, fmc_status);
#endif
return FLASH_EEPROM_WRITE_ERROR;
}
}
}
#if EEP_DEBUG
// 3. 对于需要将0改回1的操作,必须先擦除整个Flash页
flash_ptr = (volatile u32 *)n_APP_LATEST_AVAL_ADDR;
temp_val[0] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_AVAL_ADDR;
temp_val[1] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_LATEST_EN_ADDR;
temp_val[2] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_EN_ADDR;
temp_val[3] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_LATEST_CHECK_ADDR;
temp_val[4] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_CHECK_ADDR;
temp_val[5] = *flash_ptr;
// 修复:完整输出所有6个配置项的值,便于调试
printf("LatestAval:0x%x, BackupAval:0x%x, LatestEn:0x%x, "
"BackupEn:0x%x, LatestCheck:0x%x, BackupCheck:0x%x\r\n",
temp_val[0], temp_val[1], temp_val[2], temp_val[3], temp_val[4],
temp_val[5]);
#endif
return FLASH_EEPROM_OK;
}
/**
* @brief 跳转应用处理模块
* @param 无
* @retval 无
*/
void jumpToBOOT() {
// 1. 关闭所有中断
__disable_irq();
for (int i = 0; i < 8; i++) {
NVIC->ICER[i] = 0xFFFFFFFF;
}
// 2. 重置外设(特别是CAN,防止冲突)
can_deinit(CAN0);
// 3. 重置系统时钟到默认状态
rcu_system_clock_source_config(RCU_CKSYSSRC_IRC8M);
// 4. 关闭一些关键外设时钟
rcu_periph_clock_disable(RCU_GPIOA);
// rcu_periph_clock_disable(RCU_GPIOB);
rcu_periph_clock_disable(RCU_GPIOC);
rcu_periph_clock_disable(RCU_USART0);
rcu_periph_clock_disable(RCU_CAN0);
rcu_periph_clock_disable(RCU_TIMER0);
rcu_periph_clock_disable(RCU_DMA0);
// 5. 设置中断向量表偏移到应用程序起始地址
SCB->VTOR = BOOTLOADER_START_ADDR;
// 6. 设置MSP并跳转
uint32_t msp_value = *(__IO uint32_t *)BOOTLOADER_START_ADDR;
uint32_t reset_handler = *(__IO uint32_t *)(BOOTLOADER_START_ADDR + 4);
typedef void (*AppEntryFunc)(void);
AppEntryFunc app_entry = (AppEntryFunc)reset_handler;
__set_MSP(msp_value);
// 7. 跳转
app_entry();
// 如果程序执行到这里,说明跳转失败
printf("Jump to application failed!\r\n");
}
/**
* @brief 将0x08011000地址后0xC000大小区域内的数据搬运到0x08005000地址
* @param None
* @retval fmc_state_enum: 操作状态
*/
fmc_state_enum move_app_data() {
// 源地址: APPLATEST_START_ADDR (0x08011000)
// 目标地址: APPBACK_START_ADDR (0x08005000)
// 数据大小: APP_MAX_SIZE (0xC000 = 48KB)
fmc_state_enum fmc_status = FMC_READY;
#if OTA_DEBUG
printf("move_app_data\r\n");
#endif
// 关闭全局中断以防止Flash操作期间的中断干扰
__disable_irq();
fmc_unlock();
// 首先擦除目标地址的Flash页面
uint32_t num_pages =
(APP_MAX_SIZE + FMC_PAGE_SIZE - 1) / FMC_PAGE_SIZE; // 向上取整
for (uint32_t i = 0; i < num_pages; i++) {
uint32_t page_addr = APPBACK_START_ADDR + i * FMC_PAGE_SIZE;
// 擦除页面
fmc_status = fmc_page_erase(page_addr);
if (fmc_status != FMC_READY) {
fmc_lock();
#if OTA_DEBUG
printf("move_app_data erase error\r\n");
delay_1ms(1000);
#endif
__enable_irq(); // 重新开启中断
return fmc_status;
}
}
// 复制数据 - 按字(32位)进行复制以提高效率
uint32_t offset = 0;
uint32_t write_count = 0; // 记录实际写入的字数
const uint32_t *src_ptr = (const uint32_t *)APPLATEST_START_ADDR;
uint32_t *dst_ptr = (uint32_t *)APPBACK_START_ADDR;
// 预计算源数据的CRC,避免重复访问内存
crc_deinit();
crc_data_register_reset();
uint32_t src_crc = crc_block_data_calculate(
(uint32_t *)APPLATEST_START_ADDR, APP_MAX_SIZE / 4);
while (offset < APP_MAX_SIZE) {
uint32_t src_data = src_ptr[offset / 4];
// 检查源地址是否为有效的Flash数据(非0xFFFFFFFF表示有数据)
if (src_data != 0xFFFFFFFF) {
fmc_unlock();
// 清除之前的标志位
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR |
FMC_FLAG_PGERR);
fmc_status =
fmc_word_program(APPBACK_START_ADDR + offset, src_data);
// 检查写入操作是否成功
if (fmc_status != FMC_READY) {
#if OTA_DEBUG
printf(
"Flash write failed at offset 0x%08X with status: %d\r\n",
offset, fmc_status);
delay_1ms(1000);
#endif
fmc_lock();
__enable_irq(); // 重新开启中断
return fmc_status;
}
write_count++;
}
offset += 4;
// 每写入一定数量的数据后,喂狗一次
if ((offset % 4096) == 0) { // 每4KB喂狗一次
fwdgt_counter_reload();
}
}
fmc_lock();
// 重新开启全局中断
__enable_irq();
crc_data_register_reset(); // 确保CRC计算从初始状态开始
// 计算目标数据的CRC值
uint32_t dst_crc = crc_block_data_calculate((uint32_t *)APPBACK_START_ADDR,
APP_MAX_SIZE / 4);
// 比较CRC值,确保数据完整性
if (src_crc != dst_crc) {
#if OTA_DEBUG
printf("APPbackup CRC mismatch: src_crc=0x%08X, dst_crc=0x%08X\r\n",
src_crc, dst_crc);
#endif
return (fmc_state_enum)0xFF; // CRC校验失败
}
#if OTA_DEBUG
printf("APPbackup CRC OK\r\n");
#endif
// 设置备份应用可用标志
fmc_unlock();
OTA_SET(n_APP_BACKUP_AVAL_ADDR, OTA_AVAL);
OTA_SET(n_APP_BACKUP_CHECK_ADDR, OTA_AVAL);
fmc_lock();
return fmc_status;
}
+78
View File
@@ -0,0 +1,78 @@
#ifndef __FLASH_H
#define __FLASH_H
#include "gd32c10x.h" // 添加GD32主头文件以确保外设函数声明可用
#include <cstdint>
// 修改后 - 强制4字节对齐
#define ALIGN_4BYTE(addr) ((addr) & 0xFFFFFFFC) // 4字节对齐
// EEPROM操作状态
typedef enum {
FLASH_EEPROM_OK = 0, // 操作成功
FLASH_EEPROM_WRITE_ERROR, // 写入错误
FLASH_EEPROM_READ_ERROR, // 读取错误
FLASH_EEPROM_ERASE_ERROR, // 擦除错误
FLASH_EEPROM_INVALID_ADDR, // 无效地址
FLASH_EEPROM_DATA_NOT_FOUND, // 找不到数据
FLASH_EEPROM_CRC_ERROR, // CRC错误
FLASH_EEPROM_ALIGNMENT_ERROR, // 对齐错误
} FlashEepromStatus;
// Flash EEPROM类
class FlashEEPROM {
public:
// EEPROM emulation constants
static constexpr u32 EEPROM_START_ADDRESS = 0x0801F800; // 第一页(1KB)
static constexpr u32 EEPROM_DATA_PAGE2_ADDRESS = 0x801FC00; // 第二页(1KB)
static constexpr u32 EEPROM_END_ADDRESS = 0x08020000; // Flash结束地址
static constexpr u32 EEPROM_MAX_SIZE = 0x800; // EEPROM最大容量
static constexpr u32 EEPROM_DATA_START_ADDRESS =
0x0801F900; // DATA段开始地址
static constexpr u32 DATA_FLOAT_MASK = 0xFFFFFF00; // float存储地址掩码
static constexpr u32 DATA_U16_MASK = 0xFFFF0000; // u16存储地址掩码
static constexpr u32 DATA_ADDR_MASK = 0x000000FF; // 虚拟地址掩码
// 定义用户自定义的虚拟地址
static constexpr u8 ADDR_CONTROL_MODE = 0x0; // 控制模式
static constexpr u8 ADDR_ANGLE = 0x01; // 角度数据存储地址
static constexpr u8 ADDR_TARGET_ANGLE = 0x02; // 角度命令数据存储地址
static constexpr u8 ADDR_TARGET_VEL = 0x03; // 速度命令数据存储地址
static constexpr u8 ADDR_VOLTAGE_LIMIT = 0x4; // 电压限制
static constexpr u8 ADDR_VEL_LIMIT = 0x05; // 角度数据存储地址
bool angle_saved = false;
bool system_config_saved = false;
u8 EEPROMStatus;
// 构造函数
FlashEEPROM();
// 初始化Flash EEPROM模拟
u8 init();
// 从Flash EEPROM中读取数据
FlashEepromStatus read(u8 virtualAddr, u16 *data) const;
// 向Flash EEPROM写入数据
FlashEepromStatus write(u8 virtualAddr, u16 data);
// Float数据读相关函数
FlashEepromStatus readFloat(u8 virtualAddr, float *data) const;
// Float数据存储相关函数
FlashEepromStatus writeFloat(u8 virtualAddr, float data);
// 格式化Flash EEPROM页面
FlashEepromStatus format();
FlashEepromStatus save_system_config(bool saved);
u8 read_saved_system_config(void);
float read_angle();
private:
FlashEepromStatus writeCRC(u32 CRC_NUM, bool saved);
};
void flash_eeprom_example_main(void);
u8 OTA_SET(u32 addr, u32 data);
fmc_state_enum move_app_data(void);
fmc_state_enum write_ADDRESS(u32 address, u32 data);
#endif /* __FLASH_H */
+61 -15
View File
@@ -1,29 +1,42 @@
#include "health.h"
#include "config.h"
#include "Can.h"
#include "DengFOC.h"
#include "FOC.h"
#include "adc.h"
#include "flash.h"
extern sampler sampler;
extern CAN_transmiter CAN0_transmiter;
extern FOC_Controlroller FOC;
extern FlashEEPROM flashEEP;
ThermalController thermalController; // 热量控制器初始化
#define SQUARE(x) ((x) * (x))
#define max(a, b, c) \
((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c)))
constexpr u16 PROTECT_TIME = 3000; // 过热保护时间,单位*10ms
constexpr u16 PROTECT_TIME = 6000; // 过热保护时间,单位*10ms
/**
** @brief 热能计算
** @param None
** @retval 热量值
*/
u32 ThermalController::update() {
thermal_value = thermal_value * thermalRate;
thermal_value +=
SQUARE(sampler.get_drv_temp()) + SQUARE(sampler.get_mcu_temp());
thermal_value = Q16_16_MUL(thermal_value, thermalRate);
// 添加温度积累
int drv_temp = (int)sampler.get_drv_temp();
int mcu_temp = (int)sampler.get_mcu_temp();
if (drv_temp == 255)
drv_temp = 0;
if (mcu_temp == 255)
mcu_temp = 0;
thermal_value += drv_temp * drv_temp + mcu_temp * mcu_temp;
if (remainingTime10Ms) { // 当前已经过热停机,正在停机自然散热
if (thermal_value < thermal_capacity * recoveryRate) {
if (remainingTime10Ms) {
// 过热停机状态
// 检查是否可以恢复
q16_16_t recovery_threshold =
Q16_16_MUL(thermal_capacity, recoveryRate);
if (thermal_value < recovery_threshold) {
remainingTime10Ms = 1; // 可以恢复工作
}
if (remainingTime10Ms == 1) { // 过热恢复
@@ -32,13 +45,33 @@ u32 ThermalController::update() {
return --remainingTime10Ms;
}
return --remainingTime10Ms;
} else { // 当前没有过热停机
current_max =
1000 * max(sampler.get_current('U'), sampler.get_current('V'),
sampler.get_current('W')); // 获取电流最大值
thermal_value +=
SQUARE(current_max) * gapTimeMs / 100000; // 计算当前电流热积累值
} else {
// 当前没有过热停机
// 添加电流热积累
u32 currents[3] = {(u32)(sampler.get_current('U') * 1000),
(u32)(sampler.get_current('V') * 1000),
(u32)(sampler.get_current('W') * 1000)};
// 找最大电流(原始ADC值)
current_max = max(currents[0], currents[1], currents[2]);
if (current_max < 2000) {
thermal_value += current_max * current_max * gapTimeMs *
0.00007f; // 计算当前电流热积累值
} else if (current_max > 3800) {
thermal_value += current_max * current_max * gapTimeMs *
0.01f; // 添加当前电流热积累值
} else if (current_max > 3400) {
thermal_value += current_max * current_max * gapTimeMs *
0.005f; // 计算当前电流热积累值
} else if (current_max > 3000) {
thermal_value += current_max * current_max * gapTimeMs *
0.0002f; // 计算当前电流热积累值
} else if (current_max > 2000) {
thermal_value += current_max * current_max * gapTimeMs *
0.0001f; // 计算当前电流热积累值
}
}
if (thermal_value > thermal_capacity) {
FOC.shut_down();
remainingTime10Ms = PROTECT_TIME; // 过热停机
@@ -55,4 +88,17 @@ void angsens_MG_check(void) {
bool MGH = gpio_input_bit_get(GPIOB, GPIO_PIN_10);
bool MGL = gpio_input_bit_get(GPIOB, GPIO_PIN_11);
CAN0_transmiter.MagStatus = MGH or MGL;
}
void power_manage(void) {
float last_vbus = sampler.get_vbus_voltage();
sampler.update_vbus_voltage();
FOC.update_power();
float vbus = sampler.get_vbus_voltage();
if ((vbus < 22.0f) and (last_vbus > vbus) and vbus > 8.0f) {
FOC.shut_down();
flashEEP.save_system_config(true);
} else {
FOC.resume();
}
}
+17 -6
View File
@@ -1,21 +1,32 @@
#ifndef _HEALTH_H
#define _HEALTH_H
#include "stdint.h"
#include <cstdint>
typedef int32_t q16_16_t; // Q16.16格式
// 定点数运算宏
#define Q16_16_ONE 65536 // 1.0 in Q16.16
#define FLOAT_TO_Q16_16(x) ((q16_16_t)((x) * Q16_16_ONE))
#define Q16_16_TO_FLOAT(x) ((float)(x) / Q16_16_ONE)
#define Q16_16_MUL(a, b) ((q16_16_t)(((int64_t)(a) * (b)) >> 16))
#define Q16_16_SQUARE(x) Q16_16_MUL((x), (x))
class ThermalController {
private:
u8 temperature;
u16 current_max;
float thermalRate = 0.995f; // 热耗散系数(每单位时间散热比例)
float recoveryRate = 0.6f; // 自然恢复率(散热到多少以下开始工作)
q16_16_t thermalRate; // 热耗散系数(每单位时间散热比例)
q16_16_t recoveryRate; // 自然恢复率(散热到多少以下开始工作)
u32 thermal_value = 0;
u32 thermal_capacity = 2250000; // 热容量
u32 thermal_capacity = 3600000; // 热容量
u16 gapTimeMs = 10; // 单次计算间隔ms
u16 gapTimeMs = 10; // 单次计算间隔ms
u16 remainingTime10Ms = 0; // 过热冷却剩余ms
public:
ThermalController()
: thermalRate(FLOAT_TO_Q16_16(0.995f)),
recoveryRate(FLOAT_TO_Q16_16(0.33f)) {}
u32 update();
void reset() {
thermal_value = 0;
@@ -24,6 +35,6 @@ class ThermalController {
};
void angsens_MG_check(void);
void power_manage(void);
#endif
+242 -18
View File
@@ -1,14 +1,128 @@
#include "initial.h"
#include "Timer.h"
#include "ang_sensor.h"
#include <stdint.h>
#include "Can.h"
#include "config.h"
#include "flash.h"
#include "gd32c10x.h"
#include "gd32c10x_fmc.h"
#include "gd32c10x_gpio.h"
#include "gd32c10x_rcu.h"
#include "initial.h"
#include <cstdint>
#include <cstdio>
#include <cstring>
extern CAN_transmiter CAN0_transmiter; // CAN初始化
VersionManager Version;
void GPIO_config(void) {
// 使能GPIOB时钟
rcu_periph_clock_enable(RCU_GPIOB);
// 配置PB2为输入引脚,用于读取电机状态
gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
VersionManager::VersionManager() {
// 初始化版本号
setSoftwareVersion(SOFTWARE_VERSION_MAJOR, SOFTWARE_VERSION_MINOR,
SOFTWARE_VERSION_PATCH, SOFTWARE_VERSION_BUILD);
setHardwareVersion(HARDWARE_VERSION_MAJOR, HARDWARE_VERSION_MINOR,
HARDWARE_VERSION_PATCH, HARDWARE_VERSION_BUILD);
setBootVersion(BOOT_VERSION_MAJOR, BOOT_VERSION_MINOR, BOOT_VERSION_PATCH,
BOOT_VERSION_BUILD);
}
VersionManager::VersionInfo VersionManager::getSoftwareVersion() const {
return softwareVersion;
}
VersionManager::VersionInfo VersionManager::getHardwareVersion() const {
return hardwareVersion;
}
VersionManager::VersionInfo VersionManager::getBootVersion() const {
return bootVersion;
}
void VersionManager::setSoftwareVersion(u16 major, u16 minor, u16 patch,
u16 build) {
softwareVersion.major = major;
softwareVersion.minor = minor;
softwareVersion.patch = patch;
softwareVersion.build = build;
}
void VersionManager::setHardwareVersion(u16 major, u16 minor, u16 patch,
u16 build) {
hardwareVersion.major = major;
hardwareVersion.minor = minor;
hardwareVersion.patch = patch;
hardwareVersion.build = build;
}
void VersionManager::setBootVersion(u16 major, u16 minor, u16 patch,
u16 build) {
bootVersion.major = major;
bootVersion.minor = minor;
bootVersion.patch = patch;
bootVersion.build = build;
}
char *VersionManager::versionToString(const VersionInfo &version, char *buffer,
size_t bufSize) const {
if (buffer == nullptr) {
return nullptr;
}
snprintf(buffer, bufSize, "%d.%d.%d.%d", version.major, version.minor,
version.patch, version.build);
return buffer;
}
void VersionManager::sendVersionInfoViaCan() const {
// 准备发送版本信息 (ID: CANFD_VERSION_ID)
// 只使用必要的字节数(24字节)来传输三个版本的信息(每个版本6字节)
u8 versionData[24] = {0};
// 将版本信息打包到24字节数组中
// 前8字节:软件版本信息 (4个uint16_t,每个占2字节)
versionData[0] = softwareVersion.major & 0xFF; // 低字节
versionData[1] = (softwareVersion.major >> 8) & 0xFF; // 高字节
versionData[2] = softwareVersion.minor & 0xFF; // 低字节
versionData[3] = (softwareVersion.minor >> 8) & 0xFF; // 高字节
versionData[4] = softwareVersion.patch & 0xFF; // 低字节
versionData[5] = (softwareVersion.patch >> 8) & 0xFF; // 高字节
versionData[6] = softwareVersion.build & 0xFF; // 低字节
versionData[7] = (softwareVersion.build >> 8) & 0xFF; // 高字节
// 8-15字节:硬件版本信息 (4个uint16_t,每个占2字节)
versionData[8] = hardwareVersion.major & 0xFF; // 低字节
versionData[9] = (hardwareVersion.major >> 8) & 0xFF; // 高字节
versionData[10] = hardwareVersion.minor & 0xFF; // 低字节
versionData[11] = (hardwareVersion.minor >> 8) & 0xFF; // 高字节
versionData[12] = hardwareVersion.patch & 0xFF; // 低字节
versionData[13] = (hardwareVersion.patch >> 8) & 0xFF; // 高字节
versionData[14] = hardwareVersion.build & 0xFF; // 低字节
versionData[15] = (hardwareVersion.build >> 8) & 0xFF; // 高字节
// 16-23字节:BOOT版本信息 (4个uint16_t,每个占2字节)
versionData[16] = bootVersion.major & 0xFF; // 低字节
versionData[17] = (bootVersion.major >> 8) & 0xFF; // 高字节
versionData[18] = bootVersion.minor & 0xFF; // 低字节
versionData[19] = (bootVersion.minor >> 8) & 0xFF; // 高字节
versionData[20] = bootVersion.patch & 0xFF; // 低字节
versionData[21] = (bootVersion.patch >> 8) & 0xFF; // 高字节
versionData[22] = bootVersion.build & 0xFF; // 低字节
versionData[23] = (bootVersion.build >> 8) & 0xFF; // 高字节
// 使用CANFD发送函数发送版本信息
CAN0_transmiter.CANFD_AsyncSend(CANFD_VERSION_ID, 24, versionData);
}
void VersionManager::printVersions() const {
char versionStr[32];
printf(
"Software Version: %s\r\n",
versionToString(getSoftwareVersion(), versionStr, sizeof(versionStr)));
printf(
"Hardware Version: %s\r\n",
versionToString(getHardwareVersion(), versionStr, sizeof(versionStr)));
printf("BOOT Version: %s\r\n",
versionToString(getBootVersion(), versionStr, sizeof(versionStr)));
}
/* retarget the C library printf function to the USART */
@@ -32,18 +146,128 @@ u8 watchdog_init(u32 time) {
return status;
}
/**
* @brief driver输出初始化
*/
void driver_init(void) {
timer1_gpio_config();
timer1_pwm_config();
}
int fputc(int ch, FILE *f) throw() {
usart_data_transmit(EVAL_COM0, (uint8_t)ch);
usart_data_transmit(EVAL_COM0, (u8)ch);
while (RESET == usart_flag_get(EVAL_COM0, USART_FLAG_TBE))
;
return ch;
}
void unused_pin_init() {
rcu_periph_clock_enable(RCU_GPIOA); // 使能GPIOA时钟
rcu_periph_clock_enable(RCU_GPIOB); // 使能GPIOB时钟
rcu_periph_clock_enable(RCU_GPIOC); // 使能GPIOC时钟
gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_2MHZ,
GPIO_PIN_8 | GPIO_PIN_11 | GPIO_PIN_12);
gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_2MHZ,
GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_15);
gpio_init(GPIOC, GPIO_MODE_IPU, GPIO_OSPEED_2MHZ,
GPIO_PIN_14 | GPIO_PIN_15);
gpio_bit_reset(GPIOA, GPIO_PIN_8 | GPIO_PIN_11 | GPIO_PIN_12);
gpio_bit_reset(GPIOB, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_15);
gpio_bit_reset(GPIOC, GPIO_PIN_14 | GPIO_PIN_15);
}
/*!
\brief 检测并打印复位源信息
\param[in] none
\param[out] none
\retval none
*/
u16 get_reset_cause(void) {
u16 cause = 0;
if (RESET != rcu_flag_get(RCU_FLAG_FWDGTRST)) {
// printf("Free Watchdog Timer Reset\r\n");
cause = RCU_FLAG_FWDGTRST;
}
if (RESET != rcu_flag_get(RCU_FLAG_EPRST)) {
// printf("External Pin Reset\r\n");
cause = RCU_FLAG_EPRST;
}
if (RESET != rcu_flag_get(RCU_FLAG_PORRST)) {
// printf("Power Reset\r\n");
cause = RCU_FLAG_PORRST;
}
if (RESET != rcu_flag_get(RCU_FLAG_WWDGTRST)) {
// printf("Window Watchdog Timer Reset\r\n");
cause = RCU_FLAG_WWDGTRST;
}
if (RESET != rcu_flag_get(RCU_FLAG_LPRST)) {
// printf("Low Power Reset\r\n");
cause = RCU_FLAG_LPRST;
}
if (RESET != rcu_flag_get(RCU_FLAG_SWRST)) {
// printf("Software Reset\r\n");
cause = RCU_FLAG_SWRST;
}
// 清除所有复位标志
rcu_all_reset_flag_clear();
// printf("cause:%d\r\n", cause);
return cause;
}
void OTA_initial(void) {
#if OTA_DEBUG
u32 temp_val[6];
// 3. 对于需要将0改回1的操作,必须先擦除整个Flash页
volatile u32 *flash_ptr1 = (volatile u32 *)n_APP_LATEST_AVAL_ADDR;
temp_val[0] = *flash_ptr1;
flash_ptr1 = (volatile u32 *)n_APP_BACKUP_AVAL_ADDR;
temp_val[1] = *flash_ptr1;
flash_ptr1 = (volatile u32 *)n_APP_LATEST_EN_ADDR;
temp_val[2] = *flash_ptr1;
flash_ptr1 = (volatile u32 *)n_APP_BACKUP_EN_ADDR;
temp_val[3] = *flash_ptr1;
flash_ptr1 = (volatile u32 *)n_APP_LATEST_CHECK_ADDR;
temp_val[4] = *flash_ptr1;
flash_ptr1 = (volatile u32 *)n_APP_BACKUP_CHECK_ADDR;
temp_val[5] = *flash_ptr1;
// 修复:完整输出所有6个配置项的值,便于调试
printf("APP:CHECK LatestAval:0x%x, BackupAval:0x%x, LatestEn:0x%x, "
"BackupEn:0x%x, LatestCheck:0x%x, BackupCheck:0x%x\r\n",
temp_val[0], temp_val[1], temp_val[2], temp_val[3], temp_val[4],
temp_val[5]);
#endif
// 确认当前APP可用
volatile u32 *flash_ptr = (volatile u32 *)n_APP_LATEST_CHECK_ADDR;
u32 app_check = *flash_ptr;
if (app_check == OTA_NOT_AVAL) { // 新的APP刷入后第一次启动
#if OTA_DEBUG
std::printf("APP enabled\r\n");
#endif
move_app_data();
}
fmc_unlock();
OTA_SET(n_APP_LATEST_CHECK_ADDR, OTA_AVAL);
fmc_lock();
u8 transmit_data[2] = {0x0A, 0xAC};
// 确认APP可用
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 2, transmit_data);
flash_ptr = (volatile u32 *)n_APP_BACKUP_AVAL_ADDR;
u32 back_aval = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_CHECK_ADDR;
u32 back_check = *flash_ptr;
if (back_aval == OTA_NOT_AVAL) { // 如果BACK不可用
#if OTA_DEBUG
std::printf("notaval\r\n");
#endif
move_app_data();
} else if (back_aval == OTA_AVAL &&
back_check == OTA_NOT_AVAL) { // BACK已刷写,但未检查
#if OTA_DEBUG
std::printf("aval\r\n");
#endif
move_app_data();
} else {
printf("check\r\n");
}
}
+63 -16
View File
@@ -4,23 +4,12 @@
#ifdef __cplusplus
extern "C" {
#endif
#include "config.h"
#include "gd32c10x_eval.h"
#include "stdint.h"
#include <stdio.h>
#include <cstdint>
#include <cstdio>
constexpr u16 REDUCTION_RATIO = 25;
constexpr float DEG2RAD = 1.0f / 360.0f * 6.28318530718f;
constexpr float RAD2DEG = 360.0f / 6.28318530718f;
void rcu_config(void);
static volatile uint32_t timer_delay_count = 0; // volatile 很重要!
int fputc(int ch, FILE *f); // 声明fputc函数以重载标准库实现
u8 tle5210b_init(void);
u8 USART0_init(void);
u8 watchdog_init(u32 time);
void driver_init(void);
// 任务标志定义
typedef enum {
TASK_MOTOR_CONTROL = 0,
@@ -36,13 +25,71 @@ typedef enum {
TASK_COUNT
} SystemTask;
void rcu_config(void);
static volatile uint32_t timer_delay_count = 0; // volatile 很重要!
int fputc(int ch, FILE *f); // 声明fputc函数以重载标准库实现
u8 USART0_init(void);
u8 watchdog_init(u32 time);
u16 get_reset_cause(void);
void unused_pin_init();
void OTA_initial(void);
// 任务管理结构
typedef struct {
volatile u32 taskFlags; // 任务标志位(每个位代表一个任务)
} TaskScheduler;
// 版本管理类
class VersionManager {
public:
// 版本信息结构体
typedef struct {
u16 major;
u16 minor;
u16 patch;
u16 build;
} VersionInfo;
// 构造函数
VersionManager();
// 获取软件版本
VersionInfo getSoftwareVersion() const;
// 获取硬件版本
VersionInfo getHardwareVersion() const;
// 获取BOOT版本
VersionInfo getBootVersion() const;
// 设置软件版本
void setSoftwareVersion(u16 major, u16 minor, u16 patch, u16 build);
// 设置硬件版本
void setHardwareVersion(u16 major, u16 minor, u16 patch, u16 build);
// 设置BOOT版本
void setBootVersion(u16 major, u16 minor, u16 patch, u16 build);
// 将版本信息转换为字符串
char *versionToString(const VersionInfo &version, char *buffer,
size_t bufSize) const;
// 打印所有版本信息
void printVersions() const;
// 通过CAN发送版本信息
void sendVersionInfoViaCan() const;
private:
VersionInfo softwareVersion;
VersionInfo hardwareVersion;
VersionInfo bootVersion;
};
#ifdef __cplusplus
}
#endif
#endif
#endif
+159 -86
View File
@@ -1,117 +1,190 @@
/*!
\file systick.c
\brief the systick configuration file
\version 2025-06-20, V1.5.1, firmware for GD32C10x
\file systick.c
\brief the systick configuration file
\version 2025-06-20, V1.5.1, firmware for GD32C10x
*/
/*
Copyright (c) 2024, GigaDevice Semiconductor Inc.
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:
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.
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.
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.
*/
#include "gd32c10x.h"
#include "systick.h"
#include "Can.h"
#include "config.h"
#include "core_cmFunc.h"
#include "flash.h"
#include "gd32c10x.h"
#include "gd32c10x_exti.h"
#include "gd32c10x_fmc.h"
#include "initial.h"
#include "motor.h"
#include <cstdio>
volatile static uint32_t delay;
extern CAN_transmiter CAN0_transmiter;
extern FlashEEPROM flashEEP;
/*!
\brief configure systick
\param[in] none
\param[out] none
\retval none
\brief configure systick
\param[in] none
\param[out] none
\retval none
*/
void systick_config(void)
{
/* setup systick timer for 1000Hz interrupts */
if (SysTick_Config(SystemCoreClock / 1000U)){
/* capture error */
while (1){
}
}
/* configure the systick handler priority */
NVIC_SetPriority(SysTick_IRQn, 0x00U);
void systick_config(void) {
/* setup systick timer for 1000Hz interrupts */
if (SysTick_Config(SystemCoreClock / 1000U)) {
/* capture error */
while (1) {
}
}
/* configure the systick handler priority */
NVIC_SetPriority(SysTick_IRQn, 0x00U);
}
/*!
\brief delay a time in seconds
\param[in] count: count in seconds
\param[out] none
\retval none
\brief delay a time in seconds
\param[in] count: count in seconds
\param[out] none
\retval none
*/
void delay_1s(uint32_t count)
{
uint32_t i;
for(i = 0; i < count; i++){
delay_1ms(1000);
}
void delay_1s(uint32_t count) {
uint32_t i;
for (i = 0; i < count; i++) {
delay_1ms(1000);
}
}
/*!
\brief delay a time in milliseconds
\param[in] count: count in milliseconds
\param[out] none
\retval none
\brief delay a time in milliseconds
\param[in] count: count in milliseconds
\param[out] none
\retval none
*/
void delay_1ms(uint32_t count)
{
delay = count;
while(0U != delay){
void delay_1ms(uint32_t count) {
delay = count;
while (0U != delay) {
fwdgt_counter_reload();
fwdgt_counter_reload();
}
}
}
/*!
\brief delay decrement
\param[in] none
\param[out] none
\retval none
\brief delay decrement
\param[in] none
\param[out] none
\retval none
*/
void delay_decrement(void)
{
if (0U != delay){
delay--;
}
void delay_decrement(void) {
if (0U != delay) {
delay--;
}
}
/*!
\brief system soft reset
\param[in] none
\param[out] none
\retval none
\brief system soft reset
\param[in] none
\param[out] none
\retval none
*/
void system_soft_reset(void)
{
/* Set the software reset bit */
SCB->AIRCR = (0x05FA0000U | (SCB->AIRCR & (0x700U)) | (1U << 2));
/* Data Synchronization Barrier */
__DSB();
/* Wait for reset */
while (1){
__NOP();
}
}
void system_soft_reset(void) {
/* Set the software reset bit */
SCB->AIRCR = (0x05FA0000U | (SCB->AIRCR & (0x700U)) | (1U << 2));
/* Data Synchronization Barrier */
__DSB();
/* Wait for reset */
while (1) {
__NOP();
}
}
/*!
\brief prepare system to enter deep sleep mode
\param[in] none
\param[out] none
\retval none
*/
void app_prepare_deep_sleep(bool save_data) {
if (save_data) {
flashEEP.save_system_config(true);
}
// 将SIT1044设置为低功耗待机模式
// CAN0_transmiter.CAN_Sleep();
motor_sleep();
// 在睡眠前调整看门狗超时时间为最大值,使其在唤醒前不会触发
fwdgt_write_enable();
fwdgt_config(0xFFF, FWDGT_PSC_DIV256); // 设置最大超时时间
fwdgt_write_disable();
__disable_irq();
// 遍历最后一个数字,后一个地址写+1
for (u32 address = SLEEP_CONFIG_END - SIZE_U32;
address >= SLEEP_CONFIG_START; address -= SIZE_U32) { // 遍历睡眠存储区
volatile u32 *flash_ptr = (volatile u32 *)address;
u32 sleep_enable = *flash_ptr;
if (sleep_enable == FLASH_EMPTY and
address > SLEEP_CONFIG_START) { // 空数据且未到头跳过
continue;
} else { // 有数据的话读取
#if SLEEP_DEBUG
printf("app sleep found %08x at %08x\r\n", sleep_enable, address);
#endif
if (address == SLEEP_CONFIG_END - SIZE_U32) {
fmc_unlock();
fmc_state_enum fmc_status =
fmc_page_erase(SLEEP_CONFIG_START); // 擦除已满的页
if (fmc_status != FMC_READY) { // 擦除失败报错
fmc_lock();
flashEEP.EEPROMStatus = FLASH_EEPROM_ERASE_ERROR;
return;
}
address = SLEEP_CONFIG_START - SIZE_U32; // 重新开始写入
}
address += SIZE_U32;
#if SLEEP_DEBUG
printf("app sleep prepare write %08x at %08x\r\n", SLEEP_ENABLE,
address);
#endif
fmc_state_enum fmc_status =
write_ADDRESS(address, SLEEP_ENABLE); // 写入数据
#if SLEEP_DEBUG
volatile u32 *flash_ptr = (volatile u32 *)address;
u32 sleep_check = *flash_ptr;
printf("app sleep wrote %08x at %08x\r\n", sleep_check, address);
#endif
if (fmc_status != FMC_READY) { // 写入失败报错
flashEEP.EEPROMStatus = FLASH_EEPROM_WRITE_ERROR;
#if SLEEP_DEBUG
printf("app wrote %08x at %08x ERROR\r\n", SLEEP_ENABLE,
address);
#endif
return;
}
break;
}
}
jumpToBOOT(); // 跳转到bootloader正式休眠,进入低功耗待机模式
}
+5 -1
View File
@@ -38,7 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <cstdint>
/* configure systick */
void systick_config(void);
@@ -54,6 +54,10 @@ void idle_task_count(void);
uint8_t get_cpu_usage(void);
/* 系统软复位 */
void system_soft_reset(void);
/* 准备进入低功耗模式 */
void app_prepare_deep_sleep(bool save_data);
/* 中断唤醒 */
void EXTI5_9_IRQHandler(void);
#ifdef __cplusplus
}