当前位置:网站首页>三菱PLC slmp(mc)协议
三菱PLC slmp(mc)协议
2022-07-07 21:49:00 【weixin_39926429】
//对于三菱PLC,可参考mx component5.0(详见以前的文章)通讯
//本文自写解析协议。
//本文在 c++ builder平台和FX5U调试成功
#ifndef _SlmpProtocolClient_
#define _SlmpProtocolClient_
#include <winsock2.h>
#include <stdlib.h>
#include <iostream>
#include <string>
// using System.Net.Socket;
class SlmpProtocolClient
{
public:
SlmpProtocolClient();
~SlmpProtocolClient();
public :
int Open() ;
int Close();
int ReadDRegister(short address, short len, unsigned short* short_array);
int ReadMBit(short adress, short len, unsigned short* short_array);
int WriteDRegister(short address, unsigned short short_value);
int WriteMBit(short address, unsigned short short_value);
void init2();
public :
bool Connected;
private:
WSADATA wsaData;
sockaddr_in sockAddr;
SOCKET sock;
std::string tipstr[20], tipstr2[20];
void GetHighLowByte(const short addrss, unsigned char& HByte, unsigned char& LByte);
};
#endif
#include "SlmpProtocolClient.h"
//#include <winsock2.h> //
SlmpProtocolClient::SlmpProtocolClient()
{
init2();
}
void SlmpProtocolClient::init2() {
tipstr[0] = "固定";
tipstr[1] = "----";
tipstr[2] = "----";
tipstr[3] = "----";
tipstr[4] = "----";
tipstr[5] = "----";
tipstr[6] = "固定";
tipstr[7] = "长度L";
tipstr[8] = "长度H";
tipstr[9] = " 结束代码L";
tipstr[10] = " 结束代码H";
tipstr[11] = " DXXXn-L";
tipstr[12] = " DXXXn-H";
tipstr[13] = " DXXXn+1-L";
tipstr[14] = " DXXXn+1-H";
tipstr[15] = " DXXXn+2-L";
tipstr[16] = " DXXXn+2-H";
tipstr2[0] = "固定";
tipstr2[1] = "----";
tipstr2[2] = "----";
tipstr2[3] = "----";
tipstr2[4] = "----";
tipstr2[5] = "----";
tipstr2[6] = "固定";
tipstr2[7] = "长度L";
tipstr2[8] = "长度H";
tipstr2[9] = " 结束代码L";
tipstr2[10] = " 结束代码H";
tipstr2[11] = " Mn | Mn + 1";
tipstr2[12] = " MXXX2n+2| MXXXn + 3";
tipstr2[13] = " MXXXn+4| MXXXn + 5";
}
SlmpProtocolClient::~SlmpProtocolClient()
{
Close();
}
int SlmpProtocolClient::Close()
{
closesocket(sock);
//终止使用 DLL
WSACleanup();
Connected=false;
return 0;
}
int SlmpProtocolClient::Open()
{
WSAStartup(MAKEWORD(2, 2), &wsaData);
//创建套接字
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
//向服务器发起请求
memset(&sockAddr, 0, sizeof(sockAddr)); //每个字节都用0填充
sockAddr.sin_family = PF_INET;
sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
//sockAddr.sin_addr.s_addr = inet_addr("192.168.10.150");
sockAddr.sin_port = htons(1234);
// sockAddr.sin_port = htons(4999);
int ret=connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
if (ret==0) {
Connected=true;
}
return ret;
}
int SlmpProtocolClient::ReadDRegister(short address,short len, unsigned short * short_array)
{
SYSTEMTIME sys, sy2;
int a = 0;
char* str = new char[30];
while (a <1)
{
/* GetLocalTime(&sys);
std::cout << sys.wSecond << ":" << sys.wMilliseconds << std::endl;*/
//50 00 00 FF FF 03 00 0C 00 10 00 01 04 00 00 64 00 00 A8 14 00
str[0] = 0x50;//本行开始的7行固定
str[1] = 0x00;
str[2] = 0x00;
str[3] = 0xFF;
str[4] = 0xFF;
str[5] = 0x03;
str[6] = 0x00;//本行及以上固定
str[7] = 0x0C;//长度L字节
str[8] = 0x00;//长度H字节
str[9] = 0x10;//监视定时器L
str[10] = 0x00;//监视定时器H
str[11] = 0x01;//CMD-批量读取-L
str[12] = 0x04;//CMD-批量读取-H
str[13] = 0x00;//子CMD-L
str[14] = 0x00;//子CMD-H
//str[15] = 0x64;//开始地址-L
//str[16] = 0x00;//开始地址-Middle
//str[15] = 0x40;//开始地址-L
//str[16] = 0x01;//开始地址-Middle
unsigned char hByte, lByte;
GetHighLowByte(address, hByte, lByte);
str[15] = lByte;//开始地址-L
str[16] = hByte;//开始地址-Middle
str[17] = 0x00;//开始地址-H
str[18] = 0xA8;//表示D点
unsigned char hByte2, lByte2;
//str[19] = 0x03;//读取长度-L
//str[20] = 0x00;//读取长度-H
GetHighLowByte(len, hByte2, lByte2);
str[19] = lByte2;//读取长度-L
str[20] = hByte2;//读取长度-H
send(sock, str, 21, NULL);//读取D寄存器的发送报文的长度=21字节
// Sleep(1);
//接收服务器传回的数据
char szBuffer[MAXBYTE] = { 0 };
int m;
m=recv(sock, szBuffer, MAXBYTE, NULL);
//输出接收到的数据
//printf("Message form server: %s\n", szBuffer);
//printf("Message form server:\n ");
/* for (size_t i = 0; i < 13; i++)
{
if ((unsigned char)szBuffer[i] < 16)
{
printf("0%x ", (unsigned char)szBuffer[i]);
}
else
{
printf("%x ", (unsigned char)szBuffer[i]);
}
std::cout << "--" << tipstr[i] << std::endl;
}*/
//读出的放在数组里,以下按数组的索引号从0开始说明含义
// szBuffer[0]:0xD0,--固定
// szBuffer[1]:0X00,--固定
// szBuffer[2]:0X00,--固定
// szBuffer[3]:0XFF,--固定
// szBuffer[4]:0XFF,--固定
// szBuffer[5]:0X03,--固定
// szBuffer[6]:0X00,--固定
// szBuffer[7]:响应数据长L字节,如读1个字:0x04,2字:0x06,三个字0x08,依次类推
// szBuffer[8]:响应数据长高字节
// --------从szBuffer[9]开始计算长度-----
// szBuffer[9]:0x00,--结束代码,如不为0则异常
// szBuffer[10]:0x00,--结束代码,如不为0则异常
// szBuffer[11]:Dn的L字节
// szBuffer[12]:Dn的H字节
// szBuffer[13]:Dn+1的L字节
// szBuffer[14]:Dn+1的H字节
// szBuffer[15]:Dn+2的L字节
// szBuffer[16]:Dn+2的H字节
// 接收完成后,第一步先看结束代码是否为0,如为0,进行下一步,否则丢弃数据了
// 第二步判断响应数据长是否等于2*字数+2,如相等,进行下一步
// 第三步从szBuffer[11]开始取几个字的数据,注意高低字节,如Dn=256*szBuffer[12]+szBuffer[11]
short end_code= 256 * (unsigned char)szBuffer[10] + (unsigned char)szBuffer[9];
if (end_code != 0)
{
return -1;
}
short response_len= 256 * (unsigned char)szBuffer[8] + (unsigned char)szBuffer[7];
if (response_len!=(len*2+2))
{
return -1;
}
for (size_t i = 0; i < len; i++)
{
*(short_array+i) = 256 * (unsigned char)szBuffer[12+i*2] + (unsigned char)szBuffer[11+i*2];
//std::cout << "读到的第"<<i+1<<"个字=" << *short_array << std::endl;
}
/*std::cout << "读到的第1个字=" << 256 * (unsigned char)szBuffer[12] + (unsigned char)szBuffer[11] << std::endl;
std::cout << "第2个字=" << 256 * (unsigned char)szBuffer[14] + (unsigned char)szBuffer[13] << std::endl;
std::cout << "第3个字=" << 256 * szBuffer[16] + szBuffer[15] << std::endl;*/
/*GetLocalTime(&sy2);
std::cout << std::endl;
std::cout << sy2.wSecond << ":" << sy2.wMilliseconds << std::endl;
std::cout << std::endl;*/
a++;
// Sleep(1);
}
delete[] str;
return 0;
}
int SlmpProtocolClient::WriteDRegister(short address, unsigned short short_value)
{
SYSTEMTIME sys, sy2;
int a = 0;
char* str = new char[30];
while (a < 1)
{
GetLocalTime(&sys);
std::cout << sys.wSecond << ":" << sys.wMilliseconds << std::endl;
//50 00 00 FF FF 03 00 0C 00 10 00 01 04 00 00 64 00 00 A8 14 00
str[0] = 0x50;//本行开始的7行固定
str[1] = 0x00;
str[2] = 0x00;
str[3] = 0xFF;
str[4] = 0xFF;
str[5] = 0x03;
str[6] = 0x00;//本行及以上固定
//str[7] = 0x12;//长度L字节--------写三个字0x12,写2个字,0x10,写一个字,0X0E
str[7] = 0x0E;//长度L字节--------写三个字0x12,写2个字,0x10,写一个字,0X0E
str[8] = 0x00;//长度H字节--------
str[9] = 0x10;//监视定时器L
str[10] = 0x00;//监视定时器H
str[11] = 0x01;//CMD-批量写-L
str[12] = 0x14;//CMD-批量写-H
str[13] = 0x00;//子CMD-L
str[14] = 0x00;//子CMD-H
//str[15] = 0x64;//开始地址-L-----变化
//str[16] = 0x00;//开始地址-Middle-----变化
unsigned char hByte, lByte;
GetHighLowByte(address, hByte, lByte);
str[15] = lByte;//开始地址-L
str[16] = hByte;//开始地址-Middle
str[17] = 0x00;//开始地址-H-----变化
str[18] = 0xA8;//表示D点
//str[19] = 0x03;//写入长度-L-------变化
str[19] = 0x01;//写入长度-L-------变化
str[20] = 0x00;//写入长度-H-------变化
//str[21] = 0x0C;//写入Dn-L-------变化
//str[22] = 0x00;//写入Dn-H-------变化
unsigned char hByte2, lByte2;
GetHighLowByte(short_value, hByte2, lByte2);
str[21] = lByte2;//读取长度-L
str[22] = hByte2;//读取长度-H
//str[23] = 0x0D;//写入Dn+1-L-------变化
//str[24] = 0x00;//写入Dn+1-H-------变化
//str[25] = 0x0E;//写入Dn+2-L-------变化
//str[26] = 0x00;//写入Dn+2-H-------变化
//"00 FF FF 03 00 0C 00 10 00 01 04 00 00 64 00 00 A8 01 00
//send(sock, str, strlen(str) + sizeof(char), NULL);
send(sock, str, 23, NULL);//-------------注意长度,写3个字:len=27,2个字:len=25,1个字:len=23
// Sleep(20);
//接收服务器传回的数据
char szBuffer[MAXBYTE] = { 0 };
recv(sock, szBuffer, MAXBYTE, NULL);
// PLC反馈: D0 00 00 FF FF 03 00 02 00 00 00 (00:14:55:188)
//输出接收到的数据
//printf("Message form server: %s\n", szBuffer);
if (0xD0 != (unsigned char)(szBuffer[0]) ) return 1;
if (0x02 != (unsigned char)szBuffer[7]) return 2;
if (0 != szBuffer[9]) return 3;
if (0 != szBuffer[10]) return 4;
/* GetLocalTime(&sy2);
std::cout << std::endl;
std::cout << sy2.wSecond << ":" << sy2.wMilliseconds << std::endl;
std::cout << std::endl;*/
a++;
Sleep(1);
}
delete[] str;
return 0;
}
int SlmpProtocolClient::ReadMBit(short address, short len, unsigned short* short_array)
{
SYSTEMTIME sys, sy2;
int a = 0;
char* str = new char[30];
unsigned short temp;
unsigned short q;
unsigned short m;
unsigned short n;
unsigned short k;
m = len % 16;
n = (m==0)? (len - m) / 16:(len - m) / 16+1;
while (a < 1)
{
// GetLocalTime(&sys);
//std::cout << sys.wSecond << ":" << sys.wMilliseconds << std::endl;
//50 00 00 FF FF 03 00 0C 00 10 00 01 04 00 00 64 00 00 A8 14 00
str[0] = 0x50;//本行开始的7行固定
str[1] = 0x00;
str[2] = 0x00;
str[3] = 0xFF;
str[4] = 0xFF;
str[5] = 0x03;
str[6] = 0x00;//本行及以上固定
str[7] = 0x0C;//长度L字节
str[8] = 0x00;//长度H字节
str[9] = 0x10;//监视定时器L
str[10] = 0x00;//监视定时器H
str[11] = 0x01;//CMD-批量读取-L
str[12] = 0x04;//CMD-批量读取-H
str[13] = 0x00;//子CMD-L
str[14] = 0x00;//子CMD-H
//str[15] = 0x64;//开始地址-L---变化
//str[16] = 0x00;//开始地址-Middle---变化
unsigned char hByte, lByte;
GetHighLowByte(address, hByte, lByte);
str[15] = lByte;//开始地址-L
str[16] = hByte;//开始地址-Middle
str[17] = 0x00;//开始地址-H---变化
str[18] = 0x90;//表示M点
unsigned char hByte2, lByte2;
//str[19] = 0x03;//读取长度-L
//str[20] = 0x00;//读取长度-H
GetHighLowByte(n, hByte2, lByte2);
str[19] = lByte2;//读取长度-L
str[20] = hByte2;//读取长度-H
send(sock, str, 21, NULL);// /读取M的发送报文的长度=21字节
// Sleep(20);
//接收服务器传回的数据
char szBuffer[MAXBYTE] = { 0 };
recv(sock, szBuffer, MAXBYTE, NULL);
//输出接收到的数据
//printf("Message form server: %s\n", szBuffer);
/* printf("Message form server:\n ");
for (int i = 0; i < 13; i++)
{
if ((unsigned char)szBuffer[i] < 16)
{
printf("0%x ", (unsigned char)szBuffer[i]);
}
else
{
printf("%x ", (unsigned char)szBuffer[i]);
}
std::cout << tipstr2[i] << std::endl;
}
GetLocalTime(&sy2);*/
//读出的放在数组里,以下按数组的索引号从0开始说明含义
// szBuffer[0]:0xD0,--固定
// szBuffer[1]:0X00,--固定
// szBuffer[2]:0X00,--固定
// szBuffer[3]:0XFF,--固定
// szBuffer[4]:0XFF,--固定
// szBuffer[5]:0X03,--固定
// szBuffer[6]:0X00,--固定
// szBuffer[7]:响应数据长L字节,如读<=16:0x04,2字:0x06,三个字0x08,依次类推
// szBuffer[8]:响应数据长高字节
// --------从szBuffer[9]开始计算长度-----
// szBuffer[9]:0x00,--结束代码,如不为0则异常
// szBuffer[10]:0x00,--结束代码,如不为0则异常
// szBuffer[11]:Mn~M(n+7)
// szBuffer[12]:M(n+8)~M(n+15)
// 接收完成后,第一步先看结束代码是否为0,如为0,进行下一步,否则丢弃数据了
// 第二步判断响应数据长是否等于2*字数,如相等,进行下一步
// 第三步从szBuffer[11]开始取几个字的数据,注意高低字节,
//如Mn= szBuffer[12]& 0x01,Mn(n+1)= szBuffer[12]& 0x02,M(n+15)= szBuffer[13]& 0x80,Mn(n+1)= szBuffer[12]& 0x02,
short end_code = 256 * (unsigned char)szBuffer[10] + (unsigned char)szBuffer[9];
if (end_code != 0)
{
return -1;
}
short response_len = 256 * (unsigned char)szBuffer[8] + (unsigned char)szBuffer[7];
if (response_len != (n * 2 + 2))
{
return -1;
}
k = 0;
unsigned u;
for (size_t i = 0; i <n; i++)
{
temp = 256 * (unsigned char)szBuffer[12 + i * 2] + (unsigned char)szBuffer[11 + i * 2];
u = temp;
for (size_t j = 0; j< 16; j++)
{
short_array[k] =( ((u & 1) == 0) ? 0 : 1);
u = u >> 1;
k++;
if (k>=len)
{
break;
}
}
}
/* unsigned short temp = 256 * (unsigned char)szBuffer[12] + (unsigned char)szBuffer[11];
bool b;
for (int i = 0; i < 16; i++)
{
b = (temp == 1) ? true : false;
std::cout << "第" << i + 1 << "位:" << b << std::endl;
temp = temp >> 1;
}*/
/* std::cout << std::endl;
std::cout << sy2.wSecond << ":" << sy2.wMilliseconds << std::endl;
std::cout << std::endl;*/
// delete[] str;
a++;
Sleep(1);
}
delete[] str;
return 0;
}
int SlmpProtocolClient::WriteMBit(short address, unsigned short short_value)
{
//SYSTEMTIME sys, sy2;
int a = 0;
char* str = new char[30];
while (a < 1)
{/*
GetLocalTime(&sys);
std::cout << sys.wSecond << ":" << sys.wMilliseconds << std::endl;*/
//50 00 00 FF FF 03 00 0C 00 10 00 01 04 00 00 64 00 00 A8 14 00
str[0] = 0x50;//本行开始的7行固定
str[1] = 0x00;
str[2] = 0x00;
str[3] = 0xFF;
str[4] = 0xFF;
str[5] = 0x03;
str[6] = 0x00;//本行及以上固定
str[7] = 0x0D;//长度L字节--------写三个字0x12,写2个字,0x10,写一个字,0X0E
str[8] = 0x00;//长度H字节--------
str[9] = 0x10;//监视定时器L
str[10] = 0x00;//监视定时器H
str[11] = 0x01;//CMD-批量写-L
str[12] = 0x14;//CMD-批量写-H
str[13] = 0x01;//子CMD-L
str[14] = 0x00;//子CMD-H
//str[15] = 0x64;//开始地址-L-----变化
//str[16] = 0x00;//开始地址-Middle-----变化
unsigned char hByte, lByte;
GetHighLowByte(address, hByte, lByte);
str[15] = lByte;//开始地址-L
str[16] = hByte;//开始地址-Middle
str[17] = 0x00;//开始地址-H-----变化
str[18] = 0x90;//表示M点
str[19] = 0x01;//写入长度-L-------变化
str[20] = 0x00;//写入长度-H-------变化
str[21] = ((short_value==0)?0x00:0x10);//写入Mn,M(n+1)-------变化
//str[22] = 0x00;//写入M(n+2),M(n+3)------变化
//"50 00 00 FF FF 03 00 0D 00 10 00 01 14 01 00 64 00 00 90 01 00 10
//send(sock, str, strlen(str) + sizeof(char), NULL);
send(sock, str, 22, NULL);//-------------注意长度,写3个字:len=27,2个字:len=25,1个字:len=23
// Sleep(20);
//接收服务器传回的数据
char szBuffer[MAXBYTE] = { 0 };
recv(sock, szBuffer, MAXBYTE, NULL);
//输出接收到的数据
//printf("Message form server: %s\n", szBuffer);
/* printf("Message form server:\n ");
for (size_t i = 0; i < 11; i++)
{
if ((unsigned char)szBuffer[i] < 16)
{
printf("0%x ", (unsigned char)szBuffer[i]);
}
else
{
printf("%x ", (unsigned char)szBuffer[i]);
}
std::cout << "--" << tipstr[i] << std::endl;
}
GetLocalTime(&sy2);
std::cout << std::endl;
std::cout << sy2.wSecond << ":" << sy2.wMilliseconds << std::endl;
std::cout << std::endl;*/
// PLC反馈: D0 00 00 FF FF 03 00 02 00 00 00 (00:14:55:188)
//输出接收到的数据
//printf("Message form server: %s\n", szBuffer);
if (0xD0 != (unsigned char)(szBuffer[0])) return 1;
if (0x02 != (unsigned char)szBuffer[7]) return 2;
if (0 != szBuffer[9]) return 3;
if (0 != szBuffer[10]) return 4;
a++;
Sleep(1);
}
delete[] str;
return 0;
}
void SlmpProtocolClient::GetHighLowByte(const short addrss, unsigned char & HByte, unsigned char & LByte)
{
LByte = addrss % 256;
HByte = (addrss - LByte) / 256;
}
边栏推荐
- Amesim2016 and matlab2017b joint simulation environment construction
- Quick sort (diagram +c code)
- Line test - graphic reasoning - 1 - Chinese character class
- Debezium series: introducing support for the final operator
- 【测试面试题】页面很卡的原因分析及解决方案
- Debezium系列之:源码阅读之BinlogReader
- Debezium系列之:支持 mysql8 的 set role 語句
- 今日创见|企业促进创新的5大关键要素
- Debezium series: support the use of variables in the Kill Command
- Two minutes, talk about some wrong understandings of MySQL index
猜你喜欢
IP network active evaluation system -- x-vision
开发那些事儿:Go加C.free释放内存,编译报错是什么原因?
Redis集群安装
微生物健康網,如何恢複微生物群落
行测-图形推理-3-对称图形类
Line test - graphic reasoning - 3 - symmetric graphic class
消息队列与快递柜之间妙不可言的关系
微生物健康网,如何恢复微生物群落
Two minutes, talk about some wrong understandings of MySQL index
Leetcode206. Reverse linked list
随机推荐
Pyqt GUI interface and logic separation
2022 words for yourself
Line test - graphic reasoning - 4 - alphabetic class
GBU1510-ASEMI电源专用15A整流桥GBU1510
苹果在iOS 16中通过'虚拟卡'安全功能进一步进军金融领域
Cause analysis and solution of too laggy page of [test interview questions]
PHP records the pitfalls encountered in the complete docking of Tencent cloud live broadcast and im live group chat
Debezium series: binlogreader for source code reading
Nx10.0 installation tutorial
安踏DTC | 安踏转型,构建不只有FILA的增长飞轮
Leetcode94. Middle order traversal of binary trees
「开源摘星计划」Loki实现Harbor日志的高效管理
Failed to initialize rosdep after installing ROS
QT graphicsview graphical view usage summary with flow chart development case prototype
Sword finger offer 63 Maximum profit of stock
行测-图形推理-7-相异图形类
How pyGame rotates pictures
Gbu1510-asemi power supply special 15A rectifier bridge gbu1510
Quick sort (diagram +c code)
How to judge whether the input content is "number"