• CANOpen之PDO传输


    什么是PDO

    PDO的全称Process Data Object,用来传输过程数据。比如,温度、电压等等。PDO传输是属于生产者消费者模型,生产数据方把数据发送出去。消费者需要处理数据的就去处理,不需要处理的就不处理。PDO是单向传输,不需要应答,所以PDO传输效率高于SDO传输效率。

    PDO通信参数

    RPDO 通讯参数 范围:0x1400h to 15FFh;TPDO 通讯参数范围: 1800h to 19FFh。PDO的通信参数一共有6个。
    PDO通信参数规定了数据收发的形式。

    COB-ID

    PDO的帧ID = COB-ID + 节点ID。

    传输类型

    在这里插入图片描述
    对于TDO而言,
    为0时表示,映射数据变化并且收到一个同步帧,才会发送TPDO。
    为1~240时表示,收到相应个数的同步帧时就发送PDO,和映射数据是否变化没有关系。
    为254、255时表示,映射数据改变事件计时器到,就会发送PDO。 我这里测试为254或者255的情况下,如果映射数据改变的时候,不会发送PDO,只有事件计时器到才会发送PDO
    对于RPDO而言
    为0~240时表示,只要收到一个同步帧,则将RPDO的数据更新到应用。
    为254、255时表示,将接收到的数据直接更新到应用。 我这里实际测试不管是多少都会直接跟新到应用,不依赖同步帧。
    我移植的是CanFestival这个协议栈,不知道为什么是这样子。

    生产禁止约束时间

    这一项对TPDO才有用,用来规定TPDO发送的最小时间间隔。这其实就是流量控制,防止TPDO狂发,占用大量CAN总线带宽。

    事件定时器触发时间

    事件定时器触发时间需要配合传输类型去使用。

    同步帧起始值

    这个就见名知意了,就是同步帧的初始值。

    PDO映射参数

    TPDO的映射参数范围是0x1A00到0x1BFF,RPDO的映射参数范围是0x1600~0x17FF。
    PDO映射参数规定了过程数据被映射到哪里。不太好描述,借用代码说明

                        UNS8 _highestSubIndex_obj1A00 = 8; /* number of subindex - 1*/
                        UNS32 _obj1A00[] = 
                        {
                          0x20000108,	/* 536871176 */
                          0x20000208,	/* 536871432 */
                          0x20000308,	/* 536871688 */
                          0x20000408,	/* 536871944 */
                          0x20000508,	/* 536872200 */
                          0x20000608,	/* 536872456 */
                          0x20000708,	/* 536872712 */
                          0x20000808	/* 536872968 */
                        };
                        subindex _Index1A00[] = 
                         {
                           { RW, uint8, sizeof (UNS8), (void*)&_highestSubIndex_obj1A00, NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&data_obj1A00[0], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&data_obj1A00[1], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&data_obj1A00[2], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&data_obj1A00[3], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&data_obj1A00[4], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&data_obj1A00[5], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&data_obj1A00[6], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&data_obj1A00[7], NULL }
                         };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    结构体_Index1A00中保存的&data_obj1A00[0]是映射参数的地址,映射参数的内容是0x20000108。问题来了,映射参数如何去解读?映射参数是32bit的,bit16~bit31是索引,bit8 ~bit15是子索引,bit0 ~ bit7是数据长度(单位bit)。
    重点来了,拿到了0x20000108,我们就知道应用数据的地址保存在索引0x2000下的子索引0x01下。我们知道应用数据的地址,也知道了长度是8bit,那是不是就能对应用数据读写了。对于TPDO,那就从这个地址下取出数据取发送,对于RPDO,那就将接收到的数据存储到这个地址下。

    PDO数据存储区

    还是借助代码来看

                        UNS8 _highestSubIndex_obj2000 = 8; /* number of subindex - 1*/
                        subindex _Index2000[] = 
                         {
                           { RO, uint8, sizeof (UNS8), (void*)&_highestSubIndex_obj2000, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_1, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_2, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_3, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_4, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_5, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_6, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_7, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_8, NULL }
                         };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    data_data_1就是真正的应用数据。如果一个TPDO的映射参是0x20000108,那么该TPDO就会把data_data_1发送出去;如果一个RPDO的映射参数是0x20000108,那么就会把该RPDO接收到的数据存储到data_data_1中。

    真实感受收发PDO

    有了前边的理论知识,我们下面来通过配置PDO的通信参数,映射参数,数据存储区,和抓包来感受一下PDO传输数据。

    TDPO的例子

    通信参数如下:

    /* index 0x1800 :   Transmit PDO 1 Parameter. */
                        UNS8 _highestSubIndex_obj1800 = 6; /* number of subindex - 1*/
                        UNS32 _obj1800_COB_ID_used_by_PDO = 0x180;	/* 384 */
                        UNS8 _obj1800_Transmission_Type = 1;	/* 0 */
                        UNS16 _obj1800_Inhibit_Time = 0x0;	/* 0 */
                        UNS8 _obj1800_Compatibility_Entry = 0x0;	/* 0 */
                        UNS16 _obj1800_Event_Timer = 0;	/* 0 */
                        UNS8 _obj1800_SYNC_start_value = 0x0;	/* 0 */
                        subindex _Index1800[] = 
                         {
                           { RO, uint8, sizeof (UNS8), (void*)&_highestSubIndex_obj1800, NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1800_COB_ID_used_by_PDO, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&_obj1800_Transmission_Type, NULL },
                           { RW, uint16, sizeof (UNS16), (void*)&_obj1800_Inhibit_Time, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&_obj1800_Compatibility_Entry, NULL },
                           { RW, uint16, sizeof (UNS16), (void*)&_obj1800_Event_Timer, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&_obj1800_SYNC_start_value, NULL }
                         };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    映射参数如下:

    /* index 0x1A00 :   Transmit PDO 1 Mapping. */
                        UNS8 _highestSubIndex_obj1A00 = 8; /* number of subindex - 1*/
                        UNS32 _obj1A00[] = 
                        {
                          0x20000108,	/* 536871176 */
                          0x20000208,	/* 536871432 */
                          0x20000308,	/* 536871688 */
                          0x20000408,	/* 536871944 */
                          0x20000508,	/* 536872200 */
                          0x20000608,	/* 536872456 */
                          0x20000708,	/* 536872712 */
                          0x20000808	/* 536872968 */
                        };
                        subindex _Index1A00[] = 
                         {
                           { RW, uint8, sizeof (UNS8), (void*)&_highestSubIndex_obj1A00, NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1A00[0], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1A00[1], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1A00[2], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1A00[3], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1A00[4], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1A00[5], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1A00[6], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1A00[7], NULL }
                         };
    
    • 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

    数据存储区如下:

    /* index 0x2000 :   Mapped variable data */
                        UNS8 _highestSubIndex_obj2000 = 8; /* number of subindex - 1*/
                        subindex _Index2000[] = 
                         {
                           { RO, uint8, sizeof (UNS8), (void*)&_highestSubIndex_obj2000, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_1, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_2, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_3, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_4, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_5, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_6, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_7, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&data_data_8, NULL }
                         };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    通信参数中的传输类型是1,表示收到一个同步帧发送一次PDO,抓包如下:
    在这里插入图片描述
    当我把通信参数改为3的时候,就是收到3个同步帧才发送一次PDO,抓包如下:
    在这里插入图片描述

    RPDO的例子

    RPDO的通信参数:

    /* index 0x1400 :   Receive PDO 1 Parameter. */
                        UNS8 _highestSubIndex_obj1400 = 6; /* number of subindex - 1*/
                        UNS32 _obj1400_COB_ID_used_by_PDO = 0x200;	/* 512 */
                        UNS8 _obj1400_Transmission_Type = 0;	/* 0 */
                        UNS16 _obj1400_Inhibit_Time = 0x0;	/* 0 */
                        UNS8 _obj1400_Compatibility_Entry = 0x0;	/* 0 */
                        UNS16 _obj1400_Event_Timer = 0x0;	/* 0 */
                        UNS8 _obj1400_SYNC_start_value = 0x0;	/* 0 */
                        subindex _Index1400[] = 
                         {
                           { RO, uint8, sizeof (UNS8), (void*)&_highestSubIndex_obj1400, NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1400_COB_ID_used_by_PDO, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&_obj1400_Transmission_Type, NULL },
                           { RW, uint16, sizeof (UNS16), (void*)&_obj1400_Inhibit_Time, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&_obj1400_Compatibility_Entry, NULL },
                           { RW, uint16, sizeof (UNS16), (void*)&_obj1400_Event_Timer, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&_obj1400_SYNC_start_value, NULL }
                         };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    RPDO的映射参数:

    /* index 0x1600 :   Receive PDO 1 Mapping. */
                        UNS8 _highestSubIndex_obj1600 = 8; /* number of subindex - 1*/
                        UNS32 _obj1600[] = 
                        {
                          0x20010108,	/* 536936712 */
                          0x20010208,	/* 536936968 */
                          0x20010308,	/* 536937224 */
                          0x20010408,	/* 536937480 */
                          0x20010508,	/* 536937736 */
                          0x20010608,	/* 536937992 */
                          0x20010708,	/* 536938248 */
                          0x20010808	/* 536938504 */
                        };
                        subindex _Index1600[] = 
                         {
                           { RW, uint8, sizeof (UNS8), (void*)&_highestSubIndex_obj1600, NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1600[0], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1600[1], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1600[2], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1600[3], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1600[4], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1600[5], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1600[6], NULL },
                           { RW, uint32, sizeof (UNS32), (void*)&_obj1600[7], NULL }
                         };
    
    • 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

    RPDO的数据存储区:

    /* index 0x2001 :   Mapped variable rec_data */
                        UNS8 _highestSubIndex_obj2001 = 8; /* number of subindex - 1*/
                        subindex _Index2001[] = 
                         {
                           { RO, uint8, sizeof (UNS8), (void*)&_highestSubIndex_obj2001, NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&rec_data[0], NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&rec_data[1], NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&rec_data[2], NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&rec_data[3], NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&rec_data[4], NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&rec_data[5], NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&rec_data[6], NULL },
                           { RW, uint8, sizeof (UNS8), (void*)&rec_data[7], NULL }
                         };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    还没收到RPDO的时候,rec的数据全部是0:
    在这里插入图片描述
    CANOpen主站发送如下RPDO数据:
    在这里插入图片描述
    我们来看应用数据:
    在这里插入图片描述
    PDO知识就说到这里,下一篇更新对象字典相关知识。

  • 相关阅读:
    语音合成——闽南语合成(1)
    给定值,移除数组中与之相等的元素
    html、css、QQ音乐移动端静态页面,资源免费分享,可作为参考,提供InsCode在线运行演示
    node进程管理工具 pm2 常用操作命令
    UIAutomator2常用类之UiObject2
    1.6、计算机网络的性能指标(2)
    【附源码】计算机毕业设计JAVA研究生推免系统
    基于PHP+MySQL高校教务选课系统的设计与实现
    SQL注入漏洞(Mysql与MSSQL特性)
    基于图搜索的规划算法之A*家族(六):D* Lite算法
  • 原文地址:https://blog.csdn.net/zhaodong1102/article/details/126333839