我定义了一个PLCCLASS类(PlcClass.pas),类中包含OPC的读写函数:
function plc_read_byte():integer;
function plc_write_word(ym:array of word):integer;
function Tplc.plc_read_byte():integer;
var
i:integer;
begin
result := -1;
for i:=0 to 5 do
begin
HR := ReadOPCGroupItemValue(GroupIf, jubinr[i],ItemValuer[i], ItemQuality);
end;
HR := 0;
if Succeeded(HR) then
begin
result := 1;
end
else
begin
result := -1;
exit;
end;
end;
function Tplc.plc_write_word(ym:array of word):integer;
var
i:integer;
begin
result :=-1;
HR := WriteOPCGroupItemValue(GroupIf,jubinw[0],ym[0]);
if Succeeded(HR) then
begin
result := 1;
showmessage('写入成功');
end
else
begin
result := -1;
exit;
end;
end;
同步读和同步写函数中变量及接口都定义在全局变量中(GOLBALVAR.pas)中。因为读和写的项不同,我在一个窗体(st.pas)中制作了2个按钮实现连接读和连接写,调用opcutils.pas中的各个函数,分别是;
procedure Tst_form.BitBtnCWClick(Sender: TObject);
var
i:integer;
begin
xiangnamew[0] := 'S7:[S7 connection_1]DB1,WORD0';
xiangnamew[1] := 'S7:[S7 connection_1]DB1,WORD2';
xiangnamew[2] := 'S7:[S7 connection_1]DB1,WORD4';
xiangnamew[3] := 'S7:[S7 connection_1]DB1,WORD6';
HR := GroupAddItem(GroupIf,xiangname[0], 0, VT_EMPTY,Item0Handle,ItemType); //函数在OPCutils.pas中
for i := 0 to 3 do
begin
HR := GroupAddItem(GroupIf,xiangnamew[i], 0, VT_EMPTY,Item0Handle,ItemType); //函数
end;
if Succeeded(HR) then
begin
memo1.Lines.add('添加数据item成功!');
end
else
begin
memo1.Lines.add('添加数据item失败!');
Exit;
end;
jubinw[i] := Item0Handle;
end;
end;
procedure Tst_form.BitBtnCRClick(Sender: TObject);
var
i:integer;
begin
xiangnamer[0] := 'S7:[S7 connection_3]DB1,byte0';
xiangnamer[1] := 'S7:[S7 connection_3]DB1,byte2';
xiangnamer[2] := 'S7:[S7 connection_3]DB1,byte4';
xiangnamer[3] := 'S7:[S7 connection_3]DB1,byte6';
xiangnamer[4] := 'S7:[S7 connection_3]DB1,byte8';
xiangnamer[5] := 'S7:[S7 connection_3]DB1,byte10';
HR := GroupAddItem(GroupIf,xiangname[0], 0, VT_EMPTY,Item0Handle,ItemType); //函数在OPCutils.pas中
for i := 0 to 5 do
begin
HR := GroupAddItem(GroupIf,xiangnamer[i], 0, VT_EMPTY,Item0Handle,ItemType); //函数在OPCutils.pas中
jubinr[i] := Item0Handle;
end;
if Succeeded(HR) then
begin
memo1.Lines.add('添加数据item成功!');
end
else
begin
memo1.Lines.add('添加数据item失败!');
Exit;
end;
end;
连接读和写都能成功,连接写成功后,我创建了一个线程,调用plcclass 中的function Tplc.plc_write_word(ym:array of word):integer;,能够将数据成功写入。
关闭程序后,重新运行,只连接读,并连接读成功,同样是线程,调用plcclass中的function plc_write_word(ym:array of word):integer; 就会报错,大致意思是 EintfCastError with message ’Interface not supported’ ,程序停在下面标红的地方(在OPCutiIs中):
function ReadOPCGroupItemValue(GroupIf: IUnknown; ItemServerHandle: OPCHANDLE;
var ItemValue: string; var ItemQuality: Word): HResult;
var
SyncIOIf: IOPCSyncIO;
Errors: PResultList;
ItemValues: POPCITEMSTATEARRAY;
begin
Result := E_FAIL;
try
SyncIOIf := GroupIf as IOPCSyncIO;
except
SyncIOIf := nil;
end;
if SyncIOIf <> nil then
begin
Result := SyncIOIf.Read(OPC_DS_CACHE, 1, @ItemServerHandle, ItemValues,
Errors);
if Succeeded(Result) then
begin
Result := Errors[0];
CoTaskMemFree(Errors);
ItemValue := VarToStr(ItemValues[0].vDataValue);
ItemQuality := ItemValues[0].wQuality;
VariantClear(ItemValues[0].vDataValue);
CoTaskMemFree(ItemValues);
end;
end;
end;
后来,我在Form中增加一个按钮,实现在只连接读后,单击这个按钮直接调用function ReadOPCGroupItemValue(GroupIf: IUnknown; ItemServerHandle: OPCHANDLE;
var ItemValue: string; var ItemQuality: Word): HResult;
就能独到OPC中的数据。
现在的问题有2个:
1. 同样是在线程中实现,为什么同步写能成功,同步读就读不到数据(同步读和同步写是分开进行测试的)?
2. 同样是同步读,放在线程中会报错,放在按钮单击触发中就能读到数据?
后来我想有2个可能,
1. delphi6环境的问题,我看网上很多OPC案例是在delphi7环境中实现,不知道有哪位高手出来指教?
2. 怀疑是添加服务器的时候出的错,调用同一个Groupif, 出现接口不支持这种情况,但是测试中我只连一个读或者写,难道读和写中间有联系?
希望哪位高手不吝赐教!!!
2 个解决方案
#1
楼主,这个问题你解决了吗,怎么解决的
#2
感觉你这个问题不是OPC服务器的问题,和你用了线程有关系?
OPC现在用的少了,特别是基于COM的,实际运用中OPC会产生莫明其妙的错误,弄得你目瞪口呆。
如果可以的话,如果西门子PLC端是你们自己做的话,可以用串口、PPI、PROFIBUS等等
OPC现在用的少了,特别是基于COM的,实际运用中OPC会产生莫明其妙的错误,弄得你目瞪口呆。
如果可以的话,如果西门子PLC端是你们自己做的话,可以用串口、PPI、PROFIBUS等等
#1
楼主,这个问题你解决了吗,怎么解决的
#2
感觉你这个问题不是OPC服务器的问题,和你用了线程有关系?
OPC现在用的少了,特别是基于COM的,实际运用中OPC会产生莫明其妙的错误,弄得你目瞪口呆。
如果可以的话,如果西门子PLC端是你们自己做的话,可以用串口、PPI、PROFIBUS等等
OPC现在用的少了,特别是基于COM的,实际运用中OPC会产生莫明其妙的错误,弄得你目瞪口呆。
如果可以的话,如果西门子PLC端是你们自己做的话,可以用串口、PPI、PROFIBUS等等