DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: bluewind23
今日帖子: 1
在线用户: 2
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 ken0137 (顺眼即佛) ★☆☆☆☆ -
普通会员
2024/6/13 10:39:51
标题:
使用CnRS232连续接收下位机数据的问题 浏览:758
加入我的收藏
楼主: IDE:delphi7
cnvcl:Version 2022.10.01

在接收下位机每20ms发送的数据显示时总是出现单个字符串的断开显示

比如下位机每20ms发送一个8位字符串   0.123456+回车换行符
但是接收显示,会出现几次
----------
0.
123456
----------
下位机发送1000个数据
上位机触发有1000多次
要如何设置才能如下一边接收一边正确显示呢?
----------
0.123456
0.123456
0.123456
0.123456
0.123456
0.123456
----------



var
  I: Integer;
  S: string;
  Input: array of byte;
begin
  Input := Buffer;
  for I:=0 to BufferLength-1 do
  begin
    S := S + Chr(Input[I]);
  end;
  mmo1.Lines.Add(S);
end;
----------------------------------------------
只会简单使用,并未精通深入
作者:
男 bighawk (Hawk) ★☆☆☆☆ -
盒子活跃会员
2024/6/13 10:48:23
1楼: 很简单啊,缓冲区里面的读到回车换行再显示出来呗
----------------------------------------------
-
作者:
男 bighawk (Hawk) ★☆☆☆☆ -
盒子活跃会员
2024/6/13 10:50:36
2楼: 串口的特性就是这样子,没有协议的概念。
----------------------------------------------
-
作者:
男 wszysystem (wszy) ★☆☆☆☆ -
盒子活跃会员
2024/6/13 10:59:16
3楼: 有时候没有办法能直接显示出你想要的数据,只能拼凑一下。
----------------------------------------------
-
作者:
男 ken0137 (顺眼即佛) ★☆☆☆☆ -
普通会员
2024/6/13 11:12:25
4楼: 我测试到现在,只有先将接收到的数据全部放到一个全局变量msg中,最后一次性加载才能正确显示接收的内容
  Input := Buffer;
  for I:=0 to BufferLength-1 do
  begin
    S := S + Chr(Input[I]);
  end;
  Msg:=Msg+S;
----------
mmo1.text:=msg;
----------------------------------------------
只会简单使用,并未精通深入
作者:
男 bighawk (Hawk) ★☆☆☆☆ -
盒子活跃会员
2024/6/13 11:19:29
5楼: 说白了,就是下位机定义的传输协议是以回车换行结尾。但是你又不遵守这个协议……这也能怪下位机么?
----------------------------------------------
-
作者:
女 wfymqj (wfymqj) ★☆☆☆☆ -
盒子活跃会员
2024/6/13 11:36:30
6楼: CnRS232有超时属性设置了没“读间隔超时”
此帖子包含附件:
PNG 图像
大小:3,740B
----------------------------------------------
-
作者:
男 bighawk (Hawk) ★☆☆☆☆ -
盒子活跃会员
2024/6/13 11:40:13
7楼: 跟这些设置没关系。系统又没义务帮你实现这个协议,这得自己写代码。否则要程序员来做啥呢?
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2024/6/13 13:07:23
8楼: 串口就是一个字节一个字节一个字节一个字节的传。简单说,就是一个流。

你要分割,就要知道如何分割。串口控件不可能帮你分割,因为如何分割没有标准。

你这个,既然定义的协议是回车,那回车这个符号就是分隔符。你自己逐个字节处理,遇到回车,就算一次。

Delphi 控件的基本概念:把程序员都会遇到的通用的功能,写成代码,封装到控件里面,方便所有程序员使用。

因此控件不会帮你实现非通用的特定逻辑的东西。这个就是程序员存在的价值了。否则,写 Delphi 控件那帮人把世界上的程序都写完了,普通程序员就可以都下课了。
----------------------------------------------
-
作者:
男 ken0137 (顺眼即佛) ★☆☆☆☆ -
普通会员
2024/6/13 13:43:21
9楼: 我奇怪的是其他通用的串口软件,都能正常的显示
此帖子包含附件:
PNG 图像
大小:4.0K
----------------------------------------------
只会简单使用,并未精通深入
作者:
男 ken0137 (顺眼即佛) ★☆☆☆☆ -
普通会员
2024/6/13 13:50:11
10楼: @pcplayer 安装你的方法,貌似可以
就是我写出来的很奇怪

----------
var
  DHM:string;
procedure TForm1.RS1ReceiveData(Sender: TObject; Buffer: Pointer;
  BufferLength: Word);
var
  I: Integer;
  S: string;
  Input: array of byte;
begin
  Input := Buffer;
  for I:=0 to BufferLength-1 do
  begin
    S := DHM+S + Chr(Input[I]);
    DHM:='';
    if Chr(Input[I])=#13 then
    begin
      mmo1.Lines.Add(S);
      S:='';
    end;
  end;
  if S<>'' then DHM:=S;
end;
----------------------------------------------
只会简单使用,并未精通深入
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2024/6/13 15:14:46
11楼: 一般情况是开个线程用于接收串口数据,然后缓存,然后发消息给主程序处理缓存数据。

当然对于你这个简单的处理,20MS收一次数据,可以不用线程,就是要判断串口接收的数据帧了,帧结束标志就是换行符了(更完整点的还要帧起始标志、校验位等)
----------------------------------------------
-
作者:
男 bighawk (Hawk) ★☆☆☆☆ -
盒子活跃会员
2024/6/13 15:20:01
11楼: 算了,热脸贴一下冷屁股。使用以下代码,请调试确定其中的下标无误:
另,RS1ReceiveData回调函数多半是在另一个线程中运行,按照 VCL 的编码标准,所以不应该在此处直接操作 mmo1。

var
  DHM: array [0 .. 511] of AnsiChar;
  DhmLen: integer = 0;

procedure TForm1.AddLine;
begin
  mmo1.lines.add(DHM);
end;

procedure TForm1.RS1ReceiveData(Sender: TObject; Buffer: Pointer; BufferLength: Word);
var
  I: integer;
  p: PAnsiChar;
begin
  p := Buffer;
  I := 0;
  while I < BufferLength do
    case p[I] of
      #10:
        begin
          Inc(p);
          Inc(I);
        end;
      #13:
        begin
          p[I] := #0;
          Move(p^, DHM[DhmLen], I);
          Synchronize(AddLine);
          Inc(p, I + 1);
          Inc(I);
          DhmLen := 0;
          Break;
        end;
    else
      Inc(I);
    end;
  if p <> Buffer then
    Dec(BufferLength, I + 1);
  if BufferLength > 0 then
  begin
    Move(p^, DHM[DhmLen], BufferLength);
    Inc(DhmLen, BufferLength);
  end;
end;
----------------------------------------------
-
作者:
男 ken0137 (顺眼即佛) ★☆☆☆☆ -
普通会员
2024/6/13 16:03:34
12楼: @bighawk @janker 非常感谢两位的回复,我又加了一个队列用于接收处理,加了一个线程用于处理数据
----------------------------------------------
只会简单使用,并未精通深入
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2024/6/13 16:06:42
12楼: 9 楼,别说其它的工具。它什么都不做,把一段文本放进去,比如:abc回车换行xyz回车换行123,它直接就显示成:
abc
xyz
123

原因很简单,因为回车换行,到了普通的文本编辑器里面比如 Memo 里面,它就回车换行了啊。换行,换行.....

10楼,你的代码,当然怪怪的,逻辑上有问题嘛。

    S := DHM+S + Chr(Input[I]);
    DHM:='';
    if Chr(Input[I])=#13 then

你看,你的代码,是先把字符追加进去,再做判断。不是应该先判断么?

除非,你需要把回车换行,追加到字符串里面去。问题是,有必要吗?

你看 11 楼的代码,那就是先判断,再确定怎么做。这才是正确的思路。
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2024/6/13 16:35:45
13楼: procedure TForm5.Button3Click(Sender: TObject);
var
  s: string;
begin
  s := 'abc' + #13#10 + '123' + #13+#10  + 'xyz' + #13+#10;
  Memo1.Lines.Add(S);
end;

你自己测试一下,是不是它就自动换行了。
----------------------------------------------
-
作者:
男 tiez (骑牛夜旅) ★☆☆☆☆ -
普通会员
2024/6/14 9:47:12
14楼: 串口的数据流粘包和断包是正常现象,所以标志头,长度,效验,是通常的做法。有些情况下,包是固定长度,或极短的可推测长度,比如modbus之类的,通过简单的数据边界预期实现有效数据的获取。另外,短数据还常用问答机制来实现数据边界的简单划分。
完全单向的数据流,标志头,长度,或标志尾是必要的。这个也没必要偷懒,因为做一次以后照猫画虎在各个地方都可用。另外,串口的数据传输速度不高,使用程序进行判断处理一般不会有性能上的问题。
----------------------------------------------
-
作者:
男 bighawk (Hawk) ★☆☆☆☆ -
盒子活跃会员
2024/6/14 12:49:55
15楼: 其实最简单的代码是这样子的:
SetLength(S, BufferLength);
Move(Buffer^, S[1], BufferLength);
mmo1.Text := mmo1.Text + S;
只是不能保存操作上下文,就是如果用户滚动过显示区域并不会被记住,会被复位到起始位置
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2024/6/14 13:11:47
16楼: 15 楼,D7 可以这样干。新版的是 UNICODE 的,不能用 string 了。

可以考虑用 TBytes。
----------------------------------------------
-
作者:
男 ken0137 (顺眼即佛) ★☆☆☆☆ -
普通会员
2024/6/15 10:04:39
17楼: 12楼,我先把字符追加进去,再做判断,是因为一次触发有可能接收出现
0.123456#13#100.223456#13#100.323
这样的情况,那么这次触发显示的内容就是
0.123456
0.223456
----------
将0.323保存到全局变量DHM内,等到下次触发的时候连接下一段的字符
,比如下一次触发接收到是
456#13#100.423456#13#100.523456#13#10
那么就能继续显示
0.323456
0.423456
0.523456
----------
----------------------------------------------
只会简单使用,并未精通深入
作者:
男 bighawk (Hawk) ★☆☆☆☆ -
盒子活跃会员
2024/6/15 10:32:45
18楼: 因为串口传输的正好也全是可打印字符,所以你直接追加字符串到 memo 的 text 属性即可,它可以帮你换行。就是要接受一个:如果用户滚动了memo的显示区域,这个操作可能会导致显示回到顶部。或者你代码里面滚动到底也行,估计这个也不是用来编辑的
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2024/6/15 17:35:16
19楼: 18 楼:往下追加的话,需要滚动到底部。

可以考虑倒排序:
Memo1.Lines.Insert(0, TimeToStr(Now));
----------------------------------------------
-
作者:
男 bighawk (Hawk) ★☆☆☆☆ -
盒子活跃会员
2024/6/15 18:35:50
20楼: 19 楼,很有闲心啊。有没有空一起来做个东西玩呗
https://gitee.com/bighawk/unifi-platform
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2024/6/15 19:40:56
21楼: 20 楼,看了一下你的连接:一个统一的资源共享平台

究竟提供什么功能?用于什么场景的?
----------------------------------------------
-
作者:
男 bighawk (Hawk) ★☆☆☆☆ -
盒子活跃会员
2024/6/16 10:05:13
22楼: 21 楼。近期目标是实现所有设备所有资源,包括但不限于:文字、图片、视频、文件、桌面、可执行脚本等等的随意可授权访问,只要知道资源的ID,并获得了授权(资源拥有人可以定义访问者权限),可以随便在任何net位置访问它,就是不再是直连才能访问。远期目标是实现了人机操作层面自由以后,能做到支持脚本执行,不过更倾向使用自然语言,而不是类似于 python 的程序员式语言。
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行89.84375毫秒 RSS