CANopen在LPC5500系列上的实现

CANopen在LPC5500系列上的实现

CANopen协议

相信广大电工们多少都使用过CAN总线吧? 博世的CAN总线可谓占据了工业现场控制/汽车电子等领域通讯的半壁江山。
CAN总线以其优异的仲裁设计,出色的传输性能以及强大的抗干扰性,正在逐步替代老旧的485/422工业现场总线,成为工业领域现场总线事实上的标准。不过呢,本文的重点不在CAN总线上,而是建立在CAN总线上的通讯协议:CANopen。
如果将CAN总线类比于以太网的话,那么CANopen就相当于TCP/IP协议,属于OSI7层网络模型中的网络层到应用层部分,但是CANopen毕竟是工业现场总线协议,远远没有TCP/IP那么复杂,所以大家不要有畏惧心理哦~
如果之前了解过CANopen协议,那么你大概率对周立功公司的一篇技术笔记《CANopen轻松入门》不陌生,他确实是入门CANopen协议的非常好的材料,里面介绍了几乎所有CANopen DS301核心协议的内容,在这里小编就不重复造轮子了。
如果还没有看过这篇技术笔记朋友们可以抓紧补习哦,这里提供资料下载地址:
https://www.zlg.cn/data/upload/software/Can/CANopen_easy_begin.pdf

CANopen协议栈选择

小编多年前曾经使用过CANopen协议,但只是简单的PTO、SDO通信,没有深究。写这篇文章之前小编又回网上找了不少关于CANopen协议的材料。
于我们搞MCU的人而言,绝大多数都需要在MCU端实现CANopen Node(CANopen 从机),而CANopen Master(主站)一般由PLC,工控机等来扮演。
小编在网上搜了2个比较著名的CANopen开源免费的协议栈,列举如下:
协议栈
许可证
特点
Canfestival
LGPLv2
纯C编写,网上移植例子多,主站从站都支持
CANopenNode
Apache2.0
Github上著名项目,纯C编写,代码紧凑,支持从站,网上移植例子比较少

Canfestival的移植在网上已经烂大街了,这里就不介绍了,咱们另辟**,选CANopenNode协议栈进行移植。

协议栈移植(CANopenNode)

1、下载代码:
首先去github网站上下载CANopenNode版本,选择1.3LTS版本, 下载地址: https://github.com/CANopenNode/CANopenNode/tags
<ignore_js_op>
注意不要用默认的Master分支上的代码,否则会造成编译错误。
2、CANopenNode源码结构:
CANopenNode的源码结构很紧凑,文件不多十来个,包含CANopen.h/c 和 /stack下的以CO开头的为协议栈源码,这些代码不需要修改,各个文件的作用在CANopenNode的README中有详细的描述。
<ignore_js_op>

除了不需要修改的协议栈源文件,还需要和MCU CAN接口对接的driver驱动文件,源码中提供了模板文件: drvTemplate和其他一些已经移植好的MCU的driver文件:
<ignore_js_op>
另外,源码中还提供了一个example,下面是example的代码结构: 其中CO_OD.c/h是一个实例数据字典,我们要用到。
<ignore_js_op>
3、将CANopenNode加入SDK源代码

小编以LPC55S16_SDK2.8.2中的mcan 例子为基础,将CANopenNode的源代码和Example下的CO_OD.c/h和 main.c加入到SDK,包含头文件路径,并编译。CANopenNode的源码编写很规范,与硬件依赖几乎没有,我这里是一次性编译通过。
<ignore_js_op>
4、修改CO_driver.c 适配SDK的MCAN接口

这一步是是最重要也是最难的:将SDK的MCAN接口和协议栈的驱动层对接。
首先大体介绍下CANopenNode的工作流程,如官方README给出的那样,CANopenNode需要3个线程来运行,分别为:
Mainline 线程: 主线程,负责处理大部分协议栈相关函数
Timer interval 线程: 定时中断线程,推荐1ms进入一次,负责处理和时间相关的任务
CAN receive thread: CAN接收线程,当接收到1个CAN帧时进入到这里并处理。
<ignore_js_op>
对于我们裸机移植,就一切从简:Mainline线程就放到while(1)中,CAN接收线程就放到SDK的CAN回调函数中,定时线程就放到一个1ms的定时中断中即可。这些全部在CO_Driver.c中实现。


首先实现最简单的CO_CANSend函数,他的作用一看既明,就是发送一帧CAN数据:小编直接调用SDK的MCAN_TransferSendNonBlocking函数来实现,只要把CAN数据结构转换下即可:
<ignore_js_op>
下面实现定时中断线程,用SysTick开一个1ms的定时中断,然后在定时中断中调用tmrTask_thread函数即可:


<ignore_js_op>
最后是CAN接收线程,因为SDK中提供了CAN的发送完成/接收完成回调函数,我们直接在接收完成回调函数中将接收到的CAN帧拿到并且喂给协议栈, 然后开启下一帧的接收:
<ignore_js_op>

结语

到此为止,一个最简单的CANopenNode裸机移植程序就搞定了。需要注意的是,如果想要进行简单的测试需要一个USB-CAN转换设备(某宝很多),最好是带CANopen主站协议的,这种设备我能找到的最便宜的也要700+RMB,确实不算太便宜,后面打算有机会自己做一个USB转CANopen的软硬件,到时候再与大家分享!~

posted on 2022-06-20 16:32  张凌001  阅读(380)  评论(0编辑  收藏  举报

导航