CANOpen协议详解(一):CANfestival源码分析

CANOpen 协议详解(⼀):CANfestival 源码分析
CANFestival-3源码详解⼀:重要结构
有⼏点需要说明:
1.使⽤的是官⽹下载的canfestival-3源代码,下载的压缩包⽂件名是:Mongo-canfestival-3-asc-1a25f5151a8d.zip,使⽤的是源码⾥⾯⾃带的对象字典编辑器来⽣成对象字典⽂件;
2.主要解析源码⾥⾯与DS 301协议有关的代码,DS 301协议参考⽂档为301_v04000201.pdf;
3.推荐⼀个⽂档叫《CANopen轻松⼊门》,介绍了CANopen的基础知识,⼴州致远电⼦出品,写的⾮常好。还推荐⼀个⽂档《CANopen high-level protocol for CAN-bus》。
4.本⽂默认读者对CANopen有所了解,不涉及CANopen的基础知识。
1.CANOpen node structure
canfestival⾥⾯最核⼼的⼀个结构体,就是这个节点数据结构体,这个结构体包含了⼀个CANOpen节点(node)需要⽤到的所有数据信息。这个结构体定义在data.h⽂件中,源码如下:struct struct_CO_Dat
a { /* Object dictionary */ UNS8 *bDeviceNodeId; const indextable *objdict; s_PDO_status *PDO_status; TIMER_HANDLE *RxPDO_EventTimers; void (*RxPDO_EventTimers_Handler)(CO_Data*, UNS32); const quick_index *firstIndex; const quick_index *lastIndex; const UNS16 *ObjdictSize; const UNS8 *iam_a_slave; valueRangeTest_t valueRangeTest;  /* SDO */ s_transfer transfers[SDO_MAX_SIMULTANEOUS_TRANSFERS]; /* s_sdo_parameter *sdo_parameters; */ /* State machine */ e_nodeState nodeState; s_state_communication CurrentCommunicationState; initialisation_t initialisation; preOperational_t preOperational; operational_t operational; stopped_t stopped;    void (*NMT_Slave_Node_Reset_Callback)(CO_Data*);    void (*NMT_Slave_Communications_Reset_Callback)(CO_Data*);      /* NMT-heartbeat */ UNS8 *ConsumerHeartbeatCount; UNS32 *ConsumerHeartbeatEntries; TIMER_HANDLE *ConsumerHeartBeatTimers; UNS16 *ProducerHeartBeatTime; TIMER_HANDLE ProducerHeartBeatTimer; heartbeatError_t heartbeatError; e_nodeState NMTable[NMT_MAX_NODE_ID];  /* NMT-nodeguarding */ TIMER_HANDLE GuardTimeTimer; TIMER_HANDLE LifeTimeTimer; nodeguardError_t nodeguardError; UNS16 *GuardTime; UNS8 *LifeTimeFactor; UNS8 nodeGuardStatus[NMT_MAX_NODE_ID]; /* SYNC */ TIMER_HANDLE syncTimer;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
选址问题22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
先看⼀下这个结构体⾥⾯包含哪些内容。
1.1 Object dictionary 1.1.1 Node-ID
UNS8 *bDeviceNodeId ;
每个节点都有⼀个唯⼀的标识叫Node-ID,这个变量就是⽤来记录Node-ID的。
根据源码和301官⽅⽂档以及《CANopen high-level protocol for CAN-bus》⽂档来看,这个Node-ID占7位,取值的范围是:[1,127]。
判断Node-ID是否有效的源码如下,可以看到Node-ID范围是[1, 127]。
⽽有些⽹上的教程⽂档写的是[0, 127],甚⾄有些写的是最⼤128都是不对的,需要注意0是不能作为Node-ID的。1.1.2 Index table
const indextable *objdict;
这个变量⽤来存放每个对象的索引,根据索引就能到真正存放对象数据的位置。它是⼀个结构体数
组类型,这个结构体源码如下: TIMER_HANDLE syncTimer; UNS32 *COB_ID_Sync; UNS32 *Sync_Cycle_Period; /*UNS32 *Sync_window_length;;*/ post_sync_t post_sync; post_TPDO_t post_TPDO; post_SlaveBootup_t post_SlaveBootup;    post_SlaveStateChange_t post_SlaveStateChange;  /* General */ UNS8 toggle; CAN_PORT canHandle;  scanIndexOD_t scanIndexOD; storeODSubIndex_t storeODSubIndex;  /* DCF concise */    const indextable* dcf_odentry; UNS8* dcf_cursor; UNS32 dcf_entries_count; UNS8 dcf_status;    UNS32 dcf_size;    UNS8* dcf_data;  /* EMCY */ e_errorState error_state; UNS8 error_history_size; UNS8* error_number; UNS32* error_first_element; UNS8* error_register;    UNS32* error_cobid; s_errors error_data[EMCY_MAX_ERRORS]; post_emcy_t post_emcy; #ifdef CO_ENABLE_LSS  /* LSS */ lss_transfer_t lss_transfer; lss_StoreConfiguration_t lss_StoreConfiguration;#endif };
46
47
批判理论48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84if(!(nodeId>0 && nodeId<=127)){  MSG_WAR(0x2D01, "Invalid NodeID",nodeId);  return;  }
1
2
3
4
其中subindex* pSubindex;保存⼦索引的相关信息,在CANopen中,每个对象都有16位索引和8位⼦索引。
UNS8 bSubCount;表⽰⼦索引的个数,8位⼦索引最多可以表⽰255个⼦索引。UNS16 index;表⽰索引。
定义了多少个变量,这个数组长度就是多少,例如通过对象字典编辑器⽣成的对象字典源码中,这个数组初始化的源码如下:
其中定义了16个对象,这些对象的含义后⽂会讲到。
上述⼦索引结构体subindex 的源码如下:
其中
UNS8 bAccessType;表⽰权限,有三种:RW, WO, RO。
UNS8 bDataType;表⽰这个对象⾥⾯存储数据的数据类型,数据类型的源码如下,与301⽂档中的定义完全⼀致:struct td_indextable {    subindex*  pSubindex;  /* Pointer to the subindex */    UNS8  bSubCount;  /* the count of valid entries for this subindex                          * This count here defines how many memory has been                          * allocated. this memory does not have to be used.                        */    UNS16  index;};
1
2
3
4
5
6
7
8
9/**************************************************************************//* Declaration of pointed variables                                      *//**************************************************************************/const indextable TestMaster_objdict[] = {  { (subindex*)TestMaster_Index1000,sizeof(TestMaster_Index1000)/sizeof(TestMaster_Index1000[0]), 0x1000},  { (subindex*)TestMaster_Index1001,sizeof(TestMaster_Index1001)/sizeof(TestMaster_Index1001[0]), 0x1001},  { (subindex*)TestMaster_Index1017,sizeof(TestMaster_Index1017)/sizeof(TestMaster_Index1017[0]), 0x1017},  { (subindex*)TestMaster_Index1018,sizeof(TestMaster_Index1018)/sizeof(TestMaster_Index1018[0]), 0x1018},  { (subindex*)TestMaster_Index1200,sizeof(TestMaster_Index1200)/sizeof(TestMaster_Inde
x1200[0]), 0x1200},  { (subindex*)TestMaster_Index1201,sizeof(TestMaster_Index1201)/sizeof(TestMaster_Index1201[0]), 0x1201},  { (subindex*)TestMaster_Index1280,sizeof(TestMaster_Index1280)/sizeof(TestMaster_Index1280[0]), 0x1280},  { (subindex*)TestMaster_Index1281,sizeof(TestMaster_Index1281)/sizeof(TestMaster_Index1281[0]), 0x1281},  { (subindex*)TestMaster_Index1400,sizeof(TestMaster_Index1400)/sizeof(TestMaster_Index1400[0]), 0x1400},  { (subindex*)TestMaster_Index1401,sizeof(TestMaster_Index1401)/sizeof(TestMaster_Index1401[0]), 0x1401},  { (subindex*)TestMaster_Index1600,sizeof(TestMaster_Index1600)/sizeof(TestMaster_Index1600[0]), 0x1600},  { (subindex*)TestMaster_Index1601,sizeof(TestMaster_Index1601)/sizeof(TestMaster_Index1601[0]), 0x1601},  { (subindex*)TestMaster_Index1800,sizeof(TestMaster_Index1800)/sizeof(TestMaster_Index1800[0]), 0x1800},  { (subindex*)TestMaster_Index1801,sizeof(TestMaster_Index1801)/sizeof(TestMaster_Inde
x1801[0]), 0x1801},  { (subindex*)TestMaster_Index1A00,sizeof(TestMaster_Index1A00)/sizeof(TestMaster_Index1A00[0]), 0x1A00},  { (subindex*)TestMaster_Index1A01,sizeof(TestMaster_Index1A01)/sizeof(TestMaster_Index1A01[0]), 0x1A01},};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23typedef struct td_subindex {    UNS8                    bAccessType;    UNS8                    bDataType; /* Defines of what datatype the entry is */    UNS32                  size;      /* The size (in Byte) of the variable */    void*                  pObject;  /* This is the pointer of the Variable */ ODCallback_t            callback;  /* Callback function on write event */} subindex;
1
2
3
4
5
6
7
8油压开关
UNS32 size;表⽰数据的⼤⼩,即占多少字节。
void* pObject;表⽰这个对象保存数据变量的指针,即数据真正存储的位置。ODCallback_t callback;写⼊事件时的回调函数,回调函数的函数原型如下:1.1.3 PDO structure
s_PDO_status *PDO_status;
PDO_status ⽤来保存发送PDO通信参数的数组,对每⼀个TPDO都会产⽣⼀个s_PDO_status 结构体,就算没有定义TPDO,为避免编译错误,这个数组长度也⾄少是1,这⼀点在后⾯结构体初始化的时候再说。
s_PDO_status 的源码如下:/** this are static defined datatypes taken fCODE the canopen standard. They  *  are located at index 0x0001 to 0x001B. As described in the standard, they  *  are in the object dictionary for definition purpose only. a device does not  *  to support all of this datatypes. */#d
efine boolean        0x01#define int8            0x02#define int16          0x03#define int32          0x04#define uint8          0x05#define uint16          0x06#define uint32          0x07#define real32          0x08#define visible_string  0x09#define octet_string    0x0A #define unicode_string  0x0B #define time_of_day    0x0C #define time_difference 0x0D #define domain          0x0F #define int24          0x10#define real64          0x11#define int40          0x12#define int48          0x13#define int56          0x14#define int64          0x15#define uint24          0x16#define uint40          0x18#define uint48          0x19#define uint56          0x1A #define uint64          0x1B #define pdo_communication_parameter 0x20#define pdo_mapping                0x21#define sdo_parameter              0x22#define identity                    0x23/* CanFestival is using 0x24 to 0xFF to define some types containing a  value range (See how it works in objdict.c) */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
碎纸片拼接34
35
36
37
38
39
40
41typedef UNS32 (*ODCallback_t)(CO_Data* d, const indextable *, UNS8 bSubindex);
1/** The PDO structure */struct struct_s_PDO_status {  UNS8 transmit_type_parameter;  TIMER_HANDLE event_timer;  TIMER_HANDLE inhibit_timer;  Message last_message;};
1
2
3
4
5
6
7
可以看出这个结构体实际上保存了PDO的通信参数,只会保存TPDO的参数,不会保存RPDO的参数。其实PDO的通信参数在1.1.2讲的对象索引⾥⾯都会保存,为什么在这个地⽅要单独⽤⼀个结构体来保存,暂时不清楚。
⾸先回顾⼀下PDO 的通信参数
不论是TPDO还是RPDO都有通信参数和映射参数两种参数,通信参数有如下六种:
subindex
name type 0x01
COB ID UNSIGNED320x02
Transmission Type UNSIGNED80x03
Inhibit Time UNSIGNED160x04
Compatibility Entry UNSIGNED80x05
Event Time UNSIGNED160x06SYNC start value UNSIGNED8
这⾥先解释⼀下这六个参数是什么意思吧。
1.COB ID就不⽤过多解释了,简单来理解就是,通过COB ID可以让CAN节点知道,这⼀帧报⽂属于PDO、SDO、NMT、SYNC还是其他。
特别响非常近2.Transmission Type表⽰PDO的通信类型,有同步、异步、周期、⾮周期等,具体见《CANopen high-level protocol for CAN-bus》的Table3。取值范围是0~255,取值定义的源码如下:
3.Inhibit Time表⽰PDO发送的最⼩时间间隔,避免发送频率太快,总线负载太⼤,单位是100us。
4.Compatibility Entry这个不知道是啥,⽂档⾥⾯都没提到,先不管。
5.Event Time如果是定时发送PDO,那么这个参数表⽰的定时时间,如果这个参数为0,那么表⽰事件触发发送PDO,单位是ms。
6.SYNC start value同步起始值。当PDO为同步发送时,⽐如Transmission Type=10,那么收到10个同步包后才发送PDO,如果SYNC start value=2,那么刚开始时收到2个同步包就开始发送PDO,之后就按10个同步包发送。struct_s_PDO_status 结构体将TPDO的参数⾥的2、3、5参数单独拿出来保存,这样做的⽬的是啥,暂时不知道。另外⼀个参数是Message last_message;保存最新的TPDO message,同样不知道这样做的⽬的是啥。
1.1.4 RxPDO_EventTimers
TIMER_HANDLE *RxPDO_EventTimers;
void (*RxPDO_EventTimers_Handler)(CO_Data*, UNS32);
这两个放在⼀起,从字⾯上看都与接收PDO时间定时器有关。
1.1.5 First and Last Index /** definitions of the different types of PDOs' transmission  *  * SYNCHRO(n) means that the PDO will be transmited every n SYNC signal. */#define TRANS_EVERY_N_SYNC(n) (n) /*n = 1 to 240 */#define TRANS_SYNC_ACYCLIC    0    /* Trans after reception of n SYNC. n = 1 to 240 */#define TRANS_SYNC_MIN        1    /* Trans after reception of n SYNC. n = 1 to 240 */#define TRANS_SYNC_MAX        240  /* Trans after reception of n SYNC. n = 1 to 240 */#define TRANS_RTR_SYNC        252  /* Transmission on request */#define TRANS_RTR            253  /* Transmission on request */#define TRANS_EVENT_SPECIFIC  254  /* Transmission on event */#define TRANS_EVENT_PROFILE  255  /* Transmission on event */
1
2
3
4
中国电梯网5
6
7
8
9
10
11
12

本文发布于:2024-09-22 23:19:21,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/137034.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:结构   参数   对象
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议