搜索
bottom↓
回复: 22

Delphi通过串口接收下位机的数据总是乱套,内有详细描述,请指教,谢谢

[复制链接]

出0入0汤圆

发表于 2009-4-16 19:33:12 | 显示全部楼层 |阅读模式
自己在写一个PC机串口接收下位机ARM发送的AD转换的数据,并显示实时波形的东东,使用Delphi7+ComPort控件。

使用ComPort的OnRxFlag事件,事件字符设置为#10,当接收到数据帧头0x0a 时,触发这个事件,然后在事件句柄中调用ReadStr(Str,26)读取26个字节到Str中,这26个字节有一个字节的帧头0x0a,一个字节的帧尾0x0c,中间是AD采集到的数据24个字节(8通道*3字节)。

我用ARM发送26字节的固定数据到PC:
0x0a,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFE,0x0b,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFa,0xFb,0xFc,0xFD,0x0c。
用串口调试助手接收数据没有问题,可是用我自己编写的Delphi程序接收时经常会接收出错,具体是周期性发生读取到的Str不是要求的26字节,一会对,一会不对,大部分情况下是26字节,但偶尔会8个字节或18个字节,而且第一帧必是错误的。

后来我加上了判断帧头和帧尾,这样能够接收到正确数据,但是中间有大量数据被丢弃,按道理讲,每次接收到0x0a,则应该将其后的25个字节一起读取到Str中,为什么会少读呢,而且第一组数据必少?


源代码:(ComPort的RxFlag事件句柄)

procedure TForm1.ComPortRx(Sender: TObject);
var
  Str:String;  //  每次接受的字符串
  Ch1,Ch2,Ch3,Ch4,Ch5,Ch6,Ch7,Ch8: Integer;  //三个字符连接得到整形(24位AD)
  Cch1,Cch2,Cch3,Cch4,Cch5,Cch6,Cch7,Cch8: Single;  //与参考电压计算后得到的电压值

begin
  k :=ComPort1.ReadStr(Str, 26);  //读取26个字节到Str

  (*判断帧头和帧尾是否是0x0a和0x0c*)
  if ((Str[1] =Chr($0a)) and (Str[26] =Chr($0c)))then
  begin

  (*接受到正确的数据次数加一,并用Label2显示*)
  j :=j+1;
  Label2.Caption :=IntToStr(j);

  (*连接三个字符,并转化为整形*)
  Ch1 :=StrByteToInt(Str[4]+Str[3]+Str[2]);
  Ch2 :=StrByteToInt(Str[7]+Str[6]+Str[5]);
  Ch3 :=StrByteToInt(Str[10]+Str[9]+Str[8]);
  Ch4 :=StrByteToInt(Str[13]+Str[12]+Str[11]);
  Ch5 :=StrByteToInt(Str[16]+Str[15]+Str[14]);
  Ch6 :=StrByteToInt(Str[19]+Str[18]+Str[17]);
  Ch7 :=StrByteToInt(Str[22]+Str[21]+Str[20]);
  Ch8 :=StrByteToInt(Str[25]+Str[24]+Str[23]);

  (*与参考电压计算,得到实际电压值*)
  Cch1 :=3*Ch1/10000000;
  Cch2 :=3*Ch2/10000000;
  Cch3 :=3*Ch3/10000000;
  Cch4 :=3*Ch4/10000000;
  Cch5 :=3*Ch5/10000000;
  Cch6 :=3*Ch6/10000000;
  Cch7 :=3*Ch7/10000000;
  Cch8 :=3*Ch8/10000000;

  (*超过参考电压(2.5V)的转化为负数*)
  if Cch1>2.5 then
  begin
    Cch1 :=Cch1-5
  end;
  if Cch2>2.5 then
  begin
    Cch2 :=Cch2-5
  end;
  if Cch3>2.5 then
  begin
    Cch3 :=Cch3-5
  end;
  if Cch4>2.5 then
  begin
    Cch4 :=Cch4-5
  end;
  if Cch5>2.5 then
  begin
    Cch5 :=Cch5-5
  end;
  if Cch6>2.5 then
  begin
    Cch6 :=Cch6-5
  end;
  if Cch7>2.5 then
  begin
    Cch7 :=Cch7-5
  end;
  if Cch8>2.5 then
  begin
    Cch8 :=Cch8-5
  end;

  (*实时波形显示,使用Iocomp控件*)
  iPlot1.Channel[0].AddXY(px,Cch1);
  iPlot1.Channel[1].AddXY(px,Cch2);
  iPlot1.Channel[2].AddXY(px,Cch3);
  iPlot1.Channel[3].AddXY(px,Cch4);
  iPlot1.Channel[4].AddXY(px,Cch5);
  iPlot1.Channel[5].AddXY(px,Cch6);
  iPlot1.Channel[6].AddXY(px,Cch7);
  iPlot1.Channel[7].AddXY(px,Cch8);
  px :=px+1;

  end

  (*不是合法的数据帧*)
  else

  begin

  (*接收到错误数据次数加一,并送Label显示*)
  i :=i+1;
  Label1.Caption :=IntToStr(i);
  //k :=Length(Str);
  //Memo1.Lines.Add (Str);
  Memo1.Lines.Add (IntToStr(k));  //显示不合法数据帧包含字节的个数

  end;

end;


1 (原文件名:1.JPG)


2 (原文件名:2.JPG)

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2009-4-17 09:31:56 | 显示全部楼层
逻辑错误:  
if ((Str[1] =Chr($0a)) and (Str[26] =Chr($0c)))then  

应该采用 循环查找

startIndex:integer;
endIndex:integer;
startIndex:=0;
endIndex:=0;
for i:=0 to bufferlength-1 do
begin
    if Str =Chr($0a)  then
    begin
        startIndex:=i;
        break;
    end;
end ;
endIndex:=startIndex + (26-1);
if str[endIndex]<>char($0c) then exit;

这样就会 只辨认以第一个出现的 帧头,和帧头后的第26个帧尾

而且 在帧头之前接收的 一些数据 会自动忽略掉的

出0入0汤圆

 楼主| 发表于 2009-4-17 09:58:25 | 显示全部楼层
谢谢knight_avr 大侠,之前在Email中也请教过你

你说的循环查找的方法,我大致能够看懂,可是for i:=0 to bufferlength-1 do 这句中的bufferlength不知道什么意思?
因为我使用的是ComPort的RxFlag事件,即接收到0x0a这个字符就触发这个事件。然后读取26个字节到Str中。

请多多指点,谢谢

出0入0汤圆

发表于 2009-4-17 10:19:26 | 显示全部楼层
bufferlength 就是实际接收到 的字节长度 我使用的SPCOMM有一个这个参数 ,commport 没有用过 呵呵
该怎么样操作 我也不知道

出0入0汤圆

 楼主| 发表于 2009-4-17 10:23:29 | 显示全部楼层
哦 谢谢啊 我试试看
SPCOMM不知道好不好用,改天用下试试

出0入8汤圆

发表于 2009-4-17 11:42:30 | 显示全部楼层
我是这样用的:
通过起始字符和帧长度来判断一桢是否接收完毕
定义一个buf,函数ComPort.Read(buf^, Count);读到buf
buf[0]就是起始字符,buf[1]就是帧长度,如果buf[1]等于你设定的帧长就认为接收完成,开始处理接收帧

我认为像你这种通过起始字符和结束字符来判断帧的完整性应该采用DataPack,很好用的

出0入0汤圆

发表于 2009-4-17 11:58:02 | 显示全部楼层
用DataPack比较好

出0入0汤圆

 楼主| 发表于 2009-4-17 12:01:26 | 显示全部楼层
再谢谢5楼 6楼的朋友
DataPack还没听说过,我先Google下看看哈,谢谢了

出0入8汤圆

发表于 2009-4-17 12:14:17 | 显示全部楼层
不用搜了,就是comport的一部分,如图,第二个

(原文件名:截图00.jpg)

出0入8汤圆

发表于 2009-4-17 12:17:09 | 显示全部楼层
可以方便的设置StartString和StopString

出0入0汤圆

 楼主| 发表于 2009-4-17 12:21:41 | 显示全部楼层
谢谢 rube 朋友
这个我还没用过呢,试试看

出0入0汤圆

 楼主| 发表于 2009-4-17 15:35:00 | 显示全部楼层
再请教 rube 永丰庵 网友这个ComDataPacket怎么不好用呢,还是我设置有问题?
下图是我的设置,结果无法OnPacket


ComDataPacket (原文件名:com.JPG)

OnPacket事件程序:
procedure TForm1.OnPacket(Sender: TObject; const Str: String);
begin
  j :=j+1;
  Label2.Caption :=IntToStr(j);
  Memo1.Lines.Add(Str);
end;
结果是一直没有数据

出0入0汤圆

 楼主| 发表于 2009-4-17 15:36:47 | 显示全部楼层
下位机固定发送26个字符,一个开始字符0x0b(#11),一个停止字符0x0c(#12)

出0入8汤圆

发表于 2009-4-17 18:27:07 | 显示全部楼层
size设成0,或$11/$12试试,我也是初手,delphi的进制表示方法我没记住

出0入0汤圆

 楼主| 发表于 2009-4-17 18:58:15 | 显示全部楼层
Size应该表示停止位的字节数
#表示ASCII $表示十六进制吧

出0入8汤圆

发表于 2009-4-18 11:09:55 | 显示全部楼层
size和stopstring设一个就行了

出0入0汤圆

 楼主| 发表于 2009-4-19 09:26:14 | 显示全部楼层
哦 我试试看哈,谢谢

出0入8汤圆

发表于 2009-4-19 10:08:23 | 显示全部楼层
楼主能否将你的iocomps v3.0.4 SP2 R1共享一下

出0入0汤圆

 楼主| 发表于 2009-4-19 10:10:51 | 显示全部楼层
iocomps v3.0.4 SP2 R1在本站 伍奇网友发的18B20的帖子上有下载,你可以搜一下,网速不太好,上传总失败,实在找不着的话,加我QQ:277565600,我传给你

出0入0汤圆

发表于 2009-4-19 11:35:33 | 显示全部楼层
开始字符和结束字符最好在程序中设置

出0入0汤圆

 楼主| 发表于 2009-4-20 10:58:35 | 显示全部楼层
果然如 【19楼】 zhchyl 指挥 所说,要在程序中设置起始停止字符和帧长度才有效,谢谢
   ComDataPacket1.ComPort :=ComPort1;
   ComDataPacket1.CaseInsensitive :=True;
   ComDataPacket1.StartString :=Chr($55);
   ComDataPacket1.StopString :=Chr($0d);
   ComDataPacket1.Size :=28; //帧长度,不是停止位长度

谢谢 zhchyl 指挥

出0入0汤圆

发表于 2009-9-10 09:40:52 | 显示全部楼层
DataPacket设置接收固定长度的数据帧,如果帧长不固定,应该还是使用接收缓冲区循环检测好一些。Cport的OnRxChar事件函数中有一个参数Count就是接收区的长度,读数据时可以,Comport.Read/ReadStr(地址,Count).

出0入0汤圆

发表于 2009-9-10 10:57:55 | 显示全部楼层
最为可靠的办法还是自己建立缓冲区,检测到结束标志就回溯查找起始标记。(如果有校验字的话,则检测到结束标记的后一个)然后解析接收到的数据。一般不要用控件直接提供的此类方法,兼容性和依赖性都不理想。
另外,串口名称建议使用形如 "\\.\" + "COM1"类型的命名
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-20 10:55

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表