赞
踩
官网地址:https://snap7.sourceforge.net/
这里我下载的 1.4.2/snap7-full-1.4.2.7z 。
这里我使用的是 x86 架构下的 Unbuntu 64 位系统,如果使用其他系统,请根据实际情况调整。
sudo make -f x86_64_linux.mk clean
sudo make -f x86_64_linux.mk all
sudo make -f x86_64_linux.mk install
此处需要在博图软件中,查询到PLC所配置的网络的地址,并将电脑配置到同一网段。此外还需要获知所需读写的PLC的机架号与槽号,连接时需要用到。
/* RemAddress: PLC IP 地址
* Rack: PLC 机架号
* slot: PLC 槽号
*/
int ConnectTo(const char *RemAddress, int Rack, int Slot);
// 示例
TS7Client *client_ = new TS7Client();
int result = 0;
if((result = client_->ConnectTo(PLC_IP, PLC_RACK_NUMBER, PLC_SLOT_NUMBER) != 0)) {
std::cerr << "Connect PLC Error ! err msg : "
<< CliErrorText(result).data() << std::endl;
}
/* DBNumber:DB 区编号
* Start:起始地址
* Size:读取的字节数,最少读取一个字节。
* *pUsrData 存储数据的变量指针。
*/
int DBRead(int DBNumber, int Start, int Size, void *pUsrData);
// 在读取完成后,需要手动进行位运算,其中低位为x.0。
bool value = false;
unsigned char data;
client_->DBRead(66, 0, 1, &data);
value = ((data >> 3) & 1);
/* DBNumber:DB 区编号
- Start:起始地址
- Size:写入的字节数,最少写入一个字节。
- *pUsrData 存储数据的变量指针。
*/
int DBWrite(int DBNumber, int Start, int Size, void *pUsrData)
// 在读取完成后,需要手动进行位运算,其中低位为x.0。
bool value = false;
unsigned char data;
data = value > 0 ? (data | (value << 3)) : (data & (~(value << 3)));
client_->DBWrite(66, 0, 1, &data);
此外,还有MBRead、MBWrite、EBRead、EBWrite等等,使用方法上除了无需传入DBNumber外相同。
相较于 DBRead 和 DBWrite 等函数接口,使用 ReadArea 和 WriteArea 的可操作行更高。从源码中看,实际上 DBRead 和 DBWrite 等函数接口也均是基于 ReadArea 和 WriteArea 进行封装的。
/** Area : 数据块类型,需根据snap7.h中定义的 Area ID 输入
- DBNumber:DB 区编号
- Start:起始地址
- Amount:需要读取的 WordLen 数量
- WordLen:pUsrData 中的字节长度,需要使用根据snap7.h中定义的 Word Length 输入。
- *pUsrData 存储数据的变量指针
**/
int WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData)
// 示例
unsigned char data[sizeof(float)];
float read_real = 0.0f ;
int result = 0;
if((result = client_->ReadArea(S7AreaDB, 66, 0x400, sizeof(float), S7WLByte, &data) != 0){
std::cerr << "Read PLC area fail, error code : " << CliErrorText(result).data() << std::endl;
}
// 数据端序转换 !!!
for (int i = 0; i < sizeof(float); i++) {
*((unsigned char*)read_real + i) = data[sizeof(float) - i - 1];
}
std::count << "Read real : " << read_real << std::endl;
unsigned char data[sizeof(float)];
float read_real = 666.66f ;
int result = 0;
for (int i = 0; i < sizeof(float); i++) {
data[sizeof(float) - 1 - i] = *((unsigned char*)read_real + i);
}
if((result = client_->WriteArea(S7AreaDB, 66, 0x400, sizeof(float), S7WLByte, &data) != 0){
std::cerr << "Read PLC area fail, error code : " << CliErrorText(result).data() << std::endl;
}
std::count << "Read real : " << read_real << std::endl;
注意:
1、当 WordLen 类型为 S7WLBit 时,Amount只能为 1 ,否则会抛出数据长度超出限制。
2、WordLen 输入 S7WLByte 实际上相当于我们常用的枚举,和当中的值无关。
3、 pUsrData中使用 “Byte” 类型读取时,所存储的数据端序为 “大端序” 。而我们PC通常所用 x86 架构的CPU为 “小端序” 存储;ARM 则默认为 “小端序”,但可配置端序 。C/C++编程的数据存储方式与机器所使用的CPU有关,所以我们需要自行转换端序。
这里为了方便读取一整个 Struct ,我使用的是一个 unsigned char 的数组,最后根据根据实际情况机型解析。
调试过程中,我在输入地址为十进制时,则会抛出一个 “errCliAddressOutOfRange” 的错误,填写十六进制地址时,则能够正常读写。目前未知具体原因。
Snap7库中还有很多其他的接口,需要之后慢慢去了解。
如有错误,请各位大佬斧正!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。