1. CANopen协议概述:从协议栈到实战落地

各位同学,咱们今天正式开讲CANopen。说实话,我第一次接触CANopen是在一个工业伺服驱动的项目里。当时甲方要求必须支持CANopen从站,我翻着那本几百页的CiA 301标准,心里直犯嘀咕——这玩意儿也太复杂了吧?但真正用起来才发现,它的设计思路其实很清晰。

这一章,我会把CANopen的核心骨架给你拆开来讲。包括协议栈架构、对象字典、PDO和SDO怎么用、NMT状态机怎么跑。你不需要一次性全记住,但得有个整体印象。后面咱们在STM32上移植CANopenNode的时候,你会反复回来翻这一章的内容。

1.1 CANopen协议栈架构

CANopen的协议栈,说白了就是分层的。它不像TCP/IP那么复杂,但每一层都有明确的职责。

层级 名称 主要职责
应用层 CiA 301 / 设备行规 定义对象字典、通信对象、设备行为
数据链路层 CAN 2.0B 帧封装、仲裁、错误检测
物理层 ISO 11898-2 差分信号、总线电平、终端电阻

我个人习惯把CANopen协议栈想象成一个「三层小楼」:
一楼是物理层——就是那两根双绞线,CAN_H和CAN_L,加上120Ω终端电阻。这层咱们在STM32上基本不用操心,硬件电路画对就行。
二楼是数据链路层——CAN控制器(比如STM32的bxCAN或FDCAN)负责收发报文、处理仲裁和错误。这层咱们得配好波特率、滤波器。
三楼是应用层——这才是CANopen真正干活的地方。对象字典、PDO、SDO、NMT全在这一层。

关键认知:CANopen不是重新发明了一套物理层,它就是在标准CAN 2.0B上面跑的一套应用层协议。你只要会CAN收发,就能跑CANopen。

1.2 对象字典(OD)——CANopen的灵魂

对象字典是什么?我打个比方:它就像设备的「户口本」。每个设备能做什么、有什么参数、当前状态如何,全记在这个本子里。

对象字典是一个线性索引表,每个条目由16位索引(Index)和8位子索引(SubIndex)唯一标识。比如:

  • 0x1000 —— 设备类型
  • 0x1017 —— 心跳生产者时间
  • 0x6000+NodeID —— 数字量输入(具体看行规)

每个对象条目包含以下属性:

属性 说明 举例
Index 16位索引地址 0x1017
SubIndex 8位子索引 0x00
Name 对象名称 心跳生产者时间
Type 数据类型 UNSIGNED16
Access 访问权限 rw / ro / wo
PDO Mapping 是否可映射到PDO Yes / No
Default Value 默认值 0x0000

实战经验:我在做第一个CANopen从站时,对象字典配置错了索引范围,结果主站怎么都读不到设备类型。后来查了半天,发现是0x1000的访问权限写成了wo(只写)。记住:通信对象区(0x1000-0x1FFF)的配置一定要仔细核对CiA 301标准。

1.3 PDO与SDO——两种通信方式

CANopen里通信就两种路子:PDO(过程数据对象)和SDO(服务数据对象)。它们各有各的脾气。

PDO:快,但不管丢不丢

PDO是生产者-消费者模式。一个设备发,其他设备收,不需要应答。所以它快——一个PDO报文最多传8字节数据,适合传实时性要求高的数据,比如编码器位置、电机转速。

PDO分两种:

  • TPDO(发送PDO):从站主动往外发数据
  • RPDO(接收PDO):从站接收主站或其他设备的数据

触发方式有几种:

  • 事件触发:数据变化了就发(比如位置变了1mm)
  • 定时触发:每隔N毫秒发一次
  • 远程帧请求:主站发远程帧来要数据
  • SYNC同步触发:收到SYNC报文后统一发

注意:PDO没有应答机制。你发了,对方收没收到,你不管。所以对可靠性要求高的参数(比如配置参数),别用PDO,用SDO。

SDO:慢,但可靠

SDO是客户端-服务器模式。主站(客户端)发起请求,从站(服务器)回复应答。每个SDO事务需要2~4个CAN帧才能完成,所以慢,但保证数据到达。

SDO专门用来读写对象字典。比如:

  • 主站想修改从站的0x1017(心跳时间),就发SDO写请求
  • 主站想读取从站的设备名称,就发SDO读请求

SDO的CAN ID有固定规则:

  • 主站→从站(请求):0x600 + NodeID
  • 从站→主站(应答):0x580 + NodeID

举个例子,节点ID=5的从站:

  • 主站发请求:CAN ID = 0x605
  • 从站回复:CAN ID = 0x585
特性 PDO SDO
通信模式 生产者-消费者 客户端-服务器
应答机制 无 有(确认/错误响应)
数据长度 最多8字节 最多4字节(分段可更多)
传输速度 快 慢
典型用途 实时过程数据 配置参数、诊断

1.4 NMT状态机——设备的生命周期

每个CANopen从站都有一个状态机,叫NMT(网络管理)状态机。它定义了设备从上电到正常工作的完整流程。

状态机有这几个状态:

  • 初始化(Initialisation):上电后自动进入,硬件自检、加载默认参数
  • 预操作(Pre-Operational):SDO可用,PDO不可用。可以配置参数
  • 操作(Operational):SDO和PDO都可用。正常工作模式
  • 停止(Stopped):SDO和PDO都不可用。只有NMT命令能唤醒

状态切换由主站发NMT命令控制。NMT命令的CAN ID固定为0x000,数据字节包含命令码和目标节点ID。

常用的NMT命令:

命令码 功能 目标状态
0x01 启动远程节点 Operational
0x02 停止远程节点 Stopped
0x80 进入预操作 Pre-Operational
0x81 复位节点 Initialisation
0x82 复位通信 Initialisation

避坑指南:我曾经在一个项目里,从站上电后直接进了Operational状态,没经过Pre-Operational。结果主站还没来得及配置参数,从站就开始发PDO了,数据全是默认值,导致执行器乱动。后来我强制在初始化后进入Pre-Operational,等主站配置完再发NMT启动命令。记住:上电后一定要先进Pre-Operational,别急着跑。

1.5 知识结构总览

下面这张图把CANopen的核心关系画出来了。你盯着看两分钟,后面学起来会顺很多。

CANopen 核心知识结构 应用层(CiA 301 / 设备行规) NMT 状态机 对象字典(OD) PDO / SDO 数据链路层(CAN 2.0B) + 物理层(ISO 11898-2) NMT 状态机详细流程 初始化 预操作 操作 停止 自动 NMT 启动 NMT 停止 NMT 进入预操作 NMT 复位

这张图里,你重点看三个东西:

  1. 对象字典是核心——NMT、PDO、SDO都在操作它
  2. NMT状态机控制设备生命周期——上电→预操作→操作,别跳步
  3. PDO和SDO分工明确——实时数据走PDO,配置数据走SDO

我的建议:刚开始学CANopen,别急着看代码。先把对象字典的结构搞清楚,把NMT状态机的转换条件背下来。这两样搞明白了,后面移植CANopenNode就是体力活。