这是对常洲托利多地磅仪表的串口读取程序!仪表型号不同,读取数据的格式也不一样!
unit RdComm;
interface
uses
Windows, SysUtils, Classes, inifiles, forms;
type
TComInfo = record
cCommNum: string;
{ com1..com4 }
cBaudRate: integer;
{ 1200..19200 }
// cDataLen: integer;
{ 6..8 }
// cStopLen: integer;
{ 1..2 }
cParity: integer;
{ non, odd, even }
cHandle: THandle;
{ 串口打开后用来保存句柄 }
end;
TMeterInfo = record { 仪表型号不同,数值也不一样 }
DatPos: integer;
{ 过磅值在从仪表中读取的字符串中的位置 }
DatLen: integer;
{ 过磅值的长度 }
end;
function ReadMeter(MeterNum: integer;
var MeterVal: Integer):Boolean;
function ReadINI:Boolean;
procedure OpenComm(num: integer);
procedure CloseComm(num: integer);
var
ComInfo: array[1..4] of TComInfo;
MeterInfo: array[1..4] of TMeterInfo;
implementation
function ReadMeter(MeterNum: integer;
var MeterVal: integer): Boolean;
var
k: integer;
s: string;
// 发送命令给仪表
procedure SendCmd(cHandle: THandle;
cmd: char);
var
bl: Boolean;
rwBytes: Dword;
begin
sleep(5);
bl:= WriteFile( cHandle, cmd, 1, rwBytes, nil);
sleep(5);
if (not bl) or (rwBytes<1) then
bl:= WriteFile( cHandle, cmd, 1, rwBytes, nil);
// 重试再次发送命令
if (not bl) or (rwBytes<1) then
raise Exception.Create('ERR');
// 无法发送命令,提交异常来终止线程
end;
// 定位数据头
procedure SearchDataHead(cHandle: THandle);
var
i: integer;
rwBytes: Dword;
bDat: byte;
bl: Boolean;
begin
i:=0;
while i<50 do
// 这个循环定位数据头
begin
sleep(5);
bl:= ReadFile( cHandle, bDat, 1, rwbytes, nil);
if bl and (bDat = $02) then
break;
// 读到数据起始符
inc(i);
end;
// 没有能正确定位数据头则提交异常退出
if bDat <> $02 then
raise Exception.Create('ERR2');
end;
// 读取数据串
function GetDataStr(cHandle: THandle):string ;
var
i: integer;
rwBytes: Dword;
bDat: byte;
bl: Boolean;
begin
result:='';
i:=0;
while i<50 do
// 这个循环读取数据
begin
sleep(5);
bl:= ReadFile( ComInfo[MeterNum].cHandle, bDat, 1, rwBytes, nil);
if bl then
if bDat = $0D then
break // 读到数据结束符
else
result:= result + chr(bDat);
inc(i);
end;
// 没有读取到结束符,则提交异常退出
if bDat <> $0D then
raise Exception.Create('ERR2');
end;
begin
MeterVal:= 0;
s:='';
try
OpenComm(MeterNum);
try
SendCmd(Cominfo[MeterNum].cHandle, 'P');
SearchDataHead(ComInfo[MeterNum].cHandle);
s:= GetDataStr(ComInfo[MeterNum].cHandle);
// 提取数值
s:= copy(s, MeterInfo[MeterNum].DatPos, MeterInfo[MeterNum].DatLen);
try
k:= StrToInt(s);
// 此处有可能产生异常
except
raise Exception.Create('ERR3');
end;
finally
CloseComm(MeterNum);
end;
MeterVal:= k;
result:= true;
except
on E: Exception do
begin
s:= copy(E.Message,4,1);
case StrToIntDef(s,4) of
1: MeterVal:=-1;
// 串口打开失败
2: MeterVal:=-2;
// 串口通讯失败
3: MeterVal:=-3;
// 数值转换失败
4: MeterVal:=-4;
// 其它错误失败
end;
result:= False;
end;
end;
end;
// 读串口参数INI文件
function ReadINI:Boolean;
var
lpIni: TIniFile;
s: string;
i: integer;
begin
Result:= False;
s:= ExtractFileDir(Application.ExeName);
if copy(s,Length(s),1)<>'/' then
s:= s+'/';
s:= s+'LinkPara.Ini';
lpIni:= TIniFile.Create(s);
try
if not FileExists(s) then
begin
// 一号仪表
lpIni.WriteInteger('MeterInfo','1_No',1);
// 使用的串口号
lpIni.WriteInteger('MeterInfo','1_BaudRate',1200);
// 波特率
lpIni.WriteInteger('MeterInfo','1_Parity',2);
// 校验
lpIni.WriteInteger('MeterInfo','1_Pos',4);
// 数值定位
lpIni.WriteInteger('MeterInfo','1_Len',6);
// 数值串长
// 二号仪表
lpIni.WriteInteger('MeterInfo','2_No',2);
lpIni.WriteInteger('MeterInfo','2_BaudRate',1200);
lpIni.WriteInteger('MeterInfo','2_Parity',2);
lpIni.WriteInteger('MeterInfo','2_Pos',4);
lpIni.WriteInteger('MeterInfo','2_Len',6);
// 三号仪表
lpIni.WriteInteger('MeterInfo','3_No',3);
lpIni.WriteInteger('MeterInfo','3_BaudRate',1200);
lpIni.WriteInteger('MeterInfo','3_Parity',2);
lpIni.WriteInteger('MeterInfo','3_Pos',4);
lpIni.WriteInteger('MeterInfo','3_Len',6);
// 四号仪表
lpIni.WriteInteger('MeterInfo','4_No',4);
lpIni.WriteInteger('MeterInfo','4_BaudRate',1200);
lpIni.WriteInteger('MeterInfo','4_Parity',2);
lpIni.WriteInteger('MeterInfo','4_Pos',4);
lpIni.WriteInteger('MeterInfo','4_Len',6);
end;
for i:= 1 to 4 do
begin
s:= IntToStr(i);
ComInfo.cCommNum:= 'COM'+
IntToStr(lpIni.ReadInteger('MeterInfo',s+'_No',i));
ComInfo.cBaudRate:= lpIni.ReadInteger('MeterInfo',s+'_BaudRate',1200);
ComInfo.cParity:= lpIni.ReadInteger('MeterInfo',s+'_Parity',2);
MeterInfo.DatPos:= lpIni.ReadInteger('MeterInfo',s+'_Pos',4);
MeterInfo.DatLen:= lpIni.ReadInteger('MeterInfo',s+'_Len',6);
end;
result:= True;
finally
lpIni.Free;
end;
end;
// 打开并设置串口
procedure OpenComm(num: integer);
var
ComDCB: TDCB;
CTO: TCOMMTIMEOUTS;
begin
ComInfo[num].cHandle:= CreateFile( pchar(ComInfo[num].cCommNum),
GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0,0);
if ComInfo[num].cHandle=INVALID_HANDLE_VALUE then
raise Exception.Create('ERR1');
// 提交异常退出
try
GetCommState(ComInfo[num].cHandle, ComDCB);
ComDCB.BaudRate:= ComInfo[num].cBaudRate;
ComDCB.ByteSize:= 7;
ComDCB.Parity:= ComInfo[num].cParity;
ComDCB.StopBits:= 2;
if SetCommState(ComInfo[num].cHandle, ComDCB) = false then
raise Exception.Create('ERR1');
// 提交异常退出
CTO.ReadIntervalTimeout:= 0;
// 读区间超时
CTO.ReadTotalTimeoutConstant:= 0;
// 读超时常数
CTO.ReadTotalTimeoutMultiplier:= 50;
// 读总超时
CTO.WriteTotalTimeoutConstant:= 0;
// 写超时常数
CTO.WriteTotalTimeoutMultiplier:= 50;
// 写总超时
if SetCommTimeOUTs( ComInfo[num].cHandle, CTO ) = false then
raise Exception.Create('ERR1');
// 提交异常退出
except
CloseComm(num);
raise;
// 重新提交异常
end;
end;
// 关闭串口
procedure CloseComm(num: integer);
begin
if ComInfo[num].cHandle <> INVALID_HANDLE_VALUE then
CloseHandle( ComInfo[num].cHandle );
ComInfo[num].cHandle:= INVALID_HANDLE_VALUE;
end;
end.