大家好!我是大聪明-PLUS!
我想和大家分享一些我们在日常工作中总结的最佳实践。
如果谈到工业自动化,我们就会明白编程将与 IEC 61131-3 标准的语言相关联。
我找到了一台运行Ubuntu 12的Icp-Das LP-8x21控制器,还有几块来自KontrAvt的MDS DIO-16BD和AIO-4 I/O模块,可以用来测试。现在我有东西可以做实验了。

测试版本
为了连接控制器和 I/O 模块,我们将使用最常用的物理通信标准之一------RS-485。这些模块使用 Modbus 协议。
要为该控制器创建可执行文件,您需要为其处理器安装编译器:
sudo` apt install gcc-arm-linux-gnueabihf g`++-arm-linux-gnueabihf
安装构建文件和源代码libmodbus-dev:
sudo` apt install libmodbus-dev
apt `source` libmodbus-dev`
我们进入已创建的包含源代码的文件夹,并为以下编译器编译库arm-linux-gnueabihf:
`./autogen.sh
./configure `--host=`arm-linux-gnueabihf `--enable-shared` `--enable-static`
`make
文件夹中./src/.libs/ 包含了所有已编译好的库,可以添加到你的项目中。我们需要用到这些库libmodbus.a。
从 I/O 模块文档中,我们可以找到需要读取的寄存器。对于 DIO-16BD,输入寄存器是 258;对于 AIO-4,我们需要从地址 207 读取四个模拟输入。由于有四个浮点值,我们需要同时读取八个寄存器。为了测试这一点,我们来构建一个简单的 C++ 项目:
文件main.cpp:
#include <modbus/modbus.h>`
`#include <iostream>`
`#include <errno.h>`
`#include "util.h"`
`using` `namespace` `std`;
`bool` `_stop=false`;
`void` `handle_signal`(`int` `i`) {
`printf`(`"[MAIN] Terminating\n"`);
`_stop=true`;
}
`int` `main`() {
`signal`(`SIGINT`, `handle_signal`);
`signal`(`SIGTERM`, `handle_signal`);
`cout<<"Start..."<<endl`;
`uint16_t` `buffer`[`8`];
`modbus_t` `*ctx=modbus_new_rtu`(`"/dev/ttyS2"`,`115200`,`'N'`,`8`,`1`);
`if` (`modbus_connect`(`ctx`) `==` `-1`)
`cout<<"Connection failed: "<<modbus_strerror`(`errno`)`<<endl`;
`modbus_set_response_timeout`(`ctx`, `1`,`0`);
`while`(`!_stop`) {
`modbus_set_slave`(`ctx`,`1`);
`int` `rc=modbus_read_registers`(`ctx`,`258`,`1`,`buffer`);
`if` (`rc` `==` `-1`)
`cout<<"#1 MDS_DIO_16BD::Read() "<<modbus_strerror`(`errno`)`<<endl`;
`else`
`cout<<"#1 "<<buffer`[`0`]`<<endl`;
`modbus_set_slave`(`ctx`,`2`);
`nsleep`(`10`);
`rc=modbus_read_registers`(`ctx`,`258`,`1`,`buffer`);
`if` (`rc` `==` `-1`)
`cout<<"#2 MDS_DIO_16BD::Read() "<<modbus_strerror`(`errno`)`<<endl`;
`else`
`cout<<"#2 "<<buffer`[`0`]`<<endl`;
`modbus_set_slave`(`ctx`,`3`);
`nsleep`(`10`);
`rc` `=` `modbus_read_input_registers`(`ctx`, `207`, `8`, `buffer`);
`if` (`rc` `==` `-1`)
`cout<<"#3 MDS_AIO_4::Read() "<<modbus_strerror`(`errno`)`<<endl`;
`else`
`cout<<"#3 "<<modbus_get_float_badc`(`buffer`)`<<" "<<modbus_get_float_badc`(`buffer+2`)`<<" "<<modbus_get_float_badc`(`buffer+4`)`<<" "<<modbus_get_float_badc`(`buffer+6`)`<<endl`;
`nsleep`(`10`);
}
`modbus_close`(`ctx`);
`modbus_free`(`ctx`);
`cout<<"Stop..."<<endl`;
}`
文件util.cpp:
int` `nsleep`(`long` `miliseconds`) {
`struct` `timespec` `req`, `rem`;
`if`(`miliseconds` `>` `999`) {
`req`.`tv_sec` `=` (`int`)(`miliseconds` `/` `1000`);
`req`.`tv_nsec` `=` (`miliseconds` `-` ((`long`)`req`.`tv_sec` `*` `1000`)) `*` `1000000`;
}
`else` {
`req`.`tv_sec` `=` `0`;
`req`.`tv_nsec` `=` `miliseconds` `*` `1000000`;
}
`return` `nanosleep`(`&req` , `&rem`);
}`
我们使用以下命令编译并发送可执行文件:
`arm-linux-gnueabihf-g`++` `-std=`c`++11` `-I` ./libmodbus `-L`. `-o` ./main ./*.cpp `-lmodbus`
sshpass `-p` `"icpdas"` scp main root@192.168.0.2:/root/`
所有部件组装完毕后会发送到PLC。如果组装和配置都正确,终端会显示以下结果:
#1 0`
`#2 0`
`#3 4.000000 4.000001 3.999998 4.000000
一切运行正常,循环显示了所需的数据。因此,我们已经学会了如何从"字段"中检索数据。
如果我们根据这些时间节点来观察 PLC 处理器的负载情况,就会发现情况相当糟糕:三个模块就占用了控制器 10% 的负载。在生产条件下,这是一个非常非常高的负载,因为目前有些项目有十几条生产线,每条生产线都有 7-10 个模块。
我们来看一下系统启动数据。运行以下命令top:
`top - 10:47:15 up 5:28, 2 users, load average: 1.00, 1.01, 1.03
Tasks: 108 total, 1 running, 107 sleeping, 0 stopped, 0 zombie
Cpu(s): 1.3%us, 14.4%sy, 0.0%ni, 84.0%id, 0.0%wa, 0.0%hi, 0.3%si, 0.0%st
Mem: 506968k total, 95152k used, 411816k free, 0k buffers
Swap: 0k total, 0k used, 0k free, 41316k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2079 root 20 0 2660 1004 860 S 9.5 0.2 0:09.09 main...`
为了降低系统负载,您可以增加轮询所有 I/O 模块后的延迟。将延迟设置为 300 毫秒,可将此任务的 CPU 负载降低至 1.6%。
如何改进和规范大量不同设备的使用?我们需要采用建造者模式。让我们创建一个 Modbus 设备的基类:
文件ModbusModule.h:
class` `ModbusModule`
{
`public`:
`ModbusModule`(`modbus_t` `*ctx`, `int` `addr`);
`virtual` `~ModbusModule`();
`virtual` `void` `Read`() {};
`virtual` `void` `Write`() {};
`bool` `isError=true`,`isChanged=true`;
`int` `error=0`;
`protected`:
`bool` `oldIsError=false`;
`int` `rc`,`olderror`;
`protected`:
`void` `Set`();
`modbus_t` `*ctx`;
`int` `address`;
};`
文件ModbusModule.cpp:
ModbusModule::ModbusModule`(`modbus_t` `*ctx`, `int` `addr`) :
`ctx`{`ctx`},`address`{`addr`} { }
`ModbusModule::~ModbusModule`() { }
`void` `ModbusModule::Set`() {
`modbus_flush`(`ctx`);
`modbus_set_slave`(`ctx`,`address`);
`nsleep`(`5`);
}`
现在我们以MDS DIO-16BD为例来描述一下这个设备本身。其原理是将需要从中获取值或向设备写入数据的变量地址传递给它。其他线程随后就可以访问这些变量了。
文件MDS-DIO-16BD.h:
class` `MDS_DIO_16BD` : `public` `ModbusModule`
{
`public`:
`MDS_DIO_16BD`(`modbus_t` `*ctx`, `int` `addr`,
`volatile` `bool` `*rB1=NULL`,`volatile` `bool` `*rB2=NULL`,`volatile` `bool` `*rB3=NULL`,`volatile` `bool` `*rB4=NULL`,
`volatile` `bool` `*rB5=NULL`,`volatile` `bool` `*rB6=NULL`,`volatile` `bool` `*rB7=NULL`,`volatile` `bool` `*rB8=NULL`,
`volatile` `bool` `*rB9=NULL`,`volatile` `bool` `*rB10=NULL`,`volatile` `bool` `*rB11=NULL`,`volatile` `bool` `*rB12=NULL`,
`volatile` `bool` `*rB13=NULL`,`volatile` `bool` `*rB14=NULL`,`volatile` `bool` `*rB15=NULL`,`volatile` `bool` `*rB16=NULL`,
`volatile` `bool` `*wB1=NULL`,`volatile` `bool` `*wB2=NULL`,`volatile` `bool` `*wB3=NULL`,`volatile` `bool` `*wB4=NULL`,
`volatile` `bool` `*wB5=NULL`,`volatile` `bool` `*wB6=NULL`,`volatile` `bool` `*wB7=NULL`,`volatile` `bool` `*wB8=NULL`,
`volatile` `bool` `*wB9=NULL`,`volatile` `bool` `*wB10=NULL`,`volatile` `bool` `*wB11=NULL`,`volatile` `bool` `*wB12=NULL`,
`volatile` `bool` `*wB13=NULL`,`volatile` `bool` `*wB14=NULL`,`volatile` `bool` `*wB15=NULL`,`volatile` `bool` `*wB16=NULL`,
`volatile` `uint16_t` `*rC1=NULL`,`volatile` `uint16_t` `*rC2=NULL`,`volatile` `uint16_t` `*rC3=NULL`,`volatile` `uint16_t` `*rC4=NULL`,
`volatile` `bool` `*wReset1=NULL`,`volatile` `bool` `*wReset2=NULL`,`volatile` `bool` `*wReset3=NULL`,`volatile` `bool` `*wReset4=NULL`);
`~MDS_DIO_16BD`() `override`;
`void` `Write`() `override`;
`void` `Read`() `override`;
`void` `setRev`(`int` `index`);
`private`:
`uint16_t` `*buffer`;
`volatile` `bool` `*rB1`,`*rB2`,`*rB3`,`*rB4`,`*rB5`,`*rB6`,`*rB7`,`*rB8`,`*rB9`,`*rB10`,`*rB11`,`*rB12`,`*rB13`,`*rB14`,`*rB15`,`*rB16`,`*wB1`,`*wB2`,`*wB3`,`*wB4`,`*wB5`,`*wB6`,`*wB7`,`*wB8`,`*wB9`,`*wB10`,`*wB11`,`*wB12`,`*wB13`,`*wB14`,`*wB15`,`*wB16`;
`volatile` `uint16_t` `*rC1`,`*rC2`,`*rC3`,`*rC4`;
`volatile` `bool` `*wReset1`,`*wReset2`,`*wReset3`,`*wReset4`;
`bool` `rev`[`16`];
};`
文件MDS-DIO-16BD.cpp:
MDS_DIO_16BD::MDS_DIO_16BD`(`modbus_t` `*ctx`, `int` `addr`,
`volatile` `bool` `*rB1`,`volatile` `bool` `*rB2`,`volatile` `bool` `*rB3`,`volatile` `bool` `*rB4`,
`volatile` `bool` `*rB5`,`volatile` `bool` `*rB6`,`volatile` `bool` `*rB7`,`volatile` `bool` `*rB8`,
`volatile` `bool` `*rB9`,`volatile` `bool` `*rB10`,`volatile` `bool` `*rB11`,`volatile` `bool` `*rB12`,
`volatile` `bool` `*rB13`,`volatile` `bool` `*rB14`,`volatile` `bool` `*rB15`,`volatile` `bool` `*rB16`,
`volatile` `bool` `*wB1`,`volatile` `bool` `*wB2`,`volatile` `bool` `*wB3`,`volatile` `bool` `*wB4`,
`volatile` `bool` `*wB5`,`volatile` `bool` `*wB6`,`volatile` `bool` `*wB7`,`volatile` `bool` `*wB8`,
`volatile` `bool` `*wB9`,`volatile` `bool` `*wB10`,`volatile` `bool` `*wB11`,`volatile` `bool` `*wB12`,
`volatile` `bool` `*wB13`,`volatile` `bool` `*wB14`,`volatile` `bool` `*wB15`,`volatile` `bool` `*wB16`,
`volatile` `uint16_t` `*rC1`,`volatile` `uint16_t` `*rC2`,`volatile` `uint16_t` `*rC3`,`volatile` `uint16_t` `*rC4`,
`volatile` `bool` `*wReset1`,`volatile` `bool` `*wReset2`,`volatile` `bool` `*wReset3`,`volatile` `bool` `*wReset4`)
: `rB1`{`rB1`},`rB2`{`rB2`},`rB3`{`rB3`},`rB4`{`rB4`},`rB5`{`rB5`},`rB6`{`rB6`},`rB7`{`rB7`},`rB8`{`rB8`},
`rB9`{`rB9`},`rB10`{`rB10`},`rB11`{`rB11`},`rB12`{`rB12`},`rB13`{`rB13`},`rB14`{`rB14`},`rB15`{`rB15`},`rB16`{`rB16`},
`wB1`{`wB1`},`wB2`{`wB2`},`wB3`{`wB3`},`wB4`{`wB4`},`wB5`{`wB5`},`wB6`{`wB6`},`wB7`{`wB7`},`wB8`{`wB8`},
`wB9`{`wB9`},`wB10`{`wB10`},`wB11`{`wB11`},`wB12`{`wB12`},`wB13`{`wB13`},`wB14`{`wB14`},`wB15`{`wB15`},`wB16`{`wB16`},
`rC1`{`rC1`},`rC2`{`rC2`},`rC3`{`rC3`},`rC4`{`rC4`},
`wReset1`{`wReset1`},`wReset2`{`wReset2`},`wReset3`{`wReset3`},`wReset4`{`wReset4`},`ModbusModule`(`ctx`,`addr`) {
`buffer` `=` `new` `uint16_t`[`16`];
`memset`(`buffer`, `0`, `16` `*` `sizeof`(`uint16_t`));
`for`(`int` `i=0`;`i<16`;`i++`) `rev`[`i`]`=false`;
}
`MDS_DIO_16BD::~MDS_DIO_16BD`() {
`delete`[] `buffer`;
}
`void` `MDS_DIO_16BD::Write`() {
`uint16_t` `temp=0`;
`if`(`wB1!=NULL||wB2!=NULL||wB3!=NULL||wB4!=NULL||wB5!=NULL||wB6!=NULL||wB7!=NULL||wB8!=NULL||`
`wB9!=NULL||wB10!=NULL||wB11!=NULL||wB12!=NULL||wB13!=NULL||wB14!=NULL||wB15!=NULL||wB16!=NULL`) {
`temp=`((`wB1==NULL`)`?0`:`rev`[`0`]`?!`(`*wB1<<0`):(`*wB1<<0`))`|`
((`wB2==NULL`)`?0`:`rev`[`1`]`?!`(`*wB2<<1`):(`*wB2<<1`))`|`
((`wB3==NULL`)`?0`:`rev`[`2`]`?!`(`*wB3<<2`):(`*wB3<<2`))`|`
((`wB4==NULL`)`?0`:`rev`[`3`]`?!`(`*wB4<<3`):(`*wB4<<3`))`|`
((`wB5==NULL`)`?0`:`rev`[`4`]`?!`(`*wB5<<4`):(`*wB5<<4`))`|`
((`wB6==NULL`)`?0`:`rev`[`5`]`?!`(`*wB6<<5`):(`*wB6<<5`))`|`
((`wB7==NULL`)`?0`:`rev`[`6`]`?!`(`*wB7<<6`):(`*wB7<<6`))`|`
((`wB8==NULL`)`?0`:`rev`[`7`]`?!`(`*wB8<<7`):(`*wB8<<7`))`|`
((`wB9==NULL`)`?0`:`rev`[`8`]`?!`(`*wB9<<8`):(`*wB9<<8`))`|`
((`wB10==NULL`)`?0`:`rev`[`9`]`?!`(`*wB10<<9`):(`*wB10<<9`))`|`
((`wB11==NULL`)`?0`:`rev`[`10`]`?!`(`*wB11<<10`):(`*wB11<<10`))`|`
((`wB12==NULL`)`?0`:`rev`[`11`]`?!`(`*wB12<<11`):(`*wB12<<11`))`|`
((`wB13==NULL`)`?0`:`rev`[`12`]`?!`(`*wB13<<12`):(`*wB13<<12`))`|`
((`wB14==NULL`)`?0`:`rev`[`13`]`?!`(`*wB14<<13`):(`*wB14<<13`))`|`
((`wB15==NULL`)`?0`:`rev`[`14`]`?!`(`*wB15<<14`):(`*wB15<<14`))`|`
((`wB16==NULL`)`?0`:`rev`[`15`]`?!`(`*wB16<<15`):(`*wB16<<15`));
`buffer`[`1`]`=temp`;
`Set`();
`rc` `=` `modbus_write_registers`(`ctx`, `267`, `1`, `buffer+1`);
`isError=`(`rc==-1`);
`if` (`rc` `==` `-1`)
`fprintf`(`stderr`, `"#%d MDS_DIO_16BD::Write(... %s\n"`, `address`, `modbus_strerror`(`errno`));
}
`if`(`wReset1!=NULL||wReset2!=NULL||wReset3!=NULL||wReset4!=NULL`) {
`temp=`((`wReset1==NULL`)`?0`:(`*wReset1<<0`))`|`
((`wReset2==NULL`)`?0`:(`*wReset2<<1`))`|`
((`wReset3==NULL`)`?0`:(`*wReset3<<2`))`|`
((`wReset4==NULL`)`?0`:(`*wReset4<<3`));
`rc` `=` `modbus_write_register`(`ctx`, `276`, `temp`);
`isError&=`(`rc==-1`);
`if` (`rc` `==` `-1`)
`fprintf`(`stderr`, `"#%d MDS_DIO_16BD::Write(... %s\n"`,`address`, `modbus_strerror`(`errno`));
}
}
`void` `MDS_DIO_16BD::Read`() {
`if`(`rB1!=NULL||rB2!=NULL||rB3!=NULL||rB4!=NULL||rB5!=NULL||rB6!=NULL||rB7!=NULL||rB8!=NULL||`
`rB9!=NULL||rB10!=NULL||rB11!=NULL||rB12!=NULL||rB13!=NULL||rB14!=NULL||rB15!=NULL||rB16!=NULL`) {
`Set`();
`rc` `=` `modbus_read_registers`(`ctx`, `258`, `1`, `buffer`);
`isError=`(`rc==-1`);
`if` (`rc` `==` `-1`)
`fprintf`(`stderr`, `"#%d MDS_DIO_16BD::Read() %s\n"`,`address`, `modbus_strerror`(`errno`));
`else` {
`if`(`rB1!=NULL`) `*rB1=`(`buffer`[`0`]`>>0`)`&1`;
`if`(`rB2!=NULL`) `*rB2=`(`buffer`[`0`]`>>1`)`&1`;
`if`(`rB3!=NULL`) `*rB3=`(`buffer`[`0`]`>>2`)`&1`;
`if`(`rB4!=NULL`) `*rB4=`(`buffer`[`0`]`>>3`)`&1`;
`if`(`rB5!=NULL`) `*rB5=`(`buffer`[`0`]`>>4`)`&1`;
`if`(`rB6!=NULL`) `*rB6=`(`buffer`[`0`]`>>5`)`&1`;
`if`(`rB7!=NULL`) `*rB7=`(`buffer`[`0`]`>>6`)`&1`;
`if`(`rB8!=NULL`) `*rB8=`(`buffer`[`0`]`>>7`)`&1`;
`if`(`rB9!=NULL`) `*rB9=`(`buffer`[`0`]`>>8`)`&1`;
`if`(`rB10!=NULL`) `*rB10=`(`buffer`[`0`]`>>9`)`&1`;
`if`(`rB11!=NULL`) `*rB11=`(`buffer`[`0`]`>>10`)`&1`;
`if`(`rB12!=NULL`) `*rB12=`(`buffer`[`0`]`>>11`)`&1`;
`if`(`rB13!=NULL`) `*rB13=`(`buffer`[`0`]`>>12`)`&1`;
`if`(`rB14!=NULL`) `*rB14=`(`buffer`[`0`]`>>13`)`&1`;
`if`(`rB15!=NULL`) `*rB15=`(`buffer`[`0`]`>>14`)`&1`;
`if`(`rB16!=NULL`) `*rB16=`(`buffer`[`0`]`>>15`)`&1`;
}
}
`if`(`rC1!=NULL||rC2!=NULL||rC3!=NULL||rC4!=NULL`) {
`rc` `=` `modbus_read_registers`(`ctx`, `278`, `4`, `buffer`);
`isError&=`(`rc==-1`);
`if` (`rc` `==` `-1`)
`fprintf`(`stderr`, `"#%d MDS_DIO_16BD::Read() %s\n"`,`address`, `modbus_strerror`(`errno`));
`else` {
`if`(`rC1!=NULL`) `*rC1=buffer`[`0`];
`if`(`rC2!=NULL`) `*rC2=buffer`[`1`];
`if`(`rC3!=NULL`) `*rC3=buffer`[`2`];
`if`(`rC4!=NULL`) `*rC4=buffer`[`3`];
}
}
}
`void` `MDS_DIO_16BD::setRev`(`int` `index`) {
`if`(`index<0` `||` `index>15`) `return`;
`rev`[`index`]`=!rev`[`index`];
}`
我们将使用生成模式来创建用于轮询单个 RS-485 总线上的设备的类。
文件ModbusLine.h:
class` `ModbusLine` {
`public`:
`ModbusLine`(`modbus_t` `*ctx`, `long` `sleepTime=300`);
`~ModbusLine`();
`MDS_DIO_16BD*` `addMDS_DIO_16BD`(`int` `address`,
`volatile` `bool` `*rB1=NULL`,`volatile` `bool` `*rB2=NULL`,`volatile` `bool` `*rB3=NULL`,`volatile` `bool` `*rB4=NULL`,
`volatile` `bool` `*rB5=NULL`,`volatile` `bool` `*rB6=NULL`,`volatile` `bool` `*rB7=NULL`,`volatile` `bool` `*rB8=NULL`,
`volatile` `bool` `*rB9=NULL`,`volatile` `bool` `*rB10=NULL`,`volatile` `bool` `*rB11=NULL`,`volatile` `bool` `*rB12=NULL`,
`volatile` `bool` `*rB13=NULL`,`volatile` `bool` `*rB14=NULL`,`volatile` `bool` `*rB15=NULL`,`volatile` `bool` `*rB16=NULL`,
`volatile` `bool` `*wB1=NULL`,`volatile` `bool` `*wB2=NULL`,`volatile` `bool` `*wB3=NULL`,`volatile` `bool` `*wB4=NULL`,
`volatile` `bool` `*wB5=NULL`,`volatile` `bool` `*wB6=NULL`,`volatile` `bool` `*wB7=NULL`,`volatile` `bool` `*wB8=NULL`,
`volatile` `bool` `*wB9=NULL`,`volatile` `bool` `*wB10=NULL`,`volatile` `bool` `*wB11=NULL`,`volatile` `bool` `*wB12=NULL`,
`volatile` `bool` `*wB13=NULL`,`volatile` `bool` `*wB14=NULL`,`volatile` `bool` `*wB15=NULL`,`volatile` `bool` `*wB16=NULL`,
`volatile` `uint16_t` `*rC1=NULL`,`volatile` `uint16_t` `*rC2=NULL`,`volatile` `uint16_t` `*rC3=NULL`,`volatile` `uint16_t` `*rC4=NULL`,
`volatile` `bool` `*wReset1=NULL`,`volatile` `bool` `*wReset2=NULL`,`volatile` `bool` `*wReset3=NULL`,`volatile` `bool` `*wReset4=NULL`);
`protected`:
`void` `Thread`();
`modbus_t` `*ctx`;
`long` `sleepTime`;
`std::thread` `_t`;
`bool` `_stop=false`;
`std::vector<ModbusModule*>` `devices`;
};
`
文件ModbusLine.cpp:
ModbusLine::ModbusLine`(`modbus_t` `*ctx`, `long` `sleepTime`) : `ctx`{`ctx`},`sleepTime`{`sleepTime`} {
`_t=std::thread`(`&ModbusLine::Thread`,`this`);
`printf`(`"ModbusLine create\n"`);
}
`ModbusLine::~ModbusLine`() {
`_stop=true`;
`_t`.`join`();
`for`(`auto&` `dev`:`devices`) `delete` `dev`;
`devices`.`clear`();
`modbus_close`(`ctx`);
`modbus_free`(`ctx`);
`printf`(`"ModbusLine delete\n"`);
}
`void` `ModbusLine::Thread`() {
`int` `isOpen=-1`;
`auto` `olderrno=errno`;
`while`(`!_stop`) {
`if` (`isOpen==-1`) {
`cout<<"Try open port..."<<endl`;
`if` ((`isOpen` `=` `modbus_connect`(`ctx`)) `==` `-1`) {
`if`(`errno!=olderrno`) {
`fprintf`(`stderr`, `"Connection failed: %s\n"`,`modbus_strerror`(`errno`));
}
}
`modbus_set_error_recovery`(`ctx`, (`modbus_error_recovery_mode`)`6`);
`modbus_set_response_timeout`(`ctx`, `0`,`500`);
`olderrno=errno`;
`nsleep`(`1000`);
`continue`;
}
`bool` `err=true`;
`for`(`auto&` `dev`:`devices`) {
`dev->Read`();
`if`(`dev->isError==false`) `err=false`;
`nsleep`(`10`);
`dev->Write`();
`if`(`dev->isError==false`) `err=false`;
`nsleep`(`10`);
}
`if`(`err`) {
`isOpen=-1`;
}
`nsleep`(`sleepTime`);
}
}
`MDS_DIO_16BD*` `ModbusLine::addMDS_DIO_16BD`(`int` `address`,
`volatile` `bool` `*rB1`,`volatile` `bool` `*rB2`,`volatile` `bool` `*rB3`,`volatile` `bool` `*rB4`,
`volatile` `bool` `*rB5`,`volatile` `bool` `*rB6`,`volatile` `bool` `*rB7`,`volatile` `bool` `*rB8`,
`volatile` `bool` `*rB9`,`volatile` `bool` `*rB10`,`volatile` `bool` `*rB11`,`volatile` `bool` `*rB12`,
`volatile` `bool` `*rB13`,`volatile` `bool` `*rB14`,`volatile` `bool` `*rB15`,`volatile` `bool` `*rB16`,
`volatile` `bool` `*wB1`,`volatile` `bool` `*wB2`,`volatile` `bool` `*wB3`,`volatile` `bool` `*wB4`,
`volatile` `bool` `*wB5`,`volatile` `bool` `*wB6`,`volatile` `bool` `*wB7`,`volatile` `bool` `*wB8`,
`volatile` `bool` `*wB9`,`volatile` `bool` `*wB10`,`volatile` `bool` `*wB11`,`volatile` `bool` `*wB12`,
`volatile` `bool` `*wB13`,`volatile` `bool` `*wB14`,`volatile` `bool` `*wB15`,`volatile` `bool` `*wB16`,
`volatile` `uint16_t` `*rC1`,`volatile` `uint16_t` `*rC2`,`volatile` `uint16_t` `*rC3`,`volatile` `uint16_t` `*rC4`,
`volatile` `bool` `*wReset1`,`volatile` `bool` `*wReset2`,`volatile` `bool` `*wReset3`,`volatile` `bool` `*wReset4`) {
`auto` `out` `=` `new` `MDS_DIO_16BD`(`ctx`,`address`,`rB1`,`rB2`,`rB3`,`rB4`,
`rB5`,`rB6`,`rB7`,`rB8`,`rB9`,`rB10`,`rB11`,`rB12`,`rB13`,`rB14`,`rB15`,`rB16`,
`wB1`,`wB2`,`wB3`,`wB4`,`wB5`,`wB6`,`wB7`,`wB8`,`wB9`,`wB10`,`wB11`,`wB12`,`wB13`,`wB14`,`wB15`,`wB16`,
`rC1`,`rC2`,`rC3`,`rC4`,`wReset1`,`wReset2`,`wReset3`,`wReset4`);
`devices`.`push_back`((`ModbusModule*`)`out`);
`return` `out`;
}`
RS-485总线的描述如下所示:
volatile` `bool` `b1=false`,`b2=false`,`b3=false`;
`ModbusLine` `line1`(`modbus_new_rtu`(`"/dev/ttyS2"`, `115200`, `'N'`, `8`, `1`));
`line1`.`addMDS_DIO_16BD`(`1`,`&b1`,`&b2`,`&b3`);`
我们将为每一行代码创建一个单独的线程,主应用程序不会依赖设备轮询。由于使用了 volatile 关键字,变量始终包含最新参数。volatile 关键字会告知编译器变量的值可以被外部更改,并且不会对其进行缓存。
下一篇文章,我们将探讨如何使用 MQTT 在 PLC 应用程序和 MNE 之间进行通信。