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动态写入)
- [5.1 初始化:`CO_SYNC_init()`](#5.1 初始化:
- [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 如何启动)
- [6.1 初始化:`CO_TIME_init()`](#6.1 初始化:
- [7. TIME 与 SYNC 在主循环中的关系](#7. TIME 与 SYNC 在主循环中的关系)
- [8. 最小心智模型](#8. 最小心智模型)
- 参考资料

1. 先把 TIME 和 SYNC 分开
TIME 和 SYNC 都属于 CANopen 的特殊功能通信对象,但它们解决的问题不同:
| 对象 | 核心问题 | 默认 CAN-ID | 数据长度 | 典型用途 |
|---|---|---|---|---|
SYNC |
"什么时候进入一个同步周期?" | 0x080 |
0 或 1 |
同步 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_t、CO_SYNC_status_t、CO_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_t、CO_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
关键点:
0x1005决定 SYNC CAN-ID,并在启用 producer 时决定isProducer。0x1006对 producer 是必要参数;对纯 consumer,可用于超时监控。0x1007是可选参数;为空或为0时不启用同步窗口。0x1019是可选参数;源码会把非法值做约束:1修正为2,大于240修正为240。- 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
关键点:
- TIME 的启停方向由
0x1012控制,不是由 Node-ID 控制。 - consumer 使能后才注册接收 buffer。
- producer 相关编译能力还受
CO_CONFIG_TIME_PRODUCER控制;编译时没打开 producer,运行时bit30也不能让它真正发送。 - 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;
要点:
ms只取低 28 bit。days是 16 bit。- 收到 TIME 后清零
residual_us,避免前一次本地微秒余数污染对时结果。 - 返回值
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 为什么被丢? | 看 0x1007、syncIsOutsideWindow、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/应用同步逻辑
日志/时间戳/应用时间基准
记住这三条就不容易读偏:
SYNC看0x1005/0x1006/0x1007/0x1019,核心是"周期边界 + 同步窗口 + counter"。TIME看0x1012,核心是"6 字节时间戳 + 本地走时 + 可选周期发送"。- CANopenNode 的
receive()不是完整协议处理,它只是中断短路径;真正的状态变化主要在process()。
参考资料
- CiA 301 V4.2.0(中文注释版),用户上传 PDF:第 7.2.5、7.2.6、7.5.2.5、7.5.2.6、7.5.2.7、7.5.2.15、7.5.2.22 节。
- CAN in Automation: Special function protocols, https://www.can-cia.org/can-knowledge/special-function-protocols
- CAN in Automation: SYNC protocol, https://www.can-cia.org/can-knowledge/sync-protocol
- CANopenNode Doxygen: SYNC, https://canopennode.github.io/CANopenNode/group__CO__SYNC.html
- CANopenNode Doxygen: TIME, https://canopennode.github.io/CANopenNode/group__CO__TIME.html
- CANopenNode GitHub repository, https://github.com/CANopenNode/CANopenNode
- 上传源码:
CO_SYNC.h、CO_SYNC.c、CO_TIME.h、CO_TIME.c