delphi 7 开发串口通讯问题,有源码和函数库。求指教?
最近在学习delphi,想通过学习开发个串口通讯的程序,通过自己学习和别人的指导,基本开发完成,可是朋友说是接受的数据不对,不知道啥原因,求指教。麻烦高手大哥了。也可以QQ指导:262431920
- Delphi(Pascal) code
unit 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;//关闭COMprocedure 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次。}
[解决办法]
看样子,你是要对某种专用设备进行的开发,多看几遍设备开发说明书,研究透它的通讯协议,也就是它的输入输出的数据格式。
[解决办法]
mscomm没用过,不熟悉,粗看下:
Comm1ReceiveData没有判断接收到的数据长度,还有MSCOMM中是不是有个设置接收到多少个字节后才触发事件?如果是1的话,这时数据还没收全吧。应当是先判断长度,然后再考虑Move数据
[解决办法]
通信是采用485方式吧?
上位机对某台设备发个命令(就是采集数据了),等待下位机返回数据,就是在Comm1ReceiveData事件里了.
在这个事件方法里,第一句就是move(Buffer^, Pchar(@resultbuf)^, BufferLength);没有进行数据长度判断啊,(很遗憾,我也没用过spcomm,我基本是用cport)不知道spcomm是不是也有个属性设置接收到多少长度数据后才触发事件,如果没有,这种写法肯定是有问题的。
对于这种比较固定的时间的,可以采用一种简单的延时方法,在move前加个sleep(),保证能接收到一帧全部数据就行。
[解决办法]
按照你的数据格式来看,你的上传数据格式也不对啊。
还是你本来就是这样发送的?
自己对照一下看看
[解决办法]
你在move设置断点看看接收到的数据
[解决办法]
你可以先看看发送出去的数据是否正确,再看是否有返回的数据
还有就是波特率等串口参数的设置
[解决办法]
你在网上下载一个串口接收工具,然后调试,看下数据,是否正确就可以了,是十六进制显示出来!
[解决办法]
我刚做了一个这样的程序。
procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;BufferLength: Word);
事件中的接受不是将设备发送的数据一次能接受完的,有时事件可能响应2次。
最好能定义一个全局的array ,事件到来时依次判断是否有开始位,如果有就往array 中写数据,然后判断结束标志,到了作处理和清空array,重新判断开始位。