CANOpen之PDO传输

这篇具有很好参考价值的文章主要介绍了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。

传输类型

CANOpen之PDO传输
对于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 }
                     };

结构体_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 }
                     };

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 }
                     };

映射参数如下:

/* 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 }
                     };

数据存储区如下:

/* 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,表示收到一个同步帧发送一次PDO,抓包如下:
CANOpen之PDO传输
当我把通信参数改为3的时候,就是收到3个同步帧才发送一次PDO,抓包如下:
CANOpen之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 }
                     };

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 }
                     };

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 }
                     };

还没收到RPDO的时候,rec的数据全部是0:
CANOpen之PDO传输
CANOpen主站发送如下RPDO数据:
CANOpen之PDO传输
我们来看应用数据:
CANOpen之PDO传输
PDO知识就说到这里,下一篇更新对象字典相关知识。文章来源地址https://www.toymoban.com/news/detail-490443.html

到了这里,关于CANOpen之PDO传输的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Docker】什么是Docker,它用来干什么

    作者简介: 辭七七,目前大一,正在学习C/C++,Java,Python等 作者主页: 七七的个人主页 文章收录专栏: 七七的闲谈 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到

    2024年02月07日
    浏览(33)
  • Jmeter是用来做什么的?

    JMeter是一个开源的Java应用,主要用于性能测试和功能测试。它最初由Apache软件基金会设计用于测试Web应用程序,但现在已经扩展到其他测试功能。JMeter的主要功能如下: 性能测试 :性能测试是JMeter的核心功能,主要分为两大部分:负载测试和压力测试。负载测试是模拟大量

    2024年02月09日
    浏览(27)
  • 数字藏品可以用来干什么?

    一、作为数字收藏艺术品,满足收藏者的爱好。绘画、文物等艺术品是数字收藏品是最基础的应用,也是目前最受欢迎的种类,它与现实生活中的其他艺术品具有相似性,一样通过网上购买的方式获得。 数字藏品,虽然“摸不着”,但与传统艺术品相比较,又具有一定优势,

    2024年02月09日
    浏览(30)
  • 服务器是什么?它是用来干什么的?

    作者: Insist-- 个人主页: insist--个人主页 作者会持续更新网络知识和python基础知识,期待你的关注   目录 一、服务器是什么? 二、服务器的作用 1、提高访问速度 2、提高安全性 三、云服务器与物理服务器 1、云服务器 云服务器的优点: 2、物理服务器 物理服务器的优点:

    2024年02月08日
    浏览(38)
  • 【大数据】什么是Flink?Flink能用来做什么?

    Apache Flink 是一个框架和分布式处理引擎,用于在无边界和有边界数据流上进行有状态的计算。Flink 能在所有常见集群环境中运行,并能以内存速度和任意规模进行计算。 Apache Flink 功能强大,支持开发和运行多种不同种类的应用程序。它的主要特性包括:批流一体化、精密的

    2024年02月04日
    浏览(32)
  • python cv2是什么,可以用来干什么

    OpenCV (Open Source Computer Vision Library) 是一个流行的开源计算机视觉库,提供了丰富的图像和视频处理功能。通过使用 OpenCV 的 Python 绑定库 cv2,可以实现以下一些功能: 图像读取和显示:使用 cv2.imread() 读取图像文件,使用 cv2.imshow() 显示图像窗口。 图像处理:包括图像滤波、

    2024年02月14日
    浏览(34)
  • Hessian 矩阵汉语叫什么名字,是什么意思,是用来干什么的?

    问题描述:Hessian 矩阵汉语叫什么名字,是什么意思,是用来干什么的? 问题解答: Hessian 矩阵的汉语名字是“黑塞矩阵”或“海森矩阵”。 这个名字的来源是对德国数学家Ludwig Hessian(海森)的姓氏的翻译。Hessian 矩阵是一个方阵,其中的元素是一个函数的二阶偏导数,用

    2024年01月22日
    浏览(39)
  • 【PHP面试题82】system和exec是用来做什么的?有什么区别

    本文已收录于PHP全栈系列专栏:PHP面试专区。做全网最全最有营养的PHP面试大全。 计划将全覆盖PHP开发领域所有的面试题, 对标资深工程师/架构师序列 ,欢迎大家提前关注锁定。 在PHP中, system() 和 exec() 是用来执行外部程序或命令的函数。这两个函数的作用基本相同,都

    2024年02月11日
    浏览(36)
  • 有一台阿里云轻量应用服务器可以用来做什么?

    阿里云轻量应用服务器可以用来做什么?轻量服务器可用于网站搭建、个人博客、图床、云端学习环境、电商建设、论坛社区、开发环境配置 等。可以在阿里云CLUB中心查看 aliyun.club 当前最新的优惠券和活动信息。 轻量是不是性能差?不是,轻量应用服务器相对于ECS云服务

    2024年02月20日
    浏览(35)
  • 阿里云2c4g服务器可以用来做什么?

    阿里云2c4g服务器可以用来做什么?2核4G4M轻量服务器165元一年,云服务器2核4G5M优惠价格199元一年,活动  aliyunfuwuqi.com/go/youhui 阿里云2c4g服务器可以用来做什么? 阿里云ECS云服务器可以用来做什么?2核4G云服务器可以用来搭建网站、爬虫、邮件服务器、接口服务器、个人博

    2024年04月28日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包