一个串口通信的问题,大家帮忙呀!(100分)

  • 主题发起人 主题发起人 mylem
  • 开始时间 开始时间
M

mylem

Unregistered / Unconfirmed
GUEST, unregistred user!
我使用Mscomm控件来实现PC和单片机之间的串口通信,现在我需要单片机向PC机发送一些
数据(如指令为A1H),即Mscomm1.output:=A1(示意),我希望单片机在20ms时间内将数
据传回,但数据是否到来到我主程序无法知道,来的数据只能在Mscomm的OnComm事件中处理
如果在OnComm事件中将收到的数据传给主程序,主程序如何与OnComm事件同步呢?
综合起来说就是主程序和单片机通讯的一问一答的配合问题,还有当有多次问答,一问一答
如何配合,在这种情况下程序该如何使用Mscomm控件?如能提供类似的例子最好了。
 
“但数据是否到来到我主程序无法知道”?为什么不知道呢?在ONCOMM事件里看看接收缓
冲区就知道了嘛!
“主程序如何与OnComm事件同步呢?”,这个问题根本不存在,在事件响应的程序里无所
谓的同步,你的程序应该是接收到一个报文就处理一个报文,然后开始下一个报文,没什
么同不同步的问题。

Mail: treemanwww@263.net
 
问题是各报文之间是彼此相关联的,不是无联系的呀,也就是说,要处理来的报文,可能要
等待下一个报文来了以后才能处理,这该怎么办呢?
回:"但数据是否到来到我主程序无法知道”?为什么不知道呢?在ONCOMM事件里看看接收缓
冲区就知道了嘛!
我的主程序不能使用循环的方法来检查是否信息已来到,同时还要计时20ms呢?

 
20ms的计时没有什么意思,当程序有数据收到的时候,就有事件触发,
根据命令,发下一条指令
 
如果非要20ms定时来处理通信失败,可以在发送数据后,启动一个20ms的定时器,并设定
一个全局boolean变量值。等定时时间到以后,改变那个全局变量的值。
在收到单片机的事件触发后,停止计时器,并恢复全局变量的初始值,并处理事件。
这样,主程序就可以通过检查全局变量来得知通信的情况,并进行相应的处理了。
 
下载这个东东回去看看,支持PASCAL脚本,可以定制你的通信协议,有例程:
http://www.hensel-hk.com/yyh/sharesoft/ComDebugger101.zip
 
对, 来了就触发事件, 根据接受到的信息判断要不要做处理的事情.

另 , 你说的主程序和使用这个控件的程序 不是一个程序? 不能被调用吗?
你说的蛮多 可这点却没说清楚.............
 
比如说一个窗口需要从单片机读取数据,但从单片机来的数据只能由Mscomm控件的ONcomm事件
处理,当然我可以在Oncomm事件中把数据送到该窗口中显示,问题是当可能有多个窗口都
要进行这种操作,在Oncomm事件中我怎么才知道该把数据送到哪个窗口,这不能使用协议
解决,因协议仅包含主机PC的地址,不能还带上某个窗口的标记呀。
综合起来说就是主程序和单片机通讯的一问一答的配合问题,还有当有多次问答,一问一答
如何配合,在这种情况下程序该如何使用Mscomm控件?如能提供类似的例子最好了。
 
我做过类似的东东,使用用Api查询访问串口实现的,给你个例子。
//-->初始化串口。
function init_comApi(Port: Integer): Integer;
Var aPort:PAnsiChar;
sDCB:_DCB;
lp:CommTimeouts;
begin
//-->打开串口
aPort:=PChar(Format('COM%D',[Port+1]));
PortHandle:=CreateFile(aPort,GENERIC_READ or GENERIC_WRITE,0,Nil,
OPEN_EXISTING,0,0);
//Result:=PortHandle;
if PortHandle < 0 Then Begin
Result:=-1;Exit;
End;
//-->
if Not GetCommState(PortHandle,sDCB) then Begin
CloseHandle(PortHandle);
Result:=-1;Exit;
End;
sDCB.BaudRate:=CBR_57600;
sDCB.ByteSize:=8;
sDCB.Parity:=NOPARITY;
sDCB.StopBits:=ONESTOPBIT;
if Not SetCommState(PortHandle,sDCB) Then Begin
CloseHandle(PortHandle);
Result:=-1;Exit;
End;
lp.ReadIntervalTimeout :=MAXDWORD;
lp.ReadTotalTimeoutMultiplier:=0;
lp.ReadTotalTimeoutConstant:=0;
lp.WriteTotalTimeoutMultiplier:=0;
lp.WriteTotalTimeoutConstant:=0;
SetCommTimeouts(PortHandle,lp);
Result:=0;
end;
//-->接收一个Byte
Function rececodeApi(Time_Tlag:Byte;Var cData:Byte):Boolean;
Var iOldTime,iDelayTime:Integer;
lrc:LongWord;
_iDelayTime:Integer;
begin
Result:=True;
iOldTime:=0;iDelayTime:=0;_iDelayTime:=0;cData:=0;
Case Time_Tlag of
1:_iDelayTime:=40;//超时时间40=40ms
2:_iDelayTime:=500;
End;
iOldTime:=GetTickCount;
Repeat
if Not ReadFile(PortHandle,cData,1,lrc,Nil) Then
ClearCommError(PortHandle,lrc,Nil);
iDelayTime:=GetTickCount-iOldTime;
if iDelayTime>_iDelayTime Then Begin
Result:=False;Exit;
End;
Until lrc=1;
end;
//-->发送一个Byte
function sendcodeApi(cData: Byte): Boolean;
Var lrc:LongWord;
begin
Result:=True;
if Not WriteFile(PortHandle,cData,1,lrc,Nil) Then Begin
ClearCommError(PortHandle,lrc,Nil);
Result:=False;
End;
end;






 
>>当有多次问答,一问一答如何配合

我比较赞同simon707的建议,

首先是你和单片机之间的协议要设定好。
其次是你的工作流程要清楚,比如:
1. 发一命令过去,设置一标志变量;
2. 20ms内在接收到反馈信息前不做其后工作;
3. 20ms后无反应,重复1,2。
4. 重复N次后,还是无反应可视单片机死机,可发重启命令(这要与单片机端事先商定好协议)

>>当可能有多个窗口都要进行这种操作...怎么才知道该把数据送到哪个窗口
不知你的是个什么样的系统,你看是哪个窗口里要求数据,如果都要就都发。
不会是多串口操作吧。

 
第一:我没有使用Mscomm。

第二:无论你要什么样的数据,都是根据通讯协议去问单片机索取。

第三:什么叫主程序和ONCOMM同步?我觉得你没有真正理解。没有完全的同步,只有相对的同步。
可以采用消息来完成。

第四:一问一答的配合,是这样做的。设置超时。响应超时时间为20ms.假如在发送后20ms,没有数据进入串口。
那就重发。如果相应,但是得到的数据不对,那也重发。记录重发次数。如果针对某个命令的读取超时了或者重
发次数大于设定的重发最大次数。那么就认为该设备或者该命令有问题,做下个命令或者下个设备读取。

第五:你所谓的多窗口,应该是将得到的数据发送给不同窗体把。可以采用uses otherunit;然后就是将数据发给
其他窗口的全局变量了。
 
多人接受答案了。
 
后退
顶部