发表于:2004/3/29 17:22:00
#0楼
转载大富翁论坛 用Spcomm/MScomm串口通信的问题
问题:串口的老问题 (600分) ( 积分:100, 回复:9, 阅读:155 ) 分类:局域网 / 通讯
来自:wancc, 时间:2002-06-04 10:51:00, ID:970841
1.用Mscomm32(vb6带)在Delphi中的收发过程的代码
2.用Spcomm 在Delphi中的收发过程的代码
我用了上面的两个控件发现Mscomm32能发送接收 可是不知道怎样将返回的数据还原成看的
懂的数据(unicode?),我是和51单片机通讯的 谁能写出发送、接收代码将送上300分
用Spcomm也是不知道怎样将返回的数据还原成看的懂的数据,另外它能否象Mscomm一样可以
等到Buffer中有一定个数的字节后再收的功能呢?能否写出原代码将送上300分
其实我看了以前关于串口的帖子 发现大家都是说一半的多 而能写全代码的少 希望这次
各位大侠能写全些的代码供大家学习一下 谢谢!
来自:gzgylgl, 时间:2002-04-04 00:19:00, ID:1022126
我没用过单片几,但于PLC通信做过。一般传过去用字符或ACSII码。传过来用16进制的(PLC)。
来自:antelep, 时间:2002-06-01 16:58:00, ID:1137497
发送和接收都用byte型即可
来自:visualboy, 时间:2002-06-01 23:46:00, ID:1138074
一般串行通讯用ASCII码比较多,当然也有用16进制,正好我都做过。如果是发送端不断发送,那么你可以用事件方式触发。如果是应答方式,你可以用轮询的方式来做。
我以前一直是用VB写跟外围通讯的程序。所以不能提供给你delphi,不过Vb源程序和C源程序倒有
C
int _read_data_register(unsigned int uAddress,unsigned int number)
{ unsigned char uSend[]={2,0x30,0x30,0x30,0x30,0x30,0x30,0x32,3,0x30,0x30};
unsigned char uReceive[104];
unsigned int uTmp;
unsigned int uSum;
unsigned int num;
long lTmp;
int i,j;
if(TESTING==1)
{ for(i=0;i<number;i++)uRead_value[i]=0;
return TRUE;
}
init_plc();
num=number*2;
if((num/16)>=10)
uSend[6]=(unsigned char)(num/16+0x41-10);
else
uSend[6]=(unsigned char)(num/16+0x30);
if((num%16)>=10)
uSend[7]=(unsigned char)((num%16)+0x41-10);
else
uSend[7]=(unsigned char)((num%16)+0x30);
uAddress=uAddress*2+0x1000;
uTmp=uAddress & 0x000f;
uSend[5]=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
uTmp=(uAddress>>4) & 0x000f;
uSend[4]=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
uTmp=(uAddress>>8) & 0x000f;
uSend[3]=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
uTmp=(uAddress>>12)&0x000f;
uSend[2]=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
uSum=0;
for(i=1;i<9;i++)
uSum=uSum+(unsigned char)uSend[i];
uTmp=uSum&0x000f;
uSend[10]=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
uTmp=(uSum>>4)&0x000f;
uSend[9]=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
/*disable();*/
for(i=0;i<11;i++)
{ for(lTmp=0L;lTmp<DELAY_TIMES;lTmp++)
{ if((inportb(STATS_PORT)&0x20)!=0)
break;
}
if(lTmp>=DELAY_TIMES)
{
/*enable();*/
return(FALSE);
}
outportb(DATA_PORT,uSend[i]);
}
disable();
for(lTmp=0;lTmp<DELAY_TIMES;lTmp++)
{ if((inportb(STATS_PORT)&1)!=0)
break;
}
if(lTmp>=DELAY_TIMES)
{
enable();
return(FALSE);
}
uReceive[0]=inportb(DATA_PORT);
if(uReceive[0]!=2)
{
enable();
return(FALSE);
}
for(i=1;i<number*4+4;i++)
{ for(lTmp=0L;lTmp<DELAY_TIMES;lTmp++)
{ if((inportb(STATS_PORT)&1)!=0)
break;
}
if(lTmp>=DELAY_TIMES)
{
enable();
return(FALSE);
}
uReceive[i]=inportb(DATA_PORT);
}
enable();
uSum=0;
for(i=1;i<number*4+2;i++)
uSum=uSum+(unsigned int)uReceive[i];
uTmp=uSum&0xf;
uTmp=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
if((unsigned char)uTmp!=uReceive[number*4+3])return(FALSE);
uTmp=(uSum>>4)&0xf;
uTmp=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
if((unsigned char)uTmp!=uReceive[number*4+2])return(FALSE);
for(j=0;j<number;j++)
{ for(i=j*4+1;i<j*4+5;i++)
uReceive[i]=(uReceive[i]>0x39)?uReceive[i]-0x41+0xa:uReceive[i]-0x30;
uRead_value[j]=(((((uReceive[j*4+3]<<4)+uReceive[j*4+4])<<4)+uReceive[j*4+1])<<4)+uReceive[j*4+2];
}
return TRUE;
}
VB
Private Sub Command1_Click()
Dim sendByte(2) As Byte
Dim sendTXT(4) As Byte
Dim Index As Long
Dim Sendstring As String
Dim inString() As Byte
Dim sTime As Single
Dim CRCHi, CRCLo As Byte
Dim i As Integer
Command1.Enabled = False
sendByte(0) = 5
sendByte(1) = Asc("D")
sendByte(2) = Asc("L")
sendTXT(0) = sendByte(0)
sendTXT(1) = sendByte(1)
sendTXT(2) = sendByte(2)
Index = CRC16(sendByte)
CRCLo = Index Mod 256
CRCHi = Index \ 256
sendTXT(3) = CRCLo
sendTXT(4) = CRCHi
MSComm1.InBufferCount = 0
MSComm1.Output = sendTXT
sTime = Timer
Do
DoEvents
If Timer > sTime + 0.01 Then Exit Do
Loop Until MSComm1.InBufferCount > 0
If MSComm1.InBufferCount > 0 Then
inString = MSComm1.Input
If inString(0) = 6 Then
sTime = Timer
Do
If Timer > sTime + 8 Then Exit Do
Loop
MsgBox "擦除完毕!", vbExclamation, "完成"
Else
MsgBox "擦除失败!", vbExclamation, "提示"
Command1.Enabled = True
Exit Sub
End If
Else
MsgBox "擦除失败!", vbExclamation, "提示"
Command1.Enabled = True
Exit Sub
End If
来自:dracula_king, 时间:2002-06-02 10:54:00, ID:1138393
SPCOMM的例子
CommName:填写COM1
COM2…等串口的名字
在打开串口前,必须填写好此值。
BaudRate:设定波特率9600,4800等,根据实际需要来定,在串口打开后也可更改波特率,实际波特率随之更改。
ParityCheck:奇偶校验。
ByteSize:字节长度_5 _6 _7 _8等,根据实际情况设定。
Parity:奇偶校验位
StopBits:停止位
SendDataEmpty:这是一个布尔属性,为true时表示发送缓存为空,或者发送队列里没有信息;为False时表示表示发送缓存不为空,或者发送队列里有信息。
2.方法
Startcomm过程用于打开串口,当打开失败时通常会报错,错误主要有7种:
⑴串口已经打开 ;
⑵打开串口错误 ;
⑶文件句柄不是通讯句柄;
⑷不能够安装通讯缓存;
⑸不能产生事件 ;
⑹不能产生读进程;
⑺不能产生写进程;
StopComm过程用于关闭串口,没有返回值。
函数WriteCommData(pDataToWrite: PChar;dwSizeofDataToWrite:Word
): boolean 用于发送一个字符串到写线程,发送成功返回true
发送失败返回false
执行此函数将立即得到返回值,发送操作随后执行。函数有两个参数,其中
pdatatowrite是要发送的字符串,dwsizeofdatatowrite 是发送的长度。
3.事件
OnReceiveData : procedure (Sender: TObject;Buffer: Pointer;BufferLength:Word) of object
当输入缓存有数据时将触发该事件,在这里可以对从串口收到的数据进行处理。Buffer中是收到的数据,bufferlength是收到的数据长度。
OnReceiveError : procedure(Sender: TObject; EventMask: DWORD)
当接受数据时出现错误将触发该事件。
三.SPCOMM的使用
下面,我们结合一个串口通讯的例子来说明SPCOMM的使用。
为了实现PC与单片机8051之间的通讯,首先要调通它们之间的握手信号,假定它们之间的通讯协议是,PC到8051一帧数据6个字节
8051到PC一帧数据也为6个字节
当PC发出(F0 01 FF FF 01 F0)后能收到这样一帧(F0 01 FF FF 01 F0),表示数据通信握手成功,两者之间就可以按照协议相互传输数据。在PC方要发送及接受数据需要以下步骤:
1.创建一个新的工程COMM.DPR,把窗体的NAME属性改为FCOMM,把窗体的标题改为测试通讯,添加控件。
对COMM1(黑色矩形围住的控件)进行属性设计,设波特率4800,校验位无,字节长度_8,停止位_1,串口选择COM1。Memo1中将显示发送和接受的数据。选择File/Save
As将新的窗体存储为Comm.pas。
2.编写源代码
变量说明
var
FCOMM: TFCOMM;
Viewstring:string;
i:integer;
rbuf
sbuf:array[1..6] of byte;
打开串口
procedure TFCOMM.FormShow(Sender: TObject);
begin
comm1.StartComm;
end;
关闭串口
procedure TFCOMM.FormClose(Sender: TObject; var Action: TCloseAction);
begin
comm1.StopComm;
end;
发送数据
自定义的发送过程
procedure senddata;
var
i:integer;
commflg:boolean;
begin
viewstring:="";
commflg:=true;
for i:=1 to 6 do
begin
if not fcomm.comm1.writecommdata(@sbuf[i]
1) then
begin
commflg:=false;
break;
end;
sleep(2); {发送时字节间的延时}
viewstring:=viewstring+inttohex(sbuf[i] 2)+" ";
end;
viewstring:="发送"+viewstring;
fcomm.memo1.lines.add(viewstring);
fcomm.memo1.lines.add("");
if not commflg then messagedlg("发送失败!" mterror [mbyes]0);
end;
procedure TFCOMM.Btn_sendClick(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($0f); {帧尾}
senddata;{调用发送函数}
end;
接收过程
procedure TFCOMM.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[i] 2)+" ";
viewstring:="接受"+viewstring;
memo1.lines.add(viewstring);
memo1.lines.add("");
end;
如果memo1上显示发送F0 01 FF FF 0F 和 接受F0 01 FF FF F0
这表示串口已正确的发送出数据并正确的接受到数据,串口通讯成功。
不行的话联系我,我吧我的程序发给你 QQ:1975722
来自:SS2000, 时间:2002-06-02 11:14:00, ID:1138421
>>用Spcomm也是不知道怎样将返回的数据还原成看的懂的数据?
不知道什么样的数据你才能看懂??
SPComm返回的是PChar,是字符为单位的指针,你怎样才能看懂?
这个问题和SPComm没有关系,是你自己对计算机的数据表示方式理解不够
>>等到Buffer中有一定个数的字节后再收的功能呢?
这个问题可以做到,如果你想做的话,但是你需要修改SPComm控件,或者说增强SPComm
的功能,因为目前的SPComm做不到
具体方法是在
procedure TReadThread.Execute;函数中
定义有 szInputBuffer: array[0..INPUTBUFFERSIZE-1] of Char;
修改INPUTBUFFERSIZE这个值成为你所要的值,同时把ReadIntervalTimeout属性值
设置为足够大,比如1234567890或者为0,这样在获得指定的字节数之后才会
发出接收消息
来自:dracula_king, 时间:2002-06-02 11:20:00, ID:1138439
我的程序可以看懂返回的数据呀,将接收数组定义为BYTE型
来自:SupermanTm, 时间:2002-06-04 00:18:00, ID:1141667
把数据报文的格式告诉我,我给你源代码,测试后你给我分!
treemanwww@163.com
来自:cook, 时间:2002-06-04 08:23:00, ID:1141835
我做过一个给自己的下位机测试的程序(c51)
你要的话给你吧。
cook@sina.com
来自:御键飞天, 时间:2002-06-04 10:51:00, ID:1142174
这是我编写的使用MSComm控件进行串口通讯的完整例子,功能上能进行文本方式,二进制方式的通讯,
在Delphi6下编译通过,在Delphi5下只需将uses单元的Variants项去除即可,如满意,请适当给分,呵呵!
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, OleCtrls, MSCommLib_TLB, ExtCtrls, Menus, Unit2, ComCtrls, ToolWin, ImgList;
type
TForm1 = class(TForm)
Panel1: TPanel;
Memo1: TMemo;
Splitter2: TSplitter;
Memo2: TMemo;
MainMenu1: TMainMenu;
ComSet1: TMenuItem;
N1: TMenuItem;
N2: TMenuItem;
N4: TMenuItem;
N5: TMenuItem;
N6: TMenuItem;
N7: TMenuItem;
N8: TMenuItem;
N9: TMenuItem;
N10: TMenuItem;
N11: TMenuItem;
N12: TMenuItem;
N13: TMenuItem;
N14: TMenuItem;
MSComm1: TMSComm;
ControlBar1: TControlBar;
ToolBar1: TToolBar;
ToolButton1: TToolButton;
ToolButton3: TToolButton;
ToolButton4: TToolButton;
ToolButton5: TToolButton;
ImageList1: TImageList;
OpenDialog1: TOpenDialog;
SaveDialog1: TSaveDialog;
ImageList2: TImageList;
StatusBar1: TStatusBar;
procedure FormCreate(Sender: TObject);
procedure MSComm1Comm(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure N13Click(Sender: TObject);
procedure N14Click(Sender: TObject);
procedure N2Click(Sender: TObject);
procedure N4Click(Sender: TObject);
procedure N6Click(Sender: TObject);
procedure N9Click(Sender: TObject);
procedure ToolButton5Click(Sender: TObject);
private
{ Private declarations }
Recvar:variant;
BinaryFlag,TextFlag:Boolean;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
Procedure SendBinary(Str:String);
var
Sendvar:Variant;
Ch1,Ch2:Char;
Byte1,Byte2:Byte;
I:Integer;
begin
Sendvar:=VarArrayCreate([1,Length(Str) div 2],varByte);
Byte1:=0;
Byte2:=0;
for I:=1 to Length(Str) div 2 do
begin
Ch1:=Str[2*I-1];
Ch2:=Str[2*I];
if (Ch1>='0') and (Ch1<='9') then
Byte1:=Ord(Ch1)-48
else if (Ch1>='A') and (Ch1<='F') then
Byte1:=Ord(Ch1)-55;
if (Ch2>='0') and (Ch2<='9') then
Byte2:=Ord(Ch2)-48
else if (Ch2>='A') and (Ch2<='F') then
Byte2:=Ord(Ch2)-55;
Sendvar[I]:=Byte1*16+Byte2;
end;
Form1.MSComm1.Output:=Sendvar;
end;
procedure SendText(Str:String);
begin
Form1.MSComm1.Output:=Str;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
BinaryFlag:=False;
TextFlag:=True;
MsComm1.InBufferCount:=0;
MsComm1.OutBufferCount:=0;
MsComm1.InputLen:=0;
MsComm1.RThreshold:=1;
MsComm1.SThreshold:=1;
Recvar:=VarArrayCreate([0,63],varByte);
end;
procedure TForm1.MSComm1Comm(Sender: TObject);
var
I,J:Integer;
begin
if MsComm1.CommEvent=2 then //串口事件为接收;
begin
if BinaryFlag=True then
begin
I:=MSComm1.InBufferCount; //接收缓冲区内已有数据个数;
MSComm1.InputLen:=I;
Recvar:=MSComm1.Input;
for J:=0 to I-1 do
Memo2.Text:=Memo2.Text+IntToHex(Recvar[J],2);
end;
if TextFlag=True then
Memo2.Text:=Memo2.Text+MsComm1.Input;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if MSComm1.PortOpen=True then
MSComm1.PortOpen:=False;
end;
procedure TForm1.N13Click(Sender: TObject);
begin
BinaryFlag:=False;
TextFlag:=True;
N13.Checked:=True;
N14.Checked:=False;
MSComm1.InputMode:=0; //设置方式为文本方式;
end;
procedure TForm1.N14Click(Sender: TObject);
begin
BinaryFlag:=True;
TextFlag:=False;
N13.Checked:=False;
N14.Checked:=True;
MSComm1.InputMode:=1; //设置方式为二进制方式;
end;
procedure TForm1.N2Click(Sender: TObject);
begin
with Form2 do
if ShowModal=mrOK then
begin
if MSComm1.PortOpen=True then
MSComm1.PortOpen:=False;
if RadioButton1.Checked then
MsComm1.CommPort:=1
else
MsComm1.CommPort:=2;
//设置疮口参数;
MsComm1.Settings:=ComboBox1.Text+ComboBox2.Text+ComboBox3.Text+ComboBox4.Text;
//打开串口;
MsComm1.PortOpen:=True;
end;
end;
procedure TForm1.ToolButton5Click(Sender: TObject);
begin
if MSComm1.PortOpen=False then
begin
MessageDlg('串口未打开',mtError,[mbOK],0);
Exit;
end;
if BinaryFlag then
SendBinary(Memo1.Text); //发送二进制方式,注意去除回车换行符;
if TextFlag then
SendText(Memo1.Text); //发送文本方式;
end;
procedure TForm1.N4Click(Sender: TObject);
begin
if TextFlag=True then
OpenDialog1.InitialDir:=GetCurrentDir()+'\文本文件夹\';
if BinaryFlag=True then
OpenDialog1.InitialDir:=GetCurrentDir()+'\二进制文件夹\';
OpenDialog1.DefaultExt:='.txt';
if OpenDialog1.Execute then
Memo1.Lines.LoadFromFile(OpenDialog1.FileName);
end;
procedure TForm1.N6Click(Sender: TObject);
begin
if TextFlag then
SaveDialog1.InitialDir:=GetCurrentDir()+'\文本文件夹\';
if BinaryFlag then
SaveDialog1.InitialDir:=GetCurrentDir()+'\二进制文件夹\';
SaveDialog1.DefaultExt:='.txt';
if SaveDialog1.Execute then
Memo2.Lines.SaveToFile(SaveDialog1.FileName);
end;
procedure TForm1.N9Click(Sender: TObject);
begin
Close;
end;
end.
问题:串口的老问题 (600分) ( 积分:100, 回复:9, 阅读:155 ) 分类:局域网 / 通讯
来自:wancc, 时间:2002-06-04 10:51:00, ID:970841
1.用Mscomm32(vb6带)在Delphi中的收发过程的代码
2.用Spcomm 在Delphi中的收发过程的代码
我用了上面的两个控件发现Mscomm32能发送接收 可是不知道怎样将返回的数据还原成看的
懂的数据(unicode?),我是和51单片机通讯的 谁能写出发送、接收代码将送上300分
用Spcomm也是不知道怎样将返回的数据还原成看的懂的数据,另外它能否象Mscomm一样可以
等到Buffer中有一定个数的字节后再收的功能呢?能否写出原代码将送上300分
其实我看了以前关于串口的帖子 发现大家都是说一半的多 而能写全代码的少 希望这次
各位大侠能写全些的代码供大家学习一下 谢谢!
来自:gzgylgl, 时间:2002-04-04 00:19:00, ID:1022126
我没用过单片几,但于PLC通信做过。一般传过去用字符或ACSII码。传过来用16进制的(PLC)。
来自:antelep, 时间:2002-06-01 16:58:00, ID:1137497
发送和接收都用byte型即可
来自:visualboy, 时间:2002-06-01 23:46:00, ID:1138074
一般串行通讯用ASCII码比较多,当然也有用16进制,正好我都做过。如果是发送端不断发送,那么你可以用事件方式触发。如果是应答方式,你可以用轮询的方式来做。
我以前一直是用VB写跟外围通讯的程序。所以不能提供给你delphi,不过Vb源程序和C源程序倒有
C
int _read_data_register(unsigned int uAddress,unsigned int number)
{ unsigned char uSend[]={2,0x30,0x30,0x30,0x30,0x30,0x30,0x32,3,0x30,0x30};
unsigned char uReceive[104];
unsigned int uTmp;
unsigned int uSum;
unsigned int num;
long lTmp;
int i,j;
if(TESTING==1)
{ for(i=0;i<number;i++)uRead_value[i]=0;
return TRUE;
}
init_plc();
num=number*2;
if((num/16)>=10)
uSend[6]=(unsigned char)(num/16+0x41-10);
else
uSend[6]=(unsigned char)(num/16+0x30);
if((num%16)>=10)
uSend[7]=(unsigned char)((num%16)+0x41-10);
else
uSend[7]=(unsigned char)((num%16)+0x30);
uAddress=uAddress*2+0x1000;
uTmp=uAddress & 0x000f;
uSend[5]=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
uTmp=(uAddress>>4) & 0x000f;
uSend[4]=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
uTmp=(uAddress>>8) & 0x000f;
uSend[3]=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
uTmp=(uAddress>>12)&0x000f;
uSend[2]=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
uSum=0;
for(i=1;i<9;i++)
uSum=uSum+(unsigned char)uSend[i];
uTmp=uSum&0x000f;
uSend[10]=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
uTmp=(uSum>>4)&0x000f;
uSend[9]=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
/*disable();*/
for(i=0;i<11;i++)
{ for(lTmp=0L;lTmp<DELAY_TIMES;lTmp++)
{ if((inportb(STATS_PORT)&0x20)!=0)
break;
}
if(lTmp>=DELAY_TIMES)
{
/*enable();*/
return(FALSE);
}
outportb(DATA_PORT,uSend[i]);
}
disable();
for(lTmp=0;lTmp<DELAY_TIMES;lTmp++)
{ if((inportb(STATS_PORT)&1)!=0)
break;
}
if(lTmp>=DELAY_TIMES)
{
enable();
return(FALSE);
}
uReceive[0]=inportb(DATA_PORT);
if(uReceive[0]!=2)
{
enable();
return(FALSE);
}
for(i=1;i<number*4+4;i++)
{ for(lTmp=0L;lTmp<DELAY_TIMES;lTmp++)
{ if((inportb(STATS_PORT)&1)!=0)
break;
}
if(lTmp>=DELAY_TIMES)
{
enable();
return(FALSE);
}
uReceive[i]=inportb(DATA_PORT);
}
enable();
uSum=0;
for(i=1;i<number*4+2;i++)
uSum=uSum+(unsigned int)uReceive[i];
uTmp=uSum&0xf;
uTmp=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
if((unsigned char)uTmp!=uReceive[number*4+3])return(FALSE);
uTmp=(uSum>>4)&0xf;
uTmp=(uTmp<10)?(uTmp+0x30):(uTmp+0x41-0xa);
if((unsigned char)uTmp!=uReceive[number*4+2])return(FALSE);
for(j=0;j<number;j++)
{ for(i=j*4+1;i<j*4+5;i++)
uReceive[i]=(uReceive[i]>0x39)?uReceive[i]-0x41+0xa:uReceive[i]-0x30;
uRead_value[j]=(((((uReceive[j*4+3]<<4)+uReceive[j*4+4])<<4)+uReceive[j*4+1])<<4)+uReceive[j*4+2];
}
return TRUE;
}
VB
Private Sub Command1_Click()
Dim sendByte(2) As Byte
Dim sendTXT(4) As Byte
Dim Index As Long
Dim Sendstring As String
Dim inString() As Byte
Dim sTime As Single
Dim CRCHi, CRCLo As Byte
Dim i As Integer
Command1.Enabled = False
sendByte(0) = 5
sendByte(1) = Asc("D")
sendByte(2) = Asc("L")
sendTXT(0) = sendByte(0)
sendTXT(1) = sendByte(1)
sendTXT(2) = sendByte(2)
Index = CRC16(sendByte)
CRCLo = Index Mod 256
CRCHi = Index \ 256
sendTXT(3) = CRCLo
sendTXT(4) = CRCHi
MSComm1.InBufferCount = 0
MSComm1.Output = sendTXT
sTime = Timer
Do
DoEvents
If Timer > sTime + 0.01 Then Exit Do
Loop Until MSComm1.InBufferCount > 0
If MSComm1.InBufferCount > 0 Then
inString = MSComm1.Input
If inString(0) = 6 Then
sTime = Timer
Do
If Timer > sTime + 8 Then Exit Do
Loop
MsgBox "擦除完毕!", vbExclamation, "完成"
Else
MsgBox "擦除失败!", vbExclamation, "提示"
Command1.Enabled = True
Exit Sub
End If
Else
MsgBox "擦除失败!", vbExclamation, "提示"
Command1.Enabled = True
Exit Sub
End If
来自:dracula_king, 时间:2002-06-02 10:54:00, ID:1138393
SPCOMM的例子
CommName:填写COM1
COM2…等串口的名字
在打开串口前,必须填写好此值。
BaudRate:设定波特率9600,4800等,根据实际需要来定,在串口打开后也可更改波特率,实际波特率随之更改。
ParityCheck:奇偶校验。
ByteSize:字节长度_5 _6 _7 _8等,根据实际情况设定。
Parity:奇偶校验位
StopBits:停止位
SendDataEmpty:这是一个布尔属性,为true时表示发送缓存为空,或者发送队列里没有信息;为False时表示表示发送缓存不为空,或者发送队列里有信息。
2.方法
Startcomm过程用于打开串口,当打开失败时通常会报错,错误主要有7种:
⑴串口已经打开 ;
⑵打开串口错误 ;
⑶文件句柄不是通讯句柄;
⑷不能够安装通讯缓存;
⑸不能产生事件 ;
⑹不能产生读进程;
⑺不能产生写进程;
StopComm过程用于关闭串口,没有返回值。
函数WriteCommData(pDataToWrite: PChar;dwSizeofDataToWrite:Word
): boolean 用于发送一个字符串到写线程,发送成功返回true
发送失败返回false
执行此函数将立即得到返回值,发送操作随后执行。函数有两个参数,其中
pdatatowrite是要发送的字符串,dwsizeofdatatowrite 是发送的长度。
3.事件
OnReceiveData : procedure (Sender: TObject;Buffer: Pointer;BufferLength:Word) of object
当输入缓存有数据时将触发该事件,在这里可以对从串口收到的数据进行处理。Buffer中是收到的数据,bufferlength是收到的数据长度。
OnReceiveError : procedure(Sender: TObject; EventMask: DWORD)
当接受数据时出现错误将触发该事件。
三.SPCOMM的使用
下面,我们结合一个串口通讯的例子来说明SPCOMM的使用。
为了实现PC与单片机8051之间的通讯,首先要调通它们之间的握手信号,假定它们之间的通讯协议是,PC到8051一帧数据6个字节
8051到PC一帧数据也为6个字节
当PC发出(F0 01 FF FF 01 F0)后能收到这样一帧(F0 01 FF FF 01 F0),表示数据通信握手成功,两者之间就可以按照协议相互传输数据。在PC方要发送及接受数据需要以下步骤:
1.创建一个新的工程COMM.DPR,把窗体的NAME属性改为FCOMM,把窗体的标题改为测试通讯,添加控件。
对COMM1(黑色矩形围住的控件)进行属性设计,设波特率4800,校验位无,字节长度_8,停止位_1,串口选择COM1。Memo1中将显示发送和接受的数据。选择File/Save
As将新的窗体存储为Comm.pas。
2.编写源代码
变量说明
var
FCOMM: TFCOMM;
Viewstring:string;
i:integer;
rbuf
sbuf:array[1..6] of byte;
打开串口
procedure TFCOMM.FormShow(Sender: TObject);
begin
comm1.StartComm;
end;
关闭串口
procedure TFCOMM.FormClose(Sender: TObject; var Action: TCloseAction);
begin
comm1.StopComm;
end;
发送数据
自定义的发送过程
procedure senddata;
var
i:integer;
commflg:boolean;
begin
viewstring:="";
commflg:=true;
for i:=1 to 6 do
begin
if not fcomm.comm1.writecommdata(@sbuf[i]
1) then
begin
commflg:=false;
break;
end;
sleep(2); {发送时字节间的延时}
viewstring:=viewstring+inttohex(sbuf[i] 2)+" ";
end;
viewstring:="发送"+viewstring;
fcomm.memo1.lines.add(viewstring);
fcomm.memo1.lines.add("");
if not commflg then messagedlg("发送失败!" mterror [mbyes]0);
end;
procedure TFCOMM.Btn_sendClick(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($0f); {帧尾}
senddata;{调用发送函数}
end;
接收过程
procedure TFCOMM.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[i] 2)+" ";
viewstring:="接受"+viewstring;
memo1.lines.add(viewstring);
memo1.lines.add("");
end;
如果memo1上显示发送F0 01 FF FF 0F 和 接受F0 01 FF FF F0
这表示串口已正确的发送出数据并正确的接受到数据,串口通讯成功。
不行的话联系我,我吧我的程序发给你 QQ:1975722
来自:SS2000, 时间:2002-06-02 11:14:00, ID:1138421
>>用Spcomm也是不知道怎样将返回的数据还原成看的懂的数据?
不知道什么样的数据你才能看懂??
SPComm返回的是PChar,是字符为单位的指针,你怎样才能看懂?
这个问题和SPComm没有关系,是你自己对计算机的数据表示方式理解不够
>>等到Buffer中有一定个数的字节后再收的功能呢?
这个问题可以做到,如果你想做的话,但是你需要修改SPComm控件,或者说增强SPComm
的功能,因为目前的SPComm做不到
具体方法是在
procedure TReadThread.Execute;函数中
定义有 szInputBuffer: array[0..INPUTBUFFERSIZE-1] of Char;
修改INPUTBUFFERSIZE这个值成为你所要的值,同时把ReadIntervalTimeout属性值
设置为足够大,比如1234567890或者为0,这样在获得指定的字节数之后才会
发出接收消息
来自:dracula_king, 时间:2002-06-02 11:20:00, ID:1138439
我的程序可以看懂返回的数据呀,将接收数组定义为BYTE型
来自:SupermanTm, 时间:2002-06-04 00:18:00, ID:1141667
把数据报文的格式告诉我,我给你源代码,测试后你给我分!
treemanwww@163.com
来自:cook, 时间:2002-06-04 08:23:00, ID:1141835
我做过一个给自己的下位机测试的程序(c51)
你要的话给你吧。
cook@sina.com
来自:御键飞天, 时间:2002-06-04 10:51:00, ID:1142174
这是我编写的使用MSComm控件进行串口通讯的完整例子,功能上能进行文本方式,二进制方式的通讯,
在Delphi6下编译通过,在Delphi5下只需将uses单元的Variants项去除即可,如满意,请适当给分,呵呵!
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, OleCtrls, MSCommLib_TLB, ExtCtrls, Menus, Unit2, ComCtrls, ToolWin, ImgList;
type
TForm1 = class(TForm)
Panel1: TPanel;
Memo1: TMemo;
Splitter2: TSplitter;
Memo2: TMemo;
MainMenu1: TMainMenu;
ComSet1: TMenuItem;
N1: TMenuItem;
N2: TMenuItem;
N4: TMenuItem;
N5: TMenuItem;
N6: TMenuItem;
N7: TMenuItem;
N8: TMenuItem;
N9: TMenuItem;
N10: TMenuItem;
N11: TMenuItem;
N12: TMenuItem;
N13: TMenuItem;
N14: TMenuItem;
MSComm1: TMSComm;
ControlBar1: TControlBar;
ToolBar1: TToolBar;
ToolButton1: TToolButton;
ToolButton3: TToolButton;
ToolButton4: TToolButton;
ToolButton5: TToolButton;
ImageList1: TImageList;
OpenDialog1: TOpenDialog;
SaveDialog1: TSaveDialog;
ImageList2: TImageList;
StatusBar1: TStatusBar;
procedure FormCreate(Sender: TObject);
procedure MSComm1Comm(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure N13Click(Sender: TObject);
procedure N14Click(Sender: TObject);
procedure N2Click(Sender: TObject);
procedure N4Click(Sender: TObject);
procedure N6Click(Sender: TObject);
procedure N9Click(Sender: TObject);
procedure ToolButton5Click(Sender: TObject);
private
{ Private declarations }
Recvar:variant;
BinaryFlag,TextFlag:Boolean;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
Procedure SendBinary(Str:String);
var
Sendvar:Variant;
Ch1,Ch2:Char;
Byte1,Byte2:Byte;
I:Integer;
begin
Sendvar:=VarArrayCreate([1,Length(Str) div 2],varByte);
Byte1:=0;
Byte2:=0;
for I:=1 to Length(Str) div 2 do
begin
Ch1:=Str[2*I-1];
Ch2:=Str[2*I];
if (Ch1>='0') and (Ch1<='9') then
Byte1:=Ord(Ch1)-48
else if (Ch1>='A') and (Ch1<='F') then
Byte1:=Ord(Ch1)-55;
if (Ch2>='0') and (Ch2<='9') then
Byte2:=Ord(Ch2)-48
else if (Ch2>='A') and (Ch2<='F') then
Byte2:=Ord(Ch2)-55;
Sendvar[I]:=Byte1*16+Byte2;
end;
Form1.MSComm1.Output:=Sendvar;
end;
procedure SendText(Str:String);
begin
Form1.MSComm1.Output:=Str;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
BinaryFlag:=False;
TextFlag:=True;
MsComm1.InBufferCount:=0;
MsComm1.OutBufferCount:=0;
MsComm1.InputLen:=0;
MsComm1.RThreshold:=1;
MsComm1.SThreshold:=1;
Recvar:=VarArrayCreate([0,63],varByte);
end;
procedure TForm1.MSComm1Comm(Sender: TObject);
var
I,J:Integer;
begin
if MsComm1.CommEvent=2 then //串口事件为接收;
begin
if BinaryFlag=True then
begin
I:=MSComm1.InBufferCount; //接收缓冲区内已有数据个数;
MSComm1.InputLen:=I;
Recvar:=MSComm1.Input;
for J:=0 to I-1 do
Memo2.Text:=Memo2.Text+IntToHex(Recvar[J],2);
end;
if TextFlag=True then
Memo2.Text:=Memo2.Text+MsComm1.Input;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if MSComm1.PortOpen=True then
MSComm1.PortOpen:=False;
end;
procedure TForm1.N13Click(Sender: TObject);
begin
BinaryFlag:=False;
TextFlag:=True;
N13.Checked:=True;
N14.Checked:=False;
MSComm1.InputMode:=0; //设置方式为文本方式;
end;
procedure TForm1.N14Click(Sender: TObject);
begin
BinaryFlag:=True;
TextFlag:=False;
N13.Checked:=False;
N14.Checked:=True;
MSComm1.InputMode:=1; //设置方式为二进制方式;
end;
procedure TForm1.N2Click(Sender: TObject);
begin
with Form2 do
if ShowModal=mrOK then
begin
if MSComm1.PortOpen=True then
MSComm1.PortOpen:=False;
if RadioButton1.Checked then
MsComm1.CommPort:=1
else
MsComm1.CommPort:=2;
//设置疮口参数;
MsComm1.Settings:=ComboBox1.Text+ComboBox2.Text+ComboBox3.Text+ComboBox4.Text;
//打开串口;
MsComm1.PortOpen:=True;
end;
end;
procedure TForm1.ToolButton5Click(Sender: TObject);
begin
if MSComm1.PortOpen=False then
begin
MessageDlg('串口未打开',mtError,[mbOK],0);
Exit;
end;
if BinaryFlag then
SendBinary(Memo1.Text); //发送二进制方式,注意去除回车换行符;
if TextFlag then
SendText(Memo1.Text); //发送文本方式;
end;
procedure TForm1.N4Click(Sender: TObject);
begin
if TextFlag=True then
OpenDialog1.InitialDir:=GetCurrentDir()+'\文本文件夹\';
if BinaryFlag=True then
OpenDialog1.InitialDir:=GetCurrentDir()+'\二进制文件夹\';
OpenDialog1.DefaultExt:='.txt';
if OpenDialog1.Execute then
Memo1.Lines.LoadFromFile(OpenDialog1.FileName);
end;
procedure TForm1.N6Click(Sender: TObject);
begin
if TextFlag then
SaveDialog1.InitialDir:=GetCurrentDir()+'\文本文件夹\';
if BinaryFlag then
SaveDialog1.InitialDir:=GetCurrentDir()+'\二进制文件夹\';
SaveDialog1.DefaultExt:='.txt';
if SaveDialog1.Execute then
Memo2.Lines.SaveToFile(SaveDialog1.FileName);
end;
procedure TForm1.N9Click(Sender: TObject);
begin
Close;
end;
end.
如您对论坛有好的建议或创想,请加大版主微信号:gkong2015
大版主推荐【工控百家谈】微信公众号,业界大拿原创内容分享