通讯异常(200分)

  • 主题发起人 主题发起人 清越小生
  • 开始时间 开始时间

清越小生

Unregistered / Unconfirmed
GUEST, unregistred user!
我使用spcomm控件进行串口通讯,间隔2秒通讯一次,在多次通讯之后通讯就失败了,我利用自己的程序进行串口复位,还是不能进行通讯,但我将我做的程序重启,通讯正常,请高手指点!!另:我是利用普通的PCI的串口卡扩展的串口,我利用MOXA的串口卡就不出现这样的问题,但是我想程序应该是可以解决这个问题的!
 
其实就是程序重启时和我在程序中对串口复位有什么不同?
 
你动态创建SPComm试试,复位时释放后再创建。
 
你是使用什么方法控制2秒通讯一次的?
另,普通的PCI卡才不到100元,摩莎卡要4000多块钱,呵呵当然有区别了
先发一段代码上来吧并说明用什么方法控制两秒通讯一次的
我以前也遇过类似问题
 
我使用定时器来进行定时通讯的,每次进入定时器处理程序时进行通讯
 
使用定时器会出现这样的问题
我当初也是使用定时器发生问题的
原因是可能上一个两秒中通讯还没有结束,定时器激发下一次的通讯
当开始可能没有问题,若长时间运行由于线路或者各种问题两秒没有响应,则因为还占用串口,后面一系列操作都没有办法响应,时间长之后整个程序会死掉,或者被Windows强行关掉。
若是在定时器中动态创建更容易出错,在里面使用全局变量出错机会小一点

建议建立一条单独的线程来做发送的工作
若需要两秒显示一次结果,可以使用定时器将线程采集的数据两秒一次显示在界面

即采集和显示分开
 
我在定时器程序中,进入时先关掉定时器,等通讯结束后再开启定时器的。
这样理论上是不会两次通讯重叠的!
 
贴出代码吧
主要是与Timer交互的部分和Timer.OnTimer部分
 
以下是通讯部分,我不停的调用来进行不同strIPCMachineID数据的收集!
通讯的过程是先叫地址,回应地址,再发命令,回应数据。
通讯不上的时候,并没有显示我设定的错误提示,而是异常退出的fail-3,我估计是在打开串口的时候出错的!
function TFrmMain.Communication(strIPCMachineID:string):Boolean;
var
strCmd:String;
intTemp,j,intSum,intMachineId,intCom:integer;
begin
try
//com1.Close;
intCom:=strToint(copy(strIPCMachineID,1,2)) ;
Com1.DeviceName:='Com'+intTostr(intCom);
intMachineID:=strToint(copy(strIPCMachineID,3,2));
Com1.BaudRate:=TBaudRate(6);
Com1.Parity:=paMark; //发地址祯
intGetDataSum:=0;
intStep:=1;
com1.Open;
for j:=0 to 20 do
intBuffer[j]:=0;
fIsRecieve:=false;
fIsWaiting:=True;
if (not SendData(chr(intMachineID))) then
begin
Com1.Close;
btnclose.Caption:='not sendData';
btnClose.Refresh;
result:=false;
exit;
end;
intTemp:=GetTickCount;
while fIsWaiting do //等待----〉结束命令在Comm1RxChar
begin
if ((GetTickCount-intTemp)>1000) and (not fIsRecieve) then
begin
com1.Close;
btnclose.Caption:='fail-1';
btnClose.Refresh;
result:=false;
exit;
end;
if (GetTickCount-intTemp)>5000 then
begin
com1.Close;
btnclose.Caption:='Error-1';
btnClose.Refresh;
result:=false;
exit;
end;
Application.ProcessMessages;
end;
if intBuffer[0]<>intMachineID then
begin
com1.Close;
btnclose.Caption:='Num-1';
btnClose.Refresh;
result:=false;
exit;
end;
//准备发送的命令字
strCmd:=chr(intMachineID);
strCmd:=strCmd+chr(0)+chr(0)+chr(0)+chr(0);
strCmd:=strCmd+chr(0)+chr(0)+chr(0);
intGetDataSum:=0;
Com1.Parity:=paSpace;
intStep:=2;
for j:=0 to 20 do
intBuffer[j]:=0;
fIsRecieve:=false;
fIsWaiting:=True;
if (not SendData(strCmd)) then
begin
Com1.Close;
btnclose.Caption:='not2';
btnClose.Refresh;
result:=false;
exit;
end;
intTemp:=GetTickCount;
while fIsWaiting do //等待----〉结束命令在Comm1RxChar
begin
if ((GetTickCount-intTemp)>2000) and (not fIsRecieve) then
begin
com1.Close;
btnclose.Caption:='fail';
btnClose.Refresh;
result:=false;
exit;
end;
if (GetTickCount-intTemp)>10000 then
begin
com1.Close;
btnclose.Caption:='Error';
btnClose.Refresh;
result:=false;
exit;
end;
Application.ProcessMessages;
end;
com1.Close;
if intBuffer[0]<>intMachineID then //若回应的机台编号不符则跳出
begin
//com1.Close;
btnclose.Caption:='Num-2';
btnClose.Refresh;
result:=false;
exit;
end;
if intBuffer[19]<>0 then //若回应的命令字不符则跳出
begin
//com1.Close;
btnclose.Caption:='Num-3';
btnClose.Refresh;
result:=false;
exit;
end;
//判断校验和
intSum:=0;
for intTemp:=0 to 19 do //计算校验和
intSum:=intSum+intBuffer[intTemp];
intSum:=intSum mod 256;
if intSum<>intBuffer[20] then //判断校验和
begin
//com1.Close;
btnclose.Caption:='Num-4';
btnClose.Refresh;
result:=false;
exit;
end;
btnclose.Caption:='ok-1';
btnClose.Refresh;
if ProcessData(strIPCMachineId) then
begin
//com1.Close;
btnclose.Caption:='ok';
btnClose.Refresh;
result:=true;
exit;
end
else
begin
btnclose.Caption:='fail-2';
btnClose.Refresh;
result:=false;
exit;
end;
except
result:=false;
btnclose.Caption:='fail-3';
btnClose.Refresh;
//com1.Close;
end;
end;
 
如muhx所说,楼主的问题可能再于通讯时没有设置超时和异常保护。
1、用定时器也可以,毕竟比较方便,但是在开始新的通讯前,确认上一次的通讯已结束,可以用一个全局标志,开始通讯时置位,结束时清除。
2、开始新通讯前检查全局标志。
3、通讯部分加入异常保护,try..except..end;即使发生异常,串口也能正常的关闭。
 
建议:
function TFrmMain.Communication(strIPCMachineID:string):Boolean;
begin
....
Com1.Open;
if not Com1.Enable then
exit;
...
try
...
finally
Com1.Close;
end;
end;
 
那我这样试试吧!
 
你应该在串行口控件的 TxEmpty 事件里处理,因为那时串行口才真正空闲
 
SupermanTm,能说的详细一些吗?
 
虽然没有解决问题,但是还是要谢谢各位!
 
后退
顶部