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的移植在网上已经烂大街了,这里就不介绍了,咱们另辟**,选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的软硬件,到时候再与大家分享!~ |