Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Программирование устройства через COM-port [D7, WinXP]


Rafa ©   (2008-08-05 17:14:00) 

Мне требуется написать программу для отправки команды в хексе на одно промышленное устройство (контроллер "Квант-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 дайте ссылку на компонент.
Заранее спасибо...


kulibin   (2009-01-10 21:16:00) [1]

>2)Я использовал WinAPI функцию для управления COM портом >SetCommState в которую передавал Handle  
>hndCOM:=CreateFile(PChar('COM1'),GENERIC_READ
>+GENERIC_WRITE,0,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

А кто теб сказал что он COM1, а не COM5 например?


Дмитрий Белькевич   (2008-12-06 12:34:00) [2]

>Я пользуюсь вот этим http://synapse.ararat.cz/files/synaser.zip(класс TBlockSerial) - простая обертка над Windows API, которая прячет внутри себя эти громоздкие вызовы.

Спасибо. Как раз начинаем плотно ком юзать - видимо, самое оно, что бы всё то же самое не писать.

>Недостаток - все вызовы блокирующие (при обрыве линии и плохом проектировании приложения может надолго завесить всю программу)

Лечится дополнительным потоком.

Уянга - красавица :)


Германн   (2008-12-03 00:07:00) [3]


> KilkennyCat ©   (02.12.08 23:50) [16]

И все равно нравятся!
:)


KilkennyCat   (2008-12-02 23:50:00) [4]


> Германн ©   (02.12.08 10:40) [14]

Во-первых, функции, а во-вторых, одна. Вторая - THexToBin


Anatoly Podgoretsky   (2008-12-02 11:09:00) [5]

Обои жалко, а психику не жалеешь, а зря - обои можно переклеить, а мозги не заменишь.


Германн   (2008-12-02 10:40:00) [6]

А мне нравятся две процедуры HexToBin. Вот только на стенку повесить не могу. Обои жалко портить. :(


KilkennyCat   (2008-12-01 21:17:00) [7]


> clickmaker ©   (01.12.08 13:56) [12]

Что именно? сей комментарий встречается четырежды :)


clickmaker   (2008-12-01 13:56:00) [8]

а мне нравится
то, что после //Recieved Data in Binary - это просто натюрморт в коде


tesseract   (2008-12-01 11:48:00) [9]

Даа.... я в школе писал наверно лучше.


KilkennyCat   (2008-12-01 11:19:00) [10]

Вау.


Сергей М.   (2008-12-01 08:28:00) [11]


> Уянга


Шедевр программистской мысли.


Уянга   (2008-12-01 07:58:00) [12]

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.


Viktorious   (2008-08-07 00:08:00) [13]

Если есть переходник 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);
 //Прочитать данные из порта. Лучше использовать RecvBufferEx -  можно задавать тайм-аут ожидания.
   ser.RecvBuffer(@Buffer,BufSize);
 //отправить данные в последовательный порт
   ser.SendBuffer(@Buffer,BufSize);
 finally
   ser.free;
 end;
end;


brother   (2008-08-06 13:21:00) [14]

> чему передавать команду? COM порту, USB порту или драйверу
> переходника?

если после установки драйвера появился новый com порт, то ему иначе usb а дальше забота дравера)


tesseract   (2008-08-06 12:23:00) [15]


>  просто не видел такой ошибки для COM порта


Описался :-) Порт всегда конечно существует. Там ERROR_ALREADY_OPEN вроде должно стоять, точно не помню сейчас.


Variant   (2008-08-06 12:04:00) [16]


> 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 порта


tesseract   (2008-08-06 10:52:00) [17]


> Будь то передача в 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;


KilkennyCat   (2008-08-05 22:19:00) [18]

не совсем угадал :) - эта точнее
http://www.torry.net/pages.php?id=198


KilkennyCat   (2008-08-05 22:14:00) [19]


> 1)Самое важное что мне надо знать, это чему передавать команду?
>  COM порту, USB порту или драйверу переходника?


COM порту


> 2)...>  может это быть из-за неверных параметров в структуре?


Разумеется. В том числе из-за неправильного имени порта.

3) http://www.torry.net/pages.php?id=1223


Наверх

Титульная страница Поиск, карта сайта Написать письмо