[求助]一个奇怪的串口通信问题 ( 积分: 50 )

  • 主题发起人 主题发起人 citydawn
  • 开始时间 开始时间
C

citydawn

Unregistered / Unconfirmed
GUEST, unregistred user!
功能设计:PC给下位机发送命令后下位机根据命令返回数据。
//发送字符
procedure TForm1.Button3Click(Sender: TObject);
var
p:pchar;
x:integer;
begin
x:=Length(Memo1.Lines.Text);//Memo1.Lines.Text是发送的内容
p:=Pchar(Memo1.Lines.Text);
Comm1.WriteCommData(p,x);
end;
//接受字符
procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
pStr:pchar;
begin
pStr:= Buffer;
memo2.Lines.Add(pStr);
end;
我这样写可以正常收发信息,但是返回的数据:
根据通讯协议我从PC下发命令:O2O0x0d
下位机返回信息应该为:U200801FD0C6
可是却返回:%倐聜?罜6
慧_200801FD0C6
颻200801FD0C6
颻200801FD0C6
颻200801FD0C6
?200801FD0C6
问题1:他总是头一位出错,这是为什么?一般是什么原因呢?
问题2:另外我把发送代码改为如下:
var
p:pchar;
x:integer;
str:string;
begin
str:=Memo1.Lines.Text;//Memo1.Lines.Text是发送的内容
x:=Length(str);
p:=Pchar(str);
Comm1.WriteCommData(p,x);
end;
这样修改是把Memo1.Lines.Text的内容赋给STRING类型的str,但这样就无法收到信息了。
这是为什么?
 
功能设计:PC给下位机发送命令后下位机根据命令返回数据。
//发送字符
procedure TForm1.Button3Click(Sender: TObject);
var
p:pchar;
x:integer;
begin
x:=Length(Memo1.Lines.Text);//Memo1.Lines.Text是发送的内容
p:=Pchar(Memo1.Lines.Text);
Comm1.WriteCommData(p,x);
end;
//接受字符
procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
pStr:pchar;
begin
pStr:= Buffer;
memo2.Lines.Add(pStr);
end;
我这样写可以正常收发信息,但是返回的数据:
根据通讯协议我从PC下发命令:O2O0x0d
下位机返回信息应该为:U200801FD0C6
可是却返回:%倐聜?罜6
慧_200801FD0C6
颻200801FD0C6
颻200801FD0C6
颻200801FD0C6
?200801FD0C6
问题1:他总是头一位出错,这是为什么?一般是什么原因呢?
问题2:另外我把发送代码改为如下:
var
p:pchar;
x:integer;
str:string;
begin
str:=Memo1.Lines.Text;//Memo1.Lines.Text是发送的内容
x:=Length(str);
p:=Pchar(str);
Comm1.WriteCommData(p,x);
end;
这样修改是把Memo1.Lines.Text的内容赋给STRING类型的str,但这样就无法收到信息了。
这是为什么?
 
会不会是校验位的问题呢?
如,下位机返回时 首字节位Mark位校验,而后续的为校验呢?

要不,可以在网上下载现成的串口通讯调试软件,看看效果。
 
这是通讯协议请看一下:
================================================================================《通讯协议》
1.通讯模式:19200,N,8,1
2.命令格式:1字节命令字+1字节机号+.....+0x0d
3.命令含义:
1) 读读头的序列号:
上位机下发:'R'+机号+2字节校验校验 +0x0d
下位机返回:'R'+机号+8字节序列号+2字节校验校验 +0x0d
2) 读读头中的卡号
上位机下发:'o'+机号+o+0x0d
下位机返回:
若已读取卡号:'U'+机号+8字节卡号+2字节校验校验 +0x0d
若没有读取卡号:'o'+机号+‘1’+2字节校验+0x0d
8字节卡号指4字节16进制卡号转换为ASCII码
3)设置机号和读头序列号
上位机下发:'Z'+'X'+8字节序列号+2字节校验+0x0d
下位机返回:'Z'+'O'+'K'+0x0d
4)清除读卡标志命令1
上位机下发:'U'+机号+'o'+'k'+Oxod
下位机返回:无
5)清除读卡标志命令2
上位机下发:'Q'+机号+'O'+'P'+0x0d
下位机返回:无
说明:1 命令中的所有字节均为ASCII码
2 上位机下发时的校验算法为:前面所有字节异或后得到一个字节,然后将这个字节按高低位 转换为2个ASCII码
3 下位机上传时的校验算法:前面所有字节求和取反加1生成一个字节,然后将这个字节按高低 位转换为2个ASCII码
==============================================================================
根据协议我用的是无校验
会不会是硬件问题或是下位机的程序出错了?
问题2 又是怎么回事情呀?
大家帮忙呀!谢谢了!
 
上位机是正确的,下位机返回时可能字符宽度定义有错
你可以试一下把接收的数据转化为string显示在MEMO中
 
是这样改么?
procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
pStr:pchar;
s:string;
begin
pStr:= Buffer;
s:=string(pStr);//修改
memo2.Lines.Add(pStr);
end;
 
我用的接收方法!
procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
rbuf:array[0..255] of byte;
begin
Move(Buffer^, pchar(@rbuf)^, BufferLength);

end;
 
对于COM口,通讯的的时候,他接受回来的是什么信息?
Move(Buffer^, pchar(@rbuf)^, BufferLength);
这是将信息放到数组中,那么ruff[1]或ruf[2]中放的是什么信息?
是字符还是别的什么?
例如:返回一个字符R,
ruff[1]里存的是字符 R
还是 82 (十进制)
还是 $52 (十六进制)

另外在COM通讯时,他是一个字节一个字节的发信息的么?
比如说:
PC下发命令:O2O0x0d
下位机返回信息应该为:U200801FD0C6
那么当PC发送字符O后,下位机返回字符U,接着PC发2下位机返回字符2
这样单个的发送返回是么?
 
1.
ruff[1]里面存的就是个小于256的数,你理解成什么都行
需要字符就转成字符,需要数字就转成数字
在计算机里面,只有二进制数据,字符/十进制/十六进制 只是表现的方式!

2.
PC下发的是一组小于缓冲大小的数据
应该不是你说得那种方式!
可以根据波特率计算
9600:=1秒9600位,是1200多个字节,
如果下位机连续发送,你两次接收的间隔是1秒,那每次可以从缓冲收到1200多个字节
串口通讯方式是全双工的,收发同时进行.
 
你用mscomm的二进制接收方式,接收过来看看不就清楚了
 
当上位机给下位机发送数据的时候,我不管发送的是字符还是16进制他传送的时候都要转换为2进制,那么当下位机从线路上接收的时候,他接收的也是2进制。
而我疑问的是,下位机程序能识别的是字符或是16进制怎么办?如果是这样,下位机要有个程序来把这个2进制转为字符或16进制么?
 
协议里面 "将一个字节按高低位 转换为2个ASCII码"
是什么意思?
如果转换出来的是不可显示字符,那么怎么作为校验位呢?
 
下位机如果是用口线模拟串口的话,下位机出错的可能性较大,看看是否口线空闲时未置高。如果是硬件串口,那就查查是否线上有干扰。
进制是给人看的,对机器来说什么进制都是一样
 
您说的“口线”是串口线么?
我是用232/485的线从电脑连接下位机的,另外如果是线路问题,他为什么每次都只是错第一位?
这应该是串口调试软件的问题还是硬件的问题?
 
这种情况一般是硬件问题。
口线不是串口线,是指下位机里单片机的引脚。有的设备未使用单片机的硬件串口,而是用一个引脚模拟硬件串口,这时出错的概率较大。你用万用表量一下下位机的发送脚,空闲时应该是一个-5到-10V之间的电压,如果是个正电压那第一个字节就会错。
你用串口调试软件的HEX方式接收看看数据帧的第一字节是否有错
 
我这里没法打开设备,我用16进制接受的数据头一字节也是错误的,看来应该是您所说的哪个问题,十分感谢!
另外,我的问题2:
发送的代码改为这样就无法成功:
str:=Memo1.Lines.Text;//Memo1.Lines.Text是发送的内容
x:=Length(str);
p:=Pchar(str);
Comm1.WriteCommData(p,x);
这样却可以:
x:=Length(Memo1.Lines.Text);//Memo1.Lines.Text是发送的内容
p:=Pchar(Memo1.Lines.Text);
Comm1.WriteCommData(p,x);
==========================================================================
Memo1.Lines.Text里面的字符类型是STRING还是CHAR
为什么给了STRING就无法收发?
 
试了下,都可以发呀,是否你定义的字串有冲突
procedure TForm1.BitBtn1Click(Sender: TObject);
var s:string;
p:pchar;
l:integer;
begin
s:=Memo1.Text;
l:=length(s);
p:=pchar(s);
//Comm1.WriteCommData(PAnsiChar(s),Length(s));
//Comm1.WriteCommData(PChar(s),Length(s));
Comm1.WriteCommData(p,l);
end;
 
//发送字符
procedure TForm1.Button3Click(Sender: TObject);
begin
Comm1.WriteCommData(PChar(Memo1.Lines.Text), Length(Memo1.Lines.Text));
end;
//接受字符
procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
RecStr : String;
begin
SetLength(RecStr, BufferLength);
Move(Buffer^, PChar(RecStr)^, BufferLength);
memo2.Lines.Add(RecStr);
end;
 
谢谢大家!
 

Similar threads

后退
顶部