我们项目有一台电源,支持通过CANBus协议与外部通讯,我需要在程序里读取它的数据,并且对它进行控制。而程序最终是要部署到一台工控机上,但该工控机内存只有4G,内置了一个被厂家修改过的ubuntu20.04,在上面开发调试,又卡又不方便。我的计划是,先在我本机的虚拟机上开发,虚拟机装的也是ubuntu,ubuntu24.04,跑通了再移植到工控机。
这里面有一些步骤需要处理。尤其是对我这个以前很少接触硬件的程序员来说,有许多困难。首先第一步是要将电源与电脑连接;第二步是在虚拟机上写c++程序通过CANBus协议与电源通信;第三步是把电源改为与工控机连接;第四步把虚拟机的c++程序移植到工控机。
为什么会有这么多步骤呢,因为我的开发机只是普通的笔记本电脑,除了接显示器,基本只有USB口,如何跟电源相连是个问题,而工控机自带了许多端子,其中就有2个CAN口,可以直接自己找一些线与电源的引脚相连;其次是笔记本电脑的CPU架构是x86,而工控机是ARM,这个对使用的库有影响。
以下是详细介绍。
一、笔记本电脑上的虚拟机与电源相连
上面提到,我的笔记本电脑基本上只有USB口,它怎么跟电源连接呢?此前我对硬件几乎一片空白,厂家其实是代理商,他也一知半解,真正的厂家爱答不理。最后通过研读使用手册,搜索资料,特别是请教集团嵌入式开发大牛,才有了一点思路。最后是买了一个CAN转接USB口的这么一个东西连上了。
就两根线。
二、虚拟机上的程序
CAN转接USB口是个很成熟的产品了,提供了丰富翔实的资料,和供开发的库,所以开发起来并没有太多障碍。主要就是通过CAN转接USB口与电源通讯。在我们的程序中,CAN转接USB口称为Device(设备),它上面有两个CAN口,那么每个CAN口就有个编号(CANInd),第一个CANInd就是0,第二个就是1。程序运行的时候,首先要打开Device,然后初始化指定的CAN口,就可以给电源(实际上是给CAN转接USB口)发送指令,然后接收电源返回的数据了。
CANBus是很成熟的协议了,应用广泛,其指令有固定的格式。CAN转接USB口厂家做了一些封装,按照其格式填写,使用很方便。其实在工控机上采用比较原始的库写代码,也都差不多。摘录我在虚拟机上的部分源代码如下:
1、CAN转接USB口提供的库
1)数据结构
2)函数
调用顺序就是
VCI_OpenDevice
VCI_InitCAN
VCI_StartCAN
VCI_Transmit,发送指令
VCI_Receive,接收返回数据
三、工控机与电源相连
工控机跟普通电脑稍有点不一样,本身就提供了许多插口,我们买的是一种基本款,CAN口就有2个,RS485口4个,还有许多乱七八糟的口,可能是供自定义的。所以电源跟工控机直连就可以了。问题是,我接了线之后发现无法通讯。查阅资料说,H和L两个接口间需要接一个120欧姆的电阻,以防止形成通讯回路。
怪不得,之前在用CAN转接USB口的时候,一定要将电阻开关至少打开一个才行。
我也不知道电阻是啥,请教搞嵌入式开发的同事,他一听就懂。由于手头没有120欧的电阻,他就找了2个220欧姆的,并联接在H和L之间,说并联就是110欧,近似120欧,应该也可以。结果真的就是,接上电阻以后,马上就能收到返回数据了。我真是佩服得五体投地。
四、工控机上的程序
那工控机上的程序该怎么写呢?现有的程序依赖CAN转接USB口厂家提供的库,但工控机不能使用。首先是工控机并不需要接CAN转接USB口;其次工控机的CPU是ARM架构的,现有的这个库不行。
如果专门为工控机新写一套代码,简单粗暴,但不利于维护。我的思路是,尽量使用同一套代码,数据结构采用目前的,自己实现那几个与CAN操作相关的函数。在CMakeLists.txt上做区分,当系统运行在x86架构下,就用厂家的库;而在arm架构下,使用自己实现的函数。
1、自己实现CAN操作相关函数
2、CMakeLists.txt中根据情况是加载厂家库还是自己实现的库
3、效果
好处就是原有代码基本不需要更改,两边都能工作。唯一的小缺陷,就是为了迁就CAN转USB口厂家库,有些函数的参数有点勉强。比如
for 工控机的话,DeviceType没有意义,DeviceInd原先是指CAN转USB口设备,但在工控机这里,其实指的是socket。只能多加一点注释,解释一番。