一、CanOpen与CIA301协议

        CAN 报文可以分为数据部分和 ID 部分,各个厂家可以根据自己的喜好进行编写协议。所以就会出现各种各样的协议。为了消除这种乱糟糟的场面,让 CAN 报文有更加明确的分类和用途,所以产生了 CIA301协议.CIA301基本上就等同于CanOpen了。CIA301协议是CanOpen最基础的协议。它规定了 |D 和报文的分类用法,之后大家都按照这个协议去做。

CIA301协议根据ID的不同,区分不同种类报文: 表格ID

SDO: 是CANopen 协议中用于主从设备间进行可靠、点对点参数配置和数据传输的通信机制;收发一次才传输成功(效率不高);会出现超时或格式错误               

PDO: CANopen 协议中实现高效率、实时数据传输的关键机制,其通信方向以从站设备为视角进行定义:发送 PDO(TxPDO)指关节模组向主站发送数据, 接收 PDO(RxPDO)指模组从主站接收数据; 

SYNC: 用于实现同步通信, (没有SYNC, 可以定时器定时发送)

NMT: 网络管理, 控制节点工作状态

EMCY: 紧急报文(错误相应)

CAN 通信的一个特点是有 ID; 针对 ID,CanOpen做了下面的功能:

二、字典

        上面的报文就是通信的基础, 通信是为了改变参数。通信还需要配置间隔时间, 通讯方式等。这些是配置参数, 传输过程中的数据和配置参数在字典中保存。字典是CanOpen重要的概念,字典里面存有数据和配置。

表格字典(索引编号): 字典是柜子, 柜子上有格子(索引), 格子还有格子(子索引)

通信参数: 速度,温度,角度,加速度,工作模式

配置参数: 配置传输模式,时间间隔,一帧数据包含多少个参数

CIA402: 驱动器行业(有的索引是固定的参数)

索引60FF  子索引00---速度

索引6040  子索引00---位置

举例: CAN 总线上接收的报文
601,40 ff 60 00 00 00 00 00
601 = 600 + 1; 在表格ID中查找:  600h代表了它是一条SDO, 1代表向1号节点发送的数据
40: 代表读指令   
ff60是小端: 正确顺序 60ffh, 代表索引是60ff : 在字典ID中查找                                       
00: 子索引
00 00 00 00: 表示数据

字典表格ID:针对从机

三、流程

1. 上电
2. 初始化状态(主机)
3. 预操作状态(主机): 这个状态下,不能发送 PDO,但是可以发送 SDO 或 SYNC;
                                  通过 SDO 配置 PDO
                                  0X06 ...  0x07 ... 0x0f(从机)
                                  准备        打开     运行
4. 操作状态(主机) : 可以进行所有的操作 PDO,SDO,SYNC

四、NMT数据格式

0x0000 + 01 + 01
   ID + 命令CS + 节点号(01~07)
0x01: 启动; 
0x02: 停止;  
0x08: 预开始;   
0x81: 复位节点(应用层);   
0x82: 复位节点通信; 
CanOpen保存指令:601, 22 10 10 01 73 61 76 65: save--->65 76 61 73

五、SDO,PDO数据格式

SDO: 比较慢,但是稳定,会有回复

PDO: 是直接读写索引的(PDO 需要前期进行配置)

使用PDO配置: 1.通过SDO读写取 PDO 的"通讯参数"和"映射参数”; 2. 或者通过上位机


展开通信参数的索引

展开字典上映射参数的索引

要通过通讯和映射参数: 从机决定发送的数据内容

SDO的格式:

SDO 是有回复的: 所以发送一条指令,如果成功就会返回60开头的报文反之; 返回 80开头的报文(错误返回,需要查找原因)

PDO的格式:

SDO配置PDO流程:

六、Sync,Emcy,Lss数据格式

Sync: 帧ID = 0X08


0X1005: 使能的开关
0X1006: 一个周期
0X1007: 同步时间
0X1009: SYNC计数器最大值: 来一个Sync加1

Emcy: 一种错误

Lss: 用于配置节点号和波特率

修改节点号:

七、字典的组成

canfestival字典:.c和.h文件(上位机生成.c和.h文件)
Data Type Definitions: 参数的类型
Communication Parameters: 传输的数据
Transmit PDO Parameters: 通信参数
Transmit PDO Mapping: 映射参数
Manufacturer Specific: 厂家参数

.c文件的流程:
1.声明变量;变量赋值
2.填充数组;类型,数据类型,数据的长度,数据值,回调函数
3.const indextable Master_objdict:最后所有的填充这个数组中
4.const UNS16 Master_ObjdictSize = sizeof(Master_objdict)/sizeof(Master_objdict[0]); 计算对象字典大小  
5.CO_Data Master_Data = CANOPEN_NODE_DATA_INITIALIZER(Master);  初始化主站数据结构    

八、CanFestival周期性发送Sync

1.配置字典:SetAlarm(d, SYNC, &SendSync, 1000000, 1000000);
UNS32 Master_obj1005 = 0x40000080;4表示使能
UNS32 Master_obj1006 = 1000000;SYNC的周期 = 1us *1000000 = 1s
UNS32 Master_obj1007 = 1000000;SYNC窗口宽度是SYNC一个周期的有效时

2.配置时钟: TimeDispatch():通过SetAlarm()更新闹钟本
tmr_base_init(TMR1, 999, (crm_clocks_freq_struct.ahb_freq / 1000000) - 1);    
ahb_freq:240M
分频系数:240
定时器时钟:1MHZ = 1us
中断周期:1000 ×1us = 1ms    

#define TIMEVAL   UNS32                                // 32 位无符号整数:0~ 4,294,967,295
#define TIMEVAL_MAX   0xFFFF                     // 1 ms = 1 个时间单位
#define MS_TO_TIMEVAL(ms) ((ms) * 1)         // 1 ms = 1 个时间单位
#define US_TO_TIMEVAL(us) ((us) / 1000)      // 1000 µs = 1 ms = 1 个时间单位

CanFestival协议栈默认使用微秒作为时间单位;定时器中断周期为1ms,统一使用毫秒为单位。
#define TIMEVAL UNS32:
改成UNS16不可以: CanFestival 协议栈内部的时间值通常需要表示较大的数值; 16 位无符号整数的最大值仅为 65535, 远远不够

TIMEVAL_MAX: 
数值太小时: 时间范围太小,所有超时判断失效
数值太大时: 0XFFFFFFFF回绕处理逻辑有 bug,导致 SetAlarm 陷入无限循环,程序卡死

3.发送流程:
setNodeId(&Master_Data, 0x00);          //主函数 
setState(&Master_Data, Initialisation);  //初始化状态:发送SYNC
switchCommunicationState(d, &newCommunicationState); //应用通信状态:底层通信模块更新状态
1s发送一次sync,执行回调函数SyncAlarm,最后进入canSend()函数

九、CanFestival周期性发送Pdo

1.配置字典:

通讯参数:
index 0x1800 :   Transmit PDO 1 Parameter.  
UNS8 Master_highestSubIndex_obj1800 = 6;                         //对象字典条目支持的最大子索引号
UNS32 Master_obj1800_COB_ID_used_by_PDO = 0x201;   //COB-ID
UNS8 Master_obj1800_Transmission_Type = 0xff; 
同步传输:Transmission Type = 1~240 (每发送Type 个 SYNC 报文,就发送1次 TPDO)
异步/事件触发:= 0xFE, 0xFF (按 Event Timer 周期发,1s)
UNS16 Master_obj1800_Inhibit_Time = 0x0;                      //表示无禁止,即允许连续发送
UNS8 Master_obj1800_Compatibility_Entry = 0x0;            //保留或兼容性条目,通常为 0,未使用
UNS16 Master_obj1800_Event_Timer = 1000;                  //事件定时器单位 ms
UNS8 Master_obj1800_SYNC_start_value = 0x0;             //前 n 个 SYNC 忽略,从第 n+1 个 SYNC 开始发送PDO

映射参数:

UNS8 Master_highestSubIndex_obj1A00 = 1;                 //1 个有效的映射对象
UNS32 Master_obj1A00[] = { 0x20000008 };                   // 唯一的一个映射条目
0x2000:索引
0x00:子索引
0x08:一个 1 字节(8 位)变量

结果:TPDO以1 秒定时触发,协议栈会去读取对象 0x2000:00 的当前值,用 COB-ID 0x201 发出去

2.配置时钟:与CanFestival周期性发送Sync一样

3.发送流程:
setNodeId(&Master_Data, 0x00);                    //主函数 
setState(&Master_Data, Initialisation);            //初始化状态:发送SYNC
setState(&Master_Data, Pre_operational);     //预操作模式
setState(&Master_Data, Operational);            //操作模式
switchCommunicationState(d, &newCommunicationState);   //应用通信状态:通信模块更新状态
StartOrStop(csPDO,  PDOInit(d),  PDOStop(d)); //创建软件计时器:计时器触发执行回调函数,最后进入canSend()函数
SetAlarm (d, pdoNum, &PDOEventTimerAlarm, MS_TO_TIMEVAL (EventTimerDuration), 0);

十、CanFestival上电发送Sdo

1.配置字典:

UNS8 Master_highestSubIndex_obj1280 = 3;                                                     //子索引 1~3
UNS32 Master_obj1280_COB_ID_Client_to_Server_Transmit_SDO = 0x601;  //客户端→服务器 
UNS32 Master_obj1280_COB_ID_Server_to_Client_Receive_SDO = 0x581;   //服务器→客户端
UNS8 Master_obj1280_Node_ID_of_the_SDO_Server = 0x1;   //目标SDO服务器的节点ID 

2.简单发送数据

// 发送Sdo: 601,22,60,60,00,03,00,00,00
601: 客户端→服务器;  22: SDO 命令字节; 索引:60,60; 子索引:00; 4 字节数据:03,00,00,01
    unsigned long abortCode = 0;
    char size = 1;
    char sendDate[4] = {0};
    sendDate[0] = 0x03;
    sendDate[1] = 0x00;
    sendDate[2] = 0x00;    
    sendDate[3] = 0x00;       
    writeNetworkDict(&Master_Data, 0x01, 0x6060, 0x00, size, uint8, &sendDate, 0);
    while(getWriteResultNetworkDict(&Master_Data, 0x01, &abortCode) != SDO_FINISHED)


0x601上的 0x80错误响应是自己的协议栈发出的:SDO 超时时间 (SDO_TIMEOUT_MS = 3000U)
Sdo发送会出现报错:
1. sdo报错, 中止(需要查找协议)
2. emcy: 紧急报文 error code

十一、备注

1.发送NMT命令是什么意思:
发送NMT, 从站什么时候可以使用了;     主站需要发送NMT命令来同步从站的状态
start_node() → masterSendNMTstateChange() → CAN_Transmit()
masterSendNMTstateChange()    直接调用 CAN_Transmit()

2.从站处理时间:
收到完整CAN消息后,在USBFS_L_CAN1_RX0_IRQHandler()立即开始处理: 解析SDO → 查找对象字典 → 执行操作 → 发送响应

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐