CANopen TIME/SYNC 运行流程

CANopen TIME/SYNC 运行流程

文章目录

  • [CANopen TIME/SYNC 运行流程](#CANopen TIME/SYNC 运行流程)
    • [1. 先把 TIME 和 SYNC 分开](#1. 先把 TIME 和 SYNC 分开)
    • [2. 协议侧:SYNC 规定了什么](#2. 协议侧:SYNC 规定了什么)
      • [2.1 SYNC 的角色](#2.1 SYNC 的角色)
      • [2.2 SYNC 帧格式](#2.2 SYNC 帧格式)
      • [2.3 与 SYNC 直接相关的对象字典](#2.3 与 SYNC 直接相关的对象字典)
      • [2.4 同步窗口的含义](#2.4 同步窗口的含义)
    • [3. 协议侧:TIME 规定了什么](#3. 协议侧:TIME 规定了什么)
      • [3.1 TIME 的角色](#3.1 TIME 的角色)
      • [3.2 TIME 帧格式](#3.2 TIME 帧格式)
      • [3.3 与 TIME 直接相关的对象字典](#3.3 与 TIME 直接相关的对象字典)
    • [4. 源码阅读地图](#4. 源码阅读地图)
      • [4.1 四个文件各看什么](#4.1 四个文件各看什么)
      • [4.2 两个模块的共同模式](#4.2 两个模块的共同模式)
    • [5. SYNC 源码运行流程](#5. SYNC 源码运行流程)
      • [5.1 初始化:`CO_SYNC_init()`](#5.1 初始化:CO_SYNC_init())
      • [5.2 接收中断:`CO_SYNC_receive()`](#5.2 接收中断:CO_SYNC_receive())
      • [5.3 发送:`CO_SYNCsend()`](#5.3 发送:CO_SYNCsend())
      • [5.4 周期处理:`CO_SYNC_process()`](#5.4 周期处理:CO_SYNC_process())
      • [5.5 consumer 超时监控](#5.5 consumer 超时监控)
      • [5.6 `0x1005` / `0x1019` 动态写入](#5.6 0x1005 / 0x1019 动态写入)
    • [6. TIME 源码运行流程](#6. TIME 源码运行流程)
      • [6.1 初始化:`CO_TIME_init()`](#6.1 初始化:CO_TIME_init())
      • [6.2 接收中断:`CO_TIME_receive()`](#6.2 接收中断:CO_TIME_receive())
      • [6.3 周期处理:`CO_TIME_process()`](#6.3 周期处理:CO_TIME_process())
      • [6.4 接收到 TIME 后如何解析](#6.4 接收到 TIME 后如何解析)
      • [6.5 没有收到 TIME 时如何本地走时](#6.5 没有收到 TIME 时如何本地走时)
      • [6.6 TIME producer 如何启动](#6.6 TIME producer 如何启动)
    • [7. TIME 与 SYNC 在主循环中的关系](#7. TIME 与 SYNC 在主循环中的关系)
    • [8. 最小心智模型](#8. 最小心智模型)
    • 参考资料

1. 先把 TIME 和 SYNC 分开

TIME 和 SYNC 都属于 CANopen 的特殊功能通信对象,但它们解决的问题不同:

对象 核心问题 默认 CAN-ID 数据长度 典型用途
SYNC "什么时候进入一个同步周期?" 0x080 01 同步 TPDO/RPDO、周期采样、周期控制
TIME "网络当前时间是多少?" 0x100 6 网络时间校准、时间戳、日志时间基准

一句话区分:

text 复制代码
SYNC 是节拍;TIME 是时钟。

SYNC 不携带实际过程数据,它只广播一个同步事件。同步 PDO 在这个事件前后按配置动作。TIME 也不携带过程数据,它只携带"当天毫秒数 + 自 1984-01-01 起的天数"。


2. 协议侧:SYNC 规定了什么

2.1 SYNC 的角色

SYNC 使用 producer/consumer 模型:
#mermaid-svg-nN2hG4IX9pimG0wN{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nN2hG4IX9pimG0wN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nN2hG4IX9pimG0wN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nN2hG4IX9pimG0wN .error-icon{fill:#552222;}#mermaid-svg-nN2hG4IX9pimG0wN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nN2hG4IX9pimG0wN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nN2hG4IX9pimG0wN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nN2hG4IX9pimG0wN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nN2hG4IX9pimG0wN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nN2hG4IX9pimG0wN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nN2hG4IX9pimG0wN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nN2hG4IX9pimG0wN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nN2hG4IX9pimG0wN .marker.cross{stroke:#333333;}#mermaid-svg-nN2hG4IX9pimG0wN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nN2hG4IX9pimG0wN p{margin:0;}#mermaid-svg-nN2hG4IX9pimG0wN .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nN2hG4IX9pimG0wN .cluster-label text{fill:#333;}#mermaid-svg-nN2hG4IX9pimG0wN .cluster-label span{color:#333;}#mermaid-svg-nN2hG4IX9pimG0wN .cluster-label span p{background-color:transparent;}#mermaid-svg-nN2hG4IX9pimG0wN .label text,#mermaid-svg-nN2hG4IX9pimG0wN span{fill:#333;color:#333;}#mermaid-svg-nN2hG4IX9pimG0wN .node rect,#mermaid-svg-nN2hG4IX9pimG0wN .node circle,#mermaid-svg-nN2hG4IX9pimG0wN .node ellipse,#mermaid-svg-nN2hG4IX9pimG0wN .node polygon,#mermaid-svg-nN2hG4IX9pimG0wN .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nN2hG4IX9pimG0wN .rough-node .label text,#mermaid-svg-nN2hG4IX9pimG0wN .node .label text,#mermaid-svg-nN2hG4IX9pimG0wN .image-shape .label,#mermaid-svg-nN2hG4IX9pimG0wN .icon-shape .label{text-anchor:middle;}#mermaid-svg-nN2hG4IX9pimG0wN .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nN2hG4IX9pimG0wN .rough-node .label,#mermaid-svg-nN2hG4IX9pimG0wN .node .label,#mermaid-svg-nN2hG4IX9pimG0wN .image-shape .label,#mermaid-svg-nN2hG4IX9pimG0wN .icon-shape .label{text-align:center;}#mermaid-svg-nN2hG4IX9pimG0wN .node.clickable{cursor:pointer;}#mermaid-svg-nN2hG4IX9pimG0wN .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nN2hG4IX9pimG0wN .arrowheadPath{fill:#333333;}#mermaid-svg-nN2hG4IX9pimG0wN .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nN2hG4IX9pimG0wN .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nN2hG4IX9pimG0wN .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nN2hG4IX9pimG0wN .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nN2hG4IX9pimG0wN .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nN2hG4IX9pimG0wN .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nN2hG4IX9pimG0wN .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nN2hG4IX9pimG0wN .cluster text{fill:#333;}#mermaid-svg-nN2hG4IX9pimG0wN .cluster span{color:#333;}#mermaid-svg-nN2hG4IX9pimG0wN div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nN2hG4IX9pimG0wN .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nN2hG4IX9pimG0wN rect.text{fill:none;stroke-width:0;}#mermaid-svg-nN2hG4IX9pimG0wN .icon-shape,#mermaid-svg-nN2hG4IX9pimG0wN .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nN2hG4IX9pimG0wN .icon-shape p,#mermaid-svg-nN2hG4IX9pimG0wN .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nN2hG4IX9pimG0wN .icon-shape .label rect,#mermaid-svg-nN2hG4IX9pimG0wN .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nN2hG4IX9pimG0wN .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nN2hG4IX9pimG0wN .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nN2hG4IX9pimG0wN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} SYNC frame
SYNC frame
SYNC frame
SYNC producer

周期发送同步对象
SYNC consumer A
SYNC consumer B
SYNC consumer C
同步 TPDO/RPDO 动作
同步采样或控制
同步窗口判断

网络中通常只有一个 SYNC producer,其他节点作为 consumer。producer 的任务是周期性发送 SYNC 帧;consumer 收到后把它当成同步边界。

2.2 SYNC 帧格式

SYNC 默认是一个空数据帧:

text 复制代码
CAN-ID = 0x080
DLC    = 0

如果启用同步计数器,则变成:

text 复制代码
CAN-ID = 0x080
DLC    = 1
Byte0  = counter

计数器从 1 开始递增,到 0x1019 Synchronous counter overflow value 指定的最大值后回到 1。如果本地配置要求 DLC=0,却收到 DLC=1;或配置要求 DLC=1,却收到其他长度,consumer 应视为同步数据长度错误。

2.3 与 SYNC 直接相关的对象字典

OD 名称 对源码的影响
0x1005 COB-ID SYNC message 决定 SYNC CAN-ID;bit30 决定本节点是否 producer
0x1006 Communication cycle period producer 的发送周期;consumer 的超时监控基准
0x1007 Synchronous window length 同步窗口;窗口外同步 PDO 应被限制
0x1019 Synchronous counter overflow value 0 时 SYNC 无数据;大于 1 时 SYNC 携带 1 字节 counter

0x1006 = 0 等价于不启用周期 SYNC;0x1007 = 0 等价于关闭同步窗口约束;0x1019 = 0 等价于不使用 SYNC counter。

2.4 同步窗口的含义

#mermaid-svg-hnkHekimYGmSf9Tx{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hnkHekimYGmSf9Tx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hnkHekimYGmSf9Tx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hnkHekimYGmSf9Tx .error-icon{fill:#552222;}#mermaid-svg-hnkHekimYGmSf9Tx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hnkHekimYGmSf9Tx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hnkHekimYGmSf9Tx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hnkHekimYGmSf9Tx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hnkHekimYGmSf9Tx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hnkHekimYGmSf9Tx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hnkHekimYGmSf9Tx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hnkHekimYGmSf9Tx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hnkHekimYGmSf9Tx .marker.cross{stroke:#333333;}#mermaid-svg-hnkHekimYGmSf9Tx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hnkHekimYGmSf9Tx p{margin:0;}#mermaid-svg-hnkHekimYGmSf9Tx .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-hnkHekimYGmSf9Tx .cluster-label text{fill:#333;}#mermaid-svg-hnkHekimYGmSf9Tx .cluster-label span{color:#333;}#mermaid-svg-hnkHekimYGmSf9Tx .cluster-label span p{background-color:transparent;}#mermaid-svg-hnkHekimYGmSf9Tx .label text,#mermaid-svg-hnkHekimYGmSf9Tx span{fill:#333;color:#333;}#mermaid-svg-hnkHekimYGmSf9Tx .node rect,#mermaid-svg-hnkHekimYGmSf9Tx .node circle,#mermaid-svg-hnkHekimYGmSf9Tx .node ellipse,#mermaid-svg-hnkHekimYGmSf9Tx .node polygon,#mermaid-svg-hnkHekimYGmSf9Tx .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hnkHekimYGmSf9Tx .rough-node .label text,#mermaid-svg-hnkHekimYGmSf9Tx .node .label text,#mermaid-svg-hnkHekimYGmSf9Tx .image-shape .label,#mermaid-svg-hnkHekimYGmSf9Tx .icon-shape .label{text-anchor:middle;}#mermaid-svg-hnkHekimYGmSf9Tx .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-hnkHekimYGmSf9Tx .rough-node .label,#mermaid-svg-hnkHekimYGmSf9Tx .node .label,#mermaid-svg-hnkHekimYGmSf9Tx .image-shape .label,#mermaid-svg-hnkHekimYGmSf9Tx .icon-shape .label{text-align:center;}#mermaid-svg-hnkHekimYGmSf9Tx .node.clickable{cursor:pointer;}#mermaid-svg-hnkHekimYGmSf9Tx .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-hnkHekimYGmSf9Tx .arrowheadPath{fill:#333333;}#mermaid-svg-hnkHekimYGmSf9Tx .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hnkHekimYGmSf9Tx .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hnkHekimYGmSf9Tx .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hnkHekimYGmSf9Tx .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hnkHekimYGmSf9Tx .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hnkHekimYGmSf9Tx .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-hnkHekimYGmSf9Tx .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hnkHekimYGmSf9Tx .cluster text{fill:#333;}#mermaid-svg-hnkHekimYGmSf9Tx .cluster span{color:#333;}#mermaid-svg-hnkHekimYGmSf9Tx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-hnkHekimYGmSf9Tx .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hnkHekimYGmSf9Tx rect.text{fill:none;stroke-width:0;}#mermaid-svg-hnkHekimYGmSf9Tx .icon-shape,#mermaid-svg-hnkHekimYGmSf9Tx .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hnkHekimYGmSf9Tx .icon-shape p,#mermaid-svg-hnkHekimYGmSf9Tx .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-hnkHekimYGmSf9Tx .icon-shape .label rect,#mermaid-svg-hnkHekimYGmSf9Tx .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hnkHekimYGmSf9Tx .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-hnkHekimYGmSf9Tx .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-hnkHekimYGmSf9Tx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 收到/发送 SYNC

timer = 0
0 .. 0x1007

同步窗口内
timer > 0x1007

同步窗口外
下一次 SYNC

重新进入窗口

同步窗口是从 SYNC 边沿开始的一段时间。窗口内,同步 PDO 可以按配置处理;窗口外,源码用 syncIsOutsideWindow 记录状态,并通过 CO_SYNC_PASSED_WINDOW 通知上层"刚刚越过窗口"。


3. 协议侧:TIME 规定了什么

3.1 TIME 的角色

TIME 也是 producer/consumer 模型:
#mermaid-svg-Jmu9Intb2UpEwrMF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Jmu9Intb2UpEwrMF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Jmu9Intb2UpEwrMF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Jmu9Intb2UpEwrMF .error-icon{fill:#552222;}#mermaid-svg-Jmu9Intb2UpEwrMF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Jmu9Intb2UpEwrMF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Jmu9Intb2UpEwrMF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Jmu9Intb2UpEwrMF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Jmu9Intb2UpEwrMF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Jmu9Intb2UpEwrMF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Jmu9Intb2UpEwrMF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Jmu9Intb2UpEwrMF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Jmu9Intb2UpEwrMF .marker.cross{stroke:#333333;}#mermaid-svg-Jmu9Intb2UpEwrMF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Jmu9Intb2UpEwrMF p{margin:0;}#mermaid-svg-Jmu9Intb2UpEwrMF .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Jmu9Intb2UpEwrMF .cluster-label text{fill:#333;}#mermaid-svg-Jmu9Intb2UpEwrMF .cluster-label span{color:#333;}#mermaid-svg-Jmu9Intb2UpEwrMF .cluster-label span p{background-color:transparent;}#mermaid-svg-Jmu9Intb2UpEwrMF .label text,#mermaid-svg-Jmu9Intb2UpEwrMF span{fill:#333;color:#333;}#mermaid-svg-Jmu9Intb2UpEwrMF .node rect,#mermaid-svg-Jmu9Intb2UpEwrMF .node circle,#mermaid-svg-Jmu9Intb2UpEwrMF .node ellipse,#mermaid-svg-Jmu9Intb2UpEwrMF .node polygon,#mermaid-svg-Jmu9Intb2UpEwrMF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Jmu9Intb2UpEwrMF .rough-node .label text,#mermaid-svg-Jmu9Intb2UpEwrMF .node .label text,#mermaid-svg-Jmu9Intb2UpEwrMF .image-shape .label,#mermaid-svg-Jmu9Intb2UpEwrMF .icon-shape .label{text-anchor:middle;}#mermaid-svg-Jmu9Intb2UpEwrMF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Jmu9Intb2UpEwrMF .rough-node .label,#mermaid-svg-Jmu9Intb2UpEwrMF .node .label,#mermaid-svg-Jmu9Intb2UpEwrMF .image-shape .label,#mermaid-svg-Jmu9Intb2UpEwrMF .icon-shape .label{text-align:center;}#mermaid-svg-Jmu9Intb2UpEwrMF .node.clickable{cursor:pointer;}#mermaid-svg-Jmu9Intb2UpEwrMF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Jmu9Intb2UpEwrMF .arrowheadPath{fill:#333333;}#mermaid-svg-Jmu9Intb2UpEwrMF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Jmu9Intb2UpEwrMF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Jmu9Intb2UpEwrMF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Jmu9Intb2UpEwrMF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Jmu9Intb2UpEwrMF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Jmu9Intb2UpEwrMF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Jmu9Intb2UpEwrMF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Jmu9Intb2UpEwrMF .cluster text{fill:#333;}#mermaid-svg-Jmu9Intb2UpEwrMF .cluster span{color:#333;}#mermaid-svg-Jmu9Intb2UpEwrMF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Jmu9Intb2UpEwrMF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Jmu9Intb2UpEwrMF rect.text{fill:none;stroke-width:0;}#mermaid-svg-Jmu9Intb2UpEwrMF .icon-shape,#mermaid-svg-Jmu9Intb2UpEwrMF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Jmu9Intb2UpEwrMF .icon-shape p,#mermaid-svg-Jmu9Intb2UpEwrMF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Jmu9Intb2UpEwrMF .icon-shape .label rect,#mermaid-svg-Jmu9Intb2UpEwrMF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Jmu9Intb2UpEwrMF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Jmu9Intb2UpEwrMF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Jmu9Intb2UpEwrMF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 6-byte TIME stamp
6-byte TIME stamp
6-byte TIME stamp
TIME producer

网络时间源
TIME consumer A
TIME consumer B
TIME consumer C
校准本地 ms/days
日志/事件时间戳
时间相关应用

TIME 解决的是"网络时间一致性",不是"周期动作边界"。周期动作边界仍应看 SYNC。

3.2 TIME 帧格式

TIME 的数据长度固定为 6 字节:

text 复制代码
CAN-ID = 0x100 默认值
DLC    = 6
Byte0..Byte3 = milliseconds after midnight,低 28 bit 有效
Byte4..Byte5 = days since 1984-01-01

源码中的结构对应为:

c 复制代码
uint32_t ms;   /* milliseconds after midnight */
uint16_t days; /* days since January 1, 1984 */

3.3 与 TIME 直接相关的对象字典

OD 名称 对源码的影响
0x1012 COB-ID time stamp object bit31 使能 consumer;bit30 使能 producer;bits0...10 是 CAN-ID
0x1013 High resolution time stamp 高分辨率时间戳对象;当前上传的 CO_TIME.* 源码没有处理它

在 CANopenNode 的 CO_TIME.h 中,TIME 的 producer/consumer 角色完全由 0x1012 解析得到:

text 复制代码
bit31 = 1 -> isConsumer = true
bit30 = 1 -> isProducer = true
bits0..10 -> COB-ID,默认 0x100

4. 源码阅读地图

4.1 四个文件各看什么

文件 先看位置 作用
CO_SYNC.h CO_SYNC_tCO_SYNC_status_tCO_SYNCsend()CO_SYNC_process() 声明 理解 SYNC 对象状态、返回值和发送行为
CO_SYNC.c CO_SYNC_receive()OD_write_1005()OD_write_1019()CO_SYNC_init()CO_SYNC_process() 理解接收中断、OD 动态写、初始化、周期处理
CO_TIME.h CO_TIME_tCO_TIME_set()CO_TIME_process() 声明 理解 TIME 对象字段、设置当前时间和 producer 周期
CO_TIME.c CO_TIME_receive()OD_write_1012()CO_TIME_init()CO_TIME_process() 理解接收、OD 动态写、初始化、时间推进和发送

4.2 两个模块的共同模式

#mermaid-svg-HrGQ5AIpB0VFkEBX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HrGQ5AIpB0VFkEBX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HrGQ5AIpB0VFkEBX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HrGQ5AIpB0VFkEBX .error-icon{fill:#552222;}#mermaid-svg-HrGQ5AIpB0VFkEBX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HrGQ5AIpB0VFkEBX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HrGQ5AIpB0VFkEBX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HrGQ5AIpB0VFkEBX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HrGQ5AIpB0VFkEBX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HrGQ5AIpB0VFkEBX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HrGQ5AIpB0VFkEBX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HrGQ5AIpB0VFkEBX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HrGQ5AIpB0VFkEBX .marker.cross{stroke:#333333;}#mermaid-svg-HrGQ5AIpB0VFkEBX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HrGQ5AIpB0VFkEBX p{margin:0;}#mermaid-svg-HrGQ5AIpB0VFkEBX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-HrGQ5AIpB0VFkEBX .cluster-label text{fill:#333;}#mermaid-svg-HrGQ5AIpB0VFkEBX .cluster-label span{color:#333;}#mermaid-svg-HrGQ5AIpB0VFkEBX .cluster-label span p{background-color:transparent;}#mermaid-svg-HrGQ5AIpB0VFkEBX .label text,#mermaid-svg-HrGQ5AIpB0VFkEBX span{fill:#333;color:#333;}#mermaid-svg-HrGQ5AIpB0VFkEBX .node rect,#mermaid-svg-HrGQ5AIpB0VFkEBX .node circle,#mermaid-svg-HrGQ5AIpB0VFkEBX .node ellipse,#mermaid-svg-HrGQ5AIpB0VFkEBX .node polygon,#mermaid-svg-HrGQ5AIpB0VFkEBX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HrGQ5AIpB0VFkEBX .rough-node .label text,#mermaid-svg-HrGQ5AIpB0VFkEBX .node .label text,#mermaid-svg-HrGQ5AIpB0VFkEBX .image-shape .label,#mermaid-svg-HrGQ5AIpB0VFkEBX .icon-shape .label{text-anchor:middle;}#mermaid-svg-HrGQ5AIpB0VFkEBX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HrGQ5AIpB0VFkEBX .rough-node .label,#mermaid-svg-HrGQ5AIpB0VFkEBX .node .label,#mermaid-svg-HrGQ5AIpB0VFkEBX .image-shape .label,#mermaid-svg-HrGQ5AIpB0VFkEBX .icon-shape .label{text-align:center;}#mermaid-svg-HrGQ5AIpB0VFkEBX .node.clickable{cursor:pointer;}#mermaid-svg-HrGQ5AIpB0VFkEBX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HrGQ5AIpB0VFkEBX .arrowheadPath{fill:#333333;}#mermaid-svg-HrGQ5AIpB0VFkEBX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HrGQ5AIpB0VFkEBX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HrGQ5AIpB0VFkEBX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HrGQ5AIpB0VFkEBX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HrGQ5AIpB0VFkEBX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HrGQ5AIpB0VFkEBX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HrGQ5AIpB0VFkEBX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HrGQ5AIpB0VFkEBX .cluster text{fill:#333;}#mermaid-svg-HrGQ5AIpB0VFkEBX .cluster span{color:#333;}#mermaid-svg-HrGQ5AIpB0VFkEBX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HrGQ5AIpB0VFkEBX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HrGQ5AIpB0VFkEBX rect.text{fill:none;stroke-width:0;}#mermaid-svg-HrGQ5AIpB0VFkEBX .icon-shape,#mermaid-svg-HrGQ5AIpB0VFkEBX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HrGQ5AIpB0VFkEBX .icon-shape p,#mermaid-svg-HrGQ5AIpB0VFkEBX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HrGQ5AIpB0VFkEBX .icon-shape .label rect,#mermaid-svg-HrGQ5AIpB0VFkEBX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HrGQ5AIpB0VFkEBX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HrGQ5AIpB0VFkEBX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HrGQ5AIpB0VFkEBX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} CO_xxx_init()
读取对象字典
配置 CAN RX buffer
配置 CAN TX buffer

如果启用 producer
CAN receive callback

只做短路径处理
设置 CANrxNew flag
CO_xxx_process()

主循环/任务中处理

这也是 CANopenNode 很常见的设计方式:中断回调只做轻量接收和置标志,实际协议状态推进放到周期性 process() 里。


5. SYNC 源码运行流程

5.1 初始化:CO_SYNC_init()

CO_SYNC_init() 做的事情可以按对象字典展开:
#mermaid-svg-zaSWSpqEsGer4GSz{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zaSWSpqEsGer4GSz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zaSWSpqEsGer4GSz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zaSWSpqEsGer4GSz .error-icon{fill:#552222;}#mermaid-svg-zaSWSpqEsGer4GSz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zaSWSpqEsGer4GSz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zaSWSpqEsGer4GSz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zaSWSpqEsGer4GSz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zaSWSpqEsGer4GSz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zaSWSpqEsGer4GSz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zaSWSpqEsGer4GSz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zaSWSpqEsGer4GSz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zaSWSpqEsGer4GSz .marker.cross{stroke:#333333;}#mermaid-svg-zaSWSpqEsGer4GSz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zaSWSpqEsGer4GSz p{margin:0;}#mermaid-svg-zaSWSpqEsGer4GSz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zaSWSpqEsGer4GSz .cluster-label text{fill:#333;}#mermaid-svg-zaSWSpqEsGer4GSz .cluster-label span{color:#333;}#mermaid-svg-zaSWSpqEsGer4GSz .cluster-label span p{background-color:transparent;}#mermaid-svg-zaSWSpqEsGer4GSz .label text,#mermaid-svg-zaSWSpqEsGer4GSz span{fill:#333;color:#333;}#mermaid-svg-zaSWSpqEsGer4GSz .node rect,#mermaid-svg-zaSWSpqEsGer4GSz .node circle,#mermaid-svg-zaSWSpqEsGer4GSz .node ellipse,#mermaid-svg-zaSWSpqEsGer4GSz .node polygon,#mermaid-svg-zaSWSpqEsGer4GSz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zaSWSpqEsGer4GSz .rough-node .label text,#mermaid-svg-zaSWSpqEsGer4GSz .node .label text,#mermaid-svg-zaSWSpqEsGer4GSz .image-shape .label,#mermaid-svg-zaSWSpqEsGer4GSz .icon-shape .label{text-anchor:middle;}#mermaid-svg-zaSWSpqEsGer4GSz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zaSWSpqEsGer4GSz .rough-node .label,#mermaid-svg-zaSWSpqEsGer4GSz .node .label,#mermaid-svg-zaSWSpqEsGer4GSz .image-shape .label,#mermaid-svg-zaSWSpqEsGer4GSz .icon-shape .label{text-align:center;}#mermaid-svg-zaSWSpqEsGer4GSz .node.clickable{cursor:pointer;}#mermaid-svg-zaSWSpqEsGer4GSz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zaSWSpqEsGer4GSz .arrowheadPath{fill:#333333;}#mermaid-svg-zaSWSpqEsGer4GSz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zaSWSpqEsGer4GSz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zaSWSpqEsGer4GSz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zaSWSpqEsGer4GSz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zaSWSpqEsGer4GSz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zaSWSpqEsGer4GSz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zaSWSpqEsGer4GSz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zaSWSpqEsGer4GSz .cluster text{fill:#333;}#mermaid-svg-zaSWSpqEsGer4GSz .cluster span{color:#333;}#mermaid-svg-zaSWSpqEsGer4GSz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zaSWSpqEsGer4GSz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zaSWSpqEsGer4GSz rect.text{fill:none;stroke-width:0;}#mermaid-svg-zaSWSpqEsGer4GSz .icon-shape,#mermaid-svg-zaSWSpqEsGer4GSz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zaSWSpqEsGer4GSz .icon-shape p,#mermaid-svg-zaSWSpqEsGer4GSz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zaSWSpqEsGer4GSz .icon-shape .label rect,#mermaid-svg-zaSWSpqEsGer4GSz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zaSWSpqEsGer4GSz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zaSWSpqEsGer4GSz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zaSWSpqEsGer4GSz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} CO_SYNC_init()
读取 0x1005

COB-ID SYNC
读取 0x1006

communication cycle period
读取 0x1007

sync window,可选
读取 0x1019

counter overflow,可选
解析 CAN-ID / isProducer
决定 TX/RX DLC

0 或 1
CO_CANrxBufferInit()

注册 CO_SYNC_receive
CO_CANtxBufferInit()

配置发送 buffer

关键点:

  1. 0x1005 决定 SYNC CAN-ID,并在启用 producer 时决定 isProducer
  2. 0x1006 对 producer 是必要参数;对纯 consumer,可用于超时监控。
  3. 0x1007 是可选参数;为空或为 0 时不启用同步窗口。
  4. 0x1019 是可选参数;源码会把非法值做约束:1 修正为 2,大于 240 修正为 240
  5. RX buffer 注册的回调是 CO_SYNC_receive()

5.2 接收中断:CO_SYNC_receive()

接收回调只做三类事情:
#mermaid-svg-JrfsMV9D2Oxzls6O{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JrfsMV9D2Oxzls6O .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JrfsMV9D2Oxzls6O .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JrfsMV9D2Oxzls6O .error-icon{fill:#552222;}#mermaid-svg-JrfsMV9D2Oxzls6O .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JrfsMV9D2Oxzls6O .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JrfsMV9D2Oxzls6O .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JrfsMV9D2Oxzls6O .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JrfsMV9D2Oxzls6O .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JrfsMV9D2Oxzls6O .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JrfsMV9D2Oxzls6O .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JrfsMV9D2Oxzls6O .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JrfsMV9D2Oxzls6O .marker.cross{stroke:#333333;}#mermaid-svg-JrfsMV9D2Oxzls6O svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JrfsMV9D2Oxzls6O p{margin:0;}#mermaid-svg-JrfsMV9D2Oxzls6O .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JrfsMV9D2Oxzls6O .cluster-label text{fill:#333;}#mermaid-svg-JrfsMV9D2Oxzls6O .cluster-label span{color:#333;}#mermaid-svg-JrfsMV9D2Oxzls6O .cluster-label span p{background-color:transparent;}#mermaid-svg-JrfsMV9D2Oxzls6O .label text,#mermaid-svg-JrfsMV9D2Oxzls6O span{fill:#333;color:#333;}#mermaid-svg-JrfsMV9D2Oxzls6O .node rect,#mermaid-svg-JrfsMV9D2Oxzls6O .node circle,#mermaid-svg-JrfsMV9D2Oxzls6O .node ellipse,#mermaid-svg-JrfsMV9D2Oxzls6O .node polygon,#mermaid-svg-JrfsMV9D2Oxzls6O .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JrfsMV9D2Oxzls6O .rough-node .label text,#mermaid-svg-JrfsMV9D2Oxzls6O .node .label text,#mermaid-svg-JrfsMV9D2Oxzls6O .image-shape .label,#mermaid-svg-JrfsMV9D2Oxzls6O .icon-shape .label{text-anchor:middle;}#mermaid-svg-JrfsMV9D2Oxzls6O .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JrfsMV9D2Oxzls6O .rough-node .label,#mermaid-svg-JrfsMV9D2Oxzls6O .node .label,#mermaid-svg-JrfsMV9D2Oxzls6O .image-shape .label,#mermaid-svg-JrfsMV9D2Oxzls6O .icon-shape .label{text-align:center;}#mermaid-svg-JrfsMV9D2Oxzls6O .node.clickable{cursor:pointer;}#mermaid-svg-JrfsMV9D2Oxzls6O .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JrfsMV9D2Oxzls6O .arrowheadPath{fill:#333333;}#mermaid-svg-JrfsMV9D2Oxzls6O .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JrfsMV9D2Oxzls6O .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JrfsMV9D2Oxzls6O .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JrfsMV9D2Oxzls6O .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JrfsMV9D2Oxzls6O .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JrfsMV9D2Oxzls6O .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JrfsMV9D2Oxzls6O .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JrfsMV9D2Oxzls6O .cluster text{fill:#333;}#mermaid-svg-JrfsMV9D2Oxzls6O .cluster span{color:#333;}#mermaid-svg-JrfsMV9D2Oxzls6O div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JrfsMV9D2Oxzls6O .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JrfsMV9D2Oxzls6O rect.text{fill:none;stroke-width:0;}#mermaid-svg-JrfsMV9D2Oxzls6O .icon-shape,#mermaid-svg-JrfsMV9D2Oxzls6O .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JrfsMV9D2Oxzls6O .icon-shape p,#mermaid-svg-JrfsMV9D2Oxzls6O .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JrfsMV9D2Oxzls6O .icon-shape .label rect,#mermaid-svg-JrfsMV9D2Oxzls6O .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JrfsMV9D2Oxzls6O .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JrfsMV9D2Oxzls6O .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JrfsMV9D2Oxzls6O :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是





收到 CAN frame
counterOverflowValue == 0 ?
DLC == 0 ?
DLC == 1 ?
syncReceived = true
receiveError = DLC | 0x40
counter = data0

syncReceived = true
receiveError = DLC | 0x80
CANrxToggle 翻转
CO_FLAG_SET(CANrxNew)
可选 callback 唤醒任务

这里最重要的变量是:

变量 含义
CANrxNew 通知 CO_SYNC_process() 有新 SYNC 到达
CANrxToggle 给同步 RPDO 双缓冲使用;每个 SYNC 边沿翻转
receiveError 延迟到主循环里上报 EMCY,避免中断里做重处理
counter 启用 1 字节 counter 时保存收到的 counter

CANrxToggle 容易被忽略。源码注释说明,同步 RPDO 需要双接收缓冲;SYNC 边沿到来时切换 buffer,使"正在接收"和"正在处理"的 RPDO buffer 分离。

5.3 发送:CO_SYNCsend()

CO_SYNCsend()CO_SYNC.h 中的 static inline 函数。它的行为很短:
#mermaid-svg-OW8ctawP4tANHW7z{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-OW8ctawP4tANHW7z .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-OW8ctawP4tANHW7z .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-OW8ctawP4tANHW7z .error-icon{fill:#552222;}#mermaid-svg-OW8ctawP4tANHW7z .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OW8ctawP4tANHW7z .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-OW8ctawP4tANHW7z .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OW8ctawP4tANHW7z .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OW8ctawP4tANHW7z .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-OW8ctawP4tANHW7z .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OW8ctawP4tANHW7z .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OW8ctawP4tANHW7z .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OW8ctawP4tANHW7z .marker.cross{stroke:#333333;}#mermaid-svg-OW8ctawP4tANHW7z svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OW8ctawP4tANHW7z p{margin:0;}#mermaid-svg-OW8ctawP4tANHW7z .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-OW8ctawP4tANHW7z .cluster-label text{fill:#333;}#mermaid-svg-OW8ctawP4tANHW7z .cluster-label span{color:#333;}#mermaid-svg-OW8ctawP4tANHW7z .cluster-label span p{background-color:transparent;}#mermaid-svg-OW8ctawP4tANHW7z .label text,#mermaid-svg-OW8ctawP4tANHW7z span{fill:#333;color:#333;}#mermaid-svg-OW8ctawP4tANHW7z .node rect,#mermaid-svg-OW8ctawP4tANHW7z .node circle,#mermaid-svg-OW8ctawP4tANHW7z .node ellipse,#mermaid-svg-OW8ctawP4tANHW7z .node polygon,#mermaid-svg-OW8ctawP4tANHW7z .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-OW8ctawP4tANHW7z .rough-node .label text,#mermaid-svg-OW8ctawP4tANHW7z .node .label text,#mermaid-svg-OW8ctawP4tANHW7z .image-shape .label,#mermaid-svg-OW8ctawP4tANHW7z .icon-shape .label{text-anchor:middle;}#mermaid-svg-OW8ctawP4tANHW7z .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-OW8ctawP4tANHW7z .rough-node .label,#mermaid-svg-OW8ctawP4tANHW7z .node .label,#mermaid-svg-OW8ctawP4tANHW7z .image-shape .label,#mermaid-svg-OW8ctawP4tANHW7z .icon-shape .label{text-align:center;}#mermaid-svg-OW8ctawP4tANHW7z .node.clickable{cursor:pointer;}#mermaid-svg-OW8ctawP4tANHW7z .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-OW8ctawP4tANHW7z .arrowheadPath{fill:#333333;}#mermaid-svg-OW8ctawP4tANHW7z .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-OW8ctawP4tANHW7z .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-OW8ctawP4tANHW7z .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OW8ctawP4tANHW7z .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-OW8ctawP4tANHW7z .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OW8ctawP4tANHW7z .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-OW8ctawP4tANHW7z .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-OW8ctawP4tANHW7z .cluster text{fill:#333;}#mermaid-svg-OW8ctawP4tANHW7z .cluster span{color:#333;}#mermaid-svg-OW8ctawP4tANHW7z div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-OW8ctawP4tANHW7z .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-OW8ctawP4tANHW7z rect.text{fill:none;stroke-width:0;}#mermaid-svg-OW8ctawP4tANHW7z .icon-shape,#mermaid-svg-OW8ctawP4tANHW7z .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OW8ctawP4tANHW7z .icon-shape p,#mermaid-svg-OW8ctawP4tANHW7z .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-OW8ctawP4tANHW7z .icon-shape .label rect,#mermaid-svg-OW8ctawP4tANHW7z .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OW8ctawP4tANHW7z .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-OW8ctawP4tANHW7z .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-OW8ctawP4tANHW7z :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

CO_SYNCsend()
counter++
counter > counterOverflowValue ?
counter = 1
保持当前 counter
timer = 0
CANrxToggle 翻转
data0 = counter
CO_CANsend()

注意:即使 counterOverflowValue == 0,TX buffer 的 DLC 已在初始化时配置为 0,因此 data[0] 写入不会让帧变成 1 字节帧。帧长度由 CO_CANtxBufferInit() 的 DLC 参数决定。

5.4 周期处理:CO_SYNC_process()

CO_SYNC_process() 是 SYNC 的主状态推进函数:
#mermaid-svg-GX6BAgMZNgiEqpKA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-GX6BAgMZNgiEqpKA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GX6BAgMZNgiEqpKA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GX6BAgMZNgiEqpKA .error-icon{fill:#552222;}#mermaid-svg-GX6BAgMZNgiEqpKA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GX6BAgMZNgiEqpKA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GX6BAgMZNgiEqpKA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GX6BAgMZNgiEqpKA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GX6BAgMZNgiEqpKA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GX6BAgMZNgiEqpKA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GX6BAgMZNgiEqpKA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GX6BAgMZNgiEqpKA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GX6BAgMZNgiEqpKA .marker.cross{stroke:#333333;}#mermaid-svg-GX6BAgMZNgiEqpKA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GX6BAgMZNgiEqpKA p{margin:0;}#mermaid-svg-GX6BAgMZNgiEqpKA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-GX6BAgMZNgiEqpKA .cluster-label text{fill:#333;}#mermaid-svg-GX6BAgMZNgiEqpKA .cluster-label span{color:#333;}#mermaid-svg-GX6BAgMZNgiEqpKA .cluster-label span p{background-color:transparent;}#mermaid-svg-GX6BAgMZNgiEqpKA .label text,#mermaid-svg-GX6BAgMZNgiEqpKA span{fill:#333;color:#333;}#mermaid-svg-GX6BAgMZNgiEqpKA .node rect,#mermaid-svg-GX6BAgMZNgiEqpKA .node circle,#mermaid-svg-GX6BAgMZNgiEqpKA .node ellipse,#mermaid-svg-GX6BAgMZNgiEqpKA .node polygon,#mermaid-svg-GX6BAgMZNgiEqpKA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GX6BAgMZNgiEqpKA .rough-node .label text,#mermaid-svg-GX6BAgMZNgiEqpKA .node .label text,#mermaid-svg-GX6BAgMZNgiEqpKA .image-shape .label,#mermaid-svg-GX6BAgMZNgiEqpKA .icon-shape .label{text-anchor:middle;}#mermaid-svg-GX6BAgMZNgiEqpKA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-GX6BAgMZNgiEqpKA .rough-node .label,#mermaid-svg-GX6BAgMZNgiEqpKA .node .label,#mermaid-svg-GX6BAgMZNgiEqpKA .image-shape .label,#mermaid-svg-GX6BAgMZNgiEqpKA .icon-shape .label{text-align:center;}#mermaid-svg-GX6BAgMZNgiEqpKA .node.clickable{cursor:pointer;}#mermaid-svg-GX6BAgMZNgiEqpKA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-GX6BAgMZNgiEqpKA .arrowheadPath{fill:#333333;}#mermaid-svg-GX6BAgMZNgiEqpKA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GX6BAgMZNgiEqpKA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GX6BAgMZNgiEqpKA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GX6BAgMZNgiEqpKA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-GX6BAgMZNgiEqpKA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GX6BAgMZNgiEqpKA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-GX6BAgMZNgiEqpKA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GX6BAgMZNgiEqpKA .cluster text{fill:#333;}#mermaid-svg-GX6BAgMZNgiEqpKA .cluster span{color:#333;}#mermaid-svg-GX6BAgMZNgiEqpKA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GX6BAgMZNgiEqpKA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-GX6BAgMZNgiEqpKA rect.text{fill:none;stroke-width:0;}#mermaid-svg-GX6BAgMZNgiEqpKA .icon-shape,#mermaid-svg-GX6BAgMZNgiEqpKA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GX6BAgMZNgiEqpKA .icon-shape p,#mermaid-svg-GX6BAgMZNgiEqpKA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-GX6BAgMZNgiEqpKA .icon-shape .label rect,#mermaid-svg-GX6BAgMZNgiEqpKA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GX6BAgMZNgiEqpKA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-GX6BAgMZNgiEqpKA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-GX6BAgMZNgiEqpKA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否









首次越过
否则
CO_SYNC_process()
NMT pre-operational

or operational ?
清 CANrxNew / receiveError / counter / timer

返回 NONE
timer += timeDifference_us
CANrxNew ?
timer = 0

status = RX_TX

clear CANrxNew
继续
读取 0x1006 period
period > 0 ?
只做窗口/错误检查
isProducer ?
timer >= period ?
CO_SYNCsend()

status = RX_TX
更新 timerNext
consumer 超时监控

timer > 1.5 × period 则 EMCY
timer > 0x1007 ?
status = PASSED_WINDOW
更新 syncIsOutsideWindow
处理 receiveError

返回 status

返回值只有三种:

返回值 含义 上层怎么用
CO_SYNC_NONE 本轮没有 SYNC 事件 常规空转
CO_SYNC_RX_TX 本轮收到或发送了 SYNC 驱动同步 PDO / 应用同步动作
CO_SYNC_PASSED_WINDOW 本轮刚越过同步窗口 可用于禁止窗口外同步 PDO 或触发检查

5.5 consumer 超时监控

0x1006 非零、当前节点不是 producer,并且已经收到过至少一次 SYNC 后,源码开始超时监控:

text 复制代码
periodTimeout = 1.5 × OD_1006_period
if timer > periodTimeout:
    CO_errorReport(CO_EM_SYNC_TIME_OUT, ...)

收到新的 SYNC 后,如果之前处于超时错误状态,则调用 CO_errorReset() 清除错误。

5.6 0x1005 / 0x1019 动态写入

如果启用了 CO_CONFIG_FLAG_OD_DYNAMIC,写对象字典时会进入扩展写函数:
#mermaid-svg-etmoJ9FksqRmkWkU{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-etmoJ9FksqRmkWkU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-etmoJ9FksqRmkWkU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-etmoJ9FksqRmkWkU .error-icon{fill:#552222;}#mermaid-svg-etmoJ9FksqRmkWkU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-etmoJ9FksqRmkWkU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-etmoJ9FksqRmkWkU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-etmoJ9FksqRmkWkU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-etmoJ9FksqRmkWkU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-etmoJ9FksqRmkWkU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-etmoJ9FksqRmkWkU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-etmoJ9FksqRmkWkU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-etmoJ9FksqRmkWkU .marker.cross{stroke:#333333;}#mermaid-svg-etmoJ9FksqRmkWkU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-etmoJ9FksqRmkWkU p{margin:0;}#mermaid-svg-etmoJ9FksqRmkWkU .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-etmoJ9FksqRmkWkU .cluster-label text{fill:#333;}#mermaid-svg-etmoJ9FksqRmkWkU .cluster-label span{color:#333;}#mermaid-svg-etmoJ9FksqRmkWkU .cluster-label span p{background-color:transparent;}#mermaid-svg-etmoJ9FksqRmkWkU .label text,#mermaid-svg-etmoJ9FksqRmkWkU span{fill:#333;color:#333;}#mermaid-svg-etmoJ9FksqRmkWkU .node rect,#mermaid-svg-etmoJ9FksqRmkWkU .node circle,#mermaid-svg-etmoJ9FksqRmkWkU .node ellipse,#mermaid-svg-etmoJ9FksqRmkWkU .node polygon,#mermaid-svg-etmoJ9FksqRmkWkU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-etmoJ9FksqRmkWkU .rough-node .label text,#mermaid-svg-etmoJ9FksqRmkWkU .node .label text,#mermaid-svg-etmoJ9FksqRmkWkU .image-shape .label,#mermaid-svg-etmoJ9FksqRmkWkU .icon-shape .label{text-anchor:middle;}#mermaid-svg-etmoJ9FksqRmkWkU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-etmoJ9FksqRmkWkU .rough-node .label,#mermaid-svg-etmoJ9FksqRmkWkU .node .label,#mermaid-svg-etmoJ9FksqRmkWkU .image-shape .label,#mermaid-svg-etmoJ9FksqRmkWkU .icon-shape .label{text-align:center;}#mermaid-svg-etmoJ9FksqRmkWkU .node.clickable{cursor:pointer;}#mermaid-svg-etmoJ9FksqRmkWkU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-etmoJ9FksqRmkWkU .arrowheadPath{fill:#333333;}#mermaid-svg-etmoJ9FksqRmkWkU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-etmoJ9FksqRmkWkU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-etmoJ9FksqRmkWkU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-etmoJ9FksqRmkWkU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-etmoJ9FksqRmkWkU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-etmoJ9FksqRmkWkU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-etmoJ9FksqRmkWkU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-etmoJ9FksqRmkWkU .cluster text{fill:#333;}#mermaid-svg-etmoJ9FksqRmkWkU .cluster span{color:#333;}#mermaid-svg-etmoJ9FksqRmkWkU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-etmoJ9FksqRmkWkU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-etmoJ9FksqRmkWkU rect.text{fill:none;stroke-width:0;}#mermaid-svg-etmoJ9FksqRmkWkU .icon-shape,#mermaid-svg-etmoJ9FksqRmkWkU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-etmoJ9FksqRmkWkU .icon-shape p,#mermaid-svg-etmoJ9FksqRmkWkU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-etmoJ9FksqRmkWkU .icon-shape .label rect,#mermaid-svg-etmoJ9FksqRmkWkU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-etmoJ9FksqRmkWkU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-etmoJ9FksqRmkWkU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-etmoJ9FksqRmkWkU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是



SDO/本地写 OD
写 0x1005 ?
写 0x1019 ?
OD_write_1005()

校验 COB-ID 和 producer bit
必要时重新初始化 RX/TX buffer
OD_write_1019()

校验 0 或 2..240
0x1006 period == 0 ?
重新配置 TX DLC 0/1
拒绝:ODR_DATA_DEV_STATE

这里的限制很实际:0x1019 会改变 SYNC 帧 DLC,源码要求在通信周期未启用时修改,避免运行中改变帧格式造成网络不一致。


6. TIME 源码运行流程

6.1 初始化:CO_TIME_init()

CO_TIME_init() 的主线比 SYNC 更短:
#mermaid-svg-Gl8ntAe3Nif9HAbX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Gl8ntAe3Nif9HAbX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Gl8ntAe3Nif9HAbX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Gl8ntAe3Nif9HAbX .error-icon{fill:#552222;}#mermaid-svg-Gl8ntAe3Nif9HAbX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Gl8ntAe3Nif9HAbX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Gl8ntAe3Nif9HAbX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Gl8ntAe3Nif9HAbX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Gl8ntAe3Nif9HAbX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Gl8ntAe3Nif9HAbX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Gl8ntAe3Nif9HAbX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Gl8ntAe3Nif9HAbX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Gl8ntAe3Nif9HAbX .marker.cross{stroke:#333333;}#mermaid-svg-Gl8ntAe3Nif9HAbX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Gl8ntAe3Nif9HAbX p{margin:0;}#mermaid-svg-Gl8ntAe3Nif9HAbX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Gl8ntAe3Nif9HAbX .cluster-label text{fill:#333;}#mermaid-svg-Gl8ntAe3Nif9HAbX .cluster-label span{color:#333;}#mermaid-svg-Gl8ntAe3Nif9HAbX .cluster-label span p{background-color:transparent;}#mermaid-svg-Gl8ntAe3Nif9HAbX .label text,#mermaid-svg-Gl8ntAe3Nif9HAbX span{fill:#333;color:#333;}#mermaid-svg-Gl8ntAe3Nif9HAbX .node rect,#mermaid-svg-Gl8ntAe3Nif9HAbX .node circle,#mermaid-svg-Gl8ntAe3Nif9HAbX .node ellipse,#mermaid-svg-Gl8ntAe3Nif9HAbX .node polygon,#mermaid-svg-Gl8ntAe3Nif9HAbX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Gl8ntAe3Nif9HAbX .rough-node .label text,#mermaid-svg-Gl8ntAe3Nif9HAbX .node .label text,#mermaid-svg-Gl8ntAe3Nif9HAbX .image-shape .label,#mermaid-svg-Gl8ntAe3Nif9HAbX .icon-shape .label{text-anchor:middle;}#mermaid-svg-Gl8ntAe3Nif9HAbX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Gl8ntAe3Nif9HAbX .rough-node .label,#mermaid-svg-Gl8ntAe3Nif9HAbX .node .label,#mermaid-svg-Gl8ntAe3Nif9HAbX .image-shape .label,#mermaid-svg-Gl8ntAe3Nif9HAbX .icon-shape .label{text-align:center;}#mermaid-svg-Gl8ntAe3Nif9HAbX .node.clickable{cursor:pointer;}#mermaid-svg-Gl8ntAe3Nif9HAbX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Gl8ntAe3Nif9HAbX .arrowheadPath{fill:#333333;}#mermaid-svg-Gl8ntAe3Nif9HAbX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Gl8ntAe3Nif9HAbX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Gl8ntAe3Nif9HAbX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Gl8ntAe3Nif9HAbX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Gl8ntAe3Nif9HAbX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Gl8ntAe3Nif9HAbX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Gl8ntAe3Nif9HAbX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Gl8ntAe3Nif9HAbX .cluster text{fill:#333;}#mermaid-svg-Gl8ntAe3Nif9HAbX .cluster span{color:#333;}#mermaid-svg-Gl8ntAe3Nif9HAbX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Gl8ntAe3Nif9HAbX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Gl8ntAe3Nif9HAbX rect.text{fill:none;stroke-width:0;}#mermaid-svg-Gl8ntAe3Nif9HAbX .icon-shape,#mermaid-svg-Gl8ntAe3Nif9HAbX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Gl8ntAe3Nif9HAbX .icon-shape p,#mermaid-svg-Gl8ntAe3Nif9HAbX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Gl8ntAe3Nif9HAbX .icon-shape .label rect,#mermaid-svg-Gl8ntAe3Nif9HAbX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Gl8ntAe3Nif9HAbX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Gl8ntAe3Nif9HAbX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Gl8ntAe3Nif9HAbX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

CO_TIME_init()
读取 0x1012

COB-ID time stamp
解析 CAN-ID
bit31 -> isConsumer
bit30 -> isProducer
isConsumer ?
CO_CANrxBufferInit()

注册 CO_TIME_receive
不注册接收
CO_CANtxBufferInit()

DLC = 6

关键点:

  1. TIME 的启停方向由 0x1012 控制,不是由 Node-ID 控制。
  2. consumer 使能后才注册接收 buffer。
  3. producer 相关编译能力还受 CO_CONFIG_TIME_PRODUCER 控制;编译时没打开 producer,运行时 bit30 也不能让它真正发送。
  4. TX buffer 的 DLC 固定是 CO_TIME_MSG_LENGTH = 6

6.2 接收中断:CO_TIME_receive()

TIME 的接收回调只接受 6 字节帧:
#mermaid-svg-cupnTybQnpO0eItL{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cupnTybQnpO0eItL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cupnTybQnpO0eItL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cupnTybQnpO0eItL .error-icon{fill:#552222;}#mermaid-svg-cupnTybQnpO0eItL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cupnTybQnpO0eItL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cupnTybQnpO0eItL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cupnTybQnpO0eItL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cupnTybQnpO0eItL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cupnTybQnpO0eItL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cupnTybQnpO0eItL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cupnTybQnpO0eItL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cupnTybQnpO0eItL .marker.cross{stroke:#333333;}#mermaid-svg-cupnTybQnpO0eItL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cupnTybQnpO0eItL p{margin:0;}#mermaid-svg-cupnTybQnpO0eItL .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cupnTybQnpO0eItL .cluster-label text{fill:#333;}#mermaid-svg-cupnTybQnpO0eItL .cluster-label span{color:#333;}#mermaid-svg-cupnTybQnpO0eItL .cluster-label span p{background-color:transparent;}#mermaid-svg-cupnTybQnpO0eItL .label text,#mermaid-svg-cupnTybQnpO0eItL span{fill:#333;color:#333;}#mermaid-svg-cupnTybQnpO0eItL .node rect,#mermaid-svg-cupnTybQnpO0eItL .node circle,#mermaid-svg-cupnTybQnpO0eItL .node ellipse,#mermaid-svg-cupnTybQnpO0eItL .node polygon,#mermaid-svg-cupnTybQnpO0eItL .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cupnTybQnpO0eItL .rough-node .label text,#mermaid-svg-cupnTybQnpO0eItL .node .label text,#mermaid-svg-cupnTybQnpO0eItL .image-shape .label,#mermaid-svg-cupnTybQnpO0eItL .icon-shape .label{text-anchor:middle;}#mermaid-svg-cupnTybQnpO0eItL .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cupnTybQnpO0eItL .rough-node .label,#mermaid-svg-cupnTybQnpO0eItL .node .label,#mermaid-svg-cupnTybQnpO0eItL .image-shape .label,#mermaid-svg-cupnTybQnpO0eItL .icon-shape .label{text-align:center;}#mermaid-svg-cupnTybQnpO0eItL .node.clickable{cursor:pointer;}#mermaid-svg-cupnTybQnpO0eItL .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cupnTybQnpO0eItL .arrowheadPath{fill:#333333;}#mermaid-svg-cupnTybQnpO0eItL .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cupnTybQnpO0eItL .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cupnTybQnpO0eItL .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cupnTybQnpO0eItL .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cupnTybQnpO0eItL .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cupnTybQnpO0eItL .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cupnTybQnpO0eItL .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cupnTybQnpO0eItL .cluster text{fill:#333;}#mermaid-svg-cupnTybQnpO0eItL .cluster span{color:#333;}#mermaid-svg-cupnTybQnpO0eItL div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cupnTybQnpO0eItL .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cupnTybQnpO0eItL rect.text{fill:none;stroke-width:0;}#mermaid-svg-cupnTybQnpO0eItL .icon-shape,#mermaid-svg-cupnTybQnpO0eItL .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cupnTybQnpO0eItL .icon-shape p,#mermaid-svg-cupnTybQnpO0eItL .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cupnTybQnpO0eItL .icon-shape .label rect,#mermaid-svg-cupnTybQnpO0eItL .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cupnTybQnpO0eItL .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cupnTybQnpO0eItL .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cupnTybQnpO0eItL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否

收到 TIME CAN frame
DLC == CO_TIME_MSG_LENGTH(6) ?
忽略
memcpy(data -> TIME->timeStamp)
CO_FLAG_SET(CANrxNew)
可选 callback 唤醒任务

TIME 源码没有像 SYNC 那样记录接收长度错误。长度不等于 6 时直接忽略。

6.3 周期处理:CO_TIME_process()

CO_TIME_process() 有三段逻辑:
#mermaid-svg-akDnhThYvhOgQDhi{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-akDnhThYvhOgQDhi .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-akDnhThYvhOgQDhi .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-akDnhThYvhOgQDhi .error-icon{fill:#552222;}#mermaid-svg-akDnhThYvhOgQDhi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-akDnhThYvhOgQDhi .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-akDnhThYvhOgQDhi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-akDnhThYvhOgQDhi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-akDnhThYvhOgQDhi .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-akDnhThYvhOgQDhi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-akDnhThYvhOgQDhi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-akDnhThYvhOgQDhi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-akDnhThYvhOgQDhi .marker.cross{stroke:#333333;}#mermaid-svg-akDnhThYvhOgQDhi svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-akDnhThYvhOgQDhi p{margin:0;}#mermaid-svg-akDnhThYvhOgQDhi .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-akDnhThYvhOgQDhi .cluster-label text{fill:#333;}#mermaid-svg-akDnhThYvhOgQDhi .cluster-label span{color:#333;}#mermaid-svg-akDnhThYvhOgQDhi .cluster-label span p{background-color:transparent;}#mermaid-svg-akDnhThYvhOgQDhi .label text,#mermaid-svg-akDnhThYvhOgQDhi span{fill:#333;color:#333;}#mermaid-svg-akDnhThYvhOgQDhi .node rect,#mermaid-svg-akDnhThYvhOgQDhi .node circle,#mermaid-svg-akDnhThYvhOgQDhi .node ellipse,#mermaid-svg-akDnhThYvhOgQDhi .node polygon,#mermaid-svg-akDnhThYvhOgQDhi .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-akDnhThYvhOgQDhi .rough-node .label text,#mermaid-svg-akDnhThYvhOgQDhi .node .label text,#mermaid-svg-akDnhThYvhOgQDhi .image-shape .label,#mermaid-svg-akDnhThYvhOgQDhi .icon-shape .label{text-anchor:middle;}#mermaid-svg-akDnhThYvhOgQDhi .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-akDnhThYvhOgQDhi .rough-node .label,#mermaid-svg-akDnhThYvhOgQDhi .node .label,#mermaid-svg-akDnhThYvhOgQDhi .image-shape .label,#mermaid-svg-akDnhThYvhOgQDhi .icon-shape .label{text-align:center;}#mermaid-svg-akDnhThYvhOgQDhi .node.clickable{cursor:pointer;}#mermaid-svg-akDnhThYvhOgQDhi .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-akDnhThYvhOgQDhi .arrowheadPath{fill:#333333;}#mermaid-svg-akDnhThYvhOgQDhi .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-akDnhThYvhOgQDhi .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-akDnhThYvhOgQDhi .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-akDnhThYvhOgQDhi .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-akDnhThYvhOgQDhi .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-akDnhThYvhOgQDhi .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-akDnhThYvhOgQDhi .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-akDnhThYvhOgQDhi .cluster text{fill:#333;}#mermaid-svg-akDnhThYvhOgQDhi .cluster span{color:#333;}#mermaid-svg-akDnhThYvhOgQDhi div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-akDnhThYvhOgQDhi .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-akDnhThYvhOgQDhi rect.text{fill:none;stroke-width:0;}#mermaid-svg-akDnhThYvhOgQDhi .icon-shape,#mermaid-svg-akDnhThYvhOgQDhi .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-akDnhThYvhOgQDhi .icon-shape p,#mermaid-svg-akDnhThYvhOgQDhi .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-akDnhThYvhOgQDhi .icon-shape .label rect,#mermaid-svg-akDnhThYvhOgQDhi .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-akDnhThYvhOgQDhi .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-akDnhThYvhOgQDhi .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-akDnhThYvhOgQDhi :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是









CO_TIME_process()
NMT pre-operational

or operational

并且 isConsumer ?
CANrxNew ?
解析 timeStamp0..5
ms = swapped32 & 0x0FFFFFFF

days = swapped16

residual_us = 0
timestampReceived = true

clear CANrxNew
没有新 TIME
clear CANrxNew
本轮是否未收到 TIME

且 timeDifference_us > 0 ?
用 timeDifference_us 本地累计 ms/days
跳过本地累计
isProducer 且 producerInterval_ms > 0 ?
producerTimer_ms 到期 ?
打包 ms/days 到 CANtxBuff

CO_CANsend()
producerTimer_ms += 本轮新增 ms
producerTimer_ms = producerInterval_ms
返回 timestampReceived

6.4 接收到 TIME 后如何解析

源码解析逻辑:

c 复制代码
uint32_t ms_swapped = CO_getUint32(&TIME->timeStamp[0]);
uint16_t days_swapped = CO_getUint16(&TIME->timeStamp[4]);

TIME->ms = CO_SWAP_32(ms_swapped) & 0x0FFFFFFFU;
TIME->days = CO_SWAP_16(days_swapped);
TIME->residual_us = 0;

要点:

  1. ms 只取低 28 bit。
  2. days 是 16 bit。
  3. 收到 TIME 后清零 residual_us,避免前一次本地微秒余数污染对时结果。
  4. 返回值 true 只表示本轮刚收到并处理了 TIME stamp,不表示 producer 已发送 TIME。

6.5 没有收到 TIME 时如何本地走时

如果本轮没有新 TIME,源码用 timeDifference_us 累加本地时间:

c 复制代码
uint32_t us = timeDifference_us + TIME->residual_us;
ms = us / 1000U;
TIME->residual_us = us % 1000U;
TIME->ms += ms;

ms 超过一天时:

c 复制代码
if (TIME->ms >= 24h_ms) {
    TIME->ms -= 24h_ms;
    TIME->days += 1;
}

这说明 TIME consumer 并不是"只靠网络 TIME 才能走时"。收到 TIME 是校准点;两次校准之间,它仍靠本地周期时间差继续推进。

6.6 TIME producer 如何启动

TIME producer 需要两件事同时成立:

text 复制代码
编译期:CO_CONFIG_TIME_PRODUCER 打开
运行期:0x1012 bit30 = 1,并且 CO_TIME_set(..., producerInterval_ms > 0)

CO_TIME_set() 做了三件事:

c 复制代码
TIME->residual_us = 0;
TIME->ms = ms;
TIME->days = days;
TIME->producerTimer_ms = TIME->producerInterval_ms = producerInterval_ms;

因此,producer 至少要先调用一次 CO_TIME_set() 设置当前时间和发送周期。只配置 0x1012 bit30 不足以产生周期 TIME 帧。


7. TIME 与 SYNC 在主循环中的关系

在 CANopenNode 的常规处理模型中,SYNC 通常先被处理,再用它的结果驱动同步 PDO:
#mermaid-svg-97CfHsE4j9d8QXez{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-97CfHsE4j9d8QXez .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-97CfHsE4j9d8QXez .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-97CfHsE4j9d8QXez .error-icon{fill:#552222;}#mermaid-svg-97CfHsE4j9d8QXez .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-97CfHsE4j9d8QXez .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-97CfHsE4j9d8QXez .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-97CfHsE4j9d8QXez .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-97CfHsE4j9d8QXez .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-97CfHsE4j9d8QXez .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-97CfHsE4j9d8QXez .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-97CfHsE4j9d8QXez .marker{fill:#333333;stroke:#333333;}#mermaid-svg-97CfHsE4j9d8QXez .marker.cross{stroke:#333333;}#mermaid-svg-97CfHsE4j9d8QXez svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-97CfHsE4j9d8QXez p{margin:0;}#mermaid-svg-97CfHsE4j9d8QXez .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-97CfHsE4j9d8QXez .cluster-label text{fill:#333;}#mermaid-svg-97CfHsE4j9d8QXez .cluster-label span{color:#333;}#mermaid-svg-97CfHsE4j9d8QXez .cluster-label span p{background-color:transparent;}#mermaid-svg-97CfHsE4j9d8QXez .label text,#mermaid-svg-97CfHsE4j9d8QXez span{fill:#333;color:#333;}#mermaid-svg-97CfHsE4j9d8QXez .node rect,#mermaid-svg-97CfHsE4j9d8QXez .node circle,#mermaid-svg-97CfHsE4j9d8QXez .node ellipse,#mermaid-svg-97CfHsE4j9d8QXez .node polygon,#mermaid-svg-97CfHsE4j9d8QXez .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-97CfHsE4j9d8QXez .rough-node .label text,#mermaid-svg-97CfHsE4j9d8QXez .node .label text,#mermaid-svg-97CfHsE4j9d8QXez .image-shape .label,#mermaid-svg-97CfHsE4j9d8QXez .icon-shape .label{text-anchor:middle;}#mermaid-svg-97CfHsE4j9d8QXez .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-97CfHsE4j9d8QXez .rough-node .label,#mermaid-svg-97CfHsE4j9d8QXez .node .label,#mermaid-svg-97CfHsE4j9d8QXez .image-shape .label,#mermaid-svg-97CfHsE4j9d8QXez .icon-shape .label{text-align:center;}#mermaid-svg-97CfHsE4j9d8QXez .node.clickable{cursor:pointer;}#mermaid-svg-97CfHsE4j9d8QXez .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-97CfHsE4j9d8QXez .arrowheadPath{fill:#333333;}#mermaid-svg-97CfHsE4j9d8QXez .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-97CfHsE4j9d8QXez .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-97CfHsE4j9d8QXez .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-97CfHsE4j9d8QXez .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-97CfHsE4j9d8QXez .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-97CfHsE4j9d8QXez .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-97CfHsE4j9d8QXez .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-97CfHsE4j9d8QXez .cluster text{fill:#333;}#mermaid-svg-97CfHsE4j9d8QXez .cluster span{color:#333;}#mermaid-svg-97CfHsE4j9d8QXez div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-97CfHsE4j9d8QXez .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-97CfHsE4j9d8QXez rect.text{fill:none;stroke-width:0;}#mermaid-svg-97CfHsE4j9d8QXez .icon-shape,#mermaid-svg-97CfHsE4j9d8QXez .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-97CfHsE4j9d8QXez .icon-shape p,#mermaid-svg-97CfHsE4j9d8QXez .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-97CfHsE4j9d8QXez .icon-shape .label rect,#mermaid-svg-97CfHsE4j9d8QXez .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-97CfHsE4j9d8QXez .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-97CfHsE4j9d8QXez .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-97CfHsE4j9d8QXez :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是



周期 tick / RTOS task
CO_process_SYNC() 或 CO_SYNC_process()
syncWas ?
处理同步 RPDO/TPDO
处理非同步对象
CO_TIME_process()
timestampReceived ?
应用获得新的网络时间
本地时间继续递增

SYNC 和 TIME 没有直接依赖关系:

问题 看哪个对象
周期 PDO 为什么没发? 先看 SYNC、PDO 传输类型、NMT 状态
网络时间为什么没更新? 先看 TIME、0x1012、DLC 是否为 6
同步窗口外 PDO 为什么被丢? 0x1007syncIsOutsideWindow、PDO 处理顺序
节点是否收到过 SYNC? CO_SYNC_process() 返回值和 timeoutError
TIME producer 为什么没发? CO_TIME_set() 是否设置了非零 producerInterval_ms

8. 最小心智模型

#mermaid-svg-T5n0b9hgvm0gNchk{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-T5n0b9hgvm0gNchk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-T5n0b9hgvm0gNchk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-T5n0b9hgvm0gNchk .error-icon{fill:#552222;}#mermaid-svg-T5n0b9hgvm0gNchk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-T5n0b9hgvm0gNchk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-T5n0b9hgvm0gNchk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-T5n0b9hgvm0gNchk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-T5n0b9hgvm0gNchk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-T5n0b9hgvm0gNchk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-T5n0b9hgvm0gNchk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-T5n0b9hgvm0gNchk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-T5n0b9hgvm0gNchk .marker.cross{stroke:#333333;}#mermaid-svg-T5n0b9hgvm0gNchk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-T5n0b9hgvm0gNchk p{margin:0;}#mermaid-svg-T5n0b9hgvm0gNchk .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-T5n0b9hgvm0gNchk .cluster-label text{fill:#333;}#mermaid-svg-T5n0b9hgvm0gNchk .cluster-label span{color:#333;}#mermaid-svg-T5n0b9hgvm0gNchk .cluster-label span p{background-color:transparent;}#mermaid-svg-T5n0b9hgvm0gNchk .label text,#mermaid-svg-T5n0b9hgvm0gNchk span{fill:#333;color:#333;}#mermaid-svg-T5n0b9hgvm0gNchk .node rect,#mermaid-svg-T5n0b9hgvm0gNchk .node circle,#mermaid-svg-T5n0b9hgvm0gNchk .node ellipse,#mermaid-svg-T5n0b9hgvm0gNchk .node polygon,#mermaid-svg-T5n0b9hgvm0gNchk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-T5n0b9hgvm0gNchk .rough-node .label text,#mermaid-svg-T5n0b9hgvm0gNchk .node .label text,#mermaid-svg-T5n0b9hgvm0gNchk .image-shape .label,#mermaid-svg-T5n0b9hgvm0gNchk .icon-shape .label{text-anchor:middle;}#mermaid-svg-T5n0b9hgvm0gNchk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-T5n0b9hgvm0gNchk .rough-node .label,#mermaid-svg-T5n0b9hgvm0gNchk .node .label,#mermaid-svg-T5n0b9hgvm0gNchk .image-shape .label,#mermaid-svg-T5n0b9hgvm0gNchk .icon-shape .label{text-align:center;}#mermaid-svg-T5n0b9hgvm0gNchk .node.clickable{cursor:pointer;}#mermaid-svg-T5n0b9hgvm0gNchk .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-T5n0b9hgvm0gNchk .arrowheadPath{fill:#333333;}#mermaid-svg-T5n0b9hgvm0gNchk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-T5n0b9hgvm0gNchk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-T5n0b9hgvm0gNchk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-T5n0b9hgvm0gNchk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-T5n0b9hgvm0gNchk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-T5n0b9hgvm0gNchk .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-T5n0b9hgvm0gNchk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-T5n0b9hgvm0gNchk .cluster text{fill:#333;}#mermaid-svg-T5n0b9hgvm0gNchk .cluster span{color:#333;}#mermaid-svg-T5n0b9hgvm0gNchk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-T5n0b9hgvm0gNchk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-T5n0b9hgvm0gNchk rect.text{fill:none;stroke-width:0;}#mermaid-svg-T5n0b9hgvm0gNchk .icon-shape,#mermaid-svg-T5n0b9hgvm0gNchk .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-T5n0b9hgvm0gNchk .icon-shape p,#mermaid-svg-T5n0b9hgvm0gNchk .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-T5n0b9hgvm0gNchk .icon-shape .label rect,#mermaid-svg-T5n0b9hgvm0gNchk .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-T5n0b9hgvm0gNchk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-T5n0b9hgvm0gNchk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-T5n0b9hgvm0gNchk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 对象字典决定角色和参数
init() 读取 OD 并配置 CAN buffer
CAN receive callback 只搬运数据和置 flag
process() 根据 NMT 状态、timer 和 flag 推进状态
SYNC 输出同步事件/窗口状态
TIME 输出 timestampReceived 并维护 ms/days
PDO/应用同步逻辑
日志/时间戳/应用时间基准

记住这三条就不容易读偏:

  1. SYNC0x1005/0x1006/0x1007/0x1019,核心是"周期边界 + 同步窗口 + counter"。
  2. TIME0x1012,核心是"6 字节时间戳 + 本地走时 + 可选周期发送"。
  3. CANopenNode 的 receive() 不是完整协议处理,它只是中断短路径;真正的状态变化主要在 process()

参考资料