各位大虾,我现在想用Delphi实现计算机与仪表之间采用RS485通讯协议进行串口通讯,小弟不懂的串口通讯这方面的知识,那位有这方面的原代码(用delphi)或哪网站可提供下载的介绍给我好吗?先谢谢拉,很急的,在线等待!
解决方案 »
- delphi7关于一个程序只能托盘一次的代码实现
- 请问如何让listview上的column中的文字居中对齐?默认为靠左对齐,另外如何改变它的默认字体?
- 让DateTimePicker既能显示日期又能显示时间的方法
- 关于控件的问题!帮下忙!谢谢
- 想给button两个caption,该怎么做啊?
- 请教关于dbgrid的字体颜色问题
- query的用法问题!
- UP者有分,用delphi怎样实现全屏幕显示?
- 关于statusbar的问题
- 做一个网站,对防黑方面要具备哪方面的能力和要掌握哪几门技术?
- delphi可以从网卡,或串口得到数据吗
- 为什么我的ToolBar中的ToolButton不能改变大小啊!
1、找几本Delphi做数据通信的书,市面上非常多。
2、上Google用Delphi和RS485为关键字搜一搜,当然最好英文好一点。
如aiirii(ari) 所说,不用关心是什么方式的串口,系统的api接口都一样。
我以前写过一个多线程的,记得发过一次,找不到了,再发一边。一个自动控制机的硅控板检测程序,用多线程和API,没有用控件,少做改动就能用,供你参考吧!
Unit CommThread;InterfaceUses
Windows, Classes, SysUtils, Graphics, Controls, Forms,
Dialogs, ComCtrls, ExtCtrls;
Type
TThreadParam = Record
SusPended: Boolean;
BaulSpeed: integer;
Port: Byte;
Parity: Boolean;
StopBit: byte;
StartBit: Byte;
SB: TStatusBar;
LEDs: Array[0..24] Of TShape;
End;Type
TReadThread = Class(TThread)
Private
{ Private declarations }
hComm: THandle;
Port: integer;
FErr: Boolean;
FPortDescription: String;
FShape: Array[0..24] Of TShape;
FSB: TStatusBar;
cc: TCOMMCONFIG;
Data: String;
Procedure ReadPort; //读取串行端口数据
Procedure UpdateUI;
Protected
Procedure Execute; Override;
Public
Constructor Create(ThdPrm: TThreadParam);
End;Implementation
//uses Unit1; // 声明引用Unit1,必须放在implementation区段Constructor TReadThread.Create(ThdPrm: TThreadParam);
Var
i: integer;
Begin
Port := thdprm.Port;
FSB := thdprm.SB;
For i := 0 To 24 Do
Begin
FShape[i] := thdPrm.LEDs[i];
End;
FreeOnTerminate := True;
Inherited Create(ThdPrm.SusPended);
End;Procedure TReadThread.Execute;
Var
PortToOpen: String;
Begin
PortToOpen := 'COM' + inttostr(Port); // 选择所要打开的COM
hComm := CreateFile(PChar(PortToOpen), GENERIC_READ Or GENERIC_WRITE,
0, Nil, OPEN_EXISTING, 0, 0); // 打开COM
If (hComm = INVALID_HANDLE_VALUE) Then
Begin //如果COM 未打开
FErr := True;
FPortDescription := '打开端口错误!';
End
Else
Begin
FErr := False;
FPortDescription := '打开端口成功';
GetCommState(hComm, cc.dcb); // 得知目前COM 的状态
cc.dcb.BaudRate := CBR_9600; // 设置波特率为9600
cc.dcb.ByteSize := 8; //字节为 8 bit
cc.dcb.Parity := NOPARITY; // Parity 为 None
cc.dcb.StopBits := ONESTOPBIT; // 1 个Stop bit
If Not SetCommState(hComm, cc.dcb) Then
Begin // 设置COM 的状态
Ferr := True;
FPortDescription := FPortDescription + ',设置错误!';
CloseHandle(hComm); //关闭通信端口
End
Else
Begin
FErr := False;
FPortDescription := FPortDescription + ',设置成功';
While Not Terminated Do
Begin
Synchronize(ReadPort); //刚才所定义的读取数据函数
End;
Synchronize(UpdateUI);
End;
End;End;
Procedure TReadThread.ReadPort;
Var
i: integer;
inbuff: Array[0..29] Of Char;
nBytesRead, dwEvent, dwError: LongWORD;
cs: TCOMSTAT;
Rights, Emptys, Errs: integer;
Const
RightColor = clBlue;
ErrorColor = clRed;
EmptyColor = clWhite;
Begin
Rights := 0;
Emptys := 0;
Errs := 0;
If (hComm = INVALID_HANDLE_VALUE) Then
Begin
Fsb.Panels[3].Text := FPortDescription;
Terminate; //先判断是否已打开通信端口
Exit;
End
Else
Begin
Fsb.Panels[3].Text := FPortDescription;
ClearCommError(hComm, dwError, @CS); //取得状态
ReadFile(hComm, inbuff, cs.cbInQue, nBytesRead, Nil); // 接收COM 的数据
//串行在读取数据后,会自动将缓冲区中已被读取的数据清除掉
If cs.cbInQue = 0 Then exit;
// 数据是否大于我们所准备的Buffer
If cs.cbInQue <> sizeof(inbuff) Then
Begin
PurgeComm(hComm, PURGE_RXCLEAR); // 清除COM 数据
exit;
End;
Data := Copy(inbuff, 1, cs.cbInQue); //取出数据
For i := 1 To 25 Do
Begin
If (UpperCase(Data[i]) = 'Y') Then
Begin
FShape[i].Brush.Color := RightColor;
Rights := Rights + 1;
End
Else
If (UpperCase(Data[i]) = 'N') Then
Begin
FShape[i].Brush.Color := EmptyColor;
Emptys := Emptys + 1;
End
Else
If (UpperCase(Data[i]) = 'E') Then
Begin
FShape[i].Brush.Color := ErrorColor;
Errs := Errs + 1;
End;
End;
Fsb.Panels[0].Text := '正确:' + IntTostr(Rights);
fsb.Panels[1].Text := '空槽:' + IntTostr(Emptys);
fsb.Panels[2].Text := '错误:' + IntTostr(Errs);
Fsb.Panels[3].Text := FPortDescription;
Fsb.Panels[4].Text := '数据:' + Data;
End;
End;Procedure TReadThread.UpdateUI;
Begin
Fsb.Panels[0].Text := '正确:' + IntTostr(0);
fsb.Panels[1].Text := '空槽:' + IntTostr(0);
fsb.Panels[2].Text := '错误:' + IntTostr(0);
Fsb.Panels[3].Text := '';
Fsb.Panels[4].Text := '数据:' + Data;
End;End.
然后,利用API编写串口程序,用控件也可以,但是API可以节省很多的资源,直接可以控制串口,没有必要再用控件转发,但是如果你对API不是很熟悉,用不好的话,还是用控件比较方便,不用费脑筋。推荐MSCOMM控件。API的方法楼上已经说了,下面我用MSCOMM控件编写的程序。
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, OleCtrls, MSCommLib_TLB, ExtCtrls;type
TForm1 = class(TForm)
EdSend: TEdit;
BitBtnSend: TBitBtn;
MemoRec: TMemo;
LSend: TLabel;
Label2: TLabel;
MemoSend: TMemo;
Label1: TLabel;
Bevel1: TBevel;
MSComm1: TMSComm;
Button1: TButton;
BSendClear: TButton;
BRecClear: TButton;
procedure FormShow(Sender: TObject);
procedure BitBtnSendClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure BSendClearClick(Sender: TObject);
procedure BRecClearClick(Sender: TObject);
procedure MSComm1Comm(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;implementation{$R *.dfm}procedure TForm1.FormShow(Sender: TObject);
begin
EdSend.Text:='';
MemoRec.Text:='';
MemoSend.Text:='';
MsComm1.CommPort:=1;
mscomm1.PortOpen:=true;end;procedure TForm1.BitBtnSendClick(Sender: TObject);
var
SendStr:String;begin
SendStr:=Trim(EdSend.Text);
MsComm1.Output:=SendStr;
MemoSend.Lines.Add(SendStr);end;procedure TForm1.Button1Click(Sender: TObject);
begin
Mscomm1.PortOpen:=flase;
close;end;procedure TForm1.BSendClearClick(Sender: TObject);
begin
MemoSend.Clear;end;procedure TForm1.BRecClearClick(Sender: TObject);
begin
MemoRec.Clear;
end;procedure TForm1.MSComm1Comm(Sender: TObject);
Var
buffer,str :String;
i,j:integer;begin
case mscomm1.commEvent of
comEvReceive:
begin
buffer:=mscomm1.Input;
i:=MemoRec.Lines.Count;
if not (i=0) then i:=i-1;
MemoRec.Lines.Strings[i]:=MemoRec.Lines.Strings[i]+buffer; end;
end;
end;
end.
如果是全双工,则要用 RS-422 转换器
mscomm:微软的东西,是VB中带的一个ActiveX控件,使用简单,性能一般,由于是ActivX控件,打包时需要注册好多信息,在Delphi中使用,建议使用VCL控件,编译程序时直接编入程序中,再不需任何其它处理。
spcomm:比较好的vcl控件,算是比较专业的,解剖了一下,功能比较完善。
TurboPower:公认的专业通讯vcl控件。可以到其站点下载,开放源码了。
我在制作串口通讯软件时三种都用过,最终全部使用TurboPower!所以也推荐大家使用它。
写了个例子,基本的串口通讯都可以实现,可提供参考:
下载基地-》文件名称:串口通讯控制器
版权声明:以下本文只允许在本站观看,不得以任何媒体方式进行传播。
发表意见请到留言版。TurboPower串口通讯实际应用:
在串口通讯时有字符和十六进制两种数据传输方式,不论使用哪种方式,只要能正确收到数据就是目的,至于收到数据后如何处理,就要根据具体的情况来定了。1.接收数据的方法:
轮询和中断(利用windows消息激发事件)。
1)轮询:每间隔一定的时间查询一下串口接收缓存中有无数据,有就读出来。这种方法是很毫资源的,即没事找事。
2)中断:在控件中有OnTrigger事件,当串口收到数据后,即触发此事件,无数据时什么都不做,在这个事件中接收数据就比较科学了。
所以,提倡使用控件中的OnTrigger事件接收数据。2.通讯协议的制定:
接收数据的一般处理方法,最基本的思路就是通过协议进行分析,所以协议的制定是至关重要的:
1)首先要确定指令的起始点,从大量的数据流中将指令分离出来,没有起始标志的话,结果就可想而知了,一串无效的费数据!
2)然后就是指令结束识别点,可以利用指令的长度(如果长度一定或有表示长度的数据)或结束标志来确定,当然还可以利用下一条指令的指令头。
3)既然头尾都明确了,指令的截取想来不是什么问题了吧!但还有一种情况就是数据错误是的容错,如何容错呢,最简单的办法:发现不符合格式的指令,就将其抛掉或特殊处理(如要求重发)一下!
4)有效数据中如果增加一些校验,通讯将会更加可靠!
例:#(指令头)**(指令功能)0123456789(有效数据)**(有效数据校验和)%(指令尾)
注:**代表变动值。3.接收数据的分析技巧:
通讯协议制定好后,一切将以通讯协议为中心。一套协议中的所有指令可能长度都是统一的,也有可能是长短不同的,并且在OnTrigger事件中实际反应速度及快,可能一条指令数据还没有完全收齐就已经触发了此事件,即收到了半截指令,并且有可能继续收取的数据中除了下半截指令外,还有下一条指令的前半截,如何处理?
我在做这种处理时是利用全局变量,将串口收到的所有数据都收到该串中,然后按指令格式进行截取,发现不合法指令做一下特殊处理(如要求重发)或抛弃。
如收到的数据串为:
#**0000012000**%#**0000000343#**000000540560**%#**0002200000**%
分段截为:
#**0000012000**%
#**0000000343
#**000000540560**%
#**0002200000**%
四条指令,其中:#**0000000343不完整,检测到后进行抛弃处理。调试技巧篇:
对于已了解协议的支持串口产品,要想进行编程控制,可以使用“串口通讯控制器”进行调试,以摸清具体实现数据,可按如下步骤进行:
1.确定硬件连接无误,这是首要条件,如果错误将没有成功的可能;
连线必须正确,必要时可以使用计算机自带的多个端口相互进行测试,已保证硬件的连接无误。串口通讯线有9针和25针,多用9针,其中最重要的是2(RXD)、3(TXD)、5(GND)线,对应关系如下:
9针 25针
2 -- 3
3 -- 2
5 -- 72.确定通讯参数正确,如:波特率、奇偶校验位、数据位、停止位等,以及收发的是十六进制还是字符串:3.以上确保正确,则使用“串口通讯控制器”,按协议输入数据进行收发控制了。
注意:有的仪器需要进行初始化,即先发一段激活指令,然后才能进入工作状态,这种设置主要是为了实现利用硬件为软件加密,即类似加密狗,需要有激活方法才行,不过该类方法使用较少。http://218.56.11.178:8018/FileDown.aspx?FID=160http://218.56.11.178:8018/FileDown.aspx?FID=167