电子器件

西门子S7-200,ModBus从站通讯程序

  一直看到有些朋友在问ModBus主从站的通讯问题,今天抽空儿给大家发几篇。事先申明,我是调用的主从站库,库本身并不是我编写的,我没有那么大的能耐。另外,上位机是用VB编写,VB本身不是很熟,如果有什么错误,请大家海谅。最后,这仅仅只是一个测试程序,如果各位想用到商业方面,还需要各位自己去完善。说明:plc从站,PC作主站,用ModBus协议进行通讯。PC机读取PLCVW区的数据;PC机还读取PLC内部I或者O地址的状态。/以下是PLC程序实现,方便贴出,已转换为STLTITLE=程序注释Network1//网络标题//在第一个循环周期内初始化Modbus从站协议LD SM0.1CALL SBR3,1,12,9600,0,0,128,32,1000,&VB0,M10.1,MB11Network2//在每个循环周期内执行Modbus从站协议LD SM0.0CALL SBR1,M10.2,MB12Network3LD SM0.0MOVW AIW0,VW100/I+54,VW100MOVW AIW2,VW102/I+54,VW102MOVW AIW4,VW104/I+54,VW104MOVW AIW6,VW106/I+54,VW106Network4LD SM0.0=Q0.0Network5LD I0.0=Q0.1Network6LD I0.1=Q0.2/以下是VB源码Option ExplicitPrivate Declare Function GetTickCount Lib“kernel32”()As LongDim x1Dim p11,p12,p13,p14,p15,p16,p17,p18Function CRC16(data()As Byte)As StringDim CRC16Lo As Byte,CRC16Hi As Byte‘CRC寄存器Dim CL As Byte,CH As Byte’多项式码&HA001Dim SaveHi As Byte,SaveLo As ByteDim i As IntegerDim Flag As IntegerCRC16Lo=&HFFCRC16Hi=&HFFCL=&H1CH=&HA0For i=0To UBound(data)CRC16Lo=CRC16Lo Xor data(i)‘每一个数据与CRC寄存器进行异或For Flag=0To7SaveHi=CRC16HiSaveLo=CRC16LoCRC16Hi=CRC16Hi \2’高位右移一位CRC16Lo=CRC16Lo \2‘低位右移一位If(SaveHi And&H1)=&H1)Then’如果高位字节最后一位为1CRC16Lo=CRC16Lo Or&H80‘则低位字节右移后前面补1End If’否则自动补0If(SaveLo And&H1)=&H1)Then‘如果LSB为1,则与多项式码进行异或CRC16Hi=CRC16Hi Xor CHCRC16Lo=CRC16Lo Xor CLEnd IfNext FlagNext iDim ReturnData(1)As ByteReturnData(0)=CRC16Hi’CRC高位ReturnData(1)=CRC16Lo‘CRC低位CRC16=ReturnDataEnd FunctionPrivate Sub About_Click()frmAbout.ShowEnd SubPrivate Sub Form_Load()’初始化Timer1。Enabled=False‘定时器1无效Timer1。Interval=1000’定时器1时间为1STimer2。Enabled=True‘定时器2有效Timer2。Interval=1000’定时器2时间为1SText1。Text=“”Text2。Text=“”Text3。Text=“”Text4。Text=“”Text5。Text=“”Text6。Text=“”Text8。Text=“”Text10。Text=“”MSComm1。CommPort=1‘设定端口号MSComm1。Settings=“9600,n,8,1”’设定通讯波特率MSComm1。InBufferSize=1024‘接收缓冲器大小MSComm1。OutBufferSize=1024’输出缓冲器大小MSComm1。InputMode=comInputModeBinary‘以二进制传输MSComm1。RThreshold=1’MSComm1。SThreshold=0MSComm1。InputLen=0‘读取接收缓冲器所有字符MSComm1。OutBufferCount=0’清空发送缓冲区MSComm1。InBufferCount=0‘清空接收缓冲区If MSComm1。PortOpen=False ThenCommand3。Caption=“打开串口”ElseCommand3。Caption=“关闭串口”End IfEnd SubPrivate Sub Command1_Click()Timer1。Enabled=TrueEnd SubPrivate Sub Command2_Click()’退出程序,定时器1无效Timer1。Enabled=FalseClsUnload MeEnd SubPrivate Sub Command3_Click()On Error Resume NextIf MSComm1。PortOpen=False ThenMSComm1。PortOpen=TrueElseMSComm1。PortOpen=FalseEnd IfIf MSComm1。PortOpen Then‘打开关闭按钮显示文字Command3。Caption=“关闭串口”ElseCommand3。Caption=“打开串口”End IfIf Err Then’打开串口失败,则显示出错信息MsgBox Error$,48,“错误信息”Exit SubEnd IfEnd SubPrivate Sub Timer1_Timer()‘读V存储区数据Dim CRC()As ByteDim FGetData As StringDim aa()As ByteDim s As String

  Dim str As StringDim i As IntegerDim bb,cc As StringReDim aa(5)As Byte’定义动态数组aa(0)=&HCaa(1)=&H3aa(2)=&H0aa(3)=&H32aa(4)=&H0aa(5)=&H4CRC=CRC16(aa)str=CRCs=“”For i=1To LenB(str)s=s+Hex(AscB(MidB(str,i,1)Next ibb=Right(s,2)cc=Mid(s,1,2)If Len(s)<4Thencc=Mid(s,1,1)End IfReDim Preserve aa(0To7)As Byteaa(6)=Val(“&H”&bb)aa(7)=Val(“&H”&cc)MSComm1。OutBufferCount=0‘清空输出寄存器MSComm1。Output=aaFGetData=ReceiveDataText5。Text=FGetDatap11=Val(“&H”&Mid(FGetData,7,4)p12=Val(“&H”&Mid(FGetData,11,4)p13=Val(“&H”&Mid(FGetData,15,4)p14=Val(“&H”&Mid(FGetData,19,4)End SubPrivate Sub Command4_Click()’I状态Dim CRC()As ByteDim FGetData As StringDim aa()As ByteDim s As StringDim str As StringDim i As IntegerDim bb,cc As StringReDim aa(5)As Byte‘定义动态数组aa(0)=&HCaa(1)=&H2aa(2)=&H0aa(3)=&H0aa(4)=&H0aa(5)=&H1CRC=CRC16(aa)str=CRCs=“”For i=1To LenB(str)s=s+Hex(AscB(MidB(str,i,1)Next ibb=Right(s,2)cc=Mid(s,1,2)If Len(s)<4Thencc=Mid(s,1,1)End IfReDim Preserve aa(0To7)As Byteaa(6)=Val(“&H”&bb)aa(7)=Val(“&H”&cc)MSComm1。OutBufferCount=0’清空输出寄存器MSComm1。Output=aaFGetData=IReceiveDatap17=Val(“&H”&Mid(FGetData,7,2)p18=Val(“&H”&Mid(FGetData,9,2)End SubPrivate Sub Command5_Click()‘Q状态Dim CRC()As ByteDim FGetData As StringDim aa()As ByteDim s As StringDim str As StringDim i As IntegerDim bb,cc As StringReDim aa(5)As Byte’定义动态数组aa(0)=&HCaa(1)=&H1aa(2)=&H0aa(3)=&H0aa(4)=&H0aa(5)=&H1CRC=CRC16(aa)str=CRCs=“”For i=1To LenB(str)s=s+Hex(AscB(MidB(str,i,1)Next ibb=Right(s,2)cc=Mid(s,1,2)If Len(s)<4Thencc=Mid(s,1,1)End IfReDim Preserve aa(0To7)As Byteaa(6)=Val(“&H”&bb)aa(7)=Val(“&H”&cc)MSComm1。OutBufferCount=0‘清空输出寄存器MSComm1。Output=aaFGetData=QReceiveDatap15=Val(“&H”&Mid(FGetData,7,2)p16=Val(“&H”&Mid(FGetData,9,2)End SubPrivate Function ReceiveData()As String’返回V存储器区数据Dim FGetData As StringDim t1As LongDim av As VariantDim i As IntegerDim ReDataLen As IntegerFGetData=“”t1=GetTickCount()‘取时间,做延时用Do’循环等待接收数据DoEventsIf MSComm1。InBufferCount>0Then‘串口有数据了ReDataLen=MSComm1。InBufferCount’取数据长度av=MSComm1。Input‘将串口数据取出来For i=0To ReDataLen-1FGetData=FGetData&Right(“00”&Hex(av(i),2)Next iEnd IfIf Len(FGetData)>=6ThenIf Len(FGetData)>Val(“&H”&Mid(FGetData,5,2)*2+8ThenReceiveData=FGetDataExit FunctionEnd IfEnd IfIf GetTickCount-t1>2000Then’2秒没收完就不收了ReceiveData=“”Exit FunctionEnd IfLoopEnd FunctionPrivate Function IReceiveData()As String‘反回I状态Dim FGetData As StringDim t1As LongDim av As VariantDim i As IntegerDim ReDataLen As IntegerFGetData=“”t1=GetTickCount()’取时间,做延时用Do‘循环等待接收数据DoEventsIf MSComm1。InBufferCount>0Then’串口有数据了ReDataLen=MSComm1。InBufferCount‘取数据长度

  av=MSComm1。Input’将串口数据取出来For i=0To ReDataLen-1FGetData=FGetData&Right(“00”&Hex(av(i),2)Next iEnd IfIf Len(FGetData)>=6ThenIf Len(FGetData)>Val(“&H”&Mid(FGetData,5,2)*2+8ThenIReceiveData=FGetDataExit FunctionEnd IfEnd IfIf GetTickCount-t1>2000Then‘2秒没收完就不收了IReceiveData=“”Exit FunctionEnd IfLoopEnd FunctionPrivate Function QReceiveData()As String’反回Q状态Dim FGetData As StringDim t1As LongDim av As VariantDim i As IntegerDim ReDataLen As IntegerFGetData=“”t1=GetTickCount()‘取时间,做延时用Do’循环等待接收数据DoEventsIf MSComm1。InBufferCount>0Then‘串口有数据了ReDataLen=MSComm1。InBufferCount’取数据长度av=MSComm1。Input‘将串口数据取出来For i=0To ReDataLen-1FGetData=FGetData&Right(“00”&Hex(av(i),2)Next iEnd IfIf Len(FGetData)>=6ThenIf Len(FGetData)>Val(“&H”&Mid(FGetData,5,2)*2+8ThenQReceiveData=FGetDataExit FunctionEnd IfEnd IfIf GetTickCount-t1>2000Then’2秒没收完就不收了QReceiveData=“”Exit FunctionEnd IfLoopEnd FunctionPrivate Sub Timer2_Timer()x1=x1+1Text10。Text=str(x1)Text1。Text=str(p11)Text2。Text=str(p12)Text3。Text=str(p13)Text4。Text=str(p14)Text7。Text=str(p15)If Text7。Text=1Then Text7。BackColor=RGB(255,0,255)If Text7。Text=0Then Text7。BackColor=RGB(0,255,255)‘Text6。Text=str(p16)Text9。Text=str(p17)If Text9。Text=1Then Text9。BackColor=RGB(255,0,255)If Text9。Text=0Then Text9。BackColor=RGB(0,255,255)’Text8。Text=str(p18)End Sub