技术论坛

C脚本中使用MSCOMM如何发送0字符,VB脚本中如何发送大于128的字符,虽然是非主流话题,但的确客户需要,希望斑主不要删帖

作者 主题
侠圣

经验值: 3640
发帖数: 780
精华帖: 58
主题:C脚本中使用MSCOMM如何发送0字符,VB脚本中如何发送大于128的字符,虽然是非主流话题,但的确客户需要,希望斑主不要删帖


只看楼主 只看精华 楼主 2009-12-01 15:28:18
如题,客户要在WINCC中实现MODBUS RTU 协议(做为从站)与一个远端的DCS进行通讯.我已经用了很多方法,可就是这样,在C脚本中用MSCOMM控件无法发送0字符,在VB中又无法发送大于128的字符.当然我更希望在C脚本中实现发送0字符,毕竟C脚本处理数据的功能要强很多.
最后的方法我就是使用API了!不过实在不希望使用API.
 
以下网友喜欢您的帖子:

  
重要声明:

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

帖子链接:https://www.ad.siemens.com.cn/club/bbs/post.aspx?b_id=5&a_id=626729&s_id=0&num=14

侠圣

经验值: 2860
发帖数: 1760
精华帖: 55
回复:C脚本中使用MSCOMM如何发送


只看楼主 只看精华 1楼 2009-12-01 15:49:51
是字符串"0",还是Ascii码0?
超出128可能就不是字符了吧?难道有中文信息?
非淡泊无以明志,非宁静无以致远
以下网友喜欢您的帖子:

  
侠圣

经验值: 3640
发帖数: 780
精华帖: 58
回复:C脚本中使用MSCOMM如何发送


只看楼主 只看精华 楼主 2楼 2009-12-01 16:10:40
谢谢关注!
是ASCII码0.
不是有中文信息,因为是MODBUS RTU可能值大于128的.
 
以下网友喜欢您的帖子:

  
侠圣

经验值: 2860
发帖数: 1760
精华帖: 55
回复:C脚本中使用MSCOMM如何发送


只看楼主 只看精华 3楼 2009-12-01 21:12:02
额,忘了WinCC中的Mscomm控件只支持字符串格式了。

以前有个帖子也是讨论这个的:
http://www.ad.siemens.com.cn/club/bbs/post.asp?b_id=5&a_id=284783&s_id=0&num=12#anch
非淡泊无以明志,非宁静无以致远
以下网友喜欢您的帖子:

  
版主

经验值: 26270
发帖数: 10646
精华帖: 130
回复:C脚本中使用MSCOMM如何发送


只看楼主 只看精华 4楼 2009-12-01 23:05:53
谢谢,
看来楼主还需要跟3楼学习一下搜索的习惯。

微信公众号:PLC标准化编程,ZHO6371995
以下网友喜欢您的帖子:

  
yhk
侠客

经验值: 659
发帖数: 572
精华帖: 2
回复:C脚本中使用MSCOMM如何发送


只看楼主 只看精华 5楼 2009-12-02 09:54:47
MSCOMM是一个跟常用的控件,做第三方通讯经常要用到
一半是火焰,一半是海水
以下网友喜欢您的帖子:

  
侠圣

经验值: 2860
发帖数: 1760
精华帖: 55
回复:C脚本中使用MSCOMM如何发送
精华帖精华帖星级4级


只看楼主 只看精华 6楼 2009-12-03 09:13:46
几经努力,这个问题应该算是可以得到解决了,呵呵。

对于字符串来说,C中的ASCII 0代表结束符,而VBS的CHR只支持到0~127,所以要解决这个问题,MsComm控件发送时必须使用Byte()格式的字节数组数据,接收也必须使用comInputModeBinary的接收方式。
不过遗憾的是VBS并不直接支持Byte()格式,其实我们声明的Dim SendByte(x)只是Variant()格式,因此需要想办法将其转换为Byte()格式就能拿来用了。
目前我的做法是用VB编写一个DLL文件,用于实现Variant()和Byte()之间的互相转化。
经测试,0~255的ASCII均可发送和接受,下面是效果图:




示例文件如下(WinCC V6.2 SP3)以及DLL文件(使用之前请选用RegSvr32.exe 注册一下)见附件:

点击此处查看附件
非淡泊无以明志,非宁静无以致远
以下网友喜欢您的帖子:

  
版主

经验值: 16160
发帖数: 8317
精华帖: 18
回复:C脚本中使用MSCOMM如何发送


只看楼主 只看精华 7楼 2009-12-03 11:44:33
谢谢分享。
但如果通讯量较大时,不宜放在WinCC中实现。还是外挂为好。
无论成与败,无论甜与苦,我还是我。
以下网友喜欢您的帖子:

  
侠圣

经验值: 2860
发帖数: 1760
精华帖: 55
回复:C脚本中使用MSCOMM如何发送


只看楼主 只看精华 8楼 2009-12-03 14:10:10
城版客气了,其实我应该感谢“四书五经”,这个问题其实是我一直都想解决的问题,呵呵。刚才用Winsock控件试了一下,也可以使用这个DLL文件来实现字节数组的发送和接受。

另外版主说的极是,尤其是楼主要做Modbus Slave,编程难度很大啊。

非淡泊无以明志,非宁静无以致远
以下网友喜欢您的帖子:

  
版主

经验值: 26270
发帖数: 10646
精华帖: 130
回复:C脚本中使用MSCOMM如何发送


只看楼主 只看精华 9楼 2009-12-03 14:58:26
为啥不用上面引用帖子中提到的那个DLL?

微信公众号:PLC标准化编程,ZHO6371995
以下网友喜欢您的帖子:

  
侠圣

经验值: 3640
发帖数: 780
精华帖: 58
回复:C脚本中使用MSCOMM如何发送


只看楼主 只看精华 楼主 10楼 2009-12-06 12:43:37
感谢万版主和 dcount107大侠的帮助,D侠前面帖子提供的链接,前面也看过,不过实在惭愧,当时只是觉得VBS处理数据的能力不如C,一心还是想用C脚本来实现,就没有仔细的去分析链接中提供的程序。诚如D侠所说,通过DLL文件进行相应的类型转换的确可以实现发送大于127的字符,不过VBS的数据处理功能还是较弱,最后还是用C脚本和API函数实现了发送数据,用MSCOMM实现接收数据,实现了简单的MODBUS协议。
在画面打开事件中写如下代码:
Sub OnOpen()
Dim COMM1
Set COMM1 = HMIRuntime.Screens("main").ScreenItems("MScomm1")
HMIRuntime.Trace "OK1"
If COMM1.PortOpen = False Then
COMM1.Commport = 3
' Values: 9600 Baud, N - No Parity, 8 - Databit, 1 - Stopbit
COMM1.Settings = "9600,N,8,1"
COMM1.RThreshold = 8
COMM1.SThreshold = 0
COMM1.InputLen = 0
COMM1.InputMode=1
COMM1.InBufferSize=1024
COMM1.NullDiscard=False
COMM1.PortOpen = True
Else
HMIRuntime.Trace("Port is already opened." & vbCrLf)
End If
End Sub
MSCOMM的OnComm事件中写如下代码:
Sub X63A7X4EF62X0000C_OnComm(Byval Item) Dim st
Dim buff(1024)
Dim n,t,i
Dim rscomm
Dim tagobj

Set rscomm=HMIRuntime.Screens("main").ScreenItems("MScomm1")
HMIRuntime.Trace "inbuffercount=" & rscomm.InBufferCount & vbCrLf
HMIRuntime.Trace "commevent=" & rscomm.CommEvent & vbCrLf
If (rscomm.CommEvent=2 ) And (rscomm.InBufferCount>=8) Then
st=rscomm.input
rscomm.InBufferCount =0
For i=1 To lenb(st)
buff(i)=ASCB(MidB(st,i,1))
HMIRuntime.Trace buff(i) & vbCrLf
Next
'固定的MODBUS协议,CRC校验预先算好,呵呵,VB做CRC较验比较麻烦,客户就是要求读取几个模拟量
If (buff(1)=2) And (buff(2)=3) And (buff(6)=&H04) And (buff(7)=&H44) And (buff(8)=&H3a) Then
HMIRuntime.Trace "ok1" & vbCrLf
Set tagobj=HMIRuntime.Tags("TrigComm") '接收完成,触发全局C动作
tagobj.Read
tagobj.value=True
tagobj.Write
End If
End If
End Sub
帖子太长,下面另起一帖写C脚本代码
 
以下网友喜欢您的帖子:

  
侠圣

经验值: 3640
发帖数: 780
精华帖: 58
回复:C脚本中使用MSCOMM如何发送
精华帖精华帖星级5级


只看楼主 只看精华 楼主 11楼 2009-12-06 13:05:05
在全局C脚本中写一个全局动作,动作的触发条件是TAG触发,触发变量为"TrigComm"
#include "apdefap.h"

int gscAction( void )
{
typedef struct _COMMTIMEOUTS {
DWORD ReadIntervalTimeout; /* Maximum time between read chars. */
DWORD ReadTotalTimeoutMultiplier; /* Multiplier of characters. */
DWORD ReadTotalTimeoutConstant; /* Constant in milliseconds. */
DWORD WriteTotalTimeoutMultiplier; /* Multiplier of characters. */
DWORD WriteTotalTimeoutConstant; /* Constant in milliseconds. */
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
typedef struct _DCB {
DWORD DCBlength; /* sizeof(DCB) */
DWORD BaudRate; /* Baudrate at which running */
DWORD fBinary: 1; /* Binary Mode (skip EOF check) */
DWORD fParity: 1; /* Enable parity checking */
DWORD fOutxCtsFlow:1; /* CTS handshaking on output */
DWORD fOutxDsrFlow:1; /* DSR handshaking on output */
DWORD fDtrControl:2; /* DTR Flow control */
DWORD fDsrSensitivity:1; /* DSR Sensitivity */
DWORD fTXContinueOnXoff: 1; /* Continue TX when Xoff sent */
DWORD fOutX: 1; /* Enable output X-ON/X-OFF */
DWORD fInX: 1; /* Enable input X-ON/X-OFF */
DWORD fErrorChar: 1; /* Enable Err Replacement */
DWORD fNull: 1; /* Enable Null stripping */
DWORD fRtsControl:2; /* Rts Flow control */
DWORD fAbortOnError:1; /* Abort all reads and writes on Error */
DWORD fDummy2:17; /* Reserved */
WORD wReserved; /* Not currently used */
WORD XonLim; /* Transmit X-ON threshold */
WORD XoffLim; /* Transmit X-OFF threshold */
BYTE ByteSize; /* Number of bits/byte, 4-8 */
BYTE Parity; /* 0-4=None,Odd,Even,Mark,Space */
BYTE StopBits; /* 0,1,2 = 1, 1.5, 2 */
char XonChar; /* Tx and Rx X-ON character */
char XoffChar; /* Tx and Rx X-OFF character */
char ErrorChar; /* Error replacement char */
char EofChar; /* End of Input character */
char EvtChar; /* Received Event character */
WORD wReserved1; /* Fill for now. */
} DCB, *LPDCB;
#pragma code("kernel32.dll")
BOOL WriteFile( HANDLE hFile, LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten, LPVOID lpOverlapped );
DWORD GetLastError(VOID);
VOID Sleep( DWORD dwMilliseconds );
BOOL CloseHandle(
HANDLE hObject
);
HANDLE CreateFileA(
LPCSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
BOOL GetCommTimeouts( HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts );
BOOL SetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts );
BOOL GetCommState( HANDLE hFile, LPDCB lpDCB );
BOOL SetCommState( HANDLE hFile, LPDCB lpDCB );
BOOL BuildCommDCBA(LPCSTR lpDef,LPDCB lpDCB );
#pragma code()

#define GetObjectA GetObject
int i;
union{ /*定义一个联合*/
float f1;
struct{ /*在联合中定义一个结构*/
char first;
char second;
char third;
char forth;
}half;
}data;

struct{
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
LONG hEvent;
}ov1,*ov2;

char st1[100];
unsigned short crc;
DWORD n1;
HANDLE hFile;
COMMTIMEOUTS ctmoOld,ctmoNew;
DCB dcbCommPort;
__object *pdl = NULL;
__object *pic = NULL;
__object *obj = NULL;

if (GetTagBit("TrigComm")==0) return 0;
pdl = __object_create("PDLRuntime");
pic = pdl->GetPicture("MAIN");
obj = pic->GetObject("MScomm1");
data.f1=GetTagFloat("AA1");//获取数据
st1[0]=02;
st1[1]=03;
st1[2]=8;
st1[3]=data.half.first;
st1[4]=data.half.second;
st1[5]=data.half.third;
st1[6]=data.half.forth;
data.f1=GetTagFloat("AA2");
st1[7]=data.half.first;
st1[8]=data.half.second;
st1[9]=data.half.third;
st1[10]=data.half.forth;
crc=Calc_Crc((unsigned char *)st1,11);//计算CRC
st1[11]=crc & 0x00ff;
st1[12]=(crc & 0xff00)>>8;
obj->PortOpen=FALSE;
hFile = CreateFileA("COM3",0x80000000 0x40000000,0,NULL,3,0,NULL);
printf("HFILE=%d",hFile);
GetCommTimeouts(hFile,&ctmoOld);
ctmoNew.ReadTotalTimeoutConstant = 100;
ctmoNew.ReadTotalTimeoutMultiplier = 0;
ctmoNew.WriteTotalTimeoutMultiplier = 0;
ctmoNew.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(hFile, &ctmoNew);
dcbCommPort.DCBlength = sizeof(DCB);
GetCommState(hFile, &dcbCommPort);
BuildCommDCBA("9600,N,8,1", &dcbCommPort);
SetCommState(hFile, &dcbCommPort);
WriteFile(hFile, st1,13, &n1, NULL);//通过串口发送数据
printf("n1=%d",n1);
Sleep(400);
CloseHandle(hFile);
obj->PortOpen=TRUE;
SetTagBit("TrigComm",FALSE);
__object_delete(obj);
__object_delete(pic);
__object_delete(pdl);
return 0;
最终显示效果如下:


 
以下网友喜欢您的帖子:

  
版主

经验值: 26270
发帖数: 10646
精华帖: 130
回复:C脚本中使用MSCOMM如何发送


只看楼主 只看精华 11楼 2009-12-06 17:55:35
VBS和C脚本结合,呵呵
够乱的
微信公众号:PLC标准化编程,ZHO6371995
以下网友喜欢您的帖子:

  
侠客

经验值: 616
发帖数: 7
精华帖: 0
回复:C脚本中使用MSCOMM如何发送


只看楼主 只看精华 12楼 2010-03-31 21:33:43
dcount107 大侠上传的那个附件我下载下来看了一下,只能发但是接受部分出问题了,而且有时候画面莫名的就不再反应了,还有人关注这帖子么,能不能为我解惑一下,谢谢了
 
以下网友喜欢您的帖子:

  
至圣

经验值: 12473
发帖数: 4956
精华帖: 81
回复:C脚本中使用MSCOMM如何发送
精华帖精华帖星级5级


只看楼主 只看精华 13楼 2010-04-03 16:04:01
在VBS脚本里变量都是以变体的形式存在的,但也还是有各种数据类型,只是有些是在VBS里无法构建的,比如Byte()
接收可以按楼上“四书五经”的方法直接解析,为了方便,我也做了转换的函数

附件包含DLL及VB源码和使用方法


点击此处查看附件
 
精华帖版主置评: N年前的经典帖, 内容可真丰富啊!
以下网友喜欢您的帖子:

  
版主

经验值: 26270
发帖数: 10646
精华帖: 130
回复:。。。。。。。。。。


只看楼主 只看精华 15楼 2016-04-20 22:02:53

老帖                


微信公众号:PLC标准化编程,ZHO6371995
以下网友喜欢您的帖子:

  
  • 上一页
  • 1
  • 下一页
收起
C脚本中使用MSCOMM如何发送"0"字符,VB脚本中如何发送大于128的字符,虽然是非主流话题,但的确客户需要,希望斑主不要删帖

现赠您1张1847体验会员卡,可免费领取,畅学1847会员内容,是否领取?

您收到0封站内信:
×
×
信息提示
很抱歉!您所访问的页面不存在,或网址发生了变化,请稍后再试。