关于串口的问题,如何从缓冲区中判断所收到的数据是我所要的数据(50分)

  • 主题发起人 主题发起人 zheye
  • 开始时间 开始时间
Z

zheye

Unregistered / Unconfirmed
GUEST, unregistred user!
小弟做串口通信的程序时,需要从下位机(单片机)中接收发送的数据
如收到41 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 00 00 00 00 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 42这样的数据代表我的连接正常,也就是说只要收到41开始,42结束的话,就代表连接正常,如收到
43 44 30 30 31 30 31 30 31 这样的数据,就代表有我所要的数据,即43 44开始的,就代表是我要的数据信息,我在程序中该怎么判断是41开始 42结束的,怎么判断是43 44开始的数据呢。小弟是菜鸟,还望大家见谅
 
各位大侠,给小弟一点思路啊,分少了,可以另开贴再加了
 
先读到A:String中
然后赋值到B:PChar
for i:=0 to Length(B)-1 do
begin
用B判断就行了吧
end;
 
if receiverdbyte=41 then
[:D]
 
tcomport有这样的功能啊,可以让你自定义接收的开始,接收字符串及接收字符的个数
 
将数据一个一个地接收,没有接收到41或者43时就丢弃,接收到41或43时,就开始存到一个数组中,以后接收到的数据继续存入数组中.后面你应该知道怎么做了吧.
 
谢谢楼上的各位大虾
能不能给小弟个代码参考参考啊
 
安装串口控件Mscomm或者Spcomm.这些控件网上有下载,网上有一些例子说明这些控件的用法,自己看吧.
 
再次谢谢楼上的各位大虾
已有一点收获,请问中断方式的接收数据,该怎么办呢
 
var
cs:TComstat;
ReadBuf:byte;
begin
ClearCommError(com1,iperror,@cs);
if cs.cbInQue>0 then
begin
if ReadFile(com1,ReadBuf,1,nBytesRead,nil) then
begin
case ReadBuf of
$41: do something
$42: do something
$43: do something
$44: do something
...
end;
end;
end;
end;
--------------------
然后建一个线程,轮循同步读取检测
还不会就QQ联系我。 67260745
白天我上班。。不在。。HOHO。。一般晚上在。
 
在实际应用中。。。还是自己用winapi写个专用串口处理单元。。比直接用组件要灵活多了。。。实际问题中也容易解决。

我从事的工业数据采集项目中都是用自己写的通信单元的。。HOHO
 
to lijinjie 但我用的士spcomm,你的应该士api吧,但联系到我的问题,还没有具体的思路。
谢了lijinjie大虾
 
spcomm提供源代码的。。。自己可以相应的修改。。。
 
我也用spcom,你看看下面的程序是否满足你的要求
procedure TMainForm.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
s2,s1:string;
i,j:integer;
NMEA_BUF:array[1..32] of byte;
Deepth,NMEA_DATA:string;
begin
Deepth:='';
try
move(buffer^,pchar(@NMEA_BUF)^,bufferlength);
for i:=1 to bufferlength do
begin
NMEA_DATA:=NMEA_DATA+chr(NMEA_BUF)+'';
end;
NMEA_DATA:=trim(NMEA_DATA);
if length(NMEA_DATA)=你接收的字符串长度 then
begin
if (copy(NMEA_DATA,1,2)=41) and (copy(NMEA_DATA,你接收的字符串长度-1,2)=42) then
//你的处理过程
end;

except
//
end;
end;
 
我给一部分我项目中的代码。。呵呵。。不能多给。。只是讲明原理
在你的单元中创建一个线程。。或者是TTimer。
我这里是用Timer。
{
//readTimer处理过程
ReadIP:CBUf的保存指针
saveBuf:用于保存从串口读取的byte
CBuf:用于保存转换后的(2位byte) to 1个integer
}
procedure TPluck.ReadOnTimer(sender:Tobject);
var
ReadBuf:byte;
i,iRow,iCol:integer;
// temp:double;
begin
{*一次读取1个byte*
前 12个 byte为头信息。。无效
}
if pluck.ReadComm_Byte(comm,ReadBuf) then
begin
// form1.Memo1.Lines.Add(intTostr(ReadBuf[1]));
if readbuf=$7e then
begin
if messagebox(0,'数据采集结束!'+#13+#13+
'是否将本次采集数据保存到数据库中?',
'系统提示:',
mb_YesNO+MB_ICONQUESTION)=IDYES
then StorageDB;//进行保存数据库操作

(*显示到详细表中*)
form1.Label3.Caption:='正在将数据添加到详细列表中';
form1.SaveDBPanel.Show;
form1.Gauge1.MaxValue:=ReadIP-4;
i:=0;
while i<=8 do
begin
(*显示列表头*)
form1.RRTDetailGrid.Cells[i,0]:='采集时间';
form1.RRTDetailGrid.Cells[i+1,0]:='数值';
i:=i+2;
end;
//------------
irow:=1;//行
iCol:=0;//列
for i:=1 to readIp-4 do
begin
form1.Gauge1.Progress:=i;
form1.RRTDetailGrid.Cells[icol,irow]:=timeTostr(CBUF.time);
form1.RRTDetailGrid.Cells[icol+1,irow]:=floatTostr(CBUF.val);
iCol:=iCol+2;
if i mod 4=0 then
begin
(*每行显示4个数据*)
inc(iRow);
form1.RRTDetailGrid.RowCount:=iRow;
iCol:=0;
end;
application.ProcessMessages;//防止处理死锁
end;
form1.SaveDBPanel.hide;
pluck.StopRead;
exit;
end;{ if readbuf=$7e then}

if JOFlag then
begin
(*如果是偶数则进行转化*)
saveBuf[2]:=ReadBuf;//保存读取的1个byte[偶数时]
(*去掉帧头:aa 55 eb 90 eb 90 eb 90*)
// form1.Memo1.Lines.Add(intTostr(saveBuf[1])+' '+intTostr(saveBuf[2]));
if ReadIP>4 then
begin
CBuf[ReadIP-4].val:=GetVal(saveBuf,0);//记录数值
CBuf[ReadIP-4].time:=time;//记录时间
form1.Memo1.Lines.Add(floatTostr(CBuf[ReadIP-4].val));
(*绘制曲线图 时间/数值*)
form1.DBChart1.Series[0].AddXY(CBuf[ReadIP-4].time,CBuf[ReadIP-4].val);
(*2位读取好后,清空saveBuf*)
saveBuf[1]:=0;
saveBuf[2]:=0;
end;
inc(ReadIP);//CBUF读取指值加1
end else saveBuf[1]:=ReadBuf;//为奇数时保存到saveBuf[1]
JOFlag:=not JOFlag;
end; //else begin
// form1.Memo1.Lines.Add('错误');
// end;
(*BufSizeEdit显示缓冲区大小*)
form1.BufSizeEdit.Text:=intTostr(GetRXDsize(comm))
end;
--------下面是-ReadComm_Byte的原型-----------------------
//********************
//读串口 ReadComm_Byte
//读取一个Byte
//********************
Function TMyComm.ReadComm_Byte(Const Com:integer;var OneByte:byte):boolean;
begin
result:=true;
if GetRXDSize(com)<=0 then
begin
result:=false;
exit;
end;
bSuccessFlag:=ReadFile(ComHandle[com],OneByte,1,nBytesRead,nil);
if (not bSuccessFlag) or (nBytesRead=0) then
begin
//CloseComm(com); //调用关闭串口
result:=false;
end;
end;
 
处理时考虑串口的上传速度。。。。我这里做的实际项目的上传数据。。每一帧为1W多个byte.
以字段7e做为结束标识,
Timer的间隔是1毫秒。。。。
你次读1个byte。。。在注意,检查RX缓冲区是否有数据。。如果空读。。则会出错数据出错。。
 
受益匪浅
结贴!
 
后退
顶部