串口一开始实时监控数据的,所以会实时的接收数据。但是我有时候需要对下位机进行写操作,读操作和写操作分别有不同接收事件发生。有时候我对下位机进行写的时候,下位机的接收事件没发生,而是跳转到了读操作的接收事件,我该怎么样屏蔽这种情况的发生啊?请教大家了啊,比较着急,
解决方案 »
- 用Delphi和MapX开发GIS系统问题,如何实现在mapx1地图窗口中多个车辆动态显示,并当同一辆车发生位置变化时,车辆随之变化,最好能在地图上显示车辆行驶轨迹?
- 关于fastreport的三个问题???
- Socket编程高手教~!
- 关于数据插入的困惑
- 急寻下拉框选择图片的Combox控件,有人知道吗?
- com服务器与opendialog打开“我的文档”的冲突
- 回忆4年前的"爱"人
- 做过射频卡读写操作的朋友请进,帮忙(在线)
- 请教一下这样一个电子印章的解决方案可行吗?分不够再加,高分奖励!
- 如何禁用窗体的“最大化”按钮?
- 哪位朋友有MPEG1文件的格式说明?谁做过MPEG1文件的播放,分割,合并的程序?
- 怎样知道当前用户是否登录域?
你说的“下位机”是指的非PC机(嵌入式设备)吗?如果是这样的话,和上位机(PC电脑)有什么关系?
begin
if IWRCount=1 then
begin
TempString:='';
OutPutStr:='@00WR00050000';
OutPutStr:=OutPutStr+CalBcc(OutPutStr)+'*'+Chr(13);
Plength:=length(OutPutStr)+1;
while not plcComm.WriteCommData(PChar(OutPutStr),PLength) do
begin
showmessage('数据还没发出');
plcComm.WriteCommData(PChar(OutPutStr),PLength);
end;
IWRCount:=IWRCount+1;
showmessage('数据第二次已经发出'); end
else
begin
TempString:='';
OutputStr := '@00RD01460006'+CalBcc('@00RD01460006')+'*'+chr(13);
Plength:=length(OutPutStr)+1;
// sleep(10);
Application.ProcessMessages ;
plcComm.WriteCommData(PChar(OutPutStr),PLength);
IWRCount:=0;
end;
end; If Identify='RD' then
begin
if Open=true then
begin
showmessage('跳转到这里RD');
edit2.Text :=TempString;
Open:=False;
end;
省略中间过程
TempString:='';
OutputStr := '@00RD01460006'+CalBcc('@00RD01460006')+'*'+chr(13);
Plength:=length(OutPutStr)+1;
Application.ProcessMessages ;
plcComm.WriteCommData(PChar(OutPutStr),PLength);
end; 上位机没事情做的时候就是执行“RD”操作,会循环的进行。我如果对下位机操作要进行“WR”写命令,WR命令要写两次,因为只写一次的话,对操作会一直置位,我要进行复位,就要写两次,第一次是往里面写“1”,第二次是往里面写“0”,如果进行写操作,下位机理论上是应该得到“WR”标识符的,但是老是会被"RD"标识符冲掉,因为“RD”命令是一直循环进行的,我应该怎么样捕捉到“WR”标识符呢?
这个(或这些)函数是什么时候被调用的?触发这个(或这些)函数的条件是什么?(定时器?线程?用户点击按钮?接收到某些数据之后调用以作通讯上的交互?)2.Identify变量是在什么时候或什么情况下赋值的?3.If Identify='RD' then
begin
if Open=true then //这里的Open是个普通变量还是个Function名称?
procedure TForm1.BitBtn2Click(Sender: TObject);
//5.03手动停止
begin
OutPutStr:='@00WR00050008';
OutPutStr:=OutPutStr+CalBcc(OutPutStr)+'*'+Chr(13);
Plength:=length(OutPutStr)+1;
if plcComm.WriteCommData(PChar(OutPutStr),PLength) then
begin
showmessage('发送成功');
IWRCount:=1;
Open:=True;
end;
SystemTime.Enabled :=False;
end;下面的是RECIEVEDATA事件内容
procedure TForm1.plcCommReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
TempString:pChar;
Identify:String;
X,y,AdJustX,AdJustY:Single;
BinStr:String;
//D146,147X电机脉冲数,D148,149Y电机脉冲数
//D150 拉力传感器模拟量数字 D151 IO 状态
begin
TempString:=Buffer;
edit1.Text :=TempString;
Identify:=Copy(TempString,4,2);
sleep(10);
// Application.ProcessMessages ;
If Identify='SC' then
begin
TempString:='';
OutPutStr := '@00RD01460006'+CalBcc('@00RD01460006')+'*'+chr(13);
Plength:=length(OutPutStr)+1;
//sleep(10);
Application.ProcessMessages ;
plcComm.WriteCommData(PChar(OutPutStr),PLength);
end; if Identify='WD' then
begin
// showmessage('执行到了');
Edit2.Text :=TempString;
TempString:='';
OutputStr := '@00RD01460006'+CalBcc('@00RD01460006')+'*'+chr(13);
Plength:=length(OutPutStr)+1;
// sleep(10);
Application.ProcessMessages ;
plcComm.WriteCommData(PChar(OutPutStr),PLength);
end;刚才上面的是其中的一部分
Veron_04的意思是,我先判断下位机里面有没有接收到数据,然后再写?但是我想做的是随时可以写啊!
上位机没事情做的时候就是执行“RD”操作,会循环的进行。
--这句话我猜测你是在定时器中执行的
下位机理论上是应该得到“WR”标识符的,但是老是会被"RD"标识符冲掉
--这句话我应该是你没有根据WR标识去控制RD的执行。如果我的猜测正确的话,那么你的问题在于:
由于你是用定时器去定时进行发送RD命令,而这个过程没有受到双方应有的交互关系制约和控制,所以在你进行正确的交互通讯时,定时器仍然在按设置的时间进行发送RD命令,所发送的命令与正常的交互命令在时序上混在了一起,导致下位机的执行顺序混乱。建议:
1.治标不治本的办法
发送RD命令仍然采用定时器,但需要将定时器的时间延长至发送WD命令至命令响应数据返回之后的最大时间,并且当通讯软件需要向下位机发送WR命令前禁止定时器,并且只有当收到下位机对WR的响应数据之后才允许定时器的执行。
这种办法之所以说治标不治本,是因为定时器的时序比较难控制,在你的正常交互比较复杂的情况下很有可能被其干扰。
2.另外一种办法:
重新设计上位机与下位机的交互关系,将下位机的内容主动上报,而不是由上位机来实时查询
只有这样才能进行实时的循环数据的,你仔细看我的每个标识符的判断,如果没什么事情干的话,立刻进行"RD"操作,只是我“WR”操作为什么写两次呢,因为在我的硬件里面,如果只写一次的话,一直是置位状态,但是我想让它只是瞬间的接通,所以我需要复位,我需要根据得到的“WR”标识进行复位,也就是写 OutPutStr:='@00WR00050000';
OutPutStr:=OutPutStr+CalBcc(OutPutStr)+'*'+Chr(13);
Plength:=length(OutPutStr)+1; 但是我老是捕捉不到'WR'标识符,所以我的“WR”写操作老是完不成
说说我对你的代码等的疑问,希望能够有些提示作用:
1.代码中判断字符串是否等于另外一个字符串你用的是这样的表达方式:If Identify='SC' then
那么,在下位机中发送的是否全部字符,比如RD、WR、WD等是否是大写?如果不是,那么用这种判断肯定会出现捕捉不到的问题。
另外,字符串比较用等号判断的话,当长度不一至,可能判断结果是错误的。
建议使用判断字符串是否相等用语句if StrComp(Pchar(Identify),Pchar('SC'))=0 then
当然再加上大小写不敏感的话,会需要形如
if StrComp(Pchar(UpperCase(Identify)),Pchar('SC'))=0 then的语句2.事件触发及串口数据流中断:
对于Spcomm来说,它的产生接收事件的机制我不是太了解,但我觉得有如下可能:
如果一长串数据需要从串口接收,如“018438938924509824908245098245"
这一长串数据本来是一个完整帧,但是由于接收控件的缓冲区或其它接收机制造成一帧数据产生了两次接收事件(甚至更多次),每次接收到了数据的一部分,那么你在控件的接收事件中写的代码就需要考虑这种情况了。这就需要一个大的缓冲区,将收到的数据按顺序放在缓冲区中,然后再有一个程序从缓冲区中判断帧数据的开始和结束,再对分解出的完整帧的数据内容进行分析。3.楼主在17楼描述说:
只是我“WR”操作为什么写两次呢,因为在我的硬件里面,如果只写一次的话,一直是置位状态,但是我想让它只是瞬间的接通,所以我需要复位,我需要根据得到的“WR”标识进行复位,也就是写
OutPutStr:='@00WR00050000';
OutPutStr:=OutPutStr+CalBcc(OutPutStr)+'*'+Chr(13);
Plength:=length(OutPutStr)+1;
但是我老是捕捉不到'WR'标识符,所以我的“WR”写操作老是完不成
--在这个描述中,三行代码前的描述是用SpComm写WR命令到下位机的,但是三行代码之后描述“捕捉不到WR标识符”,我的理解是楼主需要在上位机给下位机发送的数据中捕捉WR标识符,而不是在下位机发给上位机的数据中捕捉这个WR标识符,不知道是我理解的不对还是楼主的描述不正确?如果我理解正确的话,那么你在接收事件中肯定是捕捉不到发送的数据的。
象你这种情况,我一般是这样处理:
采集数据过程用一个线程,在线程里就重复读数据处理过程然后用个事件TEvent,上位机如果要偶尔和下位机交互其它命令,主线程就设置这个事件有信号,在采集数据线程里,waitforsingleobject()这个事件信号,就临时停止了采集过程,主线程交互过程结束,设置事件无信号,恢复采集过程执行。(不要用suspend和resume来停止和恢复线程,不大可靠)