Professional Documents
Culture Documents
cn
Communication
Protocol
(1-1)
RS232C
Ethernet
2.1
Start
BitData BitParity BitStop Bit
Byte
z Bit
z Byte
www.plcworld.cn
1111001
(1-2)
Start - Stop
/
1
0
/
Byte
1
0 1
z Baud Rate
0 1
z ParityNoneOddEven
z Data Bits
5678
1 7 None
9600 bps ABC
ASCII Code(0) 8 8
7 ASCII 1
www.plcworld.cn
1 0
7 ASCII
2.2
SDLCHDLC
SYN
SYN
(1-3)
F
(1-4)
8
SYN16 0x16
SYN
www.plcworld.cn
20% HDLC
48 1000
48 / 1048 * 100% = 4.6%
Modbus
PLC
Modbus Plus
Modbus
Modbus
2.3 Ethernet
Ethernet Broadcast
Frame type
Data
CRC
46 - 1500
Frame type
TCPUDP . CRC
CRC Frame CRC
API
TCP/IP socket
WindowsUnixDOS
www.plcworld.cn
Modbus/TCP 6 byte
Modbus/232 TCP
socket RS232
CRC Frame .
Communication Protocol
3.1 PLC
PLC
PLC
Modicon
Modbus/232
Modbus Plus
Modbus/TCP
Ethernet TCP/IP
Allen-Brandley
DF1
EtherentIP
Ethernet
Profibus
SimaticSiemens
Ethernet
MPI
Simatic TI PLC
Task Code
GE
SNP
Ethernet
Mitsubishi MelsecA
PC-Link
Ethernet
Mitsubishi FX2
PC-Link
OMRON
HostLink
FINS
Ethernet
Koyo
U-01DM/G-01DM
(1-6)
3.2 Modbus
Modbus Modicon PLC
1979 Modbus Modbus Plus
1997 Modbus/TCP OSI
www.plcworld.cn
Modbus/TCP Ethernet
Modbus Plus
Modbus Modbus/TCP
www.plcworld.cn
Modbus
Modbus Master and Slave
Master Query Message Slave
Slave Query Message Response Message
Master
Modbus Master Slave
(HMI) MasterPLC
SlaveHMI Polling Slave relay and register
1
1.1 Query and Response Cycle
Device Address
Device Address
Query message from Master
Function code
Eight-Bit
Data Bytes
Function code
Eight-Bit
Data Bytes
Response message from Slave
Error Check
Error Check
Master
Slave
Device Address
TCP/IP IP Address Device Address
Error Check
Error Check Code message
Code
CRC and LRC TCP/IP Error Check
TCP/IP Modbus/TCP
1.2 Data Format
Query and Response Message
256
z RTU
www.plcworld.cn
T1-T2-T3-T4
Device
Function
Address
Code
8 Bits
8 Bits
Data
CRC check
Number of 8
16 Bits
T1-T2-T3-T4
Bits
(2-2)RTU data format
z ASCII
Device
Function
Address
Code
Data
LRC check
2
<CR> <LF>
ASCII
0123456789ABCDEF 16 ASCII
z TCP/IP
www.plcworld.cn
Device
Function
Address
Code
8 Bits
8 Bits
Data
Error check
Number of 8
Bits
(2-4)TCP/IP data format
6 TCP/IP
Byte 3
Byte 4Message 2 bytes Byte 45 byte
Device Address Data
256
Byte 5Message Device Address Data
Device Address Data RTU
Modbus IP Port No. 502
z
Function Code-3 Output Register Device address6Start Address
40123Modbus Output Register 40001 40001
122 0x007A3
Query Message
ASCII
RTU
TCP
Code
8-bits
field
8-bits
field
TCP Byte-0
0000 0000
TCP Byte-1
0000 0001
TCP Byte-2
0000 0000
TCP Byte-3
0000 0000
TCP Byte-4
0000 0000
TCP Byte-5
0000 0110
:
ASCII
Device Address
06
06
0000 0110
0000 0110
www.plcworld.cn
Function Code
Start Address (Hi byte)
Start Address (Lo byte)
No. of registers (Hi byte)
No. of register (Lo byte)
Error Check Byte-0
Error Check Byte-1
03
00
7A
00
03
03
00
7A
00
03
0000 0011
0000 0000
0111 1010
0000 0000
0000 0011
0000 0011
0000 0000
0111 1010
0000 0000
0000 0011
<CR><LF>
Code
8-bits field
8-bits field
TCP Byte-0
0000 0000
TCP Byte-1
0000 0001
TCP Byte-2
0000 0000
TCP Byte-3
0000 0000
TCP Byte-4
0000 0000
TCP Byte-5
0000 1001
:
ASCII
Device Address
06
06
0000 0110
0000 0110
Function Code
03
03
0000 0011
0000 0011
Byte count
06
06
0000 0110
0000 0110
Data-1 (Hi byte)
03
03
0000 0011
0000 0011
Data-1 (Lo byte)
15
15
0001 0101
0001 0101
Data-2 (Hi byte)
30
30
0011 0000
0011 0000
Data-2 (Lo byte)
39
39
0011 1001
0011 1001
Data-3 (Hi byte)
FD
FD
1111 1101
1111 1101
Data-3 (Lo byte)
C9
C9
1100 1001
1100 1001
Error Check Byte-0
Error Check Byte-1
<CR><LF>
www.plcworld.cn
www.plcworld.cn
11
01
00
13
00
0D
11
01
02
D3
17
www.plcworld.cn
17
02
00
65
00
21
17
02
05
AA
45
27
83
01
www.plcworld.cn
Device Address
29
Function Code
03
Start Address (Hi byte)
02
Start Address (Lo byte)
FC
No. of registers (Hi byte)
00
No. of registers (Lo byte)
06
Bytes 16 bits
Register 40765 99
Register 40766 12336
Register 40767 1417
Register 40768 789
Register 40769 767
Register 40770 1
Response Message
Device Address
29
Function Code
03
Byte count
0C
Data-1 (Hi byte)
00
Data-1 (Lo byte)
63
Data-2 (Hi byte)
30
Data-2 (Lo byte)
30
Data-3 (Hi byte)
FA
Data-3 (Lo byte)
77
Data-4 (Hi byte)
03
Data-4 (Lo byte)
15
Data-5 (Hi byte)
02
Data-5 (Lo byte)
FF
Data-6 (Hi byte)
00
Data-6 (Lo byte)
01
(2-10)Example of Function Code - 3 Message
www.plcworld.cn
1E
04
00
7A
00
05
Bytes 16 bits
Register 30123 2581
Register 30124 57
Register 30125 969
Register 30126 24544
Register 30127 170
Response Message
Device Address
Function Code
Byte count
Data-1 (Hi byte)
Data-1 (Lo byte)
Data-2 (Hi byte)
Data-2 (Lo byte)
Data-3 (Hi byte)
Data-3 (Lo byte)
Data-4 (Hi byte)
Data-4 (Lo byte)
Data-5 (Hi byte)
Data-5 (Lo byte)
1E
04
0A
0A
15
00
39
03
C9
A0
20
00
AA
www.plcworld.cn
0A
05
00
0B
FF
00
0A
05
00
0B
FF
00
www.plcworld.cn
0D
06
00
6F
03
E7
0D
06
00
6F
03
E7
www.plcworld.cn
11
0F
00
0A
00
0C
02
55
03
11
0F
00
12
00
03
www.plcworld.cn
27
10
01
35
00
03
06
03
10
31
A2
C0
C9
27
10
01
35
00
03
www.plcworld.cn
11
14
0E
06
00
04
00
01
00
02
06
00
03
00
09
00
02
www.plcworld.cn
Response Message
Response Message
Device Address
Function Code
Byte Count
Group-1 Byte Count
Group-1 Reference Type
Group-1 Data-1 (Hi byte)
Group-1 Data-1 (Lo byte)
Group-1 Data-2 (Hi byte)
Group-1 Data-2 (Lo byte)
Group-2 Byte Count
Group-2 Reference Type
Group-2 Data-1 (Hi byte)
Group-2 Data-1 (Lo byte)
Group-2 Data-2 (Hi byte)
Group-2 Data-2 (Lo byte)
11
14
0C
05
06
0D
FE
00
20
05
06
33
CD
00
40
www.plcworld.cn
11
15
0D
06
00
04
00
07
00
03
06
AF
04
BE
10
0D
www.plcworld.cn
0D
06
09
91
03
E7
Device Address
0D
Function Code
86
Error Code
02
(2-18)Exception Message format
1
ILLEGAL FUNCTION
Function Code Slave Function Code Slave
Function
2
ILLEGAL DATA ADDRESS
Address Start Address
Address
3
ILLEGAL DATA VALUE
Slave Function Code-6
Coil ON OFF Value ON: 0xFF00OFF: 0x0000
www.plcworld.cn
4
5
9
10
11
(2-19)Exception Code
www.plcworld.cn
RTU
Message
ASCII
2
ASCII Code RTU
Message Message
3.5
Message
Device
Message
1 start bit
1 start bit
8 data bits, least significant bit send first
7 data bits, least significant bit send first
1 bit for parity check
1 bit for parity check
1 stop bit if parity is used; 2 bits if no parity 1 stop bit if parity is used; 2 bits if no parity
Bit 1 0
Message
z CRC checkRTU CRC Cyclical Redundancy Check
16 bits
1. 0xFFFF unsigned short
CRC Register
2. Message 8 bits byte CRC Register low byte Exclusive
OR CRC Register low byte
3. CRC Register 1 bitLSB bit 0MSB
www.plcworld.cn
0D
06
09
91
03
E7
RTU
0000 1101
0000 0110
0000 1001
1001 0001
0000 0011
1110 0111
1001 1011
1100 1101
(2-21)CRC
Device Address
Function Code
Start Address (Hi byte)
Start Address (Lo byte)
Preset Data (Hi byte)
Preset Data (Lo byte)
LRC Check 1
LRC Check 2
1
(2-22)LRC
0D
06
09
91
03
E7
ASCII
Code
0D
06
09
91
03
E7
6
9
<CR>
0x0D
<LF>
0x0A
www.plcworld.cn
3 TCP/IP
Modbus/TCP 1.2.
IP Address Modbus Address Slave
Master
3.1 IP Address Modbus Address
Ethernet IP Address
Modbus Address
IP Address Modbus Address
Modbus/TCP Modbus Address
Modbus/TCP
www.plcworld.cn
C++Builder Modbus
Windows Modbus
Borland C++ Builder V5.0 Sample Porgram
source program
API
Multi-Thread C
1 DLL
Modbus RS232C
LRCCRC C
DLL C++ VB
MB_SUB.DLL Windows
1.1 RS232C
Subroutine Name BOOL seropen( int nPort, int nBaud, char parity, int
data_bit, int stop_bit, int flow)
Source Name RS232_SUB.c
Library Name MB_SUB.LIBMB_SUB.DLLMB_SUB.h
C++ Builder V5.0
Open COM port
Parameter int nPort open port no.COM1 port=1
char parityN:NoneOOddEEven
int data_bit: bits 7 or 8
int stop_bit: stop bits1 or 2
int flow: flow control0:1
Return Code truefalse
1open COM port
2 CreateFile()GetCommState()SetCommState()
GetCommTimeouts()SetCommTimeouts() RS232C
Windows System API
int port, baud, parity, data_bit, stop_bit, flow;
BOOL rc;
port=1; //COM1 port
baud= 19200; parity=N; data_bit=8; stop_bit=1;
flow= 0;
rc= seropen(port, baud, parity, data_bit, stop_bit,
flow);
www.plcworld.cn
www.plcworld.cn
www.plcworld.cn
Return Code
1 PurgeComm () Windows System API
int port;
port=1; //COM1 port
ch= serrecv(port);
www.plcworld.cn
www.plcworld.cn
www.plcworld.cn
1.3
Subroutine Name int tsleep(interval)
Source Name winsys.c
Library Name MB_SUB.LIBMB_SUB.DLLMB_SUB.h
C++ Builder V5.0
para. long interval, millsecond.
Return Code -1
0
1 Windows System API Sleep()
2 interval return
long interval;
interval=20000; // 20
tsleep(interval);
*year(4 )
*month
*day
*hour
*minute
*second
*msecmilliseconds
*week
Return Code -1
0
1 Windows System API GetLocalTime()
short year, month, day, hour, minute, second, msec, week;
get_date_time(&year, &month, &day, &hour, &minute,
&second, &msec, &week);
www.plcworld.cn
year(4 )
month
day
hour
minute
second
Return Code -1
0
1 Windows System API SetLocalTime()
www.plcworld.cn
www.plcworld.cn
www.plcworld.cn
www.plcworld.cn
www.plcworld.cn
z Message
www.plcworld.cn
(3-1)Utility
Menu
z [Master][Master RTU] Modbus Master RTU type
z [Master][Master ASCII] Modbus Master ASCII type
z [Master][Master TCP] Modbus/TCP Master type
z [Master][Exit]Utility
z [Slave][Slave RTU] Modbus Slave RTU type
z [Slave][Slave ASCII] Modbus Slave ASCII type
z [Slave][Slave TCP] Modbus/TCP Slave type
z [Windows][Cascade] Multi-Document
z [Windows][Tite Horizontally] Multi-Document
z [About]
www.plcworld.cn
(3-2)Multi-Document
(3-3)Master RTU
www.plcworld.cn
Master RTU
z [Port Define] Button RS232C baud
rateparitydata bitsstop bits COM Port
Button
z [Open] ButtonOpen COM Port
z [Close] ButtonClose COM Port
z Function Code Output CoilInput RelayHolding RegisterInput
Register
z Modbus Device Address Modbus Slave Address
1 247
z Register/Relay Address 1 9999
(3-4) (Relay )
www.plcworld.cn
www.plcworld.cn
(3-8)RS232C
www.plcworld.cn
z
z
z
z
z
Baud Rate1200240048009600192003840057600115200
ParityNoneOddEven
Data Bit78
Stop Bit12
Used COM Port COM Port
(3-9)Master ASCII
z Communication Words/BitsRegister 60
wordsRelay 960 bitsModbus Message
256 bytes Message Header
240 bytes
www.plcworld.cn
(3-10)Master TCP
www.plcworld.cn
(3-11)Slave RTU
www.plcworld.cn
www.plcworld.cn
(3-14)Slave ASCII
www.plcworld.cn
(3-15)Slave TCP
2.2 Utility
Utility
Modbus
PC Modbus_Tool
PC Modbus_Tool
Master RTU
Slave RTU
Master ASCII PC
Slave ASCII PC
Slave Server
Modbus Device
(3-16)Utility
Open Port
www.plcworld.cn
Master
Master PC-1 Master RTU Function Code PC-1 Query Message
Relay/Register Slave
0
PC-1 Master ASCII Function Code PC-1 Query Message
Modbus device Relay/Register and Response Message
AddressCommunication Words/Bits
[Send command] Button PC-2 Slave ASCII
Query Message and Response
Relay/Register Slave
0
Master PC-1 Master RTU PC-1 Query Message
Master PC-2
www.plcworld.cn
PC-1
Matser RTU
Master
PC-1
(3-17)Utility
www.plcworld.cn
2.3 Utility
MB_Sub.DLL
MB_Sub.bpr
Project
MB_Sub.DLL
Modbus Basic Subroutine DLL
MB_Sub.Lib
Modbus Basic Subroutine Link Library
MB_Sub.h
Modbus Basic Subroutine Defined Header
RS232_Sub.cpp
COM Port
Error_Check.cpp
Modbus Protocol
Winsys.cpp
Windows API
Modbus_Tool Utility
Modbus_Tool.bpr
Project
Modbus_MAIN.cpp
MB_Sub.DLL
Modbus Basic Subroutine DLL
MB_Sub.Lib
Modbus Basic Subroutine Link Library
MB_Sub.h
Modbus Basic Subroutine Defined Header
Port_Def.cpp
Master_RTU.cpp
Modbus Matser RTU
Master_ASCII.cpp
Modbus Master ASCII
Master_TCP.cpp
Modbus/TCP Master
Slave_RTU.cpp
Modbus Slave RTU
Slave_ASCII.cpp
Modbus Slave ASCII
Slave_TCP.cpp
Modbus/TCP Slave
Set_Data.cpp
Relay Register
Set_Value.cpp
Slave Server Relay
Register
STD_SUB.cpp
STD_SUB.h
About.cpp
About Dialog Box
(3-18)C++ Utility
www.plcworld.cn
Modbus_Tool
Menu
Master_RTU
Master_ASCII
Master_TCP
Multi-Documents Form
Multi-Documents Form
Multi-Documents Form
Timer1
Timer1
Socket
Timer1 RTU
Timer1 ASCII
Socket Event
Response Message
Response Message
Response Message
STD_SUB.cpp
Slave_RTU
Slave_ASCII
Slave_TCP
Multi-Documents Form
Multi-Documents Form
Multi-Documents Form
Open TCP/IP
Query
Query
Event Query
Message
Message
Message
Relay/Register
Relay/Register
Relay/Register
Response
Response
Response
Timer1
Timer1
Event
STD_SUB.cpp
www.plcworld.cn
(3-19)C++ Utility
z
Master RTU Master ASCII COM Port Query
Message Timer 5 msec Response Message
6 Multi-Document
z
z
Query Message Response
Message RelayRegister CRC
LRC MB_SUB.DLL
z RS232C RS232C
MB_SUB.DLL Query Message serwrite()
Response Message
PC Based
Controller
www.plcworld.cn
www.plcworld.cn
Timer 5msec
timer
Byte
byte
byte
timer
Byte
byte
Byte
Timer
byte
Response Messager
Memo
CRC
CRC Code
CRC
CRC code error
Memo
Response Messager
Relay
Register
Timer
Timer1->Enabled= false;
www.plcworld.cn
www.plcworld.cn
{
data= INBUFF[i];
itascxr(data, -2, buff);
s= s+ buff;
}
Memo2->Lines->Clear();
Memo2->Lines->Add(s);
CRC_check(&INBUFF[0], CNT-2, crc);
if(INBUFF[CNT-2]==crc[0] && INBUFF[CNT-1]==crc[1])
{
MB_LEN= CNT;
display_RTU_Response(StringGrid1, INBUFF, MB_LEN,
MB_WORDS, MB_SET_ROW, MB_SET_COL, MB_SET_VALUE);
}
else
{
sprintf(buff, "CRC error: Recv[%d %d] Calc[%d %d]",
INBUFF[CNT-2], INBUFF[CNT-1], crc[0], crc[1]);
Memo2->Lines->Add(buff);
}
STEP= 1000;
break;
case 990:
Timer1->Enabled= false;
serclose(MB_PORT);
Memo2->Lines->Add("Time out error");
MessageBox(NULL, "RS232C comm. time out error", "MBMaster_A",
MB_OK);
STEP=0;
break;
case 1000:
Timer1->Enabled= false;
serclose(MB_PORT);
STEP= 0;
// to set data value enabled or not
if(MB_FUN==0 || MB_FUN==2) // to set data
{
StringGrid1->ShowHint= true;
BitBtn2->Enabled= true;
}
else
{
StringGrid1->ShowHint= false;
BitBtn2->Enabled= false;
}
// set StringGrid selected cells
if(MB_FUN==0 || MB_FUN==1) // relay
{
StringGrid1->Row=1;
StringGrid1->Col=8;
}
else
{
StringGrid1->Row=1;
StringGrid1->Col=1;
}
StringGrid1->SetFocus();
return;
}
}
www.plcworld.cn
Timer 10msec
timer
Start code :
:
:
timer
Timer
< CR><LF>
Response Messager
Memo
LRC
LRC Code
LRC
LRC code error Memo
Response Messager
RelayRegister
Timer
Timer1->Enabled= false;
www.plcworld.cn
www.plcworld.cn
}
Memo2->Lines->Clear();
Memo2->Lines->Add(s);
LRC_check(&INBUFF[1], CNT-5, lrc);
if(INBUFF[CNT-4]==lrc[0] && INBUFF[CNT-3]==lrc[1])
{
MB_LEN= CNT;
display_ASCII_Response(StringGrid1, INBUFF, MB_LEN,
MB_WORDS, MB_SET_ROW, MB_SET_COL, MB_SET_VALUE);
}
else
{
sprintf(buff, "LRC error: Recv[%d %d] Calc[%d %d]",
INBUFF[CNT-4], INBUFF[CNT-3], lrc[0], lrc[1]);
Memo2->Lines->Add(buff);
}
STEP= 1000;
break;
case 990:
Timer2->Enabled= false;
serclose(MB_PORT);
Memo2->Lines->Add("Time out error");
MessageBox(NULL, "RS232C comm. time out error", "MBMaster_A",
MB_OK);
STEP=0;
break;
case 1000:
Timer2->Enabled= false;
serclose(MB_PORT);
STEP= 0;
// to set data value enabled or not
if(MB_FUN==0 || MB_FUN==2)
{
StringGrid1->ShowHint= true;
BitBtn2->Enabled= true;
}
else
{
StringGrid1->ShowHint= false;
BitBtn2->Enabled= false;
}
// set StringGrid selected cells
if(MB_FUN==0 || MB_FUN==1) // relay
{
StringGrid1->Row=1;
StringGrid1->Col=8;
}
else
{
StringGrid1->Row=1;
StringGrid1->Col=1;
}
StringGrid1->SetFocus();
return;
}
}
www.plcworld.cn
ClientSocket()->Host= IP_Address
ClientSocket()->Port= IP_Port_No
CleintSocket()->Open();
Client connect
ClientSocket()->Socket->SendBuf();
Query Message
Windows Event
OnDisconnect Event
Message RelayRegister
www.plcworld.cn
MODBUS_TOOL, MB_OK);
return;
}
s= "Query message: ";
memset(buff, 0, sizeof(buff));
buff[2]= ' '; // space code
for(i=0; i<MB_LEN; i++)
{
data= OUTBUFF[i];
itascxr(data, -2, buff);
s= s + buff;
}
Memo1->Lines->Clear();
Memo1->Lines->Add(s);
ClientSocket1->Socket->SendBuf(OUTBUFF, MB_LEN);
}
//--------------------------------------------------------------------------void __fastcall TMSTCP_Form::ClientSocket1Connect(TObject *Sender,
TCustomWinSocket *Socket)
{
AnsiString s;
s= Socket->RemoteHost ;
s= "Connect To: " + s;
s= s + " OK";
display_status_message(s);
BitBtn3->Enabled= false;
BitBtn4->Enabled= true;
}
//--------------------------------------------------------------------------void __fastcall TMSTCP_Form::ClientSocket1Disconnect(TObject *Sender,
TCustomWinSocket *Socket)
{
AnsiString s;
s= "Disconnect OK ";
display_status_message(s);
BitBtn3->Enabled= true;
BitBtn4->Enabled= false;
ClientSocket1->Host= "";
ClientSocket1->Port= 0;
}
//--------------------------------------------------------------------------void __fastcall TMSTCP_Form::ClientSocket1Error(TObject *Sender,
TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
char buff[80];
AnsiString s;
sprintf(buff, "TCP connect error rtc=%d", ErrorCode);
s= buff;
display_status_message(s);
BitBtn3->Enabled= true;
BitBtn4->Enabled= false;
ClientSocket1->Close();
ClientSocket1->Host= "";
ClientSocket1->Port= 0;
MessageBox(NULL, s.c_str(), MODBUS_TOOL, MB_OK);
}
//---------------------------------------------------------------------------
www.plcworld.cn
www.plcworld.cn
Timer 5msec
Byte
Timer
Byte
byte
byte
timer
Byte
byte
Byte
Timer
byte
Query Messager
Memo
CRC
CRC Code
CRC
CRC code error
Memo
Response Messager
Timer
www.plcworld.cn
www.plcworld.cn
//
STEP= 0;
return;
break;
}
} // while()
}
www.plcworld.cn
Timer 5msec
Byte
Timer
Start code :
:
:
timer
Timer
< CR><LF>
Query Messager Memo
LRC
LRC Code
LRC
LRC code error Memo
Response Messager
Timer
www.plcworld.cn
www.plcworld.cn
//
inbuff_ASC[CNT++]= ch;
}
break;
case 30:
ASC_response();
STEP= 1000;
break;
case 990:
Memo1->Lines->Add("Time out error");
STEP=0;
break;
case 1000:
STEP= 0;
return;
break;
}
} // while()
}
www.plcworld.cn
OnError Event
connect Memo
Memo
Windows Event
OnDisconnect Event
RelayRegister
client Memo
www.plcworld.cn
Memo1->Lines->Add(buff);
MessageBox(NULL, buff, MODBUS_TOOL, MB_OK);
}
//--------------------------------------------------------------------------void __fastcall TSLTCP_Form::ServerSocket1ClientRead(TObject *Sender,
TCustomWinSocket *Socket)
{
// receive data from client
len= Socket->ReceiveLength();
// Relay/Register response
// Source Porgram
Socket->SendBuf(outbuff_TCP, cnt);
}
www.plcworld.cn
2.4
RS232C Ethernet
Event Driven
Polling
Buffer
Buffer
buffer
(3-26)
Bug
Bug 24
www.plcworld.cn
www.plcworld.cn
J.
K.
L.
Event buffer
Polling buffer
byte buffer
RS232C
RS232C
byte byte
byte Message
CRCLRC Code byte
// old_nsec
// SECONDNSEC PC
old_nsec= SECOND * 1000 + NSEC;
timeout = 200;
// 200 millsecond
//
rc= check_nsec_timeout(old_nsec, timeout);
if( rc == 0) //
else //
int check_nsec_timeout(int old_nsec, int timeout)
{
int tt, new_nsec;
new_nsec = SECOND * 1000 + NSEC; // millsecond
www.plcworld.cn
tt = new_nsec old_nsec;
// new_nsec
// 60000
if( tt < 0) tt = tt + 60000;
if( tt >= timeout) return(-1); //
return(0); //
}
M. second
short time_out_check(short old_t, short timeout)
{
short tm, new_t;
new_t= MINUTE*60 + SECOND; //
tm= new_t - old_t;
// new_t
// 3600
if(tm < 0) tm= tm + 3600;
if(tm >= timeout) return(-1); //
else return(0); //
}
www.plcworld.cn
Sample Program
1 ICP 7524ICP 7188E5
1.1
ICP 7524 COM
Port RS232 RS485 Port
COM4 Port
RS232
RS232
RS232
COM5 Port
RS232
RS232
COM6 Port
RS232
COM7 Port
RS232
COM8 Port
RS232
1
DO (Digital
Output)
DI (Digital
3
3
5
1
1
Input)
User defined
3
I/O
Y
Y
Y
Real Time
Clock
Embedded O.S. MiniOS 7 MiniOS 7 MiniOS 7 MiniOS 7 MiniOS 7 MiniOS 7
(4-1)ICP-752X
www.plcworld.cn
512K
Ethernet Port
512K
512K
512K
512K
512K
512K
COM1 Port
Program
Download
COM2 Port
RS232
RS232
RS232
RS232
RS232
RS232
RS232
RS485
RS485
RS485
RS485
RS485
RS485
COM3 Port
RS422
RS232
RS232
RS232
RS232
COM4 Port
RS232
RS232
RS232
COM5 Port
RS232
RS232
COM6 Port
COM7 Port
RS232
RS232
COM8 Port
RS232
DO (Digital
Output)
DI (Digital
4
4
4
Input)
RTC
N
N
N
N
N
N
N
Embedded O.S. MiniOS 7 MiniOS 7 MiniOS 7 MiniOS 7 MiniOS 7 MiniOS 7 MiniOS 7
(4-2)ICP-7188E
1.2
ICP 7524 7188E OS MiniOS 7 OS
DOS DOS
DOS
www.plcworld.cn
z
z
OS delay API
millsecond Watchdog timer
DIDO LED DO
DI LED
Flash EEPROM Hard Disk
DOS DOS
C
Borland Turbo C++ 3.0
PC Compiler
ICP 7524 7188XW
Flash Memory
Debug
z PC Based Controller
Power On
24
RS232CEthernet DO
PC Based Controller
I/O
While Loop
z
Baud RateParityStop
BitData BitsIP Address
DOS Hard Disk
PC based Controller Flash EEPROM
www.plcworld.cn
24
2.1 7188XW
MiniOS 7 7188XW
RS232C COM1 Port PC
COM1 Port PC 7188XW
(4-3)7188XW
www.plcworld.cn
2.2 Command
MiniOS 7 Command
Command
Dir
Del
Date
Time
Load
PC
Typefile file
ver
MiniOS 7
Ip
Ethernet IP Address
(4-4)7188XW Command
DEMO7524.C
7188XBL.LIBICP 7524 Library
Project Library
Project C Small Model Large Model
www.plcworld.cn
640KB 64KB
ICP 75247188E SRAM 256KB
256KB Complier and Link 2.5.
COM Port
RS232422485 API
LED
LED API
Memory
EEPROM Flash Memory API
Timer
Timer OpenCloseDelayWatchdog API
Ethernet
TCP/IPUDP Socket PC
Stdio
Printgetchkbhit MiniOS 7 API
API API
(4-6)MiniOS 7 API Function
z del
DOS
z loadALT+E
z dir
www.plcworld.cn
(4-7)7188XW
autoexec.bat
7524 Power On DOS
MiniOS 7 autoexec.bat INIT
GNDMiniOS 7 autoexec.bat
www.plcworld.cn
3.1
Modbus
Common Variable
Driver
Register
Sub.
7000 I/O
ESC
Module
Common Varaible
7000 I/O
(4-8)
Modbus
www.plcworld.cn
3.2
demo7524
Sample Program
z include file define
7524sys.h Head File mod_sub.c
COM Port RS232xb.cMbascDR.c MbrtuDR.c
Modbus
#include "7188xb.h" // MiniOS 7 API head file
#include "7524sys.h" // Common variable and define file
#include "mod_sub.c" // Subroutine
#include "RS232xb.c" // MiniOS 7 API COM Port Subroutine
#include "MBascDR.c" // Modbus Slave ASCII format driver
#include "MBrtuDR.c" // Modbus Slave RTU format driver
main()
//
{
//
es= 1;
while(es)
{
//
// MbascDR MbrtuDR
// ESC es=0while loop
}
// COM port Timer Table
return; //
}
C main()
7524sys.h
BC 3.0 static
Memory
Memory
www.plcworld.cn
Driver Windows
Utility
MiniOS 7 DOS
Windows Multi-ProcessMulti-Thread
While Loop
Driver
Windows CPU Time
Shareing Driver
Driver
driver
Driver 20 millseccond Driver
10 millseccond
(Real time
control) Driver
MiniOS 7 API
GetDate(&year,&month,&date);
GetTime(&hour,&minute,&second);
SetDate(year,month,second);
SetTime(hour,minute,second);
API millseccnd
Timer Tick Value API millseccond
mod_sub.c get_time()
www.plcworld.cn
TimerOpen(void);
TimerOpen(void);
TimerResetValue(void);
new_msec= TimerReadValue(void);
Windows API millsecond
DOS INT 21 millsecond 10
z
Driver
LRCCRC
Kbhit()
Getch() C
Kbhit()
Getch() Kbhit()
Getch()
Modbus Slave
4.1 Demo7524
ICP 7524 Demo demo7524
Modbus
z Modbus RTU ASCII Slave Type Driver
z COM3 Port Modbus ASCII Slave driver
9600 O 7 1
z COM4 Port Modbus RTU Slave driver
www.plcworld.cn
z
z
z
z
z
z
9600 N 8 1
Modbus Driver
Modbus Function1234561516
7188XW
Modbus
Modbus
Power On
Modbus
Output CoilDO1024 bit
Input StatusDI1024 bit
Input RegisterAI1024 16 bit integer
Output RegisterAO1024 16 bit integer
Modbus Message
256 Byte
Output CoilDORTU 1920 ASCII 960
Input StatusDIRTU 1920 ASCII 960
Input RegisterAIRTU 120 ASCII 60
Output RegisterAORTU 120 ASCII 60
(4-9)Demo7524
Open COM3
COM4 Port [ESC]
Address
Modbus Exception code
Function Code561516
www.plcworld.cn
Address
Power On Demo
Demo7524.exe autoexec.bat
demo7524 autoexec.bat
4.2 Demo7524
Demo7524.prj
Demo7524 BC 3.0 Project file
Demo7524.c
7188xb.h
7524 System API Head File
7188xbl.lib
7524 System API Library Large Model
7524sys.h
Modbus Common Varaible and constant define
head file
MBascDR.c
Modbus ASCII Slave driver
MBrtuDR.c
Modbus RTU Slave driver
MOD_Sub.c
Modbus Common Subroutine
RS232XB.c
7524 Common COM port Subroutine
(4-10)Demo7524
RS232XB.c Subroutine
Subroutine
int seropen(int port,long baud,char
parity,int stop,int data,int xonoff)
int serclose(int port)
Byte
Byte
(n) Bytes
(4-11)RS232XB
Mod_Sub.c Subroutine
Subroutine
www.plcworld.cn
int *day)
int get_time(int *hour, int *minute, millsecond
int *second, int *nsec)
int set_date(int year, int month, int
day)
int set_time(int hour, int minute, millsecond
int second)
void LRC_check(unsigned char
Modbus LRC
*buff, int len, unsigned char *chk)
void CRC_check(unsigned char
Modbus CRC
*buff, int len, unsigned char *chk)
void CRC_calc(unsigned char c, CRC_check() Byte
unsigned short *crc)
int itascxr(unsigned int idata, int ASCII Code
nn, char* buf)
int ascxti(char* ch, int n, unsigned ASCII Code
int* data)
int bitrd(unsigned int* data, int
bit
top, int end)
(4-12)Mod_SUB
Subroutine Win2000
www.plcworld.cn
#define ED_MAX
1024 // AI, AO
#define DD_BIT_MAX
1024 // DI, DO
#define DD_BYTE_MAX
DD_BIT_MAX/8 // DI,DO
byte
static unsigned char DI[DD_BYTE_MAX]; // Modbus Coil Relay
static unsigned char DO[DD_BYTE_MAX]; // Modbus Input status
static int AI[ED_MAX]; // Modbus Input register
static int AO[ED_MAX]; // Modbus Holding register
AIAO int
DIDO C 1 bit
BOOL byte
unsigned char unsigned
1 bit Address
bit DO
DO[0]
15
14
13
12
11
10
DO[1]
1017
1016
DO[127]
1023
1022
1021
1020
1019
1018
www.plcworld.cn
second millscond
// second
int time_out_check(int old_t, int timeout)
{
int tm, new_t;
new_t= MINUTE*60 + SECOND;
tm= new_t - old_t;
if(tm < 0) tm= tm + 3600;
if(tm >= timeout) return(-1); // timeout error
else return(0);
}
//
//
//
//
10 millsecond
new_t= SECOND * 100 + NSEC SECOND * 100
* 1000 * 1000
59 * 1000 + 999 = 59999 int 32767
www.plcworld.cn
www.plcworld.cn
stepB
stepB0
stepB5
stepB10
stepB20
Open Port
byte
byte
Command
stepB
Response
bytestepB
bytewhile
stepB 5
10
loop
bytestepB
byte
millscond
stepB 20
CPU
(4-14)RTU
MbrtuDR.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
//
//
#define
stepB
RSCOMM_B.step
#define
commflagB RSCOMM_B.comm_flag
www.plcworld.cn
#define
#define
#define
countB
old_timeB
timeoutB
RSCOMM_B.count
RSCOMM_B.old_time
RSCOMM_B.rs.timeout
// buffer static
//
static unsigned char outbuff_B[256]; // comm. data output buffer
static unsigned char inbuff_B[256]; // comm. data input buffer
modbus_slave_RTU_main()
{
int ch;
switch(stepB) // stepB case
{
case 0:
// Open COM Port
ch= seropen(portB, RSCOMM_B.rs.baud, RSCOMM_B.rs.parity,
RSCOMM_B.rs.stop_bit, RSCOMM_B.rs.data_bit, 0);
stepB= 5; //
serflush(portB);
sprintf(MSG, "Open COM%d port= %ld %c %d %d "
"Slave RTU rtc=%d ",
portB, RSCOMM_B.rs.baud, RSCOMM_B.rs.parity,
RSCOMM_B.rs.data_bit, RSCOMM_B.rs.stop_bit, ch);
msg_log(MSG); // open port
// 0.05 sec. byte
timeoutB= 50;
break;
case 5: // start code check
ch = serrecv(portB);
if( ch == -1) return; //
else
{
// byte stepB=10
stepB= 10;
memset(inbuff_B, 0, sizeof(inbuff_B));
countB= 0; // byte
inbuff_B[countB++]= (char)ch; //
OLD_NSEC= SECOND * 100 + NSEC; //
}
break;
case 10: // end code check
while(1)
www.plcworld.cn
{
ch= serrecv(portB);
if(ch == -1)
{
if( nsec_out_check(OLD_NSEC, timeoutB)==0 )
{ return; } // byte
else
{ // command
stepB= 20; // stepB=20
return;
}
}
else
{
if( countB > (sizeof(inbuff_B) - 2) )
{
sprintf(MSG, "Mod Slave RTU Receive buffer over count=%d"
,countB);
msg_log(MSG);
countB= 0;
stepB= 5;
return;
}
inbuff_B[countB++]= (char)ch; // byte
stepB= 10;
OLD_NSEC= SECOND * 100 + NSEC; //
}
}
//
break;
case 20:
mod_request_RTU(); // RTU Command
stepB= 5;
break;
}
return;
www.plcworld.cn
// Local Variable
// Command Message function code
// 16 bit integer byte
funno= inbuff_B[1]; // Modbus Function Code
bf[0]= inbuff_B[3];
bf[1]= inbuff_B[2];
memcpy((char *)&addr, &bf[0], 2); // Relay or Register Address
bf[0]= inbuff_B[5];
bf[1]= inbuff_B[4];
memcpy((char *)&no, &bf[0], 2); //
// CRC Message CRC
CRC_check(inbuff_B, countB-2, chk);
if( chk[0]!=inbuff_B[countB-2] || chk[1]!=inbuff_B[countB-1])
{
// CRC Response
sprintf(MSG, "Mod Slave RTU CRC err CRC_RECV=%d %d
CRC_CALC=%d %d len=%d"
,inbuff_B[countB-2], inbuff_B[countB-1], chk[0], chk[1], countB);
msg_log(MSG);
return(-1);
}
// Function Code Response Message
switch(funno)
{
case 01:
// RELAY Coil read
case 02:
// RELAY Intput read
// addr + no 1024
// illegal addree exception code
// no 1920
// illegal addree exception code
// DI or DO CommonVairable Response
memset(outbuff_B, 0, sizeof(outbuff_B));
memcpy(&outbuff_B[0], &inbuff_B[0], 2); // ID No. and Fun. No.
len= 2;
m= no/8; // no. of bytes
n= no%8; // residue of bits
if(n >0) i= m +1; // calc. byte count
else i= m;
outbuff_B[len]= i;
len= len +1;
www.plcworld.cn
// Byte 8 bit
for(i=0; i<m; i++) // one byte DD treatment
{
code= 0;
for(j=0; j<8; j++)
{
if(funno==1) // Coil relay
dd= get_DO_bit(addr);
else
dd= get_DI_bit(addr);
// Relay outbuff_B
if( dd==1)
{ bitwt(&code, j, j, 1); }
else
{ bitwt(&code, j, j, 0); }
addr++;
}
outbuff_B[len]= code;
len= len +1;
}
// 8 bit
if( n >0) // the residue of bits treatment
{
code= 0;
for(j=0; j<n; j++)
{
if(funno==1) // Coil relay
dd= get_DO_bit(addr);
else
dd= get_DI_bit(addr);
if( dd==1)
{ bitwt(&code, j, j, 1); }
else
{ bitwt(&code, j, j, 0); }
addr++;
}
outbuff_B[len]= code;
len= len +1;
}
www.plcworld.cn
www.plcworld.cn
www.plcworld.cn
{
dd= bitrd(&code, j, j);
set_DO_bit(addr, dd);
addr++;
}
}
// 8 bit
if(n >0)
{
j= m + 7;
code= inbuff_B[j];
for(j=0; j<n; j++)
{
dd= bitrd(&code, j, j);
set_DO_bit(addr, dd);
addr++;
}
}
// Command Message 6 bytes Response Message
memset(outbuff_B, 0, sizeof(outbuff_B));
memcpy(&outbuff_B[0], &inbuff_B[0], 6);
len= 6;
CRC_check(outbuff_B, len, &outbuff_B[len]);
len= len+2;
serwrite(portB, outbuff_B, len);
break;
case 16:
// Multiple Registers write
// addr+no 1024
// illegal addree exception code
// AO Address
sprintf(MSG, "Fun-16 Multi-Point Register set addr=%d words=%d", addr, no);
msg_log(MSG);
cptr= (unsigned char *)&val;
for(i=0; i<no; i++)
{
j= i*2 +7;
*(cptr+1)= inbuff_B[j]; //Low Byte
*(cptr)= inbuff_B[j+1]; // High byte
AO[addr+i]= val;
}
www.plcworld.cn
www.plcworld.cn
stepA
stepA0
stepA5
stepA10
stepA20
Open Port
Code :
Code <LF>
Command
stepA
while loop
Response
stepA 10
stepA 5
stepA 5
stepA 20
Code
CPU
(4-15)ASCII
MbascDR.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#define
start_code ':'
//
//
#define
stepA
RSCOMM_A.step
#define
commflagA
RSCOMM_A.comm_flag
#define
countA
RSCOMM_A.count
#define
old_timeA RSCOMM_A.old_time
www.plcworld.cn
#define
timeoutA
RSCOMM_A.rs.timeout
// buffer static
//
static unsigned char outbuff_A[256]; // comm. data output buffer
static unsigned char inbuff_A[256]; // comm. data input buffer
modbus_slave_ASCII_main()
{
int ch;
switch(stepA) // stepA case
{
case 0:
ch= seropen(portA, RSCOMM_A.rs.baud, RSCOMM_A.rs.parity,
RSCOMM_A.rs.stop_bit, RSCOMM_A.rs.data_bit, 0);
stepA= 5; //
serflush(portA);
sprintf(MSG, "Open COM%d port= %ld %c %d %d "
"Slave ASCII rtc=%d ",
portA, RSCOMM_A.rs.baud, RSCOMM_A.rs.parity,
RSCOMM_A.rs.data_bit, RSCOMM_A.rs.stop_bit, ch);
msg_log(MSG); // open port
timeoutA= 3; // 3 second
break;
case 5: // start code check
ch = serrecv(portA);
if( ch == -1) return; // Byte
else if( ch== start_code)
{
// Start Code stepA=10
stepA= 10;
memset(inbuff_A, 0, sizeof(inbuff_A));
countA= 0; // byte
inbuff_A[countA++]= (char)ch; //
old_timeA= MINUTE * 60 + SECOND; //
}
break;
case 10: // end code check
ch= serrecv(portA);
if(ch == -1)
{
if( time_out_check(old_timeA, timeoutA)==0 )
{ return; } //
www.plcworld.cn
else
{ //
stepA= 5; // Start code
//
sprintf(MSG, "Mod Slave ASC req. cmd is not finished "
"recv. len=%d", countA);
msg_log(MSG);
return;
}
}
else if(ch == LF) // Code
{
inbuff_A[countA++]= (char)ch;
stepA= 20;
}
else
{
if( countA > (sizeof(inbuff_A) - 2) )
{
// buffer
sprintf(MSG, "Mod Slave ASCII Receive buffer over count=%d" ,countA);
msg_log(MSG);
countA= 0;
stepA= 5;
return;
}
inbuff_A[countA++]= (char)ch;
stepA= 10;
}
break;
case 20:
mod_request_ASCII();//ASCII Command
stepA= 5;
break;
}
return;
}
mod_request_ASCII() mod_request_RTU()
Meesage ASCII code itascxr()ascxti()
www.plcworld.cn
Modbus/TCP Slave
5.1
Demo7188 Demo7524 Modbus/TCP Slave
Driver Modbus ASCIIRTUTCP Slave Driver
7188E PC Based Controller Modbus
Server
Demo Modbus/TCP 32 Remote Modbus Client
7188XW Demo7188.exe
DEMO7188.C
7188EL.LIBICP 7188E Library
TCPIPL.LIBICP 7188E TCP Library
(4-16)BC 3.0 Compiler
www.plcworld.cn
(4-17)Demo7188
Demo7188 Dem7524
TCP Remote Modbus Client Connect Disconnet
Demo7188.prj
Demo7188 BC 3.0 Project file
Demo7188.c
7188e.h
7188E System API Head File
7188el.lib
7188E System API Library Large Model
TCPIP.h
7188E System API Head File for TCP/IP
TCPIPL.lib
7188E System API Library Large Model for
TCP/IP
7188sys.h
Modbus Common Varaible and constant define
head file
7188TCP.h
Modbus/TCP Common Varaible and constant
define head file
MBascDR.c
Modbus ASCII Slave driver
MBrtuDR.c
Modbus RTU Slave driver
MBtcpDR.c
Modbus TCP Slave driver
MOD_Sub.c
Modbus Common Subroutine
RS232XB.c
7188E or 7524 Common COM port Subroutine
TCP_SUB.c
7188E Common TCP/IP Subroutine
www.plcworld.cn
(4-18)Demo7188
MbascDR.cMbrtuDR.cMOD_SUB.cRS232XB.c Demo7524
TCP_SUB.c Subroutine
Subroutine
int tcp_main_initial()
int tcp_bind_initial(int port_no)
killsockets()
Open TCP
Bind one seocket Server socket
Remote Client connect
connect disconnet
(4-19)TCP_SUB
// Kbhit() ESC
} // while(1)
serclose(portA); // close COM3 port
TimerClose(); // close Timer table
killsockets(); // close all TCP/IP socket
Nterm();//close Ethernet
www.plcworld.cn
return;
}
MbtcpDR.cmodbus_TCP_main() Subroutine Modbus/TCP
Driver
driver
Selectsocket()
TCP message
connect
master
New Connect
(4-20)Modbus/TCP
www.plcworld.cn
modbus_TCP_main() Subroutine
int modbus_TCP_main()
{
int i, rc, err;
struct sockaddr_in ssin; /* client Internet endpoing address */
int sin_len;
/* length of sockaddr_in */
unsigned long set;
sin_len = sizeof( ssin );
for (i = 0; i < SOCKETS; i++)
{
if (SST[i].active)
{ /* re-join active sockets */
FD_SET( i, &RFDS );
}
}
SELTIME.tv_sec=0;
SELTIME.tv_usec=0;
/* Set NonBlock Mode for I/O*/
set = 1;
ioctlsocket(MASTER_SOCKET, FIONBIO, (unsigned long*) &set);
//------ check the socket come in -------rc = selectsocket( SOCKETS, &RFDS, NULL, NULL, &SELTIME );
if (rc < 0)
{
Print( "selectsocket error %d\n\r", rc );
return(-1);
}
if( !rc ) //no socket come in , continue waitting
return(0);
//some sockets come in, and scan all possible sockets
for (i = 0; i < SOCKETS; i++)
{ //------ scan all possible sockets
if (FD_ISSET(i, &RFDS))
{
if (i == MASTER_SOCKET)
{ /* master socket */
memset( &ssin, 0, sizeof(ssin) );
CLIENT_SOCKET = accept(MASTER_SOCKET, (struct sockaddr *)&ssin
www.plcworld.cn
, &sin_len );
err= CLIENT_SOCKET;
if (err < 0)
{
Print( "accept error %d\n\r", err );
return(-1);
}
//------ send connection message to client
FD_SET( CLIENT_SOCKET, &RFDS );//set the setting
SST[CLIENT_SOCKET].active = 1;//active
SST[CLIENT_SOCKET].init = 1;
memcpy( &SST[CLIENT_SOCKET].sin, &ssin, sin_len);
sprintf(MSG, "Client Sockect connect ID=%d", CLIENT_SOCKET);
msg_log(MSG);
}
else
{
/* slave socket */
// The client connection is accept and distribution to socket i
// So the user can read the Modbus Command message
// will cause one socket. So the maximun socket (connection) is 31.
// In the other word, This server can be connected by 31 client maximun.
modbus_request_TCP(i);
// do message command
}
} // if(FD_ISSET....)
} // for(i=0...)
return(0);
}
www.plcworld.cn
socket
Modbus Master
6.1
z Modbus RTU ASCII Master Type Driver
z MST7524R Modbus RTU Master/Slave
COM3 Port Modbus RTU Master driver COM4 Port
Modbus RTU Slave driver 9600 N 8 1
z MST7524A Modbus ASCII Master/Slave
COM3 Port Modbus ASCII Master driver COM4 Port
Modbus ASCII Slave driver 9600 O 7 1
z COM3 Port Master Driver
DIDOAIAO Common Variable COM4 Port Slave
Driver
z Master Driver
Unit
www.plcworld.cn
www.plcworld.cn
MST7524R.prj
MST7524R BC 3.0 Project file
MST7524R.c
7188xb.h
7524 System API Head File
7188xbl.lib
7524 System API Library Large Model
MST7524R.h
Modbus Common Varaible and constant define
head file
MSrtuDR.c
Modbus RTU Master driver
MBrtuDR.c
Modbus RTU Slave driver
MOD_Sub.c
Modbus Common Subroutine
RS232XB.c
7524 Common COM port Subroutine
MSrtuDR.cModbus RTU Master Subroutine
stepD0
stepD
Open Port
stepD
5
stepD10
stepD20
stepD25
Query
stepD5
byte
byte
Response
Unit
stepD 30
Query Message
bytestepD
bytewhile
20
loop
byte
byte
stepD30
millscond
0.1
stepD 5
stepD 99
stepD 25
stepD99
3
stepD 5
CPU
(4-23)Modbus RTU Master
www.plcworld.cn
modbus_master_RTU_main() Subroutine
{
int i, ch, len, addr, case_no, val;
unsigned char *cptr;
unsigned int crc;
float fl;
if(portD < 0) return;
switch(stepD)
{
case 0:
ch= seropen(portD, RSCOMM_D.rs.baud, RSCOMM_D.rs.parity,
RSCOMM_D.rs.stop_bit, RSCOMM_D.rs.data_bit, 0);
stepD= 5;
serflush(portD);
sprintf(MSG, "Open COM%d port= %ld %c %d %d "
"Master RTU rtc=%d ",
portD, RSCOMM_D.rs.baud, RSCOMM_D.rs.parity,
RSCOMM_D.rs.data_bit, RSCOMM_D.rs.stop_bit, ch);
msg_log(MSG);
c_caseD= -1;
break;
case 5:
c_caseD++; // unit index
// index case unit unit
if(c_caseD >= MODBUS_MASTER_UNIT_MAX) c_caseD= 0;
if(RTU_UNIT[c_caseD].station == -1) c_caseD= 0;
// prepare request command
if(RTU_UNIT[c_caseD].station == -1)
{ stepD= 5; return; }
memset(outbuff_D, 0, sizeof(outbuff_D));
outbuff_D[0]= RTU_UNIT[c_caseD].station;
outbuff_D[1]= RTU_UNIT[c_caseD].fun;
cptr=(unsigned char *)&RTU_UNIT[c_caseD].req_addr;
outbuff_D[3]=*(cptr);
outbuff_D[2]=*(cptr+1);
cptr=(unsigned char *)&RTU_UNIT[c_caseD].words;
outbuff_D[5]= *(cptr);
outbuff_D[4]=*(cptr+1);
len= 6;
CRC_check(outbuff_D, len, &outbuff_D[len]);
www.plcworld.cn
len= len+2;
serwrite(portD, outbuff_D, len); // Query Messsage
stepD= 10;
old_timeD= MINUTE * 60 + SECOND;
countD= 0;
timeoutD= 3; // 3 second
break;
case 10: // start code check
ch = serrecv(portD);
if( ch == -1)
{
if( time_out_check(old_timeD, timeoutD)==0 )
{ return; } // during comm.
else
{ // timeout error
stepD= 99; //
old_timeD= MINUTE * 60 + SECOND;
timeoutD= 3; // 3 second timeout
sprintf(MSG, "Mod RTU MASTER send command error "
"stn=%d unit=%d"
, RTU_UNIT[c_caseD].station, c_caseD );
msg_log(MSG);
return;
}
}
else
{
stepD= 20; // byte
memset(inbuff_D, 0, sizeof(inbuff_D));
countD= 0;
inbuff_D[countD++]= (char)ch;
old_nsecD= SECOND * 100 + NSEC;
}
break;
case 20: // end code check
while(1)
{
ch= serrecv(portD);
if(ch == -1)
{
if( nsec_out_check(old_nsecD, timeoutDD)==0 )
{ return; } // during comm.
else
{ // receive data finish
www.plcworld.cn
break;
case 25: // Query Message Response Message
mod_save_RTU();
old_nsecD= SECOND * 100 + NSEC;
stepD= 30;
break;
case 30: // 0.1 unit
if( nsec_out_check(old_nsecD, 10)==0 )
{ return; } // during comm.
else
stepD= 5; // goto next polling
break;
case 99: // waiting 3 second for next polling
if( time_out_check(old_timeD, timeoutD)==0 )
{ return; } // still waiting
else
stepD= 5; // goto next polling
break;
} // switch(stepD)
return;
www.plcworld.cn
MST7524A.prj
MST7524R BC 3.0 Project file
MST7524A.c
7188xb.h
7524 System API Head File
7188xbl.lib
7524 System API Library Large Model
MST7524A.h
Modbus Common Varaible and constant define
head file
MSascDR.c
Modbus ASCII Master driver
MBascDR.c
Modbus ASCII Slave driver
MOD_Sub.c
Modbus Common Subroutine
RS232XB.c
7524 Common COM port Subroutine
MSascDR.cModbus ASCII Master Subroutine
stepC0
stepA
Open Port
stepC
5
stepC5
Unit
Query Message
stepC10
stepD20
stepC25
Query
Code :
Code <LF>
Response
while loop
stepC 30
stepC 20
stepD 25
Code
stepC 99
stepD 99
stepC30
0.1
stepC 5
stepC99
3
stepC 5
CPU
www.plcworld.cn
modbus_master_ASCII_main() Subroutine
{
int i, ch, len, val, addr, case_no;
float fl;
unsigned char bf[10], change[6];
switch(stepC)
{
case 0:
ch= seropen(portC, RSCOMM_C.rs.baud, RSCOMM_C.rs.parity,
RSCOMM_C.rs.stop_bit, RSCOMM_C.rs.data_bit, 0);
stepC= 5;
sprintf(MSG, "Open COM%d port= %ld %c %d %d "
"Master ASCII rtc=%d ",
portC, RSCOMM_C.rs.baud, RSCOMM_C.rs.parity,
RSCOMM_C.rs.data_bit, RSCOMM_C.rs.stop_bit, ch);
msg_log(MSG);
c_caseC= -1;
break;
case 5:
c_caseC++; // unit index
// index case unit unit
if(c_caseC >= MODBUS_MASTER_UNIT_MAX) c_caseC= 0;
if(ASC_UNIT[c_caseC].station == -1) c_caseC= 0;
// prepare request command
if(ASC_UNIT[c_caseC].station == -1)
{ stepC= 5; return; }
memset(outbuff_C, 0, sizeof(outbuff_C));
outbuff_C[0]= ':';
sprintf(&outbuff_C[1], "%02X", ASC_UNIT[c_caseC].station);
sprintf(&outbuff_C[3], "%02X", ASC_UNIT[c_caseC].fun);
sprintf(&outbuff_C[5], "%04X", ASC_UNIT[c_caseC].req_addr);
sprintf(&outbuff_C[9], "%04X", ASC_UNIT[c_caseC].words);
len= strlen(outbuff_C);
LRC_check(&outbuff_C[1], len-1, &outbuff_C[len]);
len= len+2;
outbuff_C[len]= CR;
outbuff_C[len+1]= LF;
len= len+2;
serwrite(portC, outbuff_C, strlen(outbuff_C)); // Query Message
www.plcworld.cn
//
stepC= 10;
old_timeC= MINUTE * 60 + SECOND;
countC= 0;
timeoutC= 3; // 3 second
break;
case 10:
// response message
ch = serrecv(portC);
if( ch == -1)
{
if( time_out_check(old_timeC, timeoutC)==0 )
{ return; } // during comm.
else
{ // timeout error
stepC= 99; //
old_timeC= MINUTE * 60 + SECOND;
timeoutC= 3; // 3 second timeout
sprintf(MSG, "MODBUS ASCII MASTER send command error "
"stn=%d unit=%d"
, ASC_UNIT[c_caseC].station, c_caseC );
msg_log(MSG);
return;
}
}
else if( ch== ':' ) // Start code
{
stepC= 20;
memset(inbuff_C, 0, sizeof(inbuff_C));
countC= 0;
inbuff_C[countC++]= (char)ch;
}
else
{
Print("%04X ", ch);
}
break;
case 20: // end code <LF>
ch= serrecv(portC);
if(ch == -1)
{
if( time_out_check(old_timeC, timeoutC)==0 )
{ return; } // during comm.
else
{ // timeout error
stepC= 99; // waiting 3 second
www.plcworld.cn
www.plcworld.cn
DD_MAX_POLL
ED_MAX_POLL
960 // relay
60 // register
// initial Unit
memset((char *)ASC_UNIT, 0, sizeof(ASC_UNIT));
for(i=0; i<MODBUS_MASTER_UNIT_MAX; i++)
www.plcworld.cn
{ // 1 Unit
ASC_UNIT[i].station= -1;
// default to set no used unit
}
// Unit Unit
// Max. communication bits of Relay: (240 bytes/2) * 8 = 960 points
// Max. communication words of Register: 240 bytes / 4= 60 points
// create polling unit for Reading Output Coil
m= DD_BIT_MAX / DD_MAX_POLL;
n= DD_BIT_MAX % DD_MAX_POLL;
cnt= -1;
for(i=0; i<m; i++)
{
cnt++;
ASC_UNIT[cnt].station= 1; // Modbus Device Address
ASC_UNIT[cnt].fun= 1;
// Read Output Coil
ASC_UNIT[cnt].words= DD_MAX_POLL; // 960 points
ASC_UNIT[cnt].req_addr= i*DD_MAX_POLL; // relay start address
}
if( n>0)
{
cnt++;
ASC_UNIT[cnt].station= 1; // Modbus Device Address
ASC_UNIT[cnt].fun= 1;
// Read Output Coil
ASC_UNIT[cnt].words= n;
// residue of points
ASC_UNIT[cnt].req_addr= m*DD_MAX_POLL; // relay start
address
}
// create polling unit for Reading Input Status
m= DD_BIT_MAX / DD_MAX_POLL;
n= DD_BIT_MAX % DD_MAX_POLL;
for(i=0; i<m; i++)
{
cnt++;
ASC_UNIT[cnt].station= 1; // Modbus Device Address
ASC_UNIT[cnt].fun= 2;
// Read Input Status
ASC_UNIT[cnt].words= DD_MAX_POLL; // 960 points
ASC_UNIT[cnt].req_addr= i*DD_MAX_POLL; // relay start address
}
if( n>0)
{
cnt++;
ASC_UNIT[cnt].station= 1; // Modbus Device Address
www.plcworld.cn
ASC_UNIT[cnt].fun= 2;
// Read Input Status
ASC_UNIT[cnt].words= n;
// residue of points
ASC_UNIT[cnt].req_addr= m*DD_MAX_POLL; // relay start
address
}
// create polling unit for Reading Holding Register
m= ED_MAX / ED_MAX_POLL;
n= ED_MAX % ED_MAX_POLL;
for(i=0; i<m; i++)
{
cnt++;
ASC_UNIT[cnt].station= 1; // Modbus Device Address
ASC_UNIT[cnt].fun= 3;
// Read Input Status
ASC_UNIT[cnt].words= ED_MAX_POLL; // 60 points
ASC_UNIT[cnt].req_addr= i * ED_MAX_POLL; // register start
address
}
if(n >0)
{
cnt++;
ASC_UNIT[cnt].station= 1; // Modbus Device Address
ASC_UNIT[cnt].fun= 3;
// Read Input Status
ASC_UNIT[cnt].words= n;
// residue of points
ASC_UNIT[cnt].req_addr= m * ED_MAX_POLL; // register start
address
}
// create polling unit for Reading Input Register
m= ED_MAX / ED_MAX_POLL;
n= ED_MAX % ED_MAX_POLL;
for(i=0; i<m; i++)
{
cnt++;
ASC_UNIT[cnt].station= 1; // Modbus Device Address
ASC_UNIT[cnt].fun= 4;
// Read Input Status
ASC_UNIT[cnt].words= ED_MAX_POLL; // 60 points
ASC_UNIT[cnt].req_addr= i * ED_MAX_POLL; // register start
address
}
if(n >0)
{
cnt++;
ASC_UNIT[cnt].station= 1; // Modbus Device Address
www.plcworld.cn
ASC_UNIT[cnt].fun= 4;
// Read Input Status
ASC_UNIT[cnt].words= n;
// residue of points
ASC_UNIT[cnt].req_addr= m * ED_MAX_POLL; // register start
address
}
sprintf(MSG, "Initial Set Master Unit %d case", cnt+1);
msg_log(MSG);
return(0);
}
z byte
buffer
z Response Message DIDOAIAO
Common Variable Slave COM Port
Interval
z 3
Unit
www.plcworld.cn
Modbus/TCP Master
7.1
z Modbus TCP Master Type Driver Remote connect
Modbus Device
z Modbus TCP Slave Type Driver
z DIDOAIAO Unit
z Modbus/TCP Slave
(4-25)Modbus/TCP Master
www.plcworld.cn
(4-26)Modbus/TCP Master ()
MST7188.prj
MST7188 BC 3.0 Project file
MST7188.c
7188e.h
7188E System API Head File
7188el.lib
7188E System API Library Large Model
TCPIP.h
7188E System API Head File for TCP/IP
TCPIPL.lib
7188E System API Library Large Model for
TCP/IP
MST7188.h
Modbus Common Varaible and constant define
head file
7188TCP.h
Modbus/TCP Common Varaible and constant
define head file
MStcpDR.c
Modbus TCP Master driver
MBtcpDR.c
Modbus TCP Slave driver
MOD_Sub.c
Modbus Common Subroutine
RS232XB.c
7188E or 7524 Common COM port Subroutine
TCP_SUB.c
7188E Common TCP/IP Subroutine
www.plcworld.cn
stepT 0: Remote
Server Connect
stepT 2, 4: 5
connect
stepT 5: unit
Query Message
stepT 10:
Response Message
stepT 99:
3 Remote
Server Connect
(4-27)Modbus/TCP Master
www.plcworld.cn
modbus_master_TCP_main()
{
int i, len, ch;
unsigned int crc, crc_r;
unsigned char *cptr, bf[10];
unsigned long set;
switch(stepT)
{
case 0:
// Set NonBlock Mode for I/O
set = 1;
ioctlsocket(OUT_SOCKET, FIONBIO, (unsigned long*) &set);
if(connect(OUT_SOCKET, (struct sockaddr *)&SST[OUT_SOCKET].sin,
sizeof(SST[OUT_SOCKET].sin)) == SOCKET_ERROR )
{
if(errno == EINPROGRESS)
{
FD_ZERO(&fd_write);
FD_SET(OUT_SOCKET,&fd_write);
selectsocket(OUT_SOCKET, 0, &fd_write, 0, &SELTIME);
if(FD_ISSET(OUT_SOCKET, &fd_write)) {}
stepT=2 ;
sprintf(MSG, "Remote modbus server connecting......");
msg_log(MSG);
}
else
{
sprintf(MSG, "Connect remote modbus server error-2 rtc=%d ", errno);
msg_log(MSG);
stepT= 99; // continue try to connect
old_nsecT= SECOND * 100 + NSEC;
}
}
else
{
stepT= 2;
www.plcworld.cn
// wait 5 sec.
stepT= 5;
sprintf(MSG, "Remote modbus server Connect OK.........");
msg_log(MSG);
}
break;
case 5:
c_caseT++;
if(c_caseT >= MODBUS_MASTER_UNIT_MAX) c_caseT= 0;
if(TCP_UNIT[c_caseT].station == -1) c_caseT= 0;
// prepare request command
if(TCP_UNIT[c_caseT].station == -1)
{ stepT= 5; return; }
memset(outbuff_T, 0, sizeof(outbuff_T));
len= 6;
outbuff_T[len++]= TCP_UNIT[c_caseT].station;
outbuff_T[len++]= TCP_UNIT[c_caseT].fun;
cptr=(unsigned char *)&TCP_UNIT[c_caseT].req_addr;
outbuff_T[len++]=*(cptr+1);
outbuff_T[len++]=*(cptr);
cptr=(unsigned char *)&TCP_UNIT[c_caseT].words;
outbuff_T[len++]= *(cptr+1);
outbuff_T[len++]=*(cptr);
www.plcworld.cn
www.plcworld.cn
// it has data
{
stepT= 25;
}
break;
case 25: //
mod_save_TCP();
old_nsecT= SECOND * 100 + NSEC;
stepT= 30;
break;
case 30:
// waiting 0.1 sec and then polling next unit
if( nsec_out_check(old_nsecT, 10)==0 )
{ return; } // during comm.
else
{
// receive data finish
stepT= 5; // goto polling
}
break;
case 99: // waiting 3 second for next polling
if( nsec_out_check(old_nsecT, 300)==0 )
// wait 3 sec.
{ return; } // still waiting
else
{
stepT= 0; // goto connect again
www.plcworld.cn
reconnect();
}
break;
} // switch(stepD)
return;
}
www.plcworld.cn
else
{
cptr= (unsigned char *)&max;
*(cptr)= 0xFF;
*(cptr+1)= 0xFF;
*(cptr+2)= 0xFF;
*(cptr+3)= 0xFF;
delta= (int) ((max- OLD_TIMER_MS) + ms);
}
NNSEC= NNSEC + delta;
if(NNSEC >= 1000)
{
SECOND= SECOND + NNSEC/1000;
if(SECOND >=60)
{
SECOND= SECOND - 60;
MINUTE= MINUTE+1;
if(MINUTE >= 60) MINUTE= MINUTE - 60;
}
NNSEC= NNSEC % 1000;
}
www.plcworld.cn
NSEC= NNSEC/10;
OLD_TIMER_MS= ms;
//
Print("%d %d %d\n\r", MINUTE, SECOND, NSEC);
}
/*-------------------------------------------------------------------------*/
/* init NSEC SECOND
*/
/*-------------------------------------------------------------------------*/
void get_nsec_init(void)
{
if(TIMER_FLAG==0)
{
TimerOpen();
TIMER_FLAG= 1;
TimerResetValue();
OLD_TIMER_MS= TimerReadValue();
NSEC= 0;
SECOND= 0;
MINUTE= 0;
NNSEC= 0;
}
}
www.plcworld.cn
Demo
Demo
PC Based Controller
2.2.Utility
8.1
Demo7524 COM Port
ICP7524 Common Variable DIDOAIAO
COM1
ASCIIPC COM1
RTUPC COM2
7524 COM3
7524 COM4
PC-1Win-2000
ICP7524
PC-2Win-2000
Modbus_Tool
Demo7524
7188XW
Modbus_Tool
(4-28)Demo7524
www.plcworld.cn
(4-29)Demo7524
Demo7524
Holding Register
www.plcworld.cn
40105 2748
Query Message and Response
Message
COM1
ASCIIPC COM1
ASCIIPC COM2
7524 COM3
7524 COM4
PC-1Win-2000
ICP7524
PC-2Win-2000
Modbus_Tool
MST7524A
7188XW
Modbus_Tool
(4-31)Demo7524A
www.plcworld.cn
COM2 9600 O 7 1
3. TXRXGND Pin TX RX GND
4.
5.
6.
7.
8.
10. 7 8
11. MST7524R
www.plcworld.cn
(4-32)MST7524A
MST7524A
Input Register
www.plcworld.cn
Output Coil
00001 00005 On
www.plcworld.cn
ASCIIPC COM1
COM1
7524 COM3
RTUPC COM2
TCPEthernet
7524 COM4
Ethernet
PC-1Win-2000
ICP7188E5
PC-2Win-2000
Modbus_Tool
Demo7188
7188XW
Modbus_Tool
(4-35)Demo7188
2. PC-1PC-2ICP7188E5 IP Address
NetMask PC-1 192.168.127.2 PC-2
192.168.127.10 ICP7188E5 192.168.127.253
3. ICP7188E5 Modbus/TCP Slave
Client Connect PC-1PC-2 Master TCP
4. PC-2 COM1 ICP7188E5 COM1 7188XW
ICP7188E5 TXRX
GND ICP COM1 Port
5. PC-1Master TCP [send command] Button
ICP7188E5 Common Variable AO
5.1 Function CodeHolding Register(Addr:4xxxxx)
5.2 Modbus Device Address1
5.3 Relay/Register Address200
5.4 Communication Words/Bits50
6. PC-1Master TCP Mouse 40200
Decimal [Set Data Value] Button
www.plcworld.cn
(4-36)Demo7188
Demo7188
client connect
Holding Register
www.plcworld.cn
www.plcworld.cn
COM1
Ethernet
PC-1Win-2000
ICP7188E5
PC-2Win-2000
Modbus_Tool
Demo7188
7188XW
Modbus_Tool
(4-38)MST7188
www.plcworld.cn
(4-39)MST7188
MST7188
Connect Remote Server
www.plcworld.cn
www.plcworld.cn
8.3 OPC
OPC OPC
Trial_Modbus Trial_ModbusTCP OPC Server OPC
Server 2 Trial Version OPC Server
OPC Client
Demo7524 Modbus OPC Server COM Port
Modbus OPC Server ICP7524 Common Variable
DIDOAIAO
COM1
OPCPC COM2
OPCPC COM1
7524 COM4
7524 COM3
PC-1Win-2000
ICP7524
PC-2Win-2000
OPCTrial_Modbus
Demo7524
7188XW
OPCTrial_Modbus
OPC Sample Client
(4-42)Demo7524 OPC
www.plcworld.cn
Properties
6.1 NameDevice1
6.2 Data TypeModbus
6.3 Comm PortCOM1
6.4 Address1 ( Modbus Device Address)
6.5 TimeoutWord SwapSimulation I/O
7. PC-1 Device1 Mouse
Menu [Add][New Group] Group
8. PC-1 Device1 Group Mouse
Menu [Add][New Tag] TAG Tag
Properties
8.1 Tag1Location 2Output RegisterData Type INT properties
8.2 Tag2Location 5Output CoilData Type BIT properties
8.3 Tag3Location 15Output RegisterData Type INT properties
8.4 Tag4Location 20Output CoilData Type BIT properties
9. PC-2 6 8 Device1 Properties Comm Port
COM2
10. PC-1PC-2 configure Menu [File][Save]
test.tdb
11. PC-1PC-2 Menu [View][Monitor]
Value Bad
12. PC-1 Program Shortcut [SunWare OPC Server][OPC Sample
Client] OPC Client Menu [OPC][Connect]
Select OPC Server Dialog Box OPC Server
NameSunWareCorp.Trial_Modbus Name
13. OPC Client Menu [OPC][Add Item] Add Item Dialog Box
OPC Server DeviceGroupTag TAG
Tag
14. Mouse Tag Menu [OPC][Write Value to Item]
Write Value to Item Dialog Box [OK] Button
ICP7524 TAG
Output Coil
0 Off 0 On
15. PC-2 OPC OPC
ICP7524
16. PC-2 OPC Sample Client
OPC
17. OPC Server Background OPC Server OPC
Sample Client OPC Sample Client 12 14
www.plcworld.cn
www.plcworld.cn
www.plcworld.cn
COM1
Ethernet
PC-1Win-2000
ICP7188E5
PC-2Win-2000
OPCTrial_ModbusTCP
Demo7188
7188XW
VB6OPC Client
OPCTrial_ModbusTCP
VB6OPC Client
(4-47)Demo7188 OPC
Data TypeModbus
Comm PortPort1
Address1 ( Modbus Device Address)
TimeoutWord SwapSimulation I/O
www.plcworld.cn
www.plcworld.cn
(4-49)VB6: OPCClient_Demo
www.plcworld.cn
(4-50)VB6: OPCClient_Demo ()
www.plcworld.cn
Modbus
OPC Server Client
1.1 OPC
OPC OLE for Process Control
DCSPLC
Driver MIS
1.2 OPC
z Plant Floor
command
(A)
(B)
OPC Client
OPC Client
Ethernet
OPC Server
OPC Server
OPC Server
Vendor A
Vendor B
Vendor C
(5-1)OPC
www.plcworld.cn
z
z
z
z
OPC Server
OPC Client
Client Driver OPC Server
OPC Server
VBDelphiPower Builder
OPC Server
OPC OPC
Server
OPC
PC Automation
VB
OPC Automation
Interface
Wrapper
Local or Remote
OPC Server
C++
Physical Device or
Database
(5-2)OPC
www.plcworld.cn
OPC Server
Server Client OPC COM
COM OPC client/server
Client
OPC Client Server
Client
C++
OPC Server
1.3 OPC
OPC
Online Data AccessAlarm and Event HandlingHistorical
Data Access SecuritybatchHistorical alarm and event data
access
OPC COM
OPC
custom COM Interface OLE Automation Interface VB
Excel DCOM Remote Client
z Online Data Access
DeviceGroupItem
Device
Group Group
Item
www.plcworld.cn
www.plcworld.cn
www.plcworld.cn
Scaling Range
z Raw Min Range Low
z Raw Max Range High
z Unit
z Min Range Low
z Max Range Low
www.plcworld.cn
(5-6)
Menu [Edit][Port]
Modbus COM Port
Port COM1 COM8
Baud Rate
ParityNoneOddEven
FlowRTSCTS
Data Bits
Stop Bits
www.plcworld.cn
Modbus/TCP TCP/IP
PortTCP/IP Port1 Port8
IP Address Remote Modbus
Device IP Address
TCP PortModbus 502
(5-9)OPC Server
www.plcworld.cn
DeviceGroupTag
Status Bar Demo 120
Demo TAG Quality Flag Bad
Menu [View][Monitor]
www.plcworld.cn
PLCDCS
VB Driver
OPCClient_Demo VB OPC Data Access V1.0 and
V2.0 Server
VB 6.0
z Local or Remote Server OPC Server
z TAG Item SnychronizeUnsnychronize
TAG
z TAG Quality
z TAG OPC Server
www.plcworld.cn
(5-11)OPCClient_Demo
www.plcworld.cn
www.plcworld.cn
(5-12)OPCClient_Demo
www.plcworld.cn
www.plcworld.cn
Option Explicit
Option Base 1
' OPC Interface object
Dim IconServer As OPCServer ' OPC server object Server
Dim RemoteServer As OPCServer ' OPC server object OPC Server list
Dim IconGroups As OPCGroups ' collection of groups Group
Private WithEvents IconGroup As OPCGroup ' individual group Group
Dim IconItems As OPCItems 'collection of items Group Item
Dim OneItem_A As OPCItem 'Single item Write TAG Item
Dim OneItem_B As OPCItem 'Single item
Dim OneItem_C As OPCItem 'Single item
'item object Item read/write
'Public OpcItem As IOPCItem
Dim ClientHandles(3) As Long
Dim ServerHandles() As Long
Dim Errors() As Long
Dim pQuality As Variant
Dim pTimestamp As Variant
Dim ItemIDs(3) As String
Dim AccessPaths(3) As String
Dim Active(3) As Boolean
Dim bServerStarted As Boolean
Dim bReadOn As Boolean
Dim ItemCount As Integer
Dim ReadValue() As Variant
z
www.plcworld.cn
www.plcworld.cn
End If
If TypeName(IconServer) = TypeName(Nothing) Then
MsgBox "Connect Error" ' OPC Server
Return
Else
MsgBox "Connect OK"
End If
' Server group
Set IconGroups = IconServer.OPCGroups
' group group
' Group Name
Set IconGroup = IconGroups.Add("Group One")
IconGroup.IsSubscribed = True
www.plcworld.cn
www.plcworld.cn
Else
MsgBox "Read Data OK"
Form1.Value(14) = ReadValue(1)
Form1.Value(15) = ReadValue(2)
Form1.Value(16) = ReadValue(3)
End If
End Sub
' Data Change Event handler fired by group subscription callback
' OPC Server OPC Client ,
' call ,
Private Sub IconGroup_DataChange(ByVal TransactionID As Long, ByVal NumItems
As Long, ClientHandles() As Long, ItemValues() As Variant, Qualities() As Long,
TimeStamps() As Date)
' MsgBox "CallBack Data OK"
Dim i, m, n As Integer
For i = 1 To NumItems
If ClientHandles(i) > 0 Then
Form1.Value(ClientHandles(i)) = ItemValues(i)
m = 3 + ClientHandles(i)
Form1.Value(m) = Qualities(i)
n = 6 + ClientHandles(i)
Form1.Value(n) = TimeStamps(i)
End If
Next i
End Sub
z
www.plcworld.cn
www.plcworld.cn
2 Gateway
PLC
PLC
RS232RS422
RS485 115Kbps
PLC
RS232 RS485
Modbus(RTU, ASCII)
PLC
PLC PLC Modbus
PC PLC
PC PC-Base Controller
Size 7524
7188E
Multi-Gateway
2.1
Modbus
Multi-Gateway
PLC
(5-14)Multi-Gateway (1)
www.plcworld.cn
PLC
PLC
PLC Modbus
Multi-Gateway PLC
2.2
Multi-Gateway (2)
CCTV
Multi-Gateway
A-type PLC
(5-15)Multi-Gateway (2)
PLC2
PLC
PLC Multi-Gateway
PLC
PLC
baud rates Multi-Gateway PC
www.plcworld.cn
2.3
RS232C
RS232C
Ethernet
(5-16)Multi-Gateway (3)
z Modbus
EthernetModbus ModbusTCP
Modbus Serial Modbus Gateway
z
z Power ON
www.plcworld.cn
Modbus
1 Utility
Check List
1.
1.1
RS232422485
12002400480096001920038400
57600115200
1.3 Parity
NoneOddEven
78
Modbus RTU Format
8 bits
ASCII Format 7
bits 8 bits
12
RS232 15
1.10 RS232
01
PC
1.11 RS485
2. Ethernet
www.plcworld.cn
2.1 IP Address
Modbus IP Address
Modbus Slave IP
Address Modbus Master Driver
Remote IP Address
2.2 IP Address
IP Address
2.3 NetMask
NetMask
Pin
2.7
2.8
2.9
Ping
3. Modbus
3.1 Modbus Address RS485 Modbus
AddressID No.
1 247
3.3
Relay/Register Modbus Output CoilInput
Type
StatusInput RegisterHolding Register
Modbus Protocol Function Code1
234561516
3.4
3.5
Relay/Register
3.6
Relay/Register
Holding Register
Modbus
www.plcworld.cn
3.7
3.8
Type
Address
Unit
Code code
3.10 ASCII LRC error Modbus Slave
LRC
3.11 RTU CRC error Modbus Slave
CRC
3.12 RTU Message Modbus RTU Message
3.5
4.
4.1 COM Port COM Port
4.2 Cable
Pin
4.3
RS232/422/485
Modbus Master
10 millsecond
www.plcworld.cn
5. Utility Program
Check
(6-1)Modbus
1.1
Pin
Master
Slave
25 Pin
9 Pin
RX
RX
TX
TX
GND
GND
www.plcworld.cn
Master
Slave
25 Pin
9 Pin
RX
RX
TX
TX
GND
GND
RTS
RTS
CTS
CTS
DCD
DCD
20
DTR
DTR
DSR
DSR
Master
Slave
25 Pin
9 Pin
RX
RX
TX
TX
GND
GND
RTS
RTS
CTS
CTS
DCD
DCD
20
DTR
DTR
DSR
DSR
RS485 Pin
Master
Slave
Data +
Data +
Data -
Data -
www.plcworld.cn
(6-5)RS485 Pin
RS422 Pin
Master
Slave
RXDA -
RXDA -
RXDB +
RXDB +
TXDA -
TXDA -
TXDB +
TXDB +
(6-6)RS422 Pin
Utility Modbus
Master Slave
HubSwitch
Utility
Modbus Slave PLCPID
RS232
Ethernet
Modbus Slave
Program
RS232/485
www.plcworld.cn
(6-7)(1)
PC HMI/SCADA System
ICP 75247188
Demo7524Demo7188
(6-8)(2)
RS485 PID
Modbus RS485
RS485 CRC check
error RS232/485
Modbus Master RS232C Port
2 Modbus
z floatlong integer Modbus Protocol Register
16 bits integer 32767 ~ 32768
floatlong integer
PID 16 bits integer float
long integer 32 bits4 bytes
Register 4 bytes
Register Address
PID Controller Register Address Modbus Slave Type
Regsiter Address
Protocol Offset
Data Type
40001
float
40003
float
Manipulator Value
(MV)
40005
float
40007
float
etc.
(6-9)Data Type
www.plcworld.cn
3 Modbus
Modbus Protocol
z Modbus Protocol
http://www.modbus.org.com/default.htm
z
http://www.schneider-electric.com
z OPC OPC
http://www.opcfoundation.org
www.plcworld.cn
4 Sample Program
Demo Program
\Cbuilder50\Modbus_Tool\SRC
\Cbuilder50\Modbus_Tool\Install
\Cbuilder50\MB_SUB\SRC
\ICP\Demo7524
\ICP\Demo7188
\ICP\MST7524A
\ICP\MST7524R
\ICP\MST7188
\OPC\Trial_Modbus
\OPC\Trial_ModbusTCP
\VB6\OPCClient_Demo
(6-11)Sample Program