在Delphi中不通过第三方组件,直接利用系统函数(或者汇编语言)直接控制串口进行通讯。比如:我现在对串口发一个字节的数据,
有起始位(1 bit)、数据位(8 bit)、停止位(1 bit )、校验位(1 bit),这个比特流就11个数据位。
我怎样在发送这个数据包后改变“校验位(1 bit)”,也就是在其它通过此串口要得到的数据报以前,可改变这个数据包。说形象点就是,我要发一个字节的数据到串口,系统会把这个8ibt的数据组织成: 起始位(1 bit)+数据位(8 bit)+停止位(1 bit )+校验位(1 bit)=数据报(11 bit) 的数据流,我想在系统发送到串口时,我改变这个数据流。也就是,把校验位按照我的意图置任意位。不知能否实现。
有起始位(1 bit)、数据位(8 bit)、停止位(1 bit )、校验位(1 bit),这个比特流就11个数据位。
我怎样在发送这个数据包后改变“校验位(1 bit)”,也就是在其它通过此串口要得到的数据报以前,可改变这个数据包。说形象点就是,我要发一个字节的数据到串口,系统会把这个8ibt的数据组织成: 起始位(1 bit)+数据位(8 bit)+停止位(1 bit )+校验位(1 bit)=数据报(11 bit) 的数据流,我想在系统发送到串口时,我改变这个数据流。也就是,把校验位按照我的意图置任意位。不知能否实现。
1、Hook API
2、自己编写驱动程序
我知道用vxd 是可以的, hook api 應該也可!問題是, 你改變了 校验位 後, 另一方收到的數據包, 校驗不正确, 可能會被丟棄的,
如果你真想做到這麼底層, 你應該選擇C++ 之類的開發工具, 而不應該選delphi
因为这个产品涉及到多个下位机(也就是多个单片机),比方说有六个单片机,其中有两类,上位机发送报文下去后,下面六个单片机根据检验位来决定是否执行。关于Delphi,我觉得应该可以解决这个问题。
WriteFile,ReadFile了,自己查查资料,不难的
uses
Windows,Forms,Classes,SysUtils;Const
rc_SerialError = 0;
rc_CommError = 1;
rc_NoDevice = 2;
rc_HaveConnect = 3;Type
TParity = ( None, Odd, Even, Mark, Space );
TStopBits = ( _1, _1_5, _2 );
TByteSize = ( _5, _6, _7, _8 );
TDtrControl = ( DtrEnable, DtrDisable, DtrHandshake );
TRtsControl = ( RtsEnable, RtsDisable, RtsHandshake, RtsTransmissionAvailable ); TCommState = Record
FBaudRate: DWORD;
FParityCheck: Boolean;
FOutx_CtsFlow: Boolean;
FOutx_DsrFlow: Boolean;
FDtrControl: TDtrControl;
FDsrSensitivity: Boolean;
FTxContinueOnXoff: Boolean;
FOutx_XonXoffFlow: Boolean;
FInx_XonXoffFlow: Boolean;
FReplaceWhenParityError: Boolean;
FIgnoreNullChar: Boolean;
FRtsControl: TRtsControl;
FXonLimit: WORD;
FXoffLimit: WORD;
FByteSize: TByteSize;
FParity: TParity;
FStopBits: TStopBits;
FXonChar: AnsiChar;
FXoffChar: AnsiChar;
FReplacedChar: AnsiChar;
end;
function StartComm(CommName:String;commstate:TCommState):Thandle;
procedure StopComm(Hcomm:Thandle);
function ReadComm(hComm:Thandle;SendStr:string;FirstWait,MiddleWait:Dword;
var Buffer:string;var dwBytesRead:DWORD):Word;implementation//********************************************/
// Open a Serial Port /
// The CommName Should Has Style of 'COMn' /
// The return of INVALID_HANDLE_VALUE /
// indicate the opening of serial port failue/
//********************************************/
function StartComm(CommName:String;commstate:TCommState):Thandle;
var
dcb: Tdcb;
begin
Result :=CreateFile(Pchar(CommName),GENERIC_READ or GENERIC_WRITE,
0,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if Result <> INVALID_HANDLE_VALUE then
begin
if GetFileType(Result) <> FILE_TYPE_CHAR then
begin
CloseHandle(Result);
Result := INVALID_HANDLE_VALUE;
Exit;
end;
if not SetupComm( Result, 4096, 4096 ) then
begin
CloseHandle(Result);
Result := INVALID_HANDLE_VALUE;
Exit;
end;
end else Exit;
GetCommState( Result, dcb ); dcb.BaudRate := commstate.FBaudRate; dcb.Flags := 1; // Enable fBinary if commstate.FParityCheck then
dcb.Flags := dcb.Flags or 2; // Enable parity check // setup hardware flow control if commstate.FOutx_CtsFlow then
dcb.Flags := dcb.Flags or 4; if commstate.FOutx_DsrFlow then
dcb.Flags := dcb.Flags or 8; if commstate.FDtrControl = DtrEnable then
dcb.Flags := dcb.Flags or $10
else if commstate.FDtrControl = DtrHandshake then
dcb.Flags := dcb.Flags or $20; if commstate.FDsrSensitivity then
dcb.Flags := dcb.Flags or $40; if commstate.FTxContinueOnXoff then
dcb.Flags := dcb.Flags or $80; if commstate.FOutx_XonXoffFlow then
dcb.Flags := dcb.Flags or $100; if commstate.FInx_XonXoffFlow then
dcb.Flags := dcb.Flags or $200; if commstate.FReplaceWhenParityError then
dcb.Flags := dcb.Flags or $400; if commstate.FIgnoreNullChar then
dcb.Flags := dcb.Flags or $800; if commstate.FRtsControl = RtsEnable then
dcb.Flags := dcb.Flags or $1000
else if commstate.FRtsControl = RtsHandshake then
dcb.Flags := dcb.Flags or $2000
else if commstate.FRtsControl = RtsTransmissionAvailable then
dcb.Flags := dcb.Flags or $3000; dcb.XonLim := commstate.FXonLimit;
dcb.XoffLim := commstate.FXoffLimit; dcb.ByteSize := Ord( commstate.FByteSize ) + 5;
dcb.Parity := Ord( commstate.FParity );
dcb.StopBits := Ord( commstate.FStopBits ); dcb.XonChar := commstate.FXonChar;
dcb.XoffChar := commstate.FXoffChar; dcb.ErrorChar := commstate.FReplacedChar; SetCommState( Result, dcb )
end;//********************************************/
// Close a Serial Port /
//********************************************/
procedure StopComm(Hcomm:Thandle);
begin
if Hcomm <> INVALID_HANDLE_VALUE then
Closehandle(Hcomm);
end;//**********************************************************/
//send a command string to serial port to recive its answer /
// sendstring is the command string /
// the recieved string is saved in buffer /
// the dwbytesread will return the number bytes of read /
// set the dwbytesread to zero indicate no needing of /
// recieve only send /
// hcomm is the handle of the serial port /
//
//**********************************************************/
function ReadComm(hComm:Thandle;SendStr:string;FirstWait,MiddleWait:Dword;
var Buffer:string;var dwBytesRead:DWORD):Word;
var
timeout:TCommTimeouts;
dwWhereToStartWriting: DWORD;
dwNumberOfBytesWritten:DWORD;
dwNumberOfBytesToWrite:DWORD;
Inchar: Char; //接收缓冲区
st,et:Cardinal;
HaveRecieved:boolean;
internal:word;
begin
Result := rc_SerialError;
PurgeComm( hComm, PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR
or PURGE_RXCLEAR ) ;
timeout.ReadIntervalTimeout := MAXDWORD;
timeout.ReadTotalTimeoutMultiplier := 0;
timeout.ReadTotalTimeoutConstant := 0;
SetCommTimeOuts(hComm,timeout); //send the command string
dwWhereToStartWriting := 1;
dwNumberOfBytesWritten := 0;
dwNumberOfBytesToWrite := Length(sendstr);
repeat
WriteFile( hComm,
sendstr[dwWhereToStartWriting],
dwNumberOfBytesToWrite,
dwNumberOfBytesWritten,
nil);
Dec( dwNumberOfBytesToWrite, dwNumberOfBytesWritten );
Inc( dwWhereToStartWriting, dwNumberOfBytesWritten )
until (dwNumberOfBytesToWrite <= 0); if dwBytesRead=0 then Exit; //No Need Recieving buffer := ''; //clear the buffer
dwBytesRead := 0; //initialize the number bytes of read to zero
st := GetTickCount;
HaveRecieved := false;
while true do
begin
if ReadFile(hComm,InChar,1,dwNumberOfBytesToWrite,nil) then
begin
if dwNumberOfBytesToWrite > 0 then
begin
HaveRecieved := true;
buffer := buffer + InChar;
Inc(dwBytesRead);
st := GetTickCount;
end;
et := GetTickCount;
if HaveRecieved then
internal := MiddleWait
else
internal := FirstWait;
if ( et - st ) > internal then
begin
if internal = FirstWait then
Result := rc_NoDevice
else
Result := rc_HaveConnect;
end;
end else begin
Result := rc_CommError;
Exit;
end;
end;
end;
Initializationend.