Конференция "WinAPI" » Программирование устройства через COM-port [D7, WinXP]
 
  • Rafa © (05.08.08 17:14) [0]
    Мне требуется написать программу для отправки команды в хексе на одно промышленное устройство (контроллер "Квант-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 дайте ссылку на компонент.
    Заранее спасибо...
  • KilkennyCat © (05.08.08 22:14) [1]

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


    COM порту


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


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

    3)http://www.torry.net/pages.php?id=1223
  • KilkennyCat © (05.08.08 22:19) [2]
    не совсем угадал :) - эта точнее
    http://www.torry.net/pages.php?id=198
  • tesseract © (06.08.08 10:52) [3]

    > Будь то передача в 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;
  • Variant (06.08.08 12:04) [4]

    > 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 © (06.08.08 12:23) [5]

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


    Описался :-) Порт всегда конечно существует. Там ERROR_ALREADY_OPEN вроде должно стоять, точно не помню сейчас.
  • brother © (06.08.08 13:21) [6]
    > чему передавать команду? COM порту, USB порту или драйверу
    > переходника?

    если после установки драйвера появился новый com порт, то ему иначе usb а дальше забота дравера)
  • Viktorious © (07.08.08 00:08) [7]
    Если есть переходник 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;

  • Уянга (01.12.08 07:58) [8]
    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.
  • Сергей М. © (01.12.08 08:28) [9]

    > Уянга


    Шедевр программистской мысли.
  • KilkennyCat © (01.12.08 11:19) [10]
    Вау.
  • tesseract © (01.12.08 11:48) [11]
    Даа.... я в школе писал наверно лучше.
  • clickmaker © (01.12.08 13:56) [12]
    а мне нравится
    то, что после //Recieved Data in Binary - это просто натюрморт в коде
  • KilkennyCat © (01.12.08 21:17) [13]

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

    Что именно? сей комментарий встречается четырежды :)
  • Германн © (02.12.08 10:40) [14]
    А мне нравятся две процедуры HexToBin. Вот только на стенку повесить не могу. Обои жалко портить. :(
  • Anatoly Podgoretsky © (02.12.08 11:09) [15]
    Обои жалко, а психику не жалеешь, а зря - обои можно переклеить, а мозги не заменишь.
  • KilkennyCat © (02.12.08 23:50) [16]

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

    Во-первых, функции, а во-вторых, одна. Вторая - THexToBin
  • Германн © (03.12.08 00:07) [17]

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

    И все равно нравятся!
    :)
  • Дмитрий Белькевич © (06.12.08 12:34) [18]
    >Я пользуюсь вот этим http://synapse.ararat.cz/files/synaser.zip (класс TBlockSerial) - простая обертка над Windows API, которая прячет внутри себя эти громоздкие вызовы.

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

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

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

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

    А кто теб сказал что он COM1, а не COM5 например?
 
Конференция "WinAPI" » Программирование устройства через COM-port [D7, WinXP]
Есть новые Нет новых   [134435   +35][b:0][p:0.001]