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 occurs
    transmitMessage.tx_ft = (message->rtr == 0) ? CAN_FT_DATA : CAN_FT_REMOTE;
            
    // Transmit message
    transmit_mailbox = can_message_transmit(CAN0, &transmitMessage);
    
    // Waiting for transmit completed
    timeout = 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 careful
    Rx_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 = 240MHz
    timer_deinit(TIMER2);
                                            // CANopen requires a 10us timer, which is 100kHz
    initPara.prescaler  = 240 - 1;               // 240MHz -> 100kHz
    initPara.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 enable
    timer_flag_clear(TIMER2, TIMER_FLAG_UP);
    timer_interrupt_enable(TIMER2, TIMER_INT_UP);   // Enable count up interrupt
    
    nvic_irq_enable(TIMER2_IRQn, 1U, 1U);           // Enable and set timer interrupt priority
    timer_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 careful
    Rx_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.mfbz.cn/a/883998.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

无人便利店无人超市云值守收银系统源码

随着人力成本越来越高,很多门店越来想做无人值守模式,尤其是晚上休息时间等想让云值守客服来看店。自然要求收银系统需要可以在【有收银员值守】和【无收银员值守】两种模式灵活切换。 1. 有收银员值守模式 白天有收银员在店,收银员可以协助…

OJ在线评测系统 代码沙箱优化模版方法模式 使用与有规范的流程 并且执行流程可以复用

代码沙箱优化模版方法模式 上次我们代码沙箱的docker实现和原生实现 我们可以使用模版方法设计模式去优化我们的代码 我们原生的java实现代码沙箱和docker实现代码沙箱是有更多重复点的 比如说把文件 收集文件 进行校验 我们要用模版方法设计模式 定义一套通用的执行流程 让…

MySQL 之索引详解

想象一下,你正在图书馆寻找一本关于 MySQL 索引的书。图书馆里有成千上万本书,但没有目录。你只能一排一排、一本一本地找,直到找到你想要的书。这将会花费大量的时间!数据库索引就像图书馆的目录一样,可以帮助数据库系…

raylib实现生产者消费者模型增加缓冲提高帧率

原来增加了四叉树导致帧率下降 后来学了生产者消费者模型&#xff0c;尝试追加缓冲池&#xff0c;剥离主函数查找需要更新的数据 帧率上升稳定到60帧 多了10 帧 中间工程主要是探索数据结构体怎么安排 // 参考自 https://zhuanlan.zhihu.com/p/693482704 #include <stdio.…

Linux之我不会

一、常用命令 1.系统管理 1.1 systemctl start | stop | restart | status 服务名 案例实操 1 查看防火墙状态 systemctl status firewalld2 停止防火墙服务 systemctl stop firewalld3 启动防火墙服务 systemctl start firewalld4 重启防火墙服务 systemctl restart f…

Type-C接口相关知识:【总结大全】

Type-c现在非常通用了&#xff0c;所以了解Type-c也变得十分有必要了&#xff0c;还是秉承了解就要了解清楚的原则&#xff0c;我们深入的看看Type-c接口。 Type-c主要是取代上一代Micro usb接口&#xff0c;那么Type-c有什么优点呢&#xff1f; 正反可插&#xff0c;使用时不…

OpenHarmony(鸿蒙南向开发)——小型系统内核(LiteOS-A)【LMS调测】

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 基本概念 LMS全称为Lite Memory Sanitizer&#xff0c;是一种实时…

Xcode报错:The request was denied by service delegate (SBMainWorkspace)

Xcode报错&#xff1a;The request was denied by service delegate (SBMainWorkspace) 造成的原因: &#xff08;1&#xff09;新的M2芯片的Mac电脑 (2) 此电脑首次安装启动Xcode的应用程序 (3&#xff09;此电脑未安装Rosetta 解决方法: &#xff08;1&#xff09;打开终端…

传奇GEE引擎版本如何封挂?GEE引擎设置简单的封挂脚本教程

网关参数设置gee引擎封挂脚本 1、打开M2-选项-参数设置-游戏速度 把所有的设置限速关闭 2、打开M2-选项-客户端设置-内挂控制-速度控制&#xff1a;移动速度 攻击速度 魔法速度 设置好参数&#xff0c;一旦设置不要修改 否则封挂网关参数需重新设置 打开M2-选项-功能设置-…

计算机毕业设计 基于Flask+Vue的博客系统 Python毕业设计 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

二、kafka生产与消费全流程

一、使用java代码生产、消费消息 1、生产者 package com.allwe.client.simple;import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.clients.pr…

单通道串口服务器

型号&#xff1a; SG-TCP232-110 功能简介 SG-TCP232-110 是一款用来进行串口数据和网口数据转换的设备。解决普通串口设备在 Internet 上的联网问题。 设备的串口部分提供一个 232 接口和一个 485 接口&#xff0c;两个接口内部连接&#xff0c;同时只能使用一个口工作。 设备…

CVE-2024-46103

前言 CVE-2024-46103 SEMCMS的sql漏洞。 漏洞简介 SEMCMS v4.8中&#xff0c;SEMCMS_Images.php的search参数&#xff0c;以及SEMCMS_Products.php的search参数&#xff0c;存在sql注入漏洞。 &#xff08;这个之前就有两个sql的cve&#xff0c;这次属于是捡漏了&#x1f6…

Linux环境下安装python

Linux 环境下安装python 以下是在Linux环境下安装Python - 3.9.4.tgz的详细步骤&#xff1a;1. 下载Python - 3.9.4.tgz&#xff08;如果未下载&#xff09;2.解压文件3.安装依赖项&#xff08;如果需要&#xff09;4.配置和编译5.安装6.创建一个别名&#xff08;alias&#xf…

Sql Developer日期显示格式设置

默认时间格式显示 设置时间格式&#xff1a;工具->首选项->数据库->NLS->日期格式: DD-MON-RR 修改为: YYYY-MM-DD HH24:MI:SS 设置完格式显示&#xff1a;

JavaEE: 深入探索TCP网络编程的奇妙世界(四)

文章目录 TCP核心机制TCP核心机制四: 滑动窗口为啥要使用滑动窗口?滑动窗口介绍滑动窗口出现丢包咋办? TCP核心机制五: 流量控制 TCP核心机制 上一篇文章 JavaEE: 深入探索TCP网络编程的奇妙世界(三) 书接上文~ TCP核心机制四: 滑动窗口 为啥要使用滑动窗口? 之前我们讨…

计算机网络--HTTP协议

1.TCP,UDP的对比图 TCP:面向连接的,可靠的,字节流服务; UDP:无连接的,不可靠的,数据报服务; 2.补充网络部分的其他知识点 1).复位报文段 在某些特殊条件下&#xff0c; TCP 连接的一端会向另一端发送携带 RST 标志的报文段&#xff0c;即复位报文段&#xff0c;已通知对方…

大数据-146 Apache Kudu 安装运行 Dockerfile 模拟集群 启动测试

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

视觉分析在垃圾检测中的应用

随着城市化进程的加快&#xff0c;垃圾管理成为现代城市面临的重大挑战。有效的垃圾识别和分类不仅能提升环境保护的效率&#xff0c;还能减少资源浪费。基于视觉分析的垃圾识别算法应运而生&#xff0c;为解决这一问题提供了技术支持。 垃圾识别算法的技术实现主要依赖于深度学…

002、视频格式转换

下载地址 http://www.pcfreetime.com/formatfactory/CN/index.html