CANopen开源库canfestival的移植

本文记录将CANopen开源库CANfestival移植到GD32F470单片机的过程。CANopen协议理解请参考博客:CANopen协议的理解-CSDN博客

CANfestival开源库下载链接

CSDN链接: https://download.csdn.net/download/heqiunong/89774627

官网链接:https://hg.beremiz.org/canfestival/file/de1fc3261f21

objdictedit字典工具下载链接

https://download.csdn.net/download/heqiunong/89774674

https://download.csdn.net/download/supcool/12492303

视频参考链接

1 canfestival移植_哔哩哔哩_bilibili

移植正文

上述各种链接都是些准备工作,主要有两个东西需要下载,一个是CANfestival库,一个是objdictedit对象字典工具。

1、CANfestival库文件预处理

下载好了CANfestval库后,里面有些文件是多余的,需要删除

1.1 src文件夹下的文件删除,src重命名为source

左边红色框住的部分删除掉

1.2 include文件夹下的文件删除,AVR文件夹重命为gd32

 

1.3 gd32文件夹(原AVR文件夹)下的文件删除

2、将CANfestival库放入工程文件当中

先把预处理的CANfestivel库拷贝到keil的工程文件夹当中,具体拷到哪里由自己定。

2.1 将所有源文件添加进入项目

 

2.2 添加include路径

3、处理编译的报错

3.1 注释config.h文件中的部分内容

3.2 缺函数的问题

完成3.1后,编译工程会缺函数

 

3.3 处理前两个缺函数的报错

start_and_seek_node 和 start_node这两个函数,是有的,只是因为inline关键字没有被识别,去掉inline就可以了。

全局搜索一下,找到位置。(这两个函数定义是在dcf.c文件中)

 

 删除这两个inline,现在就只缺下面3个函数了。

3.4 添加canSend函数以及CAN接收的处理

在添加canSend函数之前,我们需要对GD32F470的CAN进行外设层的配置,这部分配置完最好拿个USB-to-CAN的工具验证一下配置成功没有。 这部分工作可GD32F470提供的参考例程,本文的重点不在这里。

假设我们已经把CAN的外设部分都配置好了,下面来添加canSend函数。

#include "canfestival.h"// This function is called by CANopen library
uint8_t canSend(CAN_PORT notused, Message *message)
{uint8_t transmit_mailbox = 0;uint32_t timeout = 0xFFFF;transmitMessage.tx_dlen = message->len;memcpy(transmitMessage.tx_data, message->data, message->len);transmitMessage.tx_ff = CAN_FF_STANDARD;transmitMessage.tx_sfid = message->cob_id;// Check here if an accident occurstransmitMessage.tx_ft = (message->rtr == 0) ? CAN_FT_DATA : CAN_FT_REMOTE;// Transmit messagetransmit_mailbox = can_message_transmit(CAN0, &transmitMessage);// Waiting for transmit completedtimeout = 0xFFFF;while((CAN_TRANSMIT_OK != can_transmit_states(CAN0, transmit_mailbox)) && (0 != timeout)){timeout--;}return (timeout!=0) ? 0:1;
}

Message这个结构体是canfestival的库里面定义的,所以这里需要包含canfestival.h。我们需要做的是理解Message结构体里面的内容,然后把信息通过gd32的CAN对应的外设函数把Message发送出去。

★那么同样的道理,当CAN在接收外部发来的信息的时候,我们也要把接收到的信息,按照Message的格式,存到Message里面去。gd32的CAN接收是用中断来做的,下面给出代码参考一下。

void CAN0_RX0_IRQHandler(void)
{// For CANopen communication   Message Rx_Message;can_message_receive(CAN0, CAN_FIFO0, &receiveMessage);Rx_Message.cob_id = receiveMessage.rx_sfid;Rx_Message.rtr = (receiveMessage.rx_ft == CAN_FT_DATA) ? 0:1;  // be carefulRx_Message.len =receiveMessage.rx_dlen;memcpy(Rx_Message.data, receiveMessage.rx_data, receiveMessage.rx_dlen);// TODO we need objdictedit// canDispatch(&GD32Master_Data,&Rx_Message);}

 

注意函数最后一行的// canDispatch(&GD32Master_Data,&Rx_Message);是需要添加完对象字典后,需要解开注释的,

可以从上述函数分析,CAN接收中断函数把接收到的信息,存到了一个Message类型的结构体变量里面,最后调用canDispatch(&GD32Master_Data,&Rx_Message)函数,把接收到的信息和对象字典两个变量传进canfestival库进行处理。

那么搞完3.4这一步,就只剩下两个错误了。

 

3.5 添加getElapsedTime和setTimer函数

canfestival库的运行是需要一个定时器的,这个定时器需要由单片机给它提供,因此我们需要配置一个gd32的定时器给canfestival库。关于GD32的定时器配置内容,不是本文的重点,这里直接给出代码供参考。

static void CanOpenTimerConfig(void)
{timer_parameter_struct initPara;rcu_periph_clock_enable(RCU_TIMER2);    // Timer 0 1 3 4 7 has been used for other purposes // TIMER2_CLK = 240MHztimer_deinit(TIMER2);// CANopen requires a 10us timer, which is 100kHzinitPara.prescaler  = 240 - 1;               // 240MHz -> 100kHzinitPara.period     = TIMEVAL_MAX - 1;         initPara.alignedmode       = TIMER_COUNTER_EDGE;initPara.counterdirection  = TIMER_COUNTER_UP;initPara.clockdivision     = TIMER_CKDIV_DIV1;  initPara.repetitioncounter = 0;timer_init(TIMER2, &initPara);timer_auto_reload_shadow_enable(TIMER2);        // Auto-reload preload enabletimer_flag_clear(TIMER2, TIMER_FLAG_UP);timer_interrupt_enable(TIMER2, TIMER_INT_UP);   // Enable count up interruptnvic_irq_enable(TIMER2_IRQn, 1U, 1U);           // Enable and set timer interrupt prioritytimer_enable(TIMER2);
}// This function is called by CANopen library
void setTimer(TIMEVAL value)  
{  TIMER_CAR(TIMER2) =  value;  
}// This function is called by CANopen library
TIMEVAL getElapsedTime(void)  
{  return TIMER_CNT(TIMER2);  
}// TIMER2 is assigned as a CANopen timer 
void TIMER2_IRQHandler(void)  
{  if(SET == timer_interrupt_flag_get(TIMER2,TIMER_INT_UP)){  TimeDispatch();  timer_interrupt_flag_clear(TIMER2,TIMER_INT_UP);  }       
}

我们把定时器的计数频率配置成了1MHz。计数周期这里配置成TIMEVAL_MAX - 1;

注意:canfestival库里面默认的频率是125kHz,所以canfestival库里面timerscfg.h文件几个定义需要改改

 

注意:除了报错所要求我们添加的getElapsedTime和setTimer函数以外, 定时器的计数溢出中断里面,也调用了一个canfestival库里的函数TimeDispatch(); 而且canfestival库规定,计数中断周期是2ms。所以我们在配置定时器的时候才使用TIMEVAL_MAX-1来配置的。 如何理解#define TIMEVAL_MAX 2000的意思?定时器是1MHz,2000即表示2000*(1/1MHz)= 2000us = 2ms,这个细节需要去理解和注意的。

同理,比如我是100kHz(10us计数一次)定时器呢?那TIMEVAL_MAX这里就是 200了,200*(1/100kHz)= 2000us = 2ms。 一个计数值 = 10us, 下面这两个define应该这么改。

最需要注意的就是3.4和3.5,这里很容易出问题。  

4、添加对象字典

如果前面的操作都没有问题,那么这时候编译工程是不会报错的啦,但是这时候移植是没有完成的。 我们还需要添加单片机主节点的CANopen对象字典。 这时候就要用到前面我们提到的objdictedit字典啦。Objdictedit这个工具可以保存你的配置到一个xxxxx.od文件中,在开发的过程中,你可以每次只修改一部分。然后保存到.od文件中。下一次再改呢,又把这个.od文件再打开。 我们keil工程里面,需要的不是.od文件,而是利用.od文件生成的.c和.h文件。所以我们每次修改完.od文件保存之后,同时,我们还要利用objdictedit来生成一次.c和.h文件,把更新后的.c和.h文件替换keil工程里面原来的对象字典.c和.h文件。

下面我们以配置一个1ms的同步报文为例,来举例说明objdictedit的使用过程。

 

 

 把objdictedit生成的Master.c Master.h添加进入项目中。

 将Master.c代码最底部的对象字典变量名拷贝一下

 

下面把代码贴出了,方便copy 

// user_can.c...
#include "canfestival.h"extern CO_Data Master_Data;...
...
...void CAN0_RX0_IRQHandler(void)
{// For CANopen communication   Message Rx_Message;can_message_receive(CAN0, CAN_FIFO0, &receiveMessage);Rx_Message.cob_id = receiveMessage.rx_sfid;Rx_Message.rtr = (receiveMessage.rx_ft == CAN_FT_DATA) ? 0:1;  // be carefulRx_Message.len =receiveMessage.rx_dlen;memcpy(Rx_Message.data, receiveMessage.rx_data, receiveMessage.rx_dlen);// ★canDispatch(&Master_Data,&Rx_Message);}...

另外,在main主函数这边也需要做一个CANopen的基本的初始化操作。

// main.c...
#include "Master.h"
...void main()
{
...setNodeId(&Master_Data,0x00);setState(&Master_Data,Initialisation);setState(&Master_Data,Pre_operational);setState(&Master_Data,Operational);...
}

5、实验现象

温故而知新,写这篇文章的时候对3.4,3.5这部分内容理解又加深了。 CANfestival的移植相比于CANopen协议的理解还是要简单一些,后续应该会根据实际的项目,更新一些除了SYNC操作以外的其他操作,欢迎关注/阅订。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1540192.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

HTML常见语法设计

HTML常见语法设计 1.HTML类和ID类id 2.HTML 响应式 Web 设计3.HTML5 语义元素4.HTML 字符实体5.HTML 编码(字符集) 1.HTML类和ID 类 对 HTML 进行分类(设置类),使我们能够为元素的类定义 CSS 样式。为相同的类设置相…

耐高温滑环的应用场景及市场前景分析

耐高温滑环是一种重要的电气连接装置,广泛应用于需要传递电力和信号的旋转设备中。随着工业技术的发展,对耐高温滑环的需求不断增加,尤其是在极端温度环境下的应用场合,耐高温滑环展现出其独特的优势。 耐高温滑环在工业自动化领…

第157天: 安全开发-Python 自动化挖掘项目SRC 目标FOFA 资产Web 爬虫解析库

案例一:Python-WEB 爬虫库&数据解析库 这里开发的内容不做过多描述,贴上自己写的代码 爬取数据 要爬取p标签,利用Beautyfulsoup模块 import requests,time from bs4 import BeautifulSoup#url"https://src.sjtu.edu.cn/rank/firm…

双十一好物狂欢派对,五款剁手超值好物分享

在这个全民狂欢的购物节,我们迎来了一年一度的双十一盛典。双十一不仅是一场双十一好物狂欢派对,更是我们表达对生活品质追求的最佳时机。无论是智能家电、时尚潮品、还是日常必备,每一件好物都蕴含着对美好生活的无限向往。今年的双十一&…

内控合规管理

内控合规管理 1.内控合规概述2.信息科技风险管理概述组织架构与指责管理内容 3.监督检查4.制度管理5.业务连续性管理6.信息科技外包管理7.分支机构管理 1.内控合规概述 在具体实践中,IT内控合规管理的领域包括:信息科技风险管理、监督检查、制度和公文管…

Postman如何测试WebSocket接口!

01、WebSocket 简介 WebSocket是一种在单个TCP连接上进行全双工通信的协议。 WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直…

rpm方式安装Mysql报错依赖冲突解决

使用rpm安装mysql时在安装到client包时报错依赖库冲突以及GPG密钥问题, 解决 1,下载 MySQL 的 YUM 存储库文件。 wget https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm 2,安装下载的 YUM 存储库文件。 sudo rpm -…

Excel lookup函数使用方法及案例说明

大家好,这里是效率办公指南! 🔍 在Excel中,LOOKUP函数是一个强大的工具,用于查找和返回数据。无论是从一列中查找对应的值,还是在数据表中进行复杂的查找,LOOKUP函数都能帮助我们快速找到所需的…

VScode 修改 cursor 键盘设置

vscode 中按下 ctrl K 后 ctrl s 打开键盘快捷键设置。 搜索光标 cursor 找到 cursorDown 以及对应需要修改的快捷键命令 右键 添加快捷键设置 修改即可 alt space 关闭win设置中的中英文切换 代码提示下移 selectPrevSuggestion 上移

电脑usb控制软件有哪些?6款软件帮你轻松解决USB端口泄密烦恼!

在数字化时代,企业的信息安全成为重中之重。 然而,USB端口泄密事件频发,给企业的数据安全和业务连续性带来了巨大威胁。 此前,某大型制造企业,由于员工在日常工作中频繁使用U盘等USB存储设备,导致公司核心…

推荐五种msvcr71.dll丢失的解决方法,msvcr71.dll为什么会丢失?

当你的电脑提示msvcr71.dll丢失时是什么情况?为什么会出现这样的问题?msvcr71.dll丢失和什么有关呢?那么msvcr71.dll丢失应该如何解决呢?今天就和大家聊聊msvcr71.dll丢失的解决办法的详细解决步骤。 msvcr71.dll丢失是否与系统更…

在 Windows 上安装 Python

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storm…

Nexus3的妙用

nexus 3使用场景 Nexus是一个全能仓库,通过部署nexus可以实现包含yum、apt、Maven、pypi、docker等的多种仓库。以下是nexus的适用场景: 当公共仓库无法访问或缓慢时,搭建nexus。比如国内docker无法访问,需要镜像加速。可以使用海外主机部署nexus,在nexus中创建docker(p…

redis安装(以6.0.13为例)

redis-6.0.13安装 1.创建安装目录2. 上传安装包3. 替换repo文件4.依赖安装5. redis安装5.1 解压5.2 编译5.3 安装5.4 配置 6. 常用命令 1.创建安装目录 mkdir -p /apps/scripts/ cd /apps/scripts/2. 上传安装包 将redis-6.0.13.tar.gz 上传至/apps/scripts/目录下 下载链接…

在泰国旅游不会口语怎么办?求推荐翻译软件!!!

如果在泰国旅游时遇到语言障碍,可以采取以下措施:学习一些基础的泰语短语,使用翻译应用程序,携带翻译卡片,利用身体语言,参加有导游的旅行团,选择提供中文服务的酒店和旅行社,使用地…

xtop:multi_driven_net与incomplete_timing_cell fail reason 分析

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 xtop做时序收敛时报告fail reason&#x

【技术实操】银河麒麟操作系统安装Node.js运行环境及其进程管理

了解更多银河麒麟操作系统全新产品,请点击访问 麒麟软件产品专区:https://product.kylinos.cn 开发者专区:https://developer.kylinos.cn 文档中心:https://documentkylinos.cn 前言 Node.js作为一个开源、跨平台的JavaScrip…

智能BI项目第五期

本期主要内容 系统问题分析异步化业务流程分析线程池讲解(入门 原理 实战)系统异步化改造开发 1.系统问题分析 当系统面临大量用户请求时,我们后端的 AI 处理能力有限,例如服务器的内存、CPU、网络带宽等资源有限&#xff0c…

前端web端项目运行的时候没有ip访问地址

我们发现 没有netWork 的地址 导致 团队内其他同学无法打开我们的地址 进行访问 在page.json 中的运行 指令中 添加 --host 记得加上空格 这样我们就可以看到这个地址了 团队其他同学 就可以访问我们这个地址了

Nuxt Kit 中的模板处理

title: Nuxt Kit 中的模板处理 date: 2024/9/20 updated: 2024/9/20 author: cmdragon excerpt: 摘要:本文详细介绍了在Nuxt 3框架中,使用Nuxt Kit进行模板处理的方法,包括理解模板基本概念、使用addTemplate动态生成文件、应用addTypeTemplate注册类型模板以增强TypeScr…