type
status
date
slug
summary
tags
category
icon
password
CodeSYS中调用外部动态库
1.前言
如果我们需要在CodeSys的编程环境中使用我们自己的开发的功能,例如:与第三方的IO板卡通讯、采集数据并处理等等一些复杂的功能,那就可以使用CodeSys提供的Extension SDK功能,通过C语言动态库接口来实现。 值得注意的是:目前仿真模式无法使用C语言模块 。
2.环境准备
这里我运行codesys runtime的环境是一个X64 架构的开发板,设备安装的是 Debian 12,并编译运行了实时内核以及 gcc 等编译工具。具体样编译实时内核请参考我的另外一篇文章Ubuntu22.04编译安装实时内核,基本流程是一致的,这里就不再赘述。
2.1. 配置CodeSys Runtime Linux SL
打开 codesys ide,点击 工具-> CODESYS 安装程序

安装 CodeSys controller,根据你的设备平台架构选择,支持 X86 和 ARM 架构,我这里将 X86 和 ARM64 都安装了,然后等待安装完成。

当安装完成后,在你的 IDE 工具菜单栏下会多出一个Deploy Control SL的菜单项

点击Deploy Control SL,出现以下界面,在界面上输入相关信息,然后点击连接。注意:请提前在设备段开启 SSH 服务,并让设备和运行 CodeSys IDE 的机器处于同一个局域网段

image-20250910124432772
连接成功后,你将在设备信息中看到关于你的设备信息,其中重启按键可以重启你的设备。

image-20250910124744384
选择部署页,安装CODESYS Control for Linux SL和

image-20250910125218605

安装完成后,你将看到以下结果。

在操作页面,启动服务。

3.创建CodeSys库工程
CodeSys 中如果要调用一个外部库,需要创建一个CodeSys库工程对外部库进行封装。
3.1 配置库工程
- 打开 CodeSys IDE 点击文件->新建工程,创建 Library 工程

- 添加 C 实现库

- 选择 POU 实现 库接口

注意:**这里的 POU 的名称必须以“_cext”结尾**

修改 POU 属性,设置成外部实现

- 实现函数接口

- 点击菜单栏:工程->工程信息,添加和修改项目工程信息。 特别注意标题名称,建议和库的工程名称一致,这样当添加生成的 so 库的时候可以避免 so库的名称和标题名称不一致导致的报错情况。缺省名称会在我们使用这个库时用到,相当于库的命名空间,占位符也必须填写,否则使用库时导致无法添加库。缺省名称和占位符可以根据自己的喜好设定。

- 生成 C 库的框架文件


image-20250910144032941
将在输出目录中产生两个文件

image-20250910144334325
3.2. 编译动态库
编译动态库需要利用到 CodeSys 的 CODESYS Control SL Extension Package,这个包可以从 CodeSys 的安装目录中找到。
- 将 ExtensionSDK 拷贝到你的设备平台,例如我的是运行 Debian 12 的 X86 平台。

image-20250910144825042

image-20250910145008673
如果没有这个包,则通过 CodeSys IDE 点击 工具-> CODESYS 安装程序,搜索 Extension进行安装

image-20250910145305744
- 创建 C 动态库工程并编译工程
将生成的libDemoCLib.so 拷贝到 CodeSys IDE 所在的机器的库工程目录(其他目录也行)

image-20250910145934432
3.3. CodeSys库工程绑定C动态库
- 在 CodeSys 库工程的 C 实现库中添加 C 动态库

image-20250910150347342

- 保存工程,并编译成库

image-20250910150833666
在工程目录下会得到DemoCLib.compiled-library文件

image-20250910150911808
4. 使用CodeSys库
为了验证我们生成的 CodeSys 库,我们创建一个 CodeSys 工程。
- 新建 Project 工程

image-20250910164745242

按图中选择对应的设备和 PRG 的类型

- 导入生成的 CodeSys 库

image-20250910170221081
点击安装

选择生成的 CodeSys 库

image-20250910170330344
在杂项一栏中,会出现刚才添加的库

- 添加库到工程

image-20250910171017796

添加完后的结果如下:

image-20250910171233776
- 编写 PLC 代码,请注意这里代码中的 DemoCLib 就是我们当初设置的库的缺省名称,我在前文中有提到过。

image-20250910171345270
- 编译代码

image-20250910171439430
- 运行代码
连接设备

image-20250910171549774


image-20250910171751410
如果失败,可能是由于 CodeSys runtime 没有 license,每两个小时会自动停止。

image-20250910171921452
在设备端手动启动 codesyscontrol 服务,然后重新扫描设备

image-20250910172034659
连接成功后如下:

重新点击菜单栏:在线->登录,注意第一次登录,会要求你设置用户名和密码,填入你设置的用户名称和密码,登录设备。

下载程序

image-20250910172704430
程序下载成功后,你可以登录设备在下图的路径中发现我们编译的 so 库已经下载到了/var/opt/codesys/PlcLogic 中

image-20250910174257951
启动程序

image-20250910172750814
查看执行过程

image-20250910173129689
暂停程序

image-20250910173506471
通过菜单栏在线->冷复位后,可以重新执行程序,另外可以通过菜单栏在线->复位原点后重新下载程序。
5. 对C++类封装
CodeSys 默认只支持对外部 C 库进行封装成 CodeSys 的 Library,供其他工程使用。如果要封装 C++的类,比较好的做法是将 C++代码单独封装一个 so 库,然后用 C 库根据 CodeSys 的接口规范封装 C++代码中的接口函数,另外添加两个函数:Init 和 destroy,Init 函数中进行 C++类实例化,destroy 函数实现 C++类实例的销毁工作。
5.1 Function Block接口函数
参考上文中的步骤和方法,创建一个 CodeSys Library 工程,根据 C++类中的方法进行对应的FB 接口申明,注意要额外添加 Init 和 destory 的 FB 接口声明。

image-20250918164924844
5.2 编译So库
在设备端编译 so 库,例如 CppLibDemo 工程的代码结构如下:
修改makefile文件
编译程序
将生成的libcppfb.so 拷贝到设备的/usr/lib 目录,这样 PLC 代码调用libCppLibDemo.so 时,libCppLibDemo.so 能链接到对应的 C++库。
5.2 编译生成 CodeSys Library 库
将产生的libCppLibDemo.so 库,按前文的方式拷贝的CodeSys Library 所在的工程目录下,按前文介绍的步骤和方法,编译 CodeSys Library。
5.3 创建测试工程
按照前文介绍的方法,创建测试工程,调用生成的 CodeSys Library 库,进行测试。

image-20250918174113838
6. 对Python脚本封装
对 Python 脚本的封装原理上和前文的介绍是一致的,这里主要的区别是在 C 文件中,需要利用 Libpython3.x 库将 python 解析器封装在 C 代码中,这样可以通过 C 代码直接调用 python 脚本中的函数。注意的是:需要添加你的 python 脚本所在的目录到代码中,这样 C 代码执行的时候才能找到你的 python 脚本。其他方法和步骤,请参考前文,基本上和 C++库的封装一致。

image-20250918174404418
7. 调用外部库解析json文件
对 json 文件的解析,我们采用外部开源代码:https://github.com/nlohmann/json 通过 codesys 的 c 实现库来对 json 文件进行解析。
7.1 创建Library工程
- 按前文介绍的方法创建 CodeSys Library 工程,工程结构如下:

image-20251009093555820
- C 实现库的工程目录如下:
由于所依赖的 json 库是它是一个头文件库,只需要将头文件引入项目即可使用,其中 thirdpart/json 目录的内容对应于工程代码的include/nlohmann 目录内容。
- 修改 Makefile 文件
- 参考前文的方法编译生成libJsonLibDemo.so,拷贝到CodeSys Library工程目录并加入到Library工程中,最后生成其他CodeSys能调用的JsonLibDemo.compiled-library文件,此处不再赘述。
7.2. 创建测试工程
为了验证我们生成的库是否能正常创建和解析json文件,我们来创建一个测试工程来调用这个库文件。创建测试工程的方法参考前文。此工程与前面的测试工程不同之处是我们添加了一个可视化管理器来显示构建的Json文件内容和对其解析的结果。

image-20251009103206137
具体如何添加可视化管理器并创建UI展示内容,请参考:可视化输出 “codesys的printf()“第一个hello world工程
工程运行结果如下:

image-20251009104218218
工程运行视频:
8. 调用外部库解析xml文件
我们采用第三方库:tinyxml2来解析xml文件,基本流程和解析json文件一致,区别是tinyxml2是一个 so 库,而解析 json 的是一个头文件库。
8.1. 在PLC控制器上安装tinyxml2 库
8.2. 创建CodeSys Library工程
- 参考前文方法创建 CodeSys Library 工程,工程结构如下:

image-20251009112304649
- C 实现库的工程目录如下:
XmlLibDemo.c 文件内容如下:
- 修改 Makefile 文件
- 创建一个用于测试的xml文件:test.xml,内容如下:
- 参考前文的方法编译生成libXmlLibDemo.so,拷贝到CodeSys Library工程目录并加入到Library工程中,最后生成其他CodeSys能调用的XmlLibDemo.compiled-library文件,此处不再赘述。
8.3. 创建测试工程
为了验证我们生成的库是否能正常创建和解析xml文件,我们来创建一个测试工程来调用这个库文件。创建测试工程的方法参考前文。 注意:这里的xml文件路径是前文创建的/home/chenx/test.xml。

image-20251009113124712
运行结果:

9 . CodeSys Trace功能
Codesys IDE 环境的 Trace 功能支持 PLC 变量的跟踪检测。以下是通过两个 IO 模块来演示这个功能。
- 创建一个 Codesys 工程,添加 EtherCat Master,并登录设备,扫描从设备,将扫描到的两个 DO、DI 从设备复制到工程中。

image-20250924085926809

image-20250924090215036
- 编写相关代码,周期性的改表 DO 某个 pin 脚的电平,使其驱动 DI。观察 DO 和 DI 模块的 LED 行为。

image-20250924090533235
- 添加 Trace
- 下载执行 PLC 程序,然后在跟踪上右键选择下载跟踪,这时候你就可以看到两个方波,蓝色的是 DO 的输出,绿色的是 DI 接收到的输入,每次蓝色的变化后,绿色的紧随其后变化。

image-20250924090822739
添加需要监控的变量

image-20250924090937113

image-20250924085858115
10.结语
有了这个接口,我们对其他第三方库进行封装,然后提供对应的操作函数给接口,就可以实现PLC的复杂的功能。完美。