CAN多节点通信实战:基于系统RTC及系统时钟Tick的心跳风暴抑制方案

方案定义

本方案采用两级时基:

  • 系统RTC:用于计算统一周期起点 periodStart
  • 系统时钟Tick:用于保证发送窗口精度

本方案支持两种通信模式:

  • 主从通信:由 Master 周期发布系统 RTC
  • 对等通信:由 1号节点 周期发布系统 RTC

系统 RTC 发布节点只负责授时,不直接参与其他节点的心跳调度计算。


全局参数

  • Thb:节点心跳周期
  • N:系统容量
  • NodeId:节点号
  • rtcNow:当前节点本地 RTC 时间
  • localTickNow:当前节点本地系统 Tick

当前参数示例:

  • Thb = 30s
  • N = 200
  • 系统 RTC 发布周期 = 10分钟
  • 本地 Tick 精度 = 10ms

系统RTC来源

主从通信模式

系统 RTC 由 Master 周期发布。

Slave 接收后同步本地 RTC。

对等通信模式

系统 RTC 由 1号节点 周期发布, 其他节点接收后同步本地 RTC。

对等通信模式下,1号节点 发送,所有节点仍按统一规则计算心跳周期与发送窗口。


周期起点计算

当前心跳周期起点由节点本地 RTC 直接计算:

c 复制代码
periodStart = (rtcNow / Thb) * Thb;

其中:

  • rtcNow 为以秒为单位的系统时间戳
  • Thb 为以秒为单位的心跳周期

示例:

c 复制代码
rtcNow = 1719833725;
Thb = 30;
periodStart = (1719833725 / 30) * 30 = 1719833710;

所有节点只要 RTC 已同步到同一系统时间基准,计算得到的 periodStart 就一致。


发送窗口计算

每个节点固定映射到一个发送窗口:

c 复制代码
windowSize = Thb / N;
sendOffset = (NodeId % N) * windowSize;

参数代入:

c 复制代码
windowSize = 30000ms / 200 = 150ms;

即在每个 30 秒周期内,200 个节点均匀分散到 200 个发送窗口中。


本地Tick映射

在轮询中根据当前 RTC 计算当前周期起点:

c 复制代码
periodStartRtc = (rtcNowSec / T_hbSec) * T_hbSec;

若检测到进入新周期,则记录当前本地 Tick:

c 复制代码
periodStartTick = localTickNow;

该值表示当前周期起点在本地 Tick 时间轴上的映射时刻。


心跳发送规则

本节点发送偏移为:

c 复制代码
sendOffset = (NodeId % N) * windowSize;
sendTick = periodStartTick + sendOffset;

发送条件:

c 复制代码
if (!sentFlag && localTickNow >= sendTick) {
    send_heartbeat();
    sentFlag = 1;
}

每个周期只发送一次心跳。

进入新周期后清除 sentFlag


RTC同步规则

系统 RTC 发布节点周期发送 RTC 同步报文。

节点收到后执行本地 RTC 同步。

RTC 同步报文只用于:

  • 更新本地 RTC

RTC 同步报文不用于:

  • 不直接计算 periodStart
  • 不直接修改发送窗口
  • 不直接触发心跳发送

运行流程

1. 节点初始化

初始化上下文参数:

  • 心跳周期 Thb
  • 系统容量 N
  • 节点号 NodeId
  • 本周期发送标志 sentFlag

2. 系统RTC同步

系统 RTC 发布节点周期发送 RTC 同步报文, 其他节点接收后同步本地 RTC。

3. 周期轮询

节点周期调用轮询函数,输入:

  • 当前 RTC
  • 当前本地 Tick

4. 计算周期起点

根据当前 RTC 计算:

c 复制代码
periodStartRtc = (rtcNowSec / T_hbSec) * T_hbSec;

5. 新周期处理

periodStartRtc 发生变化:

  • 更新记录的周期起点
  • 保存新的 periodStartTick
  • 清除 sentFlag

6. 发送判定

根据节点号计算发送偏移与发送时刻,满足条件后发送一次心跳。


参考实现

c 复制代码
#include <stdint.h>

typedef struct {
    uint32_t lastPeriodStartRtc;  // 当前周期起点,单位:秒
    uint32_t periodStartTick;     // 当前周期起点对应的本地Tick,单位:ms
    uint32_t windowSizeMs;        // 窗口宽度,单位:ms
    uint32_t periodSec;           // 心跳周期,单位:秒
    uint16_t nodeId;
    uint16_t nodeCount;
    uint8_t sentFlag;
} HeartbeatCtx;

void heartbeat_init(HeartbeatCtx *ctx,
                    uint16_t nodeId,
                    uint16_t nodeCount,
                    uint32_t periodSec)
{
    ctx->lastPeriodStartRtc = 0;
    ctx->periodStartTick = 0;
    ctx->windowSizeMs = (periodSec * 1000) / nodeCount;
    ctx->periodSec = periodSec;
    ctx->nodeId = nodeId;
    ctx->nodeCount = nodeCount;
    ctx->sentFlag = 0;
}

void heartbeat_poll(HeartbeatCtx *ctx, uint32_t rtcNowSec, uint32_t localTickNow)
{
    uint32_t periodStartRtc = (rtcNowSec / ctx->periodSec) * ctx->periodSec;

    if (periodStartRtc != ctx->lastPeriodStartRtc) {
        ctx->lastPeriodStartRtc = periodStartRtc;
        ctx->periodStartTick = localTickNow;
        ctx->sentFlag = 0;
    }

    uint32_t sendOffset =(uint32_t)(ctx->nodeId % ctx->nodeCount) * ctx->windowSizeMs;
    uint32_t sendTick = ctx->periodStartTick + sendOffset;

    if (!ctx->sentFlag && localTickNow >= sendTick) {
        send_heartbeat();
        ctx->sentFlag = 1;
    }
}

参数示例

按当前项目参数:

  • nodeCount = 200
  • periodSec = 30
  • windowSizeMs = 150
  • RTC 发布周期 = 10分钟
  • local Tick = 10ms

小结

本方案统一以系统 RTC 计算 periodStart,以节点号分配固定发送窗口,以本地 Tick 实现窗口级精确发送。系统 RTC 可由 Master 发布,也可在对等通信模式下由 1 号机发布。RTC 同步仅用于统一各节点本地时间,不直接参与心跳调度逻辑。

相关推荐
凡人叶枫14 小时前
Effective C++ 条款03:尽可能使用 const
linux·开发语言·c++·嵌入式开发
俊基科技3 天前
AU-48 双麦语音处理模组详解:AEC+ENC 一体化音频方案,兼容 A-47 无缝替换
语音识别·嵌入式开发·硬件开发·ai降噪·回声消除
chipsense10 天前
变频空调能效虚标技术揭秘:压缩机电流检测的硬核解析
嵌入式开发·霍尔传感器·变频空调·电流传感器·an1v·foc控制·pfc电路
止观止12 天前
在 WSL2 上从零搭建 ARM 混合编程环境
汇编·arm开发·嵌入式开发·混合编程
十年编程老舅12 天前
读懂 MCU 启动:从上电到程序运行全链路
单片机·嵌入式硬件·mcu·嵌入式·cpu·嵌入式开发·ram
dozenyaoyida13 天前
RISC-V嵌入式开发:彻底解决“undefined reference to isatty“错误全攻略
经验分享·c·cmake·嵌入式开发·isatty·没有定义问题
wotaifuzao16 天前
指针和中断不是魔法:用第一性原理看穿嵌入式底层(万字解析)
stm32·嵌入式开发·内存模型·c语言指针·arm架构·中断机制·rtos内核
武汉唯众智创17 天前
全栈物联网实训平台拆解:通信协议+边缘AI+实战源码
人工智能·物联网·嵌入式开发·物联网实训平台·高校实训·python物联网
2601_9583529018 天前
A-68双麦波束模组深度解析:90dB降噪、60°夹角、3-5米拾音,一篇讲透
人工智能·语音识别·嵌入式开发·音频降噪·回音消除
啊哈哈哈118 天前
Modbus 协议官方规范资料包:中文翻译版 / 英文原版 / 中英对照版
串口通信·modbus·嵌入式开发·工业通信·plc通信·上位机开发·协议规范