使用Spcomm的Comm1.WriteCommByte,接受时怎么样才能转换为byte?程序(有关图象传送)贴出,帮忙解决问题的再加50分!!! (50分)

两种方案:
1.先发送数据长度,然后发送数据接收时也是先接收长度,当然用流来接收.
2.转换成BASE64,象字符串那样接收,然后转换回来.
 
你的通讯协议中最好不要使用一个字节来作为文件结束的判断。
另外,保存图片不一定用Image,同样可以使用文件流来处理。
在你的通讯协议中可以加上发送文件名、文件大小等相关参数。
这样接收方就可以清楚发送过来的东西了。
我做的 多串口调试工具(MulitComWatch)就使用这样的思路
来完成文件的传送的。
http://www.onlinedown.net/mcom.htm
 
Block_K_E,我见过你的软件,很不错,继续加油呀
>>你的通讯协议中最好不要使用一个字节来作为文件结束的判断。
这个问题祥和你探讨一下。如果不用一个字节,那么你认为用几个字节合适?
从理论上讲,无论用多少个字节,无论什么组合,文件中都有可能出现,如何
判断是结束标志还是真正的数据?除非出现的字符及其组合是文件中不可能出
现的,但这也是不可能的。所以,才必须用转义字符来正确的表示是结束符还
是数据,这样的话,用一个字节是最好实现的,也是非常可靠的,也是最好的
办法,这在通讯专业是最常用的方法。当然,先传输大小,再传数据,就不需
要结束标志,这也是一种办法。还有一点,就是串口通信不是100%可靠,这样
可能会出现错误的字符,要是正好是结束标志,岂不糟糕?不过,这又是另一
个话题,是容错、纠错等差错控制的问题了,和这个问题关系不大,就不再讨
论了
 
为什么还是不行?!
还有ss2000大侠,我已经按您的建议把com的设置改了,可是好象还是不行:(
我真的很木纳吗?唉……
unit Bitmap;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
SPComm, StdCtrls, ExtCtrls, ComCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Comm1: TComm;
Image1: TImage;
ComboBox1: TComboBox;
Edit1: TEdit;
Button2: TButton;
StatusBar1: TStatusBar;
Bevel1: TBevel;
Label1: TLabel;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button2Click(Sender: TObject);
private
Bitmap1: TBitmap;
Stream2 : TMemoryStream;
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
I:Boolean=False;
const
EscapeChar = #$1B;
EndChar = '`';

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
Stream1:TFileStream;
J:Integer;
B:Byte;
begin
//将图形数据放于stream中,然后再按字节读出,发送
Stream1:=TFileStream.Create('C:/My Documents/My Pictures/3.bmp', fmOpenRead);
try
for J:=0 to Stream1.Size do
begin
Stream1.Read(B,1);
if chr(B)=EscapeChar then
Comm1.WriteCommData(EscapeChar,1);
if chr(B)=EndChar then
Comm1.WriteCommData(EscapeChar,1);
if not Comm1.WriteCommByte(B) then
begin
Messagedlg('通讯错误!',mtWarning,[mbOk],0);
exit;
end;
end;
//以Esc为结束标志
Comm1.WriteCommData(EscapeChar,1);
MessageDlg('数据传送结束!',mtInformation,[mbOk],0);
finally
Stream1.Free;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
try
Comm1.StartComm;
StatusBar1.SimpleText:='正常工作';
except
StatusBar1.SimpleText:='串口被占用或不存在!';
end;
Stream2:=TMemoryStream.Create;
//创建bitmap
Bitmap1:=TBitmap.Create;
////////////////////////////////////////
Edit1.Text:=IntToStr(Comm1.BaudRate);
ComboBox1.Text:=Comm1.CommName;
end;

procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
S:Array [0..2047] of byte;//String;
I:Integer;
Flg:Boolean;
begin
Flg:=False;
// SetLength(S,BufferLength);
Move(Buffer^,Pchar(@S)^,BufferLength);
//判断是否结束
//////////////////////////
// Memo1.Lines.Add(S);
// Memo1.Invalidate;
//////////////////////////
for I:=0 to Length(S) do
begin
if Flg then
begin
Flg:=False;
Continue;
end; //前面也是Esc,只要一个

if chr(S)=EscapeChar then //遇到转义符,Esc为转义符
if chr(S[I+1])=EscapeChar then Flg:=True //转义符后面的字符只有两种可能
else Continue; //要么是Esc要么是`,对两种情况分别判断
if ((chr(S)=EndChar) and (chr(S[I-1])<>EscapeChar)) then //只有`,前面没有Esc,结束
begin
//将接受到的图片存放文件中,并显示在image中
Stream2.Position:=0;
Bitmap1.LoadFromStream(Stream2);
Image1.Picture:=TPicture(Bitmap1);
end
else
begin
Stream2.Write(S,1);
end;
end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Comm1.StopComm;
Bitmap1.FreeImage;
Stream2.Free;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
Combobox1.Enabled:=not Combobox1.Enabled;
Edit1.Enabled:=not Edit1.Enabled;
I:= not I;
if I then
begin
Button2.Caption:='设置';
//
Comm1.StopComm;
Comm1.BaudRate:=StrtoInt(Edit1.text);
Comm1.CommName:=Combobox1.Text;
//
try
Comm1.StartComm;
StatusBar1.SimpleText:='正常';
except
StatusBar1.SimpleText:='被占用或不存在!';
end;
end
else
Button2.Caption:='修改';
end;

end.
另:ss2000大侠,谢谢进来的不倦教诲,请去下面地方拿分:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1364653
 

接受部分使用字符串接受(注释部分)也是不行!

另:哪位大侠对图象扫描,然后把扫描的颜色以二进制的形式存储(比如:对于单色,象素为白色,则为1,黑色为0;每个字节存八个象素的颜色)方面有经验,
敬请指教,愿奉高分!
 
该程序其实已经基本完成,但是图象显示只有一半是正确的,另一半花屏:(
估计是转义方面还有问题,我再努力……
 
>>接受部分使用字符串接受(注释部分)也是不行!
兄弟,如果你初学,大家都会帮你,可是如果帮你你却不看,那就没有人帮你了
Move(Buffer^,Pchar(@S)^,BufferLength);

Move(Buffer^,Pchar(S)^,BufferLength);
的区别,以及当是S定义为String时,该如何用,我前面已经说得很清楚了,不是
不行,是你用错了,伤心,更伤心你对别人的帮助视而不见,本来想把你那段循环
重做一遍,因为你的循环中的判断做得不好,但现在没有心思给你做了,分我也
不想要了!
 
大侠,你误会我了!你的每一条解答我都认真的看了,而且也样做了!有关mov部分的代码我是没有错的呀?!我的程序传送已经可以了
只是在转义部分还有点小问题,黑白图象的传输已经没有问题了。所以我认为是转移部分的问题!
再次谢谢您的教诲!
unit Bitmap;

interface

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

type
TForm1 = class(TForm)
Button1: TButton;
Comm1: TComm;
Image1: TImage;
ComboBox1: TComboBox;
Edit1: TEdit;
Button2: TButton;
StatusBar1: TStatusBar;
Bevel1: TBevel;
Label1: TLabel;
Button3: TButton;
OpenDialog1: TOpenDialog;
Image2: TImage;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
Bitmap1: TBitmap;
Stream2 : TMemoryStream;
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
I:Boolean=False;
FileName:TFileName;
const
EscapeChar = #$1B;
EndChar = '<';

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
Stream1:TFileStream;
J:Integer;
B:Byte;
begin
//将图形数据放于stream中,然后再按字节读出,发送
Stream1:=TFileStream.Create(FileName, fmOpenRead);
try
for J:=0 to Stream1.Size do
begin
Stream1.Read(B,1);
if chr(B)=EscapeChar then
Comm1.WriteCommData(EscapeChar,1);
if chr(B)=EndChar then
Comm1.WriteCommData(EscapeChar,1);
if not Comm1.WriteCommByte(B) then
begin
Messagedlg('通讯错误!',mtWarning,[mbOk],0);
exit;
end;
end;
//以Esc为结束标志
Comm1.WriteCommData(EscapeChar,1);
MessageDlg('数据传送结束!',mtInformation,[mbOk],0);
finally
Stream1.Free;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
try
Comm1.StartComm;
StatusBar1.SimpleText:='正常工作';
except
StatusBar1.SimpleText:='串口被占用或不存在!';
end;
Stream2:=TMemoryStream.Create;
//创建bitmap
Bitmap1:=TBitmap.Create;
////////////////////////////////////////
Edit1.Text:=IntToStr(Comm1.BaudRate);
ComboBox1.Text:=Comm1.CommName;
end;

procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
S:Array [0..2047] of byte;//String;
I:Integer;
Flg:Boolean;
begin
Flg:=False;
// SetLength(S,BufferLength);
Move(Buffer^,S,BufferLength);
//判断是否结束
//////////////////////////
for I:=0 to Length(S) do
begin
if Flg then
begin
Flg:=False;
Continue;
end; //前面也是Esc,只要一个

if chr(S)=EscapeChar then //遇到转义符,Esc为转义符
if chr(S[I+1])=EscapeChar then Flg:=True //转义符后面的字符只有两种可能
else Continue; //要么是Esc要么是`,对两种情况分别判断
if ((chr(S)=EndChar) and (chr(S[I-1])<>EscapeChar)) then //只有`,前面没有Esc,结束
begin
//将接受到的图片存放文件中,并显示在image中
Stream2.Position:=0;
Bitmap1.LoadFromStream(Stream2);
Image1.Picture:=TPicture(Bitmap1);
Image1.Refresh;
MessageDlg('接受结束',mtInformation,[mbOK],0);
end
else
begin
Stream2.Write(S,1);
end;
end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Comm1.StopComm;
Bitmap1.FreeImage;
Stream2.Free;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
Combobox1.Enabled:=not Combobox1.Enabled;
Edit1.Enabled:=not Edit1.Enabled;
I:= not I;
if I then
begin
Button2.Caption:='设置';
//
Comm1.StopComm;
Comm1.BaudRate:=StrtoInt(Edit1.text);
Comm1.CommName:=Combobox1.Text;
//
try
Comm1.StartComm;
StatusBar1.SimpleText:='正常';
except
StatusBar1.SimpleText:='被占用或不存在!';
end;
end
else
Button2.Caption:='修改';
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
FileName:=OpenDialog1.FileName;
Image2.Picture.LoadFromFile(FileName);
end
else
MessageDlg('打开文件错误',mtWarning,[mbOk],0);
end;

end.

您如果觉得还有不妥的地方,敬请指教!真心的!!
 
ss2000:
大侠,如果我在什么地方使您感到不愉快,本人在此向您表示最诚挚的歉意,鄙人一定改正!对您的
帮助我是由衷的感激的!!
 
今天发生件事儿我得告诉大家。
我在做大唐地磅称重模块时,发现地磅报来的有效数据有时候是四帧、有时候是五帧。
我以为就是这么设计的,就想,可能厂家就这么设计的,没有管它。可是一天之中总有那么
一两次报数不准。询问厂家后才知道不可能是四帧。原来我以前都是处理ASCII码格式,而
大唐的磅所的是BCD码格式。地磅报过来的很多数据都被SPComm 滤掉了。
所以传输过程中如果不需要进行速度控制,应该关闭XOn/XOff功能。
 
>>接受部分使用字符串接受(注释部分)也是不行!
那我先问你,为什么你用字符串不行?
肯定是可以的.
而且,在这里你根本用不着Move函数
你只要这么定义就可以
S: PChar;
S := PChar(Buffer);
for I:=0 to BufferLength-1 do( for I:=0 to Length(S) do 是错误的)
~~~~~~~~~
下面的代码就不用变了,就OK了
 
to SS2000:
我在这里和你探讨一下自己定义通讯协议的问题:
在传送二进制文件时,所有的转义符都可能出现在文件中,如果我有一个文件,其内容就是:
/x00/x01/x02/x03/x04........../xFC/xFD/xFE/xFF
共256个字节,你说用啥来作为你的文件结尾符标记呢?
我知道一般工业上都爱使用转义符作为数据的开始和结束标记。但别忘了,他使用的转义符
在他的通讯协议中都是保留字,不能随意出现的。
而我们发送二进制文件就不同了。二进制文件可能是任意字符。
因此我们就要尽最大可能来排除二进制文件中的数据与你的通讯协议关键字相同的几率。
因此我说使用多个字符。比如我程序中使用:
#13 + 'XueTxtEnd>' + #13
作为我程序中发送文件结束的标记。当然二进制文件中可能会出现以上字符串,但出现在
几率就会比你用一个字节作标记小得多。
还要注意:发送接收二进制文件时,不只要将Inx_XonXoffFlow和Out_XonXoffFlow属性设置
为False,还有将要将spcomm的IgnoreNullChar 的属性设置为False,否则无法接收发送/x00

 
to Block_K_E:
首先,我声明这种方法不是我自定义的,是通讯中常用的,我还没有那么厉害,呵呵
第二,可能你对转义符的用法不是太明白,我解释一下。
在通信中,我们不是要尽可能的减小结束标志的出现几率,而是要100%的避免。象你说
的用#13 + 'XueTxtEnd>' + #13作为结束符,可能出现的几率是亿分之一(256的12次方)
,但是,就是这亿分之一说明你的程序有Bug,起码是理论上的Bug。当我们使用转义符,
比如用楼主的定义为ESC(0x1B),再定义结束符'<',显然,要求在数据不出现'<'是不现
实的,在一个随机的二进制文件中,出现的概率是1/256,很大了。怎么办,用转义符。
当有数据'<'的时候,我们发送ESC(0x1B)+'<',当然更好的办法是发送
ESC(0x1B) + '<'xor $55,这样,就避免了真个数据中出现'<'字符,这样,当出现'<'
时候,一定就是结束了。同样,当数据中出现ESC怎么办,一样的解决办法用
ESC + ESC'xor $55,那么,在整个数据中就不会出现ESC和'<'字符,遇到ESC一定是转义,
遇到'<'一定是结束,OK,这样就从理论上100%的排除误判。之所要异或$55,主要是为了
接受端处理上逻辑更清楚,更简单,因为异或后,在整个数据中就不会出现结束符,一旦
出现,就是结束。就不会出现楼主的那个别扭的判断
>>if ((chr(S)=EndChar) and (chr(S[I-1])<>EscapeChar)) then //只有`,前面没有Esc,结束
这种判断方法是错误的。
顺便说一句,这种方法是用牺牲效率换来的,你想,如果有一个文件大小为1000个字节,
全部是结束符,实际上就需要传输2001个字符,而用你的方法,只需要1012个字符!
当然,这是理论上的极端情况,实际情况大家该很清楚了。所以,转义符和结束符的定义
要尽可能的为最少出现的字符.



 
按照大侠的提示我又将程序改如下!这虽是个很小的程序却让我学习到了很多东西,再次感谢各位的解答特别是ss2000!我在学习中确实存在有浮躁的现象,如果因为这个给大家带来不愉快,本人表示歉意!
现在这个程序基本可以进行图象的传送,但在图象太大时还是有点问题(会花屏)!我会继续的努力的。
另:请ss2000去下面的地方取分,不要浪费吗!
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1364653




unit Bitmap;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
SPComm, StdCtrls, ExtCtrls, ComCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Comm1: TComm;
Image1: TImage;
ComboBox1: TComboBox;
Edit1: TEdit;
Button2: TButton;
StatusBar1: TStatusBar;
Bevel1: TBevel;
Label1: TLabel;
Button3: TButton;
OpenDialog1: TOpenDialog;
Image2: TImage;
SaveDialog1: TSaveDialog;
Button4: TButton;
Button5: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
private
Bitmap1: TBitmap;
Stream2 : TMemoryStream;
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
I:Boolean=False;
FileName:TFileName;
const
EscapeChar = #$1B;
EndChar = '<';
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
Stream1:TFileStream;
J:Integer;
B,St:Byte;
begin
//将图形数据放于stream中,然后再按字节读出,发送
Stream1:=TFileStream.Create(FileName, fmOpenRead);
try
for J:=0 to Stream1.Size do
begin
Stream1.Read(B,1);
if chr(B)=EscapeChar then
begin
Comm1.WriteCommData(EscapeChar,1);
St:=B xor $55;
Comm1.WriteCommByte(St);
Continue;
end;
if chr(B)=EndChar then
begin
Comm1.WriteCommData(EscapeChar,1);
St:=B xor $55;
Comm1.WriteCommByte(St);
Continue;
end;
if not Comm1.WriteCommByte(B) then
begin
Messagedlg('通讯错误!',mtWarning,[mbOk],0);
exit;
end;
end;
//以Esc为结束标志
Comm1.WriteCommData(EscapeChar,1);
MessageDlg('数据传送结束!',mtInformation,[mbOk],0);
finally
Stream1.Free;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
try
Comm1.StartComm;
StatusBar1.SimpleText:='正常工作';
except
StatusBar1.SimpleText:='串口被占用或不存在!';
end;
Stream2:=TMemoryStream.Create;
//创建bitmap
Bitmap1:=TBitmap.Create;
////////////////////////////////////////
Edit1.Text:=IntToStr(Comm1.BaudRate);
ComboBox1.Text:=Comm1.CommName;
end;

procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
S:Array [0..2047] of byte;//String;
temp:byte;
I:Integer;
Flg:Boolean;
begin
Flg:=False;
// SetLength(S,BufferLength);
Move(Buffer^,S,BufferLength);
//判断是否结束
//////////////////////////
for I:=0 to Length(S) do
begin
if Flg then
begin
Flg:=False;
temp:=S xor $55;
Stream2.Write(temp,1);
Continue;
end; //前面也是Esc,只要一个

if chr(S)=EscapeChar then //遇到转义符,Esc为转义符
begin
Flg:=True;
Continue;
end;

if chr(S)=EndChar then //结束
begin
//将接受到的图片存放文件中,并显示在image中
Stream2.Position:=0;
Bitmap1.LoadFromStream(Stream2);
Image1.Picture:=TPicture(Bitmap1);
Image1.Refresh;
MessageDlg('数据接受结束!',mtInformation,[mbOK],0);
end
else
begin
Stream2.Write(S,1);
end;
end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Comm1.StopComm;
Bitmap1.FreeImage;
Stream2.Free;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
Combobox1.Enabled:=not Combobox1.Enabled;
Edit1.Enabled:=not Edit1.Enabled;
I:= not I;
if I then
begin
Button2.Caption:='设置';
//
Comm1.StopComm;
Comm1.BaudRate:=StrtoInt(Edit1.text);
Comm1.CommName:=Combobox1.Text;
//
try
Comm1.StartComm;
StatusBar1.SimpleText:='正常';
except
StatusBar1.SimpleText:='被占用或不存在!';
end;
end
else
Button2.Caption:='修改';
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
FileName:=OpenDialog1.FileName;
Image2.Picture.LoadFromFile(FileName);
end
else
MessageDlg('打开文件错误',mtWarning,[mbOk],0);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
SaveDialog1.InitialDir:='C:/My Documents/My Pictures';
if SaveDialog1.Execute then
Image1.Picture.SaveToFile(SaveDialog1.FileName);
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
Stream2.Clear;
end;

end.
 
我以前在信中不是告诉过你:
>同时,你得根据 onSendDataEmpty 来判断数据是否发送成功。
发送成功再发送下个数据,否则文件一大了就会丢数据。

 
谢谢Block_K_E,现在没分了,以后挣了分一定给您!
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
828
SUNSTONE的Delphi笔记
S
顶部