硬汉嵌入式论坛

 找回密码
 立即注册
查看: 2471|回复: 20
收起左侧

[CAN/FDCAN] CANopenNode主机做SDO通信测试代码

  [复制链接]

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116230
QQ
发表于 2023-10-14 07:39:09 | 显示全部楼层 |阅读模式

主机对应的是SDO客户端,从机对应的是SDO服务器,这点不要搞反了。

[C] 纯文本查看 复制代码
/**
 * @defgroup CO_SDOclient SDO client
 * CANopen Service Data Object - client protocol.
 *
 * @ingroup CO_CANopen_301
 * @{
 * SDO client is able to access Object Dictionary variables from remote nodes.
 * Usually there is one SDO client on CANopen network, which is able to
 * configure other CANopen nodes. It is also possible to establish individual
 * SDO client-server communication channels between devices.
 *
 * SDO client is used in CANopenNode from CO_gateway_ascii.c with default SDO
 * CAN identifiers. There is quite advanced usage in non-blocking function.
 *
 * If enabled, SDO client is initialized in CANopen.c file with
 * @ref CO_SDOclient_init() function.
 *
 * Basic usage:
 * @code{.c}
CO_SDO_abortCode_t read_SDO(CO_SDOclient_t *SDO_C, uint8_t nodeId,
                            uint16_t index, uint8_t subIndex,
                            uint8_t *buf, size_t bufSize, size_t *readSize)
{
    CO_SDO_return_t SDO_ret;

    // setup client (this can be skipped, if remote device don't change)
    SDO_ret = CO_SDOclient_setup(SDO_C,
                                 CO_CAN_ID_SDO_CLI + nodeId,
                                 CO_CAN_ID_SDO_SRV + nodeId,
                                 nodeId);
    if (SDO_ret != CO_SDO_RT_ok_communicationEnd) {
        return CO_SDO_AB_GENERAL;
    }

    // initiate upload
    SDO_ret = CO_SDOclientUploadInitiate(SDO_C, index, subIndex, 1000, false);
    if (SDO_ret != CO_SDO_RT_ok_communicationEnd) {
        return CO_SDO_AB_GENERAL;
    }

    // upload data
    do {
        uint32_t timeDifference_us = 10000;
        CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE;

        SDO_ret = CO_SDOclientUpload(SDO_C,
                                     timeDifference_us,
                                     false,
                                     &abortCode,
                                     NULL, NULL, NULL);
        if (SDO_ret < 0) {
            return abortCode;
        }

        sleep_us(timeDifference_us);
    } while(SDO_ret > 0);

    // copy data to the user buffer (for long data function must be called
    // several times inside the loop)
    *readSize = CO_SDOclientUploadBufRead(SDO_C, buf, bufSize);

    return CO_SDO_AB_NONE;
}

CO_SDO_abortCode_t write_SDO(CO_SDOclient_t *SDO_C, uint8_t nodeId,
                             uint16_t index, uint8_t subIndex,
                             uint8_t *data, size_t dataSize)
{
    CO_SDO_return_t SDO_ret;
    bool_t bufferPartial = false;

    // setup client (this can be skipped, if remote device is the same)
    SDO_ret = CO_SDOclient_setup(SDO_C,
                                 CO_CAN_ID_SDO_CLI + nodeId,
                                 CO_CAN_ID_SDO_SRV + nodeId,
                                 nodeId);
    if (SDO_ret != CO_SDO_RT_ok_communicationEnd) {
        return -1
    }

    // initiate download
    SDO_ret = CO_SDOclientDownloadInitiate(SDO_C, index, subIndex,
                                           dataSize, 1000, false);
    if (SDO_ret != CO_SDO_RT_ok_communicationEnd) {
        return -1
    }

    // fill data
    size_t nWritten = CO_SDOclientDownloadBufWrite(SDO_C, data, dataSize);
    if (nWritten < dataSize) {
        bufferPartial = true;
        // If SDO Fifo buffer is too small, data can be refilled in the loop.
    }

    //download data
    do {
        uint32_t timeDifference_us = 10000;
        CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE;

        SDO_ret = CO_SDOclientDownload(SDO_C,
                                       timeDifference_us,
                                       false,
                                       bufferPartial,
                                       &abortCode,
                                       NULL, NULL);
        if (SDO_ret < 0) {
            return abortCode;
        }

        sleep_us(timeDifference_us);
    } while(SDO_ret > 0);

    return CO_SDO_AB_NONE;
}


通信格式:

12.png
回复

使用道具 举报

1

主题

6

回帖

9

积分

新手上路

积分
9
发表于 2023-10-25 16:44:01 | 显示全部楼层
感谢分享,期待后续课程
回复

使用道具 举报

4

主题

189

回帖

201

积分

高级会员

积分
201
发表于 2023-11-27 14:27:15 | 显示全部楼层
这个移植简单吗
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116230
QQ
 楼主| 发表于 2023-11-27 15:25:11 | 显示全部楼层
fyyxxm 发表于 2023-11-27 14:27
这个移植简单吗

简单,底层驱动都是做好的,简单配置即可。此贴一楼末尾有主从机例子。

BSP视频教程第28期:CANopen协议栈专题,CANopen主从机组网实战,CAN词典工具使用方法以及吃透PDO玩法(2023-11-01)
https://www.armbbs.cn/forum.php?mod=viewthread&tid=121619
回复

使用道具 举报

1

主题

10

回帖

13

积分

新手上路

积分
13
发表于 2024-11-7 16:58:33 | 显示全部楼层
请问这个代码在哪里能找到。
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116230
QQ
 楼主| 发表于 2024-11-8 09:29:45 | 显示全部楼层
aqtcwangwy 发表于 2024-11-7 16:58
请问这个代码在哪里能找到。

一楼末尾
BSP视频教程第28期:CANopen协议栈专题,CANopen主从机组网实战,CAN词典工具使用方法以及吃透PDO玩法(2023-11-01)
https://www.armbbs.cn/forum.php?mod=viewthread&tid=121619
回复

使用道具 举报

0

主题

8

回帖

8

积分

新手上路

积分
8
发表于 2025-5-22 13:50:12 | 显示全部楼层
硬汉哥,sleep_us()这个延迟函数是阻塞的还是非阻塞的?
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116230
QQ
 楼主| 发表于 2025-5-23 07:44:56 | 显示全部楼层
MingChao 发表于 2025-5-22 13:50
硬汉哥,sleep_us()这个延迟函数是阻塞的还是非阻塞的?

我用的阻塞的
回复

使用道具 举报

0

主题

8

回帖

8

积分

新手上路

积分
8
发表于 2025-5-23 13:55:56 | 显示全部楼层

硬汉哥,我看到你的例程从机和主机配置的时候设置的节点是不一样的
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116230
QQ
 楼主| 发表于 2025-5-24 08:06:04 | 显示全部楼层
MingChao 发表于 2025-5-23 13:55
硬汉哥,我看到你的例程从机和主机配置的时候设置的节点是不一样的

这个没关系,不影响测试
回复

使用道具 举报

0

主题

8

回帖

8

积分

新手上路

积分
8
发表于 2025-5-26 11:16:24 | 显示全部楼层
eric2013 发表于 2025-5-24 08:06
这个没关系,不影响测试

如果想要使用例程让从机主机通信,是要把这两个节点设置成一样的吗
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116230
QQ
 楼主| 发表于 2025-5-27 09:24:33 | 显示全部楼层
MingChao 发表于 2025-5-26 11:16
如果想要使用例程让从机主机通信,是要把这两个节点设置成一样的吗

可以参考本期视频配套例子,是一个主机,两个从机

BSP视频教程第28期:CANopen协议栈专题,CANopen主从机组网实战,CAN词典工具使用方法以及吃透PDO玩法(2023-11-01)
https://www.armbbs.cn/forum.php? ... 1619&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

0

主题

8

回帖

8

积分

新手上路

积分
8
发表于 2025-5-27 15:14:52 | 显示全部楼层
硬汉哥,移植完成后,h7tool作为主机发送给从机,从机会从心跳报文直接停止,没有错误报文什么的,就直接停止,这是怎么回事
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116230
QQ
 楼主| 发表于 2025-5-28 10:29:24 | 显示全部楼层
MingChao 发表于 2025-5-27 15:14
硬汉哥,移植完成后,h7tool作为主机发送给从机,从机会从心跳报文直接停止,没有错误报文什么的,就直接停 ...

这种情况的话,大概率是没有移植好,特别是底层读写函数的实现,你看下是否有问题,另外你的目标板是什么芯片。

方便的话,你的底层接口实现,截图我看下
回复

使用道具 举报

0

主题

8

回帖

8

积分

新手上路

积分
8
发表于 2025-5-28 16:30:17 | 显示全部楼层
eric2013 发表于 2025-5-28 10:29
这种情况的话,大概率是没有移植好,特别是底层读写函数的实现,你看下是否有问题,另外你的目标板是什么 ...

硬汉哥你好,用的是F303CBT6这个板子,堆空间已经设置了8k了,这个是CAN底层配置,波特率1000K,只开启了开启RX0中断



tim16设置的中断时间是1ms,只作为从机。H7tool作为主机发送数据都会卡住。

只要点发送就会卡住

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116230
QQ
 楼主| 发表于 2025-5-29 09:10:43 | 显示全部楼层
MingChao 发表于 2025-5-28 16:30
硬汉哥你好,用的是F303CBT6这个板子,堆空间已经设置了8k了,这个是CAN底层配置,波特率1000K,只开启了 ...

图片要单独上传下。另外工程文件方便的话分享到百度云,今天晚些时候我帮你看下
回复

使用道具 举报

0

主题

8

回帖

8

积分

新手上路

积分
8
发表于 2025-5-30 12:01:04 | 显示全部楼层
eric2013 发表于 2025-5-29 09:10
图片要单独上传下。另外工程文件方便的话分享到百度云,今天晚些时候我帮你看下

硬汉哥,解决了,是因为我移植的是CANopenNode官方的文件,有一处要修改的地方没有修改
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116230
QQ
 楼主| 发表于 7 天前 | 显示全部楼层
MingChao 发表于 2025-5-30 12:01
硬汉哥,解决了,是因为我移植的是CANopenNode官方的文件,有一处要修改的地方没有修改

回复

使用道具 举报

0

主题

1

回帖

1

积分

新手上路

积分
1
发表于 5 天前 | 显示全部楼层
硬汉哥,最近我在移植canopennode到windows做为主站使用,驱动这块遇到一些问题,可以咨询下细节吗?我看在linux和单片机,can接收都是回调或者信号,方便留下联系方式吗?我没权限私信
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116230
QQ
 楼主| 发表于 4 天前 | 显示全部楼层
zhangzheng 发表于 2025-6-5 14:58
硬汉哥,最近我在移植canopennode到windows做为主站使用,驱动这块遇到一些问题,可以咨询下细节吗?我看在 ...

我头像下面有QQ
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-6-10 20:05 , Processed in 0.612283 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表