串口通信(100分)

  • 主题发起人 主题发起人 weixj2003ld
  • 开始时间 开始时间
W

weixj2003ld

Unregistered / Unconfirmed
GUEST, unregistred user!
我准备做个计算机通过串口与读卡机(水电气的卡),客户给了个通信协议。我就不懂了,
在delphi中,用spcomm实现串口通信,它本身就有校验设置等。为什么协议(客户给的)中也有校验位,偶是新手。高手说一下二者的关系。是不是做串口通信,都有自己规定的协议呀?
 
要不一致的话,大家怎么能获得一致的内容呀?就好象你说中文,另外一个人说德语,大家都是说呀,你就能听懂人家的了吗???
 
硬件的奇偶校验与通讯报文的校验是两回事。
硬件的奇偶校验是通讯芯片每收到的一个字节数据进行校验,纠错。
而通讯报文里的校验,是给应用程序识别通讯报文是否有效。即是否有硬件无法纠错,对而导致的数据丢失,软件接收过程中的丢失等。

通讯协议的用途如同楼上说的。
许多设备生产厂商有自已的通讯协议,也有国标。按照标准通讯协议生产的产品,其通用性也好一些。就是因为使用者只要知道它采用什么通讯标准,立即就可以连接使用。
 
to:楼上的朋友,
连接串口上的设备不一样时,它们的通信协议应该不一样,此协议是生产该设备的厂家写的,协议的内容设备能够辨认,计算机能够处理各种协议(因为协议的内容要读到缓冲区中,我们编程从缓冲区中取出数据进行处理),我这样理解对不对?
另外我想问个问题:spcomm控件中有一个stopbits属性,该属性的值是:_1, _1_5, _2 ,不知道怎样理解stopbits及其值。客户协议中规定了10位/字节,1位起始位,8位数据位,1位停止位,不知道这里的停止位和前面的有何关系?计算机每个字节8位,怎样定义10位/字节?谢谢!
 
计算机并不能处理各种通讯协议,通讯协议是应用软件之间的交互标准。
计算机只负责将报文读进缓冲区,我们做的应用程序读出数据后,按协议从分解出需要的信息。如通讯协议对一信息帧的定义为:
D8h Len len D8h type data crc
---------------
计算机接收数据时并不能保证都是从一个报文帧的起始位置接收,所以你的程序应该能在接收到的大量报文中找到一个报文帧的超始位置,并提取出来,如:
A0 35 D8 10 10 D8 3E 28 29 E4 5D 7A AC 82 76 8D AE EC 23 76 E3 CA D8 21 21 D8 ..
-----------------------------------------------------------
一个完整的报文帧
分解时,按前面定义的格式,分解出:
报文头:D8 10 10 D8
帧类型:3E
数据区:28 29 E4 5D 7A AC 82 76 8D AE EC 23 76 E3
校验各:CA
 
客户给了我的通信协议xt-1、2中规定:每次传32字节,这32个字节各代表了不同的含义(其中最后一个字节是校验和)。那么,我定义缓冲区的大小是不是应该为32字节?另外,起始位、停止位都是在spcomm的属性中定义的吧?
 
没人!apw,在哪,我会给分的,我很着急用呀
 
以下是一个跟字符叠加器的通讯,使用ComPort控件,你参考一下。
以下代码是指电脑串口有数据到时的处理过程:
procedure TFormqt_sale.ComPort1RxChar(Sender: TObject; Count: Integer);
var
Str: String;
Send_byte : array[0..2] of byte;
begin
ComPort1.ReadStr(Str, Count);
if Str = chr($55) then //等待命令
begin
label_zfdj.Caption := '等待命令';
end
else
if Str = chr($77) then //等待接收
begin
if iFlag <= 27 then //1..27的字符
begin
label_zfdj.Caption := '发送' + inttostr(iFlag);
Send_byte[0] := iFlag;
Send_byte[1] := sendstring[iFlag];
Send_byte[2] := sendstring[iFlag];
AddNum := AddNum + sendstring[iflag] + iFlag;
iFlag := iFlag + 1;
Comport1.Write(Send_byte,3);
end
else
begin //传送校验位
AddNum := AddNum and 255;
label_zfdj.Caption := '校验';
Send_byte[0] := $A7;
Send_byte[1] := AddNum;
Send_byte[2] := AddNum;
Comport1.Write(Send_byte,3);
end;
end
else
if str = chr($A7) then //校验错误,重发
begin
label_zfdj.Caption := '校验错误';
iFlag := 1;
end;
end;
 
我MM的问一下:户给了我一个通信协议,规定每次传32字节,我是不是(在spcomm控件中)设置缓冲区的大小为32字节?然后将客户规定的32字节在计算机与串口设备来回传送?
 
每次传32个字节,你不一定能在一次接收过程取到完整的信息帧。
最好将缓冲区设大一些,具本多大,还要考虑通讯速率。通常4096Byte的循环队列作缓冲区够你用了。

可以这样构造缓冲区:
[********************..............................................] 缓冲区
^ ^
读指针 写指针

[...................********************...........................] 缓冲区
^ ^
读指针 写指针

[************....................................*****************] 缓冲区
^ ^
写指针 读指针

2.从缓冲区取数据帧:
1)如果通讯协议有同步头,即每一帧数据有确定的开始标识,则:
a.在缓冲区内找到同步头;
b.找到帧长度,找到校验和;
c.校验取到的帧,
d.正确,则这一帧有效,不正确,则从上次找到同步头位置的下一字节开始,继续找。
2)如果能讯协议没有同步头,则要根据预定好的长度,每次取一定长度的数据进行校验,成功,则算找到;不成功,则从下一位位置开始继续找。

接收数据是可以通过上面的缓冲区来进行。楼主说通讯协议规定按32个字节传数据;按上面方法取数据帧,再进行分解。

3.你发数据时能常不需要大的缓冲区,建一个32字节的缓冲区要完全解问题。反缓冲区组织好,填写信息后,直接发出去就完了。
 
spcomm的stop位是表示串行通信中停止位的长度,一般停止位为1位,_1,_1_5和_2分别表示1位、1.5位和两位停止位,按你的设备要求,你可设为_1,另:你不用更多地考虑启始位和停止位,这些位都是由硬件产生的,你只需将8位数据(即1个字节)处理好就行了,在你将此字节送往串行输出缓冲器时,硬件会自动加上启始位和停止位发出的,接收时则相反,硬件会自动去掉启始位和停止位,你收到的仍是1字节(8位)。
 
多人接受答案了。
 
后退
顶部