小弟泪洒大富翁求解---------delphi串口通信!!! ( 积分: 100 )

  • 主题发起人 主题发起人 vieriliu
  • 开始时间 开始时间
V

vieriliu

Unregistered / Unconfirmed
GUEST, unregistred user!
问题:我现在有个通信协议是这样的:开头的字符1002(16进制)表示一桢的开始,然后开始收数据,(若不是1002,则等待)接受数据的字符长度是不定的,当收到1003时,表示一帧结束,下位机是不断发一帧一帧数据的,那上位机一边接受,一边处理提取1002到1003之间的有用信息。(下位机发送数据的时候,如果中间有用信息有10就直接在后面插入10,再发给我上位机,所以我上位机还要删除这个插入的10)

我现在已经可以用spcomm控件接受到下位机发上来的连续的一帧帧16进制数据
但是只能接受不能提取有用的字符,不知道各位高手有什么高见?
如果一边发一边处理是不是要多线程的呢?
还有spcomm控件可以不可以完成这个任务呢?
 
问题:我现在有个通信协议是这样的:开头的字符1002(16进制)表示一桢的开始,然后开始收数据,(若不是1002,则等待)接受数据的字符长度是不定的,当收到1003时,表示一帧结束,下位机是不断发一帧一帧数据的,那上位机一边接受,一边处理提取1002到1003之间的有用信息。(下位机发送数据的时候,如果中间有用信息有10就直接在后面插入10,再发给我上位机,所以我上位机还要删除这个插入的10)

我现在已经可以用spcomm控件接受到下位机发上来的连续的一帧帧16进制数据
但是只能接受不能提取有用的字符,不知道各位高手有什么高见?
如果一边发一边处理是不是要多线程的呢?
还有spcomm控件可以不可以完成这个任务呢?
 
通信协议有多少字节,就把上位机接受缓冲区设置多大,并且相应地设置触发条件(通信协议有多少字节),上位机在oncomm事件中处理这些收到的字节。其实这样设置最终只能对下位机传上来的一帧数据处理。setlength(Amin,通信协议字节),处理这个动态数组。
还有。“(下位机发送数据的时候,如果中间有用信息有10就直接在后面插入10,再发给我上位机,所以我上位机还要删除这个插入的10)”什么意思,说清楚,看了好多遍,还是不理解。。
 
谢谢wjqhyg
首先说清楚那个插入10的问题,因为一帧的开头是1002,结尾是1003,那如果中间帧的内容需要1002,那下位机送上来的如果还是1002,那很容易和帧头混淆,所以插入个10变成101002,同样如果中间帧的内容需要是1003,那也要插入10,变成101003,这样可以区别于帧尾1003。这 次我说清楚了么?
那接下来就回到你说的
“通信协议有多少字节,就把上位机接受缓冲区设置多大,并且相应地设置触发条件(通信协议有多少字节),上位机在oncomm事件中处理这些收到的字节。”
因为可能要插入10,所以事先是不知道一帧 是多少字节的
 
1003插入10变成101003,那还不是包含了1003吗?上位机照样会把它认为是帧尾的吧!!!
 
to :77391
不会的,因为先确认是不是‘10’,再确认后面的字符是不是‘03’
而101003在确认了10后,接下来是10
所以不会认为是帧尾的
 
我觉得主要问题是字符串的处理,如果你不能保证每次接收的是一个完整有帧头帧尾的帧。那么就定义一个全局字串变量rx,把每次接收的数据加在rx的后面rx:=rx+s;然后对rx进行检查帧头帧尾的工作。
下面是几个字串操作很有用的函数:
(函数具体用法我记不太清了,可能有错,你再查一下)
字串定位:if pos(char(#10)+char(#02),rx)>0 then 有帧头
if pos(char(#10)+char(#03),rx)>0 then 有帧尾
if pos(char(#10)+char(#10),rx)>0 then 有插入字符
字串拷贝 s:=copy(rx,pos(char(#10)+char(#02),rx)-2,pos(char(#10)+char(#03),rx));
字串删除 delete(rx,1,pos(char(#10)+char(#03),rx));
delete(rx,pos(char(#10)+char(#10),rx)-1,pos(char(#10)+char(#10),rx));
 
如果你对效率要求不是太高的话,还是用定长的帧结构比较好.这样程序处理比较方便.就是定长帧效率也还是可以的.我的应用是一个实时音频系统,使用的就是定长帧.第个帧有64个字节,有固定的帧头和帧尾.效果还是可以的.
 
多谢maxim88和ayu310的建议
首先对于ayu310 的建议,我也想帧长固定,但是下位机不是我做,所以也没有办法
还有就是下面是我写的程序
可以接受但发现处理不了,我是综合了wjqhyg和maxim88大哥的意见,下位机每一帧的间隔是1s发上来,我程序是按一帧一帧的处理,其中要说明的就是:
对于spcomm控件里的readintervaltimeout和readtotaltimeout我不大明白什么意思,但我设置为100和3(发现3和5的效果没什么不同,但是10的话就收不到数据了)请各位大哥帮我指正,谢谢!!
procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
buffer_ptr: pChar;
i: Integer;
j: Integer;
f,str_1,b,x,m,z:string;
e,a,h,c,l: integer;
begin
j:=0;
buffer_ptr:=Buffer;
ReceiveCount:=ReceiveCount+1;
if ReceiveCount=1000 then
ReceiveCount:=0;
Edit2.Text:=IntToStr(ReceiveCount);
Str_1:='';
if BufferLength>=1 then
begin
while j<=BufferLength-1 do
begin
i:=Integer((Buffer_ptr+j)^);
Str_1:=Str_1+IntTohex(i,2);
j:=j+1;
end;
memo1.Text:=Str_1;
a:=pos('1002',x);
delete(x,1,a+3);
memo2.text:=x;
x:=memo2.Text;
while not pos('1010',x)=0 do
begin
e:=pos('1010',x);
f:=copy(x,a+4,2);
edit1.text:=f;
if f='02' then
begin
m:=m+copy(x,1,e-1)+'1002';
delete(x,1,e+5);
end
else if f='03' then
begin
m:=m+copy(x,1,e-1)+'1003';
delete(x,1,e+5);
end;
end;

h:=pos('1003',x);
z:=copy(x,1,h-1) ;
memo3.Text:=m+z;


end;

end;
 
//串口数据接收
procedure TForm1.COMReceiveData(Sender: TObject; Buffer: Pointer; BufferLength: Word);
var s:string;
begin
setlength(s,bufferlength);
move(buffer^,s[1],bufferlength);
按你的情况数据帧用上面的方法接收就可以了,然后对s做处理
不知道你说的不能处理是什么情况?
 
to maxim88
我现在是可以收到数据的,我放在了memo1里面了,可以看到
但是我还要处理提取1002到1003之间的信息字符,最后处理完得到的数据我是放在memo3里面,但是实际却看不到
所以我就怀疑它处理不了
 
a:=pos('1002',x);再这之前x应该赋个值吧?
delete(x,1,a+3);
memo2.text:=x;
x:=memo2.Text;这两句是什么用途?
 
to maxim88
现在可以处理了
我是用while do 语句表示如果有101002,就删除它后补上1002
如果有101003,就删除它补上1003
但是实际过程中
不能达到我的要求
不知道为什么?
还有就是wjqhyg你还有什么高见么?
谢谢!
 
我认为你的通信协议得得改,不然总会出问题,也会加大上位机程序的难度
不如使用类似于IP包的协议,我在串口通讯及网络通讯中都使用了结构
实践表明很有效
还有就是我喜欢用API,串口通讯我是完全用API自定义的多线程处理类
Socket通讯我继承并改造了Delphi原有的类,效果不错
 
估计是删除时的位置不准确,你可以单步跟踪一下,看看每次删除字串后的结果。
还可以用字串覆盖函数试试
replace(s,'1010','10');
 
to maxim88
刚刚也许表达的不清楚,我现在可以得到1002到1003之间的字符了
但是不能删除中间出现的多余的10
也就上如果下位机给的是10 02 01 02 03 10 10 02 05 10 03
那我只能处理成01 02 03 10 10 02 05
我程序中的while do 应该是有问题的
因为我用edit1.text:=inttostr(e)看不到东西
但下位机给的字符中明显是有‘1010’字符 的
我不知道为什么?
 
to mike1234567890
谢谢你的指点
也许你的方法比较高深
我基本体会不到,呵呵
我是个新手
如果你有时间,可以帮我写个大概的参考发到我邮箱
谢谢!!liuxue_au@163.com
 
to maxim88
不怕你笑话,我不会用单步
因为我每次用F7 F8的时候好象都没发现什么所以然来
而且程序还老是跑到project里面去
我很无奈
 
假设s:='1002010203101002051003';
replace(s,'1002','');
replace(s,'1003','');
replace(s,'1010','10');
执行完应该是s:='010203100205';
 
to maxim88
好象不对哦,因为你replace(s,'1002','');的时候,那我的101002中的1002不也被你replace掉了么?
 
后退
顶部