feat(CAN): 添加静默模式支持并优化节点ID处理

- 添加静默模式功能,在接收到base_id=0x0000消息时停止发送10秒
- 修正节点ID加载逻辑,区分有效节点ID(0-65534)和Flash擦除状态(0xFFFF)
- 添加静默模式相关的状态检查和时间管理功能
- 在CAN通信检查中集成静默模式处理流程

fix(FOC): 修复速度控制中的方向参数应用
- 在velocity_control、angle_control_with_velocity_limit和MIT_Mode函数中
 正确应用DIR参数调整速度误差的符号
- 添加详细注释说明DIR参数对速度误差计算的影响

refactor(systick): 添加毫秒级系统时间功能
- 实现get_systick_ms()函数提供毫秒级系统时间
- 添加SysTick中断处理程序更新系统时间计数器

chore(init): 调整初始化顺序优化系统启动流程
- 将EEPROM初始化移至CAN初始化之前,确保正确的依赖关系
This commit is contained in:
cbb
2026-03-19 23:49:08 +08:00
parent 9f56ab394e
commit bdf03517b3
9 changed files with 126 additions and 36 deletions
+79 -22
View File
@@ -33,6 +33,7 @@ extern EncoderAngleKalman Angle_kalman; // 角度滤波
extern EncoderVelocityKalman Vel_kalman; // 速度滤波
extern FlashEEPROM flashEEP;
extern VersionManager Version; // 声明外部版本管理器实例
extern u32 motor_runtime_50us; // 电机驱动计算轮次(用于静默模式计时)
// 添加 DMA 相关变量
dma_parameter_struct dma_rx_parameter;
@@ -105,16 +106,17 @@ void CAN_transmiter::set_node_id(u16 new_id) {
\retval FLASH_EEPROM_OK: 加载成功
其他:加载失败,使用默认值
\note Flash 擦除状态为 0xFFFF,需要特殊处理避免误判
注意:0 是有效的节点 ID,不应被视为无效值
*/
u8 CAN_transmiter::load_node_id_from_flash() {
u16 node_id_temp = 0xFFFF; // 初始化为 Flash 擦除值
FlashEepromStatus status =
flashEEP.read(FlashEEPROM::ADDR_NODE_ID, &node_id_temp);
// 检查 Flash 是否为擦除状态 (0xFFFF 或 0) 或读取失败
// 注意:Flash 未写入时读到的值是 0xFFFF,但有些情况可能读到 0
if (status != FLASH_EEPROM_OK || node_id_temp == 0xFFFF ||
node_id_temp == 0) {
// 检查 Flash 是否为擦除状态 (0xFFFF) 或读取失败
// 注意:Flash 未写入时读到的值是 0xFFFF
// 0 是有效的节点 ID,不应被视为无效值
if (status != FLASH_EEPROM_OK || node_id_temp == 0xFFFF) {
node_id = DEFAULT_NODE_ID;
CAN_DEBUG_PRINT(
"Node ID not found in Flash (status=%d, val=0x%04X), using "
@@ -123,7 +125,7 @@ u8 CAN_transmiter::load_node_id_from_flash() {
return FLASH_EEPROM_DATA_NOT_FOUND;
}
// 检查节点 ID 是否有效
// 检查节点 ID 是否有效 (0-65534 都是有效值)
if (node_id_temp <= MAX_NODE_ID) {
node_id = node_id_temp;
CAN_DEBUG_PRINT("Node ID loaded from Flash: %d\r\n", node_id);
@@ -203,6 +205,37 @@ bool CAN_transmiter::dequeue_rx_message(can_receive_message_struct &message) {
return false;
}
// 静默模式相关函数实现
// 使用 systick 获取系统时间(ms)
extern u32 get_systick_ms(void);
/*!
\brief 进入静默模式(停发 10 秒)
*/
void CAN_transmiter::enter_silent_mode() {
is_silent = true;
silent_start_time = get_systick_ms(); // 记录当前时间(ms)
CAN_DEBUG_PRINT("Enter silent mode for %d ms, start_time=%d\r\n", CAN_SILENT_DURATION_MS, silent_start_time);
}
/*!
\brief 检查是否在静默模式中
*/
bool CAN_transmiter::is_in_silent_mode() { return is_silent; }
/*!
\brief 检查静默模式是否结束
*/
void CAN_transmiter::check_silent_mode() {
if (is_silent) {
u32 current_time = get_systick_ms(); // 当前时间(ms)
if (current_time - silent_start_time >= CAN_SILENT_DURATION_MS) {
is_silent = false;
CAN_DEBUG_PRINT("Exit silent mode, elapsed=%d ms\r\n", current_time - silent_start_time);
}
}
}
/*!
\brief initialize CAN GPIO
\param[in] none
@@ -645,10 +678,16 @@ void CAN_transmiter::update(void) {
/**
* @brief CANFD 发送函数
* @retval 0: 发送失败
* @retval 0: 发送失败(或处于静默模式)
* 1: 发送成功
*/
u8 CAN_transmiter::CANFD_all_Send() {
// 检查是否在静默模式中,如果是则不发送
if (is_in_silent_mode()) {
check_silent_mode(); // 检查是否已退出静默
return 0;
}
u32 success_flag = 0;
// 打包 status 数据 - 只清零实际使用的 32 字节
@@ -694,11 +733,13 @@ u8 CAN_transmiter::CANFD_all_Send() {
void CAN_transmiter::communication_check() {
// CAN0 发送数据标志
if (SET == can0_send_flag) {
// CAN_DEBUG_PRINT("\r\n can0 %X receive data:",
// receive_message.rx_efid);
update();
// CAN0_transmiter.CAN_all_Send();
CANFD_all_Send();
// 检查是否在静默模式中
if (!is_in_silent_mode()) {
update();
CANFD_all_Send();
} else {
check_silent_mode(); // 检查静默是否结束
}
can0_send_flag = RESET;
}
@@ -709,14 +750,37 @@ void CAN_transmiter::communication_check() {
// current_message.rx_efid); for (i = 0; i < current_message.rx_dlen;
// i++) { CAN_DEBUG_PRINT(" %02x", current_message.rx_data[i]);
// }
// 检查消息是否是发给本节点的 (检查高 16 位)
// 提取基础 ID (低 16 位,去除高 16 位节点 ID 部分)
u32 base_id = current_message.rx_efid & 0xFFFF;
// 提取发送方的节点 ID
u16 sender_node_id = (u16)((current_message.rx_efid >> 16) & 0xFFFF);
// 特殊处理 base_id=0x0000(BOOT 命令):即使是其他节点的广播消息也要处理
if (base_id == CANFD_BOOT_ID) {
// 判断是广播消息还是其他节点的命令
if (sender_node_id == BROADCAST_NODE_ID || sender_node_id != node_id) {
// 广播消息或其他节点的命令 → 进入静默模式(停发 10 秒)
CAN_DEBUG_PRINT("Received base_id=0x0000 from node %d, entering silent mode for 10s\r\n", sender_node_id);
enter_silent_mode();
} else {
// 自己节点的命令 → 执行 BOOT 功能
CAN_DEBUG_PRINT("Received base_id=0x0000 from self, jumping to BOOT\r\n");
motor_sleep();
flashEEP.save_system_config(false);
fmc_unlock();
OTA_SET(n_APP_LATEST_EN_ADDR, OTA_NOT_AVAL); // 设置 APP 为不激活
fmc_lock();
jumpToBOOT();
}
continue; // BOOT 命令处理完跳过后续逻辑
}
// 其他 base_id 的消息,检查是否是发给本节点的
if (!is_message_for_me(current_message.rx_efid)) {
continue; // 不是发给本节点的消息,跳过
}
// 提取基础 ID (低 16 位,去除高 16 位节点 ID 部分)
u32 base_id = current_message.rx_efid & 0xFFFF;
if (base_id == CANFD_CMD_ID) {
// 控制模式
FOC.control_mode = current_message.rx_data[0];
@@ -787,13 +851,6 @@ void CAN_transmiter::communication_check() {
} else if (base_id == CANFD_VERSION_ID) {
// 处理版本号请求,发送当前系统版本信息
Version.sendVersionInfoViaCan();
} else if (base_id == CANFD_BOOT_ID) {
motor_sleep();
flashEEP.save_system_config(false);
fmc_unlock();
OTA_SET(n_APP_LATEST_EN_ADDR, OTA_NOT_AVAL); // 设置 APP 为不激活
fmc_lock();
jumpToBOOT();
} else if (base_id == CANFD_OTA_ACK_ID) {
volatile u32 *flash_ptr = (volatile u32 *)n_APP_LATEST_EN_ADDR;
u32 app_enable = *flash_ptr;