最近在学习delphi,想通过学习开发个串口通讯的程序,通过自己学习和别人的指导,基本开发完成,可是朋友说是接受的数据不对,不知道啥原因,求指教。麻烦高手大哥了。也可以QQ指导:262431920unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, SPComm, StdCtrls, ComCtrls, ExtCtrls, Menus;
type
Tmybytes = array[0..255] of byte;
TForm1 = class(TForm)
Panel1: TPanel;
StatusBar1: TStatusBar;
Button1: TButton;
Button2: TButton;
Edit1: TEdit;
Label1: TLabel;
Memo1: TMemo;
Comm1: TComm;
Label3: TLabel;
Edit3: TEdit;
Button4: TButton;
Edit4: TEdit;
Label4: TLabel;
PopupMenu1: TPopupMenu;
N1: TMenuItem;
N2: TMenuItem;
N3: TMenuItem;
N4: TMenuItem;
N5: TMenuItem;
N6: TMenuItem;
N7: TMenuItem;
PopupMenu2: TPopupMenu;
N8: TMenuItem;
procedure Button2Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
procedure menuClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure N8Click(Sender: TObject);
private
// function CheckCRC8(InputBuff: Pchar; BuffLen: integer; Jiaoyan: word): boolean; function senddataFUN(sendvalue: string): string;
function GetCmd(var cmd: Tmybytes; data: string): integer;
procedure menuClickopen(openvalue: integer);
{ Private declarations }
public
strlist: Tstringlist;
{ Public declarations }
end;
function CheckCRC8(InputBuff: Pchar; BuffLen: integer; Jiaoyan: Word): boolean;var
Form1: TForm1;
rbuf, sbuf: array[0..7] of byte;
resultbuf: array[0..39] of byte; table8: array[0..255] of byte =
($00, $07, $0E, $09, $1C, $1B, $12, $15, $38, $3F, $36, $31, $24, $23, $2A, $2D,
$70, $77, $7E, $79, $6C, $6B, $62, $65, $48, $4F, $46, $41, $54, $53, $5A, $5D,
$E0, $E7, $EE, $E9, $FC, $FB, $F2, $F5, $D8, $DF, $D6, $D1, $C4, $C3, $CA, $CD,
$90, $97, $9E, $99, $8C, $8B, $82, $85, $A8, $AF, $A6, $A1, $B4, $B3, $BA, $BD,
$C7, $C0, $C9, $CE, $DB, $DC, $D5, $D2, $FF, $F8, $F1, $F6, $E3, $E4, $ED, $EA,
$B7, $B0, $B9, $BE, $AB, $AC, $A5, $A2, $8F, $88, $81, $86, $93, $94, $9D, $9A,
$27, $20, $29, $2E, $3B, $3C, $35, $32, $1F, $18, $11, $16, $03, $04, $0D, $0A,
$57, $50, $59, $5E, $4B, $4C, $45, $42, $6F, $68, $61, $66, $73, $74, $7D, $7A,
$89, $8E, $87, $80, $95, $92, $9B, $9C, $B1, $B6, $BF, $B8, $AD, $AA, $A3, $A4,
$F9, $FE, $F7, $F0, $E5, $E2, $EB, $EC, $C1, $C6, $CF, $C8, $DD, $DA, $D3, $D4,
$69, $6E, $67, $60, $75, $72, $7B, $7C, $51, $56, $5F, $58, $4D, $4A, $43, $44,
$19, $1E, $17, $10, $05, $02, $0B, $0C, $21, $26, $2F, $28, $3D, $3A, $33, $34,
$4E, $49, $40, $47, $52, $55, $5C, $5B, $76, $71, $78, $7F, $6A, $6D, $64, $63,
$3E, $39, $30, $37, $22, $25, $2C, $2B, $06, $01, $08, $0F, $1A, $1D, $14, $13,
$AE, $A9, $A0, $A7, $B2, $B5, $BC, $BB, $96, $91, $98, $9F, $8A, $8D, $84, $83,
$DE, $D9, $D0, $D7, $C2, $C5, $CC, $CB, $E6, $E1, $E8, $EF, $FA, $FD, $F4, $F3);implementationuses
uCRC16;
{$R *.dfm}{ TForm1 }{function CheckCRC8(InputBuff: Pchar; BuffLen: integer; Jiaoyan: Word): boolean;
var
i: integer;
Index, CRCvalue: byte;
begin
Result := false;
CRCvalue := 0;
for i := 0 to BuffLen - 1 do
begin
Index := CRCvalue xor byte(InputBuff[i]);
CRCvalue := table8[Index];
end;
// CRCvalue := not CRCvalue;
if CRCvalue = Jiaoyan then Result := true;
end; }
function CheckCRC8(InputBuff: Pchar; BuffLen: integer; Jiaoyan: Word): boolean;
var
i: integer;
temp, CRCvalue: byte;
begin
CRCvalue := 0;
for i := 0 to BuffLen - 1 do
begin
temp := table8[CRCvalue];
CRCvalue := temp xor byte(InputBuff[i]);
end;
if CRCvalue = Jiaoyan then Result := true;
end;
function HexToByte(const Hex: Char): byte;
const
H: array[0..21] of Char = '0123456789abcdefABCDEF';
X: Pointer = @H;
asm
MOV ECX, 21
MOV EDX, [X]
@LoopBegin:
CMP AL, byte PTR [EDX + ECX]
JZ @Find
LOOP @LoopBegin XOR AL,AL
JMP @End @Find:
CMP CL,15
JNG @NotGreaterThan15
SUB CL,6
@NotGreaterThan15:
MOV AL, CL
@End:
end;
//得到校验码
function TForm1.GetCmd(var cmd: Tmybytes; data: string): integer;
var
i, len: integer;
begin
len := length(data) div 2;
for i := 0 to len - 1 do
begin
cmd[i] := HexToByte(data[2 * i + 1]) * 16 + HexToByte(data[2 * i + 2]);
end;
cmd[len] := GetCRC8(@cmd, len);
cmd[len + 1] := $4E;
end;
//发送数据
function TForm1.senddataFUN(sendvalue: string): string;
var
len, i: integer;
commflg: boolean;
arrcmd: Tmybytes;
strsend: string;
begin commflg := true;
strsend := sendvalue + GetCRC8B(@arrcmd, length(sendvalue) div 2) + '4E';
len := length(strsend) div 2;
for i := 0 to len - 1 do
begin
if not Comm1.writecommdata(@strsend[i], 1) then
begin
commflg := false;
break;
end;
sleep(2); {发送时字节间的延时}
end;
if not commflg then
showmessage('发送失败!');
Result := strsend;
end;//接受
procedure TForm1.Button2Click(Sender: TObject);
begin
with Comm1 do
begin
StopComm;
CommName := Edit3.Text;
StartComm;
end;end;
//关闭COM
procedure TForm1.Button4Click(Sender: TObject);
begin
Comm1.StopComm;
end;
//串口接受数据下发事件
procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
viewstring1, viewstring, hexstringr: string;
len, i: integer;
begin
move(Buffer^, Pchar(@resultbuf)^, BufferLength);
len := 20 + 10;
for i := 0 to len - 1 do
begin
hexstringr := hexstringr + inttohex(resultbuf[i], 2);
end;
Memo1.Lines.Add('收到02 16进制数据:' + hexstringr);
Memo1.Lines.Add('');
if (resultbuf[0] = $53) and (resultbuf[len - 1] = $4E) then
begin
if CheckCRC8(@resultbuf, (len - 2), ord(resultbuf[len - 2])) then
begin
for i := 0 to BufferLength - 1 do
viewstring := viewstring + inttohex(resultbuf[i], 2) + ' ';
viewstring := '接受:' + viewstring;
Memo1.Lines.Add(viewstring);
Memo1.Invalidate;
case resultbuf[5] of
$03:
begin
viewstring1 := '电池电压:' + floattostr((ord(resultbuf[16]) * 256 + ord(resultbuf[17])) / 100) + ' V'
+ #13 + #10;
viewstring1 := viewstring1 + '温度值:' + floattostr((ord(resultbuf[20]) * 256 + ord(resultbuf[21])) /
100) + ' C';
end;
$05:
Memo1.Lines.Add('操作应答数据报');
end;
Memo1.Lines.Add(#13 + #10 + viewstring1 + #13 + #10);
if strlist.Count > 0 then
for i := 0 to strlist.Count - 1 do
begin
menuClickopen(strtoint(strlist[i]));
end
else
menuClickopen(5);
strlist.Clear;
end;
end;
if strlist.Count > 0 then
for i := 0 to strlist.Count - 1 do
begin
menuClickopen(strtoint(strlist[i]));
end
else
menuClickopen(5);
end;procedure TForm1.menuClickopen(openvalue: integer);
var
strdata: string;
senddata: string;
begin
case openvalue of
1: // 上传时间间隔
senddata := '53' + inttohex(strtoint(Edit1.Text), 4) + '01' + inttohex(strtoint(Edit4.Text), 4);
2: //进入测试模式
senddata := '53' + inttohex(strtoint(Edit1.Text), 4) + '020001';
3: //退出测试模式
senddata := '53' + inttohex(strtoint(Edit1.Text), 4) + '020002';
4: //重新上传数据
senddata := '4E' + inttohex(strtoint(Edit1.Text), 4) + '040003';
5: //不需要重新上传数据
senddata := '53' + inttohex(strtoint(Edit1.Text), 4) + '040000';
end; case openvalue of
1..5:
begin
strdata := senddataFUN(senddata);
Memo1.Lines.Add('向设备下发16进制数据 :' + strdata);
Memo1.Lines.Add('');
end;
end;end;
procedure TForm1.menuClick(Sender: TObject);
var
strdata: string;
senddata: string;
begin
strlist.Add(inttostr((Sender as TMenuItem).Tag));
menuClickopen(2);
end;procedure TForm1.Button1Click(Sender: TObject);
begin
PopupMenu1.Popup(left + Button1.left + Button1.Parent.left, top + Button1.Parent.top + Button1.top + Button1.Height *
2);
end;procedure TForm1.FormShow(Sender: TObject);
begin
strlist := Tstringlist.Create;
Button2Click(button2);
end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Comm1.StopComm;
end;procedure TForm1.N8Click(Sender: TObject);
begin
Memo1.Lines.Clear;
end;end.{
1. COM==0x01,设置数据上传时间间隔,PARAM表示将要设置的时间间隔,以分钟为单位。
2. COM==0x02,测试模式选择命令,
若PARAM==0x0001,进入测试模式,30分钟后自动退出测试模式。在测试模式下,传感器每两分钟上传一次数据。
若PARAM==0x0002,退出测试模式。
3. COM==0x04,应答命令。
PARAM==0x0003,要求传感器重新上传数据。主机接收到传感器上传的数据后发现有误码或者其它原因需要重新上传时可用此命令;
PARAM==0x0000,数据接收完整,不需要重新上传。如果传感器20ms内收不到任何应答命令,则认为主机没收到数据,自动重发,最多重试2次。
}
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, SPComm, StdCtrls, ComCtrls, ExtCtrls, Menus;
type
Tmybytes = array[0..255] of byte;
TForm1 = class(TForm)
Panel1: TPanel;
StatusBar1: TStatusBar;
Button1: TButton;
Button2: TButton;
Edit1: TEdit;
Label1: TLabel;
Memo1: TMemo;
Comm1: TComm;
Label3: TLabel;
Edit3: TEdit;
Button4: TButton;
Edit4: TEdit;
Label4: TLabel;
PopupMenu1: TPopupMenu;
N1: TMenuItem;
N2: TMenuItem;
N3: TMenuItem;
N4: TMenuItem;
N5: TMenuItem;
N6: TMenuItem;
N7: TMenuItem;
PopupMenu2: TPopupMenu;
N8: TMenuItem;
procedure Button2Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
procedure menuClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure N8Click(Sender: TObject);
private
// function CheckCRC8(InputBuff: Pchar; BuffLen: integer; Jiaoyan: word): boolean; function senddataFUN(sendvalue: string): string;
function GetCmd(var cmd: Tmybytes; data: string): integer;
procedure menuClickopen(openvalue: integer);
{ Private declarations }
public
strlist: Tstringlist;
{ Public declarations }
end;
function CheckCRC8(InputBuff: Pchar; BuffLen: integer; Jiaoyan: Word): boolean;var
Form1: TForm1;
rbuf, sbuf: array[0..7] of byte;
resultbuf: array[0..39] of byte; table8: array[0..255] of byte =
($00, $07, $0E, $09, $1C, $1B, $12, $15, $38, $3F, $36, $31, $24, $23, $2A, $2D,
$70, $77, $7E, $79, $6C, $6B, $62, $65, $48, $4F, $46, $41, $54, $53, $5A, $5D,
$E0, $E7, $EE, $E9, $FC, $FB, $F2, $F5, $D8, $DF, $D6, $D1, $C4, $C3, $CA, $CD,
$90, $97, $9E, $99, $8C, $8B, $82, $85, $A8, $AF, $A6, $A1, $B4, $B3, $BA, $BD,
$C7, $C0, $C9, $CE, $DB, $DC, $D5, $D2, $FF, $F8, $F1, $F6, $E3, $E4, $ED, $EA,
$B7, $B0, $B9, $BE, $AB, $AC, $A5, $A2, $8F, $88, $81, $86, $93, $94, $9D, $9A,
$27, $20, $29, $2E, $3B, $3C, $35, $32, $1F, $18, $11, $16, $03, $04, $0D, $0A,
$57, $50, $59, $5E, $4B, $4C, $45, $42, $6F, $68, $61, $66, $73, $74, $7D, $7A,
$89, $8E, $87, $80, $95, $92, $9B, $9C, $B1, $B6, $BF, $B8, $AD, $AA, $A3, $A4,
$F9, $FE, $F7, $F0, $E5, $E2, $EB, $EC, $C1, $C6, $CF, $C8, $DD, $DA, $D3, $D4,
$69, $6E, $67, $60, $75, $72, $7B, $7C, $51, $56, $5F, $58, $4D, $4A, $43, $44,
$19, $1E, $17, $10, $05, $02, $0B, $0C, $21, $26, $2F, $28, $3D, $3A, $33, $34,
$4E, $49, $40, $47, $52, $55, $5C, $5B, $76, $71, $78, $7F, $6A, $6D, $64, $63,
$3E, $39, $30, $37, $22, $25, $2C, $2B, $06, $01, $08, $0F, $1A, $1D, $14, $13,
$AE, $A9, $A0, $A7, $B2, $B5, $BC, $BB, $96, $91, $98, $9F, $8A, $8D, $84, $83,
$DE, $D9, $D0, $D7, $C2, $C5, $CC, $CB, $E6, $E1, $E8, $EF, $FA, $FD, $F4, $F3);implementationuses
uCRC16;
{$R *.dfm}{ TForm1 }{function CheckCRC8(InputBuff: Pchar; BuffLen: integer; Jiaoyan: Word): boolean;
var
i: integer;
Index, CRCvalue: byte;
begin
Result := false;
CRCvalue := 0;
for i := 0 to BuffLen - 1 do
begin
Index := CRCvalue xor byte(InputBuff[i]);
CRCvalue := table8[Index];
end;
// CRCvalue := not CRCvalue;
if CRCvalue = Jiaoyan then Result := true;
end; }
function CheckCRC8(InputBuff: Pchar; BuffLen: integer; Jiaoyan: Word): boolean;
var
i: integer;
temp, CRCvalue: byte;
begin
CRCvalue := 0;
for i := 0 to BuffLen - 1 do
begin
temp := table8[CRCvalue];
CRCvalue := temp xor byte(InputBuff[i]);
end;
if CRCvalue = Jiaoyan then Result := true;
end;
function HexToByte(const Hex: Char): byte;
const
H: array[0..21] of Char = '0123456789abcdefABCDEF';
X: Pointer = @H;
asm
MOV ECX, 21
MOV EDX, [X]
@LoopBegin:
CMP AL, byte PTR [EDX + ECX]
JZ @Find
LOOP @LoopBegin XOR AL,AL
JMP @End @Find:
CMP CL,15
JNG @NotGreaterThan15
SUB CL,6
@NotGreaterThan15:
MOV AL, CL
@End:
end;
//得到校验码
function TForm1.GetCmd(var cmd: Tmybytes; data: string): integer;
var
i, len: integer;
begin
len := length(data) div 2;
for i := 0 to len - 1 do
begin
cmd[i] := HexToByte(data[2 * i + 1]) * 16 + HexToByte(data[2 * i + 2]);
end;
cmd[len] := GetCRC8(@cmd, len);
cmd[len + 1] := $4E;
end;
//发送数据
function TForm1.senddataFUN(sendvalue: string): string;
var
len, i: integer;
commflg: boolean;
arrcmd: Tmybytes;
strsend: string;
begin commflg := true;
strsend := sendvalue + GetCRC8B(@arrcmd, length(sendvalue) div 2) + '4E';
len := length(strsend) div 2;
for i := 0 to len - 1 do
begin
if not Comm1.writecommdata(@strsend[i], 1) then
begin
commflg := false;
break;
end;
sleep(2); {发送时字节间的延时}
end;
if not commflg then
showmessage('发送失败!');
Result := strsend;
end;//接受
procedure TForm1.Button2Click(Sender: TObject);
begin
with Comm1 do
begin
StopComm;
CommName := Edit3.Text;
StartComm;
end;end;
//关闭COM
procedure TForm1.Button4Click(Sender: TObject);
begin
Comm1.StopComm;
end;
//串口接受数据下发事件
procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
viewstring1, viewstring, hexstringr: string;
len, i: integer;
begin
move(Buffer^, Pchar(@resultbuf)^, BufferLength);
len := 20 + 10;
for i := 0 to len - 1 do
begin
hexstringr := hexstringr + inttohex(resultbuf[i], 2);
end;
Memo1.Lines.Add('收到02 16进制数据:' + hexstringr);
Memo1.Lines.Add('');
if (resultbuf[0] = $53) and (resultbuf[len - 1] = $4E) then
begin
if CheckCRC8(@resultbuf, (len - 2), ord(resultbuf[len - 2])) then
begin
for i := 0 to BufferLength - 1 do
viewstring := viewstring + inttohex(resultbuf[i], 2) + ' ';
viewstring := '接受:' + viewstring;
Memo1.Lines.Add(viewstring);
Memo1.Invalidate;
case resultbuf[5] of
$03:
begin
viewstring1 := '电池电压:' + floattostr((ord(resultbuf[16]) * 256 + ord(resultbuf[17])) / 100) + ' V'
+ #13 + #10;
viewstring1 := viewstring1 + '温度值:' + floattostr((ord(resultbuf[20]) * 256 + ord(resultbuf[21])) /
100) + ' C';
end;
$05:
Memo1.Lines.Add('操作应答数据报');
end;
Memo1.Lines.Add(#13 + #10 + viewstring1 + #13 + #10);
if strlist.Count > 0 then
for i := 0 to strlist.Count - 1 do
begin
menuClickopen(strtoint(strlist[i]));
end
else
menuClickopen(5);
strlist.Clear;
end;
end;
if strlist.Count > 0 then
for i := 0 to strlist.Count - 1 do
begin
menuClickopen(strtoint(strlist[i]));
end
else
menuClickopen(5);
end;procedure TForm1.menuClickopen(openvalue: integer);
var
strdata: string;
senddata: string;
begin
case openvalue of
1: // 上传时间间隔
senddata := '53' + inttohex(strtoint(Edit1.Text), 4) + '01' + inttohex(strtoint(Edit4.Text), 4);
2: //进入测试模式
senddata := '53' + inttohex(strtoint(Edit1.Text), 4) + '020001';
3: //退出测试模式
senddata := '53' + inttohex(strtoint(Edit1.Text), 4) + '020002';
4: //重新上传数据
senddata := '4E' + inttohex(strtoint(Edit1.Text), 4) + '040003';
5: //不需要重新上传数据
senddata := '53' + inttohex(strtoint(Edit1.Text), 4) + '040000';
end; case openvalue of
1..5:
begin
strdata := senddataFUN(senddata);
Memo1.Lines.Add('向设备下发16进制数据 :' + strdata);
Memo1.Lines.Add('');
end;
end;end;
procedure TForm1.menuClick(Sender: TObject);
var
strdata: string;
senddata: string;
begin
strlist.Add(inttostr((Sender as TMenuItem).Tag));
menuClickopen(2);
end;procedure TForm1.Button1Click(Sender: TObject);
begin
PopupMenu1.Popup(left + Button1.left + Button1.Parent.left, top + Button1.Parent.top + Button1.top + Button1.Height *
2);
end;procedure TForm1.FormShow(Sender: TObject);
begin
strlist := Tstringlist.Create;
Button2Click(button2);
end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Comm1.StopComm;
end;procedure TForm1.N8Click(Sender: TObject);
begin
Memo1.Lines.Clear;
end;end.{
1. COM==0x01,设置数据上传时间间隔,PARAM表示将要设置的时间间隔,以分钟为单位。
2. COM==0x02,测试模式选择命令,
若PARAM==0x0001,进入测试模式,30分钟后自动退出测试模式。在测试模式下,传感器每两分钟上传一次数据。
若PARAM==0x0002,退出测试模式。
3. COM==0x04,应答命令。
PARAM==0x0003,要求传感器重新上传数据。主机接收到传感器上传的数据后发现有误码或者其它原因需要重新上传时可用此命令;
PARAM==0x0000,数据接收完整,不需要重新上传。如果传感器20ms内收不到任何应答命令,则认为主机没收到数据,自动重发,最多重试2次。
}
Comm1ReceiveData没有判断接收到的数据长度,还有MSCOMM中是不是有个设置接收到多少个字节后才触发事件?如果是1的话,这时数据还没收全吧。应当是先判断长度,然后再考虑Move数据
谁能帮我讲讲吗?上传数据格式:
开始标志1byte 设备地址4byte 控制字1byte 数据长度2byte 数据区
n个byte 校验和
1byte 结束标志
1byte
(STX)
0x53 (ADDR)
0x00000002 (COM)
0x03 (SIZE)
0x14 (DATA)
20-bytes数据区 (CHK)
校验和 (ETX)
0x4e
(83, 0, 0, 0, 2, 3, 0, 20, 0, 16, 255, 236, 0, 0, 61, 189, 3, 241, 0, 0, 5, 200, 0, 0, 10, 191, 0, 0, 20, 78, 83, 0, 0, 0, 2, 3, 0, 20, 0, 255) 78数据区格式:
2byte 2byte 2byte 2byte 2byte 2byte 2byte 2byte 2byte 2byte
本次开机后发送数据包计数 发送数据包总计数 未用 温度模数转换值 电池电压模数转换值 未用 电池电压值 未用 温度值 未用
上位机对某台设备发个命令(就是采集数据了),等待下位机返回数据,就是在Comm1ReceiveData事件里了.
在这个事件方法里,第一句就是move(Buffer^, Pchar(@resultbuf)^, BufferLength);没有进行数据长度判断啊,(很遗憾,我也没用过spcomm,我基本是用cport)不知道spcomm是不是也有个属性设置接收到多少长度数据后才触发事件,如果没有,这种写法肯定是有问题的。
对于这种比较固定的时间的,可以采用一种简单的延时方法,在move前加个sleep(),保证能接收到一帧全部数据就行。
procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;BufferLength: Word);
事件中的接受不是将设备发送的数据一次能接受完的,有时事件可能响应2次。
最好能定义一个全局的array ,事件到来时依次判断是否有开始位,如果有就往array 中写数据,然后判断结束标志,到了作处理和清空array,重新判断开始位。