关于串口通讯的简单问题,各位大侠帮忙啊,谢谢先!(100分)

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

csgcsw

Unregistered / Unconfirmed
GUEST, unregistred user!
我需要做一个串口通讯的程序,由于以前没有做过这方面的程序,现在有几个问题向各位请教(我使用的是spcomm控件):
1.下面的附件是客户给我的通讯协议(其它的客户也不知道了),可是我有些不是很明白,哪位能帮我解释一下(或者帮我猜测一下):
(1) 其中数据格式说明中A是每一桢中数据的每一个字节的说明吗?
(2) 对spcomm控件来说,rs485和rs232在编程方面有什么差别吗?
(3) 如果还需要用户提供信息,还需要哪些数据?
(4) 求和低位、求和高位又是什么东东?
2.哪位能不能帮我写一下发送数据的代码?即Tcomm.writecommdata里面的内容怎么写?例如“上位机检测下位机的状态”,发送的代码怎么写?


               附:KB30D/LCD与上位机的通信协议
(下述的下位机即指kb300D/LCD仪器,上位机指电脑)
数据格式
A 起始位 Bito Bit1 Bit2 Bit3 Bit4 Bit5 Bit6 Bit7 结束位

第一位起始位为“0”,后面8位数据位
Bit0 ~Bit7最后一位是结束位为“1”

B 通信速率 4800bit/s
C 通信方式 RS-485

一.上位机发给下位机每帧共12个字节
格式: 起始码 识别码 命令码 地址码 数据1 数据2 数据3 数据4
数据5 数据6  求和低位 求和高位

1.上位机检测下位机的状态:识别码0BBH,命令为0F0H
格式:55 BB 命令 机地址 04 01 08 08 08 08 求和低位 求和高位

2.上位机对下位机发操作命令:识别码0BBH
自动40,手动41,联络42,停止D0,复位D1,运行DD,识别码BB
格式:55 BB 命令 机地址 00 00 00 00 00 00 求和低位 求和高位

3.下载工艺:识别码0BBH,命令80H
格式:55 BB 命令 机地址 ****** 求和低位 求和高位
“******”含义为:工艺号 步号 目标温度 温度小数 升温率,保温时间
4.调出待运行工艺:识别码01H,命令0D2H
格式:55 01 命令 机地址 工艺号 步号 00 00 00 00 求和低位 求和高位

5.运行调出工艺:识别码01H,命令0DDH
格式:55 01 命令 机地址 工艺号 步号 00 00 00 00 求和低位 求和高位

6.上载工艺:识别码0BBH,命令0F1H
格式:55 BB 命令 机地址 工艺号 步号 00 00 00 00 求和低位 求和高位

二.上位机接收实时数据每帧共23个字节:
格式:00 集控命令 机地址  0F0H/0F1H Rd Rc Rb CPU 工艺号 步号 目标温度 温度小数 升温率 保温时间 实时温度 实时温度小数 主缸水位 料桶水位 压力 步运行时间 求和高位 求和低位 结束码(0CF)

集控命令:自动40H,手动41H,联络42H

Rd7~Rd0:运行 排冷 缸锁 放水2 平衡 溢流 主泵 料泵
Rc7~Rc0:* * 反转 正转  冷却 加热 * *
Rb7~Rb0:卸压 进水2 直加 进水1  呼叫 *  * 放水1
CPU7~CPU0:* 保温 * *  * * * *

F0H/F1H:0F0为上传实时数据,0F1为上传工艺。
结束码:0CFH
当CPU or Rd为0H时,程序运行结束,曲线自动存盘;
 
和我联系,我的qq,57737508
 
(1) 其中数据格式说明中A是每一桢中数据的每一个字节的说明吗?
A是每一桢的数据结构,但你数一数,肯定不止一个字节;

我个人认为此项目的设定中有一定的问题:
PC机上的串口一般是RS232C标准的,我好象没有听说有RS485的,不过可能是俺孤陋寡闻。

对于RS232与RS485,我觉得它们的主要区别是在工作方式、直接传输的最大距离、最大传输数据速率、信号电平、传输线上允许的驱动器和接收器的数目等方面,但它们应该遵从相同的传输协议,因此软件上应该相同,但要注意控件是否能支持。
...
var
sbuf:array [1..12] of byte;
...
sbuf[1]:=byte($55);//起始码
sbuf[2]:=byte($bb);//识别码
sbuf[3]:=byte($f0);//命令
sbuf[4]:=byte($01 );//机地址,例如 01H
sbuf[5]:=byte($04);//数据1
sbuf[6]:=byte($01);//数据2
sbuf[7]:=byte($08);//数据3
sbuf[8]:=byte($08);//数据4
sbuf[9]:=byte($08);//数据5
sbuf[10]:=byte($08);//数据6
sbuf[11]:=byte($ );//求和低位,我不知求和低位和高位是否为校验措施
sbuf[12]:=byte($ );//求和高位,


procedure comm1_send(rbuf:array [1..12] of byte);
var
i:integer;
begin
for i:=1 to 12 do
comm1.WriteCommData(@rbuf,1); //发送
sleep(2); //延时
end;

此程序不知是否有问题,看看有没有更好的方法。

 
to luckyduo:
我按照你的方法试了一下,下位机没任何反映,估计是发送的数据不对(我这里有一套程序,可以很好的控制该下位机,可惜没有源代码)。
 
刚才是上位机对下位机的检测,如果发送成功的话下位机应该有状态的返回响应,你有没有编写上位机的接收程序??
 
我想,即使是上位机查询成功了,下位机上也未必能直接看到反映,真正成功没还要看接收的数据。。
我刚才的方法应该是正确的,只是不理解求和低位和求和高位。
 
我有接收程序:

var
viewstring:string;

procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
i:integer;
begin
viewstring:='';
move(buffer^,pchar(@rbuf)^,bufferlength);
for i:=1 to bufferlength do
viewstring:=viewstring+inttohex(rbuf,2)+'';
viewstring:='接收+viewstring;
memo1.lines.add(viewstring);
memo1.lines.add('');
end;
但是并没有任何数据显示。
我现在不知道求和低位和求和高位应该怎样取值,客户也不清楚。

 
你试一下:
procedure tform1.comm1receivedata(sender:tobject;buffer:pointer;bufferlength:word);
var
strreceive:string;
buffer:pointer;
bufferlength:word;
begin
setlength(strreceive,bufferlength);
move(buffer^,pchar(strreceive)^,bufferlength);
memo1.lines.add(strreceive);
end;
注意要加一个MEMO控件
 
我试过了,还是不行。
你能帮我看一下代码吗?

unit Unit_Comm;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, SPComm;

type
TForm1 = class(TForm)
Comm1: TComm;
Button1: TButton;
Memo1: TMemo;
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
procedure Button1Click(Sender: TObject);
procedure Comm1ReceiveError(Sender: TObject; EventMask: Cardinal);
private
{ Private declarations }
procedure senddata;
public
{ Public declarations }
end;

var
Form1: TForm1;
viewstring:string;
i:integer;
rbuf:array[1..16] of byte;
//sbuf:array[1..16] of byte;
sbuf:array [1..12] of byte;
implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
comm1.StartComm;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
comm1.StopComm;
end;

procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
{
var
i:integer;
begin
viewstring:='';
move(buffer^,pchar(@rbuf)^,bufferlength);
for i:=1 to bufferlength do
viewstring:=viewstring+inttohex(rbuf,2)+'';
viewstring:='½ÓÊÕ'+viewstring;
memo1.lines.add(viewstring);
memo1.lines.add('');
end;
}
var
strreceive:string;
//buffer1:pointer;
//bufferlength1:word;
begin
setlength(strreceive,bufferlength);
move(buffer^,pchar(strreceive)^,bufferlength);
memo1.lines.add(strreceive);
end;
{var
s: string;
begin
SetLength(S, BufferLength); //½ÓÊÕRS232µÄÊý¾Ý²¢ÏÔʾMemo1ÉÏ¡£
Move(Buffer^, PChar(S)^, BufferLength);
Memo1.Lines.Add(S);
Memo1.Invalidate;
end;
}

procedure TForm1.Button1Click(Sender: TObject);
begin
{
sbuf[1]:=byte($f0); //Ö¡Í·
sbuf[2]:=byte($01);//ÃüÁîºÅ
sbuf[3]:=byte($ff);
sbuf[4]:=byte($ff);
sbuf[5]:=byte($01);
sbuf[6]:=byte($f0); //֡β
senddata;//µ÷Ó÷¢Ëͺ¯Êý
}

sbuf[1]:=byte($55);//ÆðʼÂë
sbuf[2]:=byte($BB);//ʶ±ðÂë
sbuf[3]:=byte($D1);//ÃüÁî
sbuf[4]:=byte($02);//»úµØÖ·£¬ÀýÈç 01H
sbuf[5]:=byte($00);//Êý¾Ý1
sbuf[6]:=byte($00);//Êý¾Ý2
sbuf[7]:=byte($00);//Êý¾Ý3
sbuf[8]:=byte($00);//Êý¾Ý4
sbuf[9]:=byte($00);//Êý¾Ý5
sbuf[10]:=byte($00);//Êý¾Ý6
sbuf[11]:=byte($01);//ÇóºÍµÍλ,ÎÒ²»ÖªÇóºÍµÍλºÍ¸ßλÊÇ·ñΪУÑé´ëÊ©
sbuf[12]:=byte($02);//ÇóºÍ¸ßλ,
senddata;//µ÷Ó÷¢Ëͺ¯Êý

end;

procedure TForm1.Comm1ReceiveError(Sender: TObject; EventMask: Cardinal);
begin
showmessage('error');
end;

procedure TForm1.senddata;
var
i:integer;
begin
for i:=1 to 12 do
begin
comm1.WriteCommData(@sbuf,1); //·¢ËÍ
sleep(2); //ÑÓʱ
end;

end;
end.

object Form1: TForm1
Left = 328
Top = 181
Width = 696
Height = 480
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnClose = FormClose
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 40
Top = 40
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object Memo1: TMemo
Left = 80
Top = 160
Width = 313
Height = 193
Lines.Strings = (
'Memo1')
TabOrder = 1
end
object Edit1: TEdit
Left = 80
Top = 96
Width = 329
Height = 21
TabOrder = 2
Text = 'Edit1'
end
object Comm1: TComm
CommName = 'COM1'
BaudRate = 4800
ParityCheck = False
Outx_CtsFlow = False
Outx_DsrFlow = False
DtrControl = DtrEnable
DsrSensitivity = False
TxContinueOnXoff = True
Outx_XonXoffFlow = True
Inx_XonXoffFlow = True
ReplaceWhenParityError = False
IgnoreNullChar = False
RtsControl = RtsEnable
XonLimit = 500
XoffLimit = 500
ByteSize = _8
Parity = None
StopBits = _1
XonChar = #17
XoffChar = #19
ReplacedChar = #0
ReadIntervalTimeout = 100
ReadTotalTimeoutMultiplier = 0
ReadTotalTimeoutConstant = 0
WriteTotalTimeoutMultiplier = 0
WriteTotalTimeoutConstant = 0
OnReceiveData = Comm1ReceiveData
OnReceiveError = Comm1ReceiveError
Left = 376
Top = 64
end
end
 
你等等,我看看先
 
我想问一下,你的下位机地址是否正确?求和高位、低位的值是否正确?

我看完了,没发现什么问题。你运行的结果是什么?MEMO中什么都没有收到么?
有没有错误提示?
 
对了,别人的协议中数据为04 01 08 08 08 08。。,你为何写入00 00 00 。。?

///////////////////////////////////////////////////////////////////////
1.上位机检测下位机的状态:识别码0BBH,命令为0F0H
格式:55 BB 命令 机地址 [red]04 01 08 08 08 08 [/red]求和低位 求和高位
 
你仔细检查一下,sbuf[1] to sbuf[12]中的数据,命令字也错了,请参照以下来填写

1.上位机检测下位机的状态:识别码0BBH,命令为0F0H
格式:55 BB 命令 机地址 [red]04 01 08 08 08 08 [/red]求和低位 求和高位


 
怎么没看到你在TYPE中对 procedure TForm1.senddata; 过程的声明?编译时没有报错么?
 
我发送的命令是按这个格式的:
上位机对下位机发操作命令:识别码0BBH
自动40,手动41,联络42,停止D0,复位D1,运行DD,识别码BB
格式:55 BB 命令 机地址 00 00 00 00 00 00 求和低位 求和高位
其中机地址应该是下位机控制的机器的号码,应该是00-03之间一个(我都试过了)。
我窗口上的MEMO中什么都没有收到么,也没有错误提示。 
 
按你说的情况,你现在发的是复位命令给下位机,下位机虽可以响应此命令但不一定会有返回值,你能否改用1中的状态查询命令试试看?这个应该有返回值的。而且如果求和低位和高位是校验作用的话,该位添错了也是不行的。
再试试看吧。。
 
顺便说一句,kb300D/LCD仪器是什么仪器?它的地址是怎么设定的?你是怎么得出00~03这个值的?
 
看来我只能再问问客户关于求和高位和求和低位的意思了。
kb300D/LCD连接了很多别的仪器,机地址应该是这些仪器的号码(估计),我也只能再问问客户了。
谢谢luckyduo和fanronghua不厌其烦的解答。
 
行,希望有正确方法时告诉我一声。
 
1.下面的附件是客户给我的通讯协议(其它的客户也不知道了),可是我有些不是很明白,哪位能帮我解释一下(或者帮我猜测一下):
(1) 其中数据格式说明中A是每一桢中数据的每一个字节的说明吗?
答:是,异步串行通信中双方为了正确得确定一个字符,必须有起始位(值恒为比特0)与停止位(值恒为比特1),在此,起始位为1位,停止位为1位
(2) 对spcomm控件来说,rs485和rs232在编程方面有什么差别吗?
答:对你来说,只需关心RS232编程,RS232和RS485之间可购买一通信转换器
(3) 如果还需要用户提供信息,还需要哪些数据?
答:不需
(4) 求和低位、求和高位又是什么东东?
答:指除起始码外(一般是这样,向用户确认一下),其余各字节的累加和(在此为双字节,Word),求和低位为该双字节的低字节
2.哪位能不能帮我写一下发送数据的代码?即Tcomm.writecommdata里面的内容怎么写?例如“上位机检测下位机的状态”,发送的代码怎么写?
1.上位机检测下位机的状态:识别码0BBH,命令为0F0H
格式:55 BB 命令 机地址 04 01 08 08 08 08 求和低位 求和高位

var
Cmd: array[0..11] of Byte;
sCmd: string;
i: Integer;
wSum: Word;
begin
sCmd := '55BBF001040108080808';//假设机地址为$01
wSum := 0;
for i := 0 to Length(sCmd) div 2-1 do
begin
Cmd := StrToInt('$'+Copy(sCmd,i*2+1,2));
wSum := wSum + Cmd;
end;
Cmd[10] := wSum and $FF;
Cmd[11] := wSum shr 8;
Spcomm1.WriteCommData(Cmd, 12);



 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
650
import
I
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
1K
DelphiTeacher的专栏
D
后退
顶部