-
Мне требуется написать программу для отправки команды в хексе на одно промышленное устройство (контроллер "Квант-1" если это кому-то важно). Устройство управляется через COM-port, использовать можно только ноуты, так как тем кто будет использовать программу требуется мобильность, там кроме USB нету ничего. Они используют для соединения с устройствами переходник USB-COM, на который есть свой драйвер. Теперь вопросы: 1)Самое важное что мне надо знать, это чему передавать команду? COM порту, USB порту или драйверу переходника? 2)Я использовал WinAPI функцию для управления COM портом SetCommState в которую передавал Handle hndCOM:=CreateFile(PChar('COM1'),GENERIC_READ+GENERIC_WRITE,0,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); и структуру TDCB. Когда я протестировал програмку не произошло даже отправки чего-нибудь устройству, даже попытки отправить как я понял. Быть может я неправильно установил параметры порта в структуре? Если кто встречался с подобной проблемой, может это быть из-за неверных параметров в структуре? 3) Будь то передача в COM порт, USB или ещё что-нибудь, передайте пожалуйста хоть какой-нибудь пример используемых функций, или если вы знаете как можно решить без использования WinAPI дайте ссылку на компонент. Заранее спасибо...
-
> 1)Самое важное что мне надо знать, это чему передавать команду? > COM порту, USB порту или драйверу переходника?
COM порту > 2)...> может это быть из-за неверных параметров в структуре?
Разумеется. В том числе из-за неправильного имени порта. 3) http://www.torry.net/pages.php?id=1223
-
-
> Будь то передача в COM порт, USB или ещё что-нибудь, передайте > пожалуйста хоть какой-нибудь пример используемых функций, >
hCom:=CreateFile(PChar(fPortName),GENERIC_READ OR GENERIC_WRITE,0,NIL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED,0); // Если неверен выходим if (hCom=INVALID_HANDLE_VALUE) or (hcom=ERROR_ALREADY_EXISTS) then exit; // Устанавливаем буфер FillChar(ReadOl,SizeOF(ReadOL),0); ReadOl.hevent:=CreateEvent(nil,true,true,nil);
result:=false; if not(SetupComm(hCom,512,512)) then exit; // Чистим буфер if not(PurgeComm(hCom,PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR )) then exit; GetCommTimeOuts(hCom,CommTimeOuts); // Устанавливаем задержки/время ожидания CommTimeOuts.ReadIntervalTimeout:= 50; CommTimeOuts.ReadTotalTimeoutMultiplier := 40; CommTimeOuts.ReadTotalTimeoutConstant := 0; CommTimeOuts.WriteTotalTimeoutMultiplier := 10; CommTimeOuts.WriteTotalTimeoutConstant := 0;
// Если не получилось выходим if not(SetCommTimeouts(hCom,CommTimeOuts)) then exit; // Устанавливаем параметры порта через DCB
//Заполняем нужные параметры hdcb.BaudRate :=fBaudRate; hdcb.ByteSize := fByteSize; hdcb.StopBits := fStopBits; hdcb.Parity := fParity; // Устанавливаем DpCB if not(SetCommState(hCom,hdcb)) then exit;
succ:=ReadFile(hCom,result,1,fRead,@ReadOL); if not succ then begin if GetLastError=ERROR_IO_PENDING then if WaitForSingleObject(ReadOl.hEvent,waitint)=WAIT_OBJECT_0 then if GetOverlappedResult(hCom, ReadOL, fREad,true) then Succ:=true; end; // if not succ if not(GetCommState(hCom,hDCB)) then exit;
-
> tesseract © (06.08.08 10:52) [3]
> if (hCom=INVALID_HANDLE_VALUE) or (hcom=ERROR_ALREADY_EXISTS) > then .......
ERROR_ALREADY_EXISTS - лишнее,не вернется в данном случае. Эта ошибка возвращается уже при вызове GetLastError. Но мне кажется, что и при вызове GetLastError она не вернется для COM порта.. , но... точно не скажу, просто не видел такой ошибки для COM порта
-
> просто не видел такой ошибки для COM порта
Описался :-) Порт всегда конечно существует. Там ERROR_ALREADY_OPEN вроде должно стоять, точно не помню сейчас.
-
> чему передавать команду? COM порту, USB порту или драйверу > переходника?
если после установки драйвера появился новый com порт, то ему иначе usb а дальше забота дравера)
-
Если есть переходник USB-COM, его драйвера обычно ставят виртуальный COM-порт, с которым программы работают как с самым обычным последовательным портом, а преобразование сигналов посл. порта в USB интерфейс и обратно - это уже забота драйвера и собственно переходника. Я пользуюсь вот этим http://synapse.ararat.cz/files/synaser.zip (класс TBlockSerial) - простая обертка над Windows API, которая прячет внутри себя эти громоздкие вызовы. Недостаток - все вызовы блокирующие (при обрыве линии и плохом проектировании приложения может надолго завесить всю программу). Пример использования:
var Ser:TBlockSerial;
Buffer:packed array[0..1024]of byte;
BufSize:integer;
begin
BufSize := 32;
ser:=TBlockSerial.Create;
try
ser.Connect('COM3');
ser.config(9600,8,'N',ONESTOPBIT,false,false);
ser.RecvBuffer(@Buffer,BufSize);
ser.SendBuffer(@Buffer,BufSize);
finally
ser.free;
end;
end;
-
unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, TeeProcs, TeEngine, Chart, Series;
type TForm1 = class(TForm) Button1: TButton; Edit1: TEdit; Chart1: TChart; Timer1: TTimer; Button2: TButton; Edit2: TEdit; Label1: TLabel; Label2: TLabel; Edit3: TEdit; Label3: TLabel; Edit4: TEdit; Label4: TLabel; Button3: TButton; Button4: TButton; Series2: TFastLineSeries; procedure Button1Click(Sender: TObject); procedure DrawGraphics(); procedure Timer1Timer(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure Button4Click(Sender: TObject);
private { Private declarations } public { Public declarations } end; Type TProcedure = procedure; var Form1: TForm1; Data, TData: integer; ComFile: THandle; t, dt, t0: real; a, b, c, d, e, f, g, h, m : integer; dataToSend: string; BytesWritten: DWORD;
function Out32(wAddr:word;bOut:byte):byte; stdcall; external 'inpout32.dll'; function Inp32(wAddr:word):byte; stdcall; external 'inpout32.dll';
implementation
{$R *.dfm}
function HexToBin():integer; begin a:=data and $01; b:=data and $02; b:=b shr 1; b:=b*10; c:=data and $04; c:=c shr 2; c:=c*100; d:=data and $08; d:=d shr 3; d:=d*1000; e:=data and $010; e:=e shr 4; e:=e*10000; f:=data and $20; f:=f shr 5; f:=f*100000; g:=data and $40; g:=g shr 6; g:=g*1000000; h:=data and $80; h:=h shr 7; h:=h*10000000; m:=h+g+f+e+d+c+b+a; result:=m; end;
function THexToBin():integer; begin a:=Tdata and $01; b:=Tdata and $02; b:=b shr 1; b:=b*10; c:=Tdata and $04; c:=c shr 2; c:=c*100; d:=Tdata and $08; d:=d shr 3; d:=d*1000; e:=Tdata and $010; e:=e shr 4; e:=e*10000; f:=Tdata and $20; f:=f shr 5; f:=f*100000; g:=Tdata and $40; g:=g shr 6; g:=g*1000000; h:=Tdata and $80; h:=h shr 7; h:=h*10000000; m:=h+g+f+e+d+c+b+a; result:=m; end;
function SetupCOMPort: Boolean; const RxBufferSize = 256; TxBufferSize = 256; var DCB: TDCB; Config: string; CommTimeouts: TCommTimeouts; begin Result := True;
if not SetupComm(ComFile, RxBufferSize, TxBufferSize) then Result := False;
if not GetCommState(ComFile, DCB) then Result := False;
// define the baudrate, parity,... // hier die Baudrate, Parität usw. konfigurieren
Config := 'baud=1200 parity=n data=8 stop=1';
if not BuildCommDCB(@Config[1], DCB) then Result := False;
if not SetCommState(ComFile, DCB) then Result := False;
with CommTimeouts do begin ReadIntervalTimeout := 0; ReadTotalTimeoutMultiplier := 0; ReadTotalTimeoutConstant := 1000; WriteTotalTimeoutMultiplier := 0; WriteTotalTimeoutConstant := 1000; end;
if not SetCommTimeouts(ComFile, CommTimeouts) then Result := False; end;
function OpenCOMPort: Boolean; var DeviceName: array[0..80] of Char; begin StrPCopy(DeviceName, 'COM1:'); ComFile := CreateFile(DeviceName, GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if ComFile = INVALID_HANDLE_VALUE then Result := False else Result := True; WriteFile(ComFile, datatosend[1], Length('30'), BytesWritten, nil); end;
procedure TForm1.DrawGraphics(); begin Series2.AddXY(t, data); end;
procedure TForm1.FormCreate(Sender: TObject); begin t0:=0.0; dt:=0.01; t:=t0; end;
procedure TForm1.Button1Click(Sender: TObject); begin Series2.Clear; t0:=0.0; dt:=0.01; t:=t0; timer1.Enabled:=true; end;
procedure TForm1.Timer1Timer(Sender: TObject); var gg: integer; begin t:=t+dt; OpenComPort(); SetupComPort(); edit1.Text:=IntToStr(Inp32($3f8)); Data:=StrToInt(Edit1.Text); CloseHandle(ComFILE);
//Recieved Data in Binary gg:=HexToBin(); if(h=0)then begin edit2.Text:='0'+IntToStr(g+f+e+d+c+b+a); if(g=0)then begin edit2.Text:='00'+IntToStr(f+e+d+c+b+a); if(f=0)then begin edit2.Text:='000'+IntToStr(e+d+c+b+a); if(e=0)then begin edit2.Text:='0000'+IntToStr(d+c+b+a); if(d=0)then begin edit2.Text:='00000'+IntToStr(c+b+a); if(c=0)then begin edit2.Text:='000000'+IntToStr(b+a); if(b=0)then begin edit2.Text:='0000000'+IntToStr(a); if(a=0)then begin edit2.Text:='00000000'; end; end; end; end; end; end; end; end else edit2.Text:=IntToStr(gg); //Recieved Data in Binary DrawGraphics(); end;
procedure TForm1.Button4Click(Sender: TObject); begin timer1.Enabled:=false; end;
//Start of Transmitting Data procedure TForm1.Button3Click(Sender: TObject); var kk: integer; begin OpenComPort(); SetupComPort(); TData:=StrToInt(edit3.Text); out32($3f8, TData);
//Recieved Data in Binary kk:=THexToBin(); if(h=0)then begin edit4.Text:='0'+IntToStr(g+f+e+d+c+b+a); if(g=0)then begin edit4.Text:='00'+IntToStr(f+e+d+c+b+a); if(f=0)then begin edit4.Text:='000'+IntToStr(e+d+c+b+a); if(e=0)then begin edit4.Text:='0000'+IntToStr(d+c+b+a); if(d=0)then begin edit4.Text:='00000'+IntToStr(c+b+a); if(c=0)then begin edit4.Text:='000000'+IntToStr(b+a); if(b=0)then begin edit4.Text:='0000000'+IntToStr(a); if(a=0)then begin edit4.Text:='00000000'; end; end; end; end; end; end; end; end else edit4.Text:=IntToStr(kk); //Recieved Data in Binary CloseHandle(ComFILE); end;
//Application is close procedure TForm1.Button2Click(Sender: TObject); begin Application.Terminate; end;
end.
-
> Уянга
Шедевр программистской мысли.
-
Вау.
-
Даа.... я в школе писал наверно лучше.
-
а мне нравится то, что после //Recieved Data in Binary - это просто натюрморт в коде
-
> clickmaker © (01.12.08 13:56) [12]
Что именно? сей комментарий встречается четырежды :)
-
А мне нравятся две процедуры HexToBin. Вот только на стенку повесить не могу. Обои жалко портить. :(
-
Обои жалко, а психику не жалеешь, а зря - обои можно переклеить, а мозги не заменишь.
-
> Германн © (02.12.08 10:40) [14]
Во-первых, функции, а во-вторых, одна. Вторая - THexToBin
-
> KilkennyCat © (02.12.08 23:50) [16]
И все равно нравятся! :)
-
>Я пользуюсь вот этим http://synapse.ararat.cz/files/synaser.zip (класс TBlockSerial) - простая обертка над Windows API, которая прячет внутри себя эти громоздкие вызовы. Спасибо. Как раз начинаем плотно ком юзать - видимо, самое оно, что бы всё то же самое не писать. >Недостаток - все вызовы блокирующие (при обрыве линии и плохом проектировании приложения может надолго завесить всю программу) Лечится дополнительным потоком. Уянга - красавица :)
-
>2)Я использовал WinAPI функцию для управления COM портом >SetCommState в которую передавал Handle >hndCOM:=CreateFile(PChar('COM1'),GENERIC_READ >+GENERIC_WRITE,0,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
А кто теб сказал что он COM1, а не COM5 например?
|