先说一下本人的基础,本人是一个小公司初来乍到的实习生,拿到这个任务的时候,不懂PLC,而对于linux只懂一点点皮毛的操作。结果硬是把程序移植完毕且能顺利运行。
该程序是嵌入式软PLC,主要代码是对四元式指令的解析。说白了就是移植一个软PLC的运行时。
拿到任务初期,首先是去了解了一下软PLC是什么,然后研读了一下公司工程师开发这个程序的设计文档、交互文档等。说实话,光看文档看了一周,看得云里雾里,不知道文档在说什么。
然后就是在网上疯狂搜索程序移植的文章,想汲取点前辈的经验,奈何没有多少前辈写过文章。
然后就是去了解了一下linux的开发,即应用开发和驱动开发。当然移植软PLC程序只涉及到了应用开发。
了解完了这些,就去找工程师要了代码,只需要移植,所以代码不需要自己写。
拿到代码时更是一脸懵,一头雾水,看代码看到要抓狂的程度。这个代码是针对于裸机开发的,所以里面涉及到了一些关于STM32的库的内容。
回忆一下从拿到代码,是怎么一步一步移植过来的叭。
一、了解程序框架
首先肯定要知道的就是每个文件都大体有什么功能,通篇看一下代码,从代码文件名入手,就能大致知道里面的代码是干什么的了,或者简单点,直接请教工程师,每个文件都是什么功能。然后确定哪些功能,哪些文件是我们需要移植的。比如说:原先有关于硬件操作的文件是不需要的,或者说是需要改的。
二、排除有关STM32的内容
由先前看文档、搜资料的基础知道,STM32的库在linux里是用不了的,我用了最粗暴的办法,将所需要的文件里有关于HAL库的头文件删除,然后看报错部分。想想看移植后的程序是否需要这个,需要这个的话,就用linux里可以用的函数替代。比如说:定时器、延时函数等。
三、进一步深入看看代码,理清楚代码逻辑
主要了解每个函数是干嘛的,一般也可以从函数名儿入手(前提是工程师函数命名规范,清晰易懂),然后理清函数执行的先后逻辑。
第二是从入口函数入手。一般来说,keil开发的程序,都有单独的main.c文件,这里面包含了移植用不到的函数,有两个办法,就是将不需要的函数删除,单独留下需要的函数写一个入口函数main。但由于我需要的函数不多,直接在主代码里添加了main函数。将函数的执行逻辑重新在里面实现。
三、初编译
上面的步骤完成了,就可以将代码放入linux里开始编译了。这个时候的编译的目的并不是获得可执行文件,而是找错误——编译后会有报错,都是一些不兼容的错误或者函数未定义啥的。接下来就是根据这些错误一步一步到代码里修改。这里还是需要一定的c语言基础的。当然,我就是小白一个。这里借助了GPT,每个问题都让它进行了辅助修改,简直事半功倍。
四、实现通讯模块
编译那一步,直到所有问题都被解决后,即能生成可执行文件了,有个问题便接踵而来——怎么验证程序移植成功。所以还得实现通讯模块来与上位机通讯。
这里简单介绍一下:上位机也是软PLC的一部分,即软PLC的开发系统。
我们公司开发的这套软PLC的开发系统与运行时通过UDP通讯。
硬件与上位机通讯是通过公司自己实现的udp协议。而移植到linux中用UDP的socket编程即可。确定好ip地址以及端口号就可以实现udp的收发。由于需要实时接收数据,所以我创建了两个线程,用于接收数据。为什么是来两个线程,因为需要监听两个端口号。
在这个过程中,我遇到了一个问题值得注意:没有注意linux端发送数据是的目的端口号,这个需要用同一个套接字发送数据,不能在创建一个套接字进程发送,不然会导致数据发送到其他端口号,从而上位机接收不到数据。
五、调试
通讯部份完成后,就开始调通上位机与下位机。调通不是大问题,就不赘述了。
回顾来看整个移植过程看似并不复杂,但是对于我这样一个对那方面都近乎小白的人来说,还是耗费了好多心力。
其实主要就是API的更换,数据类型的转换(因为我linux是64位的,源程序是针对32位的,所以有区别)、socket通讯的实现等内容。
总之,不管是拿到什么任务,都是发现问题与解决问题的过程。