1 (изменено: Alectric, 2017-05-07 09:21:54)

Тема: AHK: Работа с COM портом для микроконтроллеров

Скрипт отправляет данные в последовательный COM Port и затем читает ответные данные из буфера КОМ Порта.

Скрипт делался для микроконтроллера Ардуино (Arduino) для снятия данных и управления микроконтроллером (скетчи для ардуины могу дать если кому надо).

Но подойдет для любых других целей связи с ком портом.

Источник

Тема для обсуждения


Читайте комментарии.

#SingleInstance,Force
CoordMode,ToolTip
SetBatchLines,-1
SetWorkingDir,%A_ScriptDir%
OnExit,EXIT

DebugMode=1 ; показывать отладочную информацию

global COMFail ; 1 - ошибка ком порта
tie_interval=100 ; начальный интервал связи, если длина запрошенных
                 ; и полученных байт будет отличаться - интервал увеличится

PortName:="USB-SERIAL CH340" ; имя порта для автоматического поиска

Receive_Data_Size=32 ; длина запрошенных из порта байт
Send_Data_Size=32    ; длина отправляемых в порт байт

loop ; основной цикл
{
  sleep,10
  Loop_Time:=oldLoop_Time!="" ? a_tickcount-oldLoop_Time : 0 ; вычисляем время одного цикла
  oldLoop_Time:=a_tickcount

  if (!RS232_FileHandle or COMFail) ; если хэндл порта не взят или ошибка ком порта
  {
    COMFail=0
    ; повторно искать порт и брать хэндл
    RS232_FileHandle:=Get_RS232_FileHandle(COMPort:=Seach_COM(PortName))
   ;RS232_FileHandle:=Get_RS232_FileHandle(COMPort:="COM2") ; вместо поиска можно жёстко задать порт
    ; Get_RS232_FileHandle(номер порта, скорость связи в бодах, четность, битность, стоповые биты)

  }
  if RS232_FileHandle ; если хендл есть, читаем и пишем в порт
  {
    if (!tie:=tie>tie_interval ? 0 : tie="" ? 1 : tie+Loop_Time) ; с интервалом в tie_interval милисекунд
    {
      ; данные для отправки
      b_0=0          ; 1 байт
      b_1++          ; 1 байт
      b_2=255        ; 1 байт
      w_0=1234567890 ; 4 байта
      b_3=128        ; 1 байт

      varsetcapacity(Out_Data,Send_Data_Size) ; задаём размер переменной для отправки
      NumPut(b_0,Out_Data,0,"Uchar")          ; 1 байт
      NumPut(b_1,Out_Data,1,"Uchar")          ; 1 байт
      NumPut(b_2,Out_Data,2,"Uchar")          ; 1 байт
      NumPut(w_0,Out_Data,3,"Uint")           ; 4 байта
      NumPut(b_3,Out_Data,7,"Uchar")          ; 1 байт
                                              ; остальные байты резервные

      ; пишем данные в порт
      RS232_Write(RS232_FileHandle,&Out_Data,Send_Data_Size)

      ; читаем ответ от порта в HEX формате
      data:=RS232_Read(RS232_FileHandle,Receive_Data_Size,RS232_Bytes_Received)

      ; если длина запрошенных и полученных байт одинакова заполняем массив byte
      if (RS232_Bytes_Received==Receive_Data_Size)
      {
        loop,% RS232_Bytes_Received*2
        {
          if (a_index&0x1)
          {
            bytenum:=(a_index-1)//2 ; номер байта
            ; сам байт состоит из 2х символов HEX
            byte%bytenum%:=chr(numget(data,2*(a_index-1),"uchar")) . chr(numget(data,2*(a_index-1)+2,"uchar"))
          }
        }
      }
      else ; если не одинакова - увеличиваем интервал между запросами
      {
        tie_interval+=1
        if tie_interval>500 ; максимально возможный интервал
          tie_interval=100
      }

      if DebugMode ; показывать отладочную информацию
      {            ; перечислять все полученные байты, независимо от размеров данных
        v=
        loop,% RS232_Bytes_Received*2
        {
          if (a_index&0x1)
            v.=(a_index-1)//2 "`t0x" chr(numget(data,2*(a_index-1),"uchar")) . chr(numget(data,2*(a_index-1)+2,"uchar")) "`n"
        }
        RS232_Bytes_Received:=RS232_Bytes_Received+0 ; перевести в Dec формат для удобства
        tooltip,
(
COMPort=%COMPort%
COM handle=%RS232_FileHandle%
Bytes Received=%RS232_Bytes_Received%/%Receive_Data_Size%

Recieved data:
%v%
),400,0,2
      }

      ; пишем полученные данные в свои переменные
      b0:="0x" byte0                    ; 1 байт
      b1:="0x" byte1                    ; 1 байт
      b2:="0x" byte2                    ; 1 байт
      b3:="0x" byte3                    ; 1 байт
      b4:="0x" byte4                    ; 1 байт
      b5:="0x" byte5                    ; 1 байт
      b6:="0x" byte6                    ; 1 байт
      b7:="0x" byte7                    ; 1 байт
      w0:="0x" byte11 byte10 byte9 byte8 ; 4 байта

      ; выводим на экран
      tooltip,% "b0=" b0+0 "`nb1=" b1+0 "`nb2=" b2+0 "`nb3=" b3+0 "`nb4=" b4+0 "`nb5=" b5+0 "`nb6=" b6+0 "`nb7=" b7+0 "`nw0=" w0+0
    }
  }
}
return


esc::
EXIT:
if RS232_FileHandle
  RS232_Close(RS232_FileHandle)
exitapp

Seach_COM(name)
{
  Loop,HKLM,HARDWARE\DEVICEMAP\SERIALCOMM\
  {
    RegRead,COMPort
    com.=COMPort "|"
    num++
  }
  loop,parse,com,|
  {
    if !A_loopfield
      continue
    COMPort:=A_loopfield
    Loop,HKLM,SYSTEM\CurrentControlSet\Enum,1,1
    {
      if (A_LoopRegName="PortName")
      {
        RegRead,Outputvar
        if (Outputvar=COMPort)
        {
          RegRead,FriendlyName,% A_LoopRegKey,% RegExReplace(A_LoopRegSubKey, "(.*)\\Device Parameters", "$1"),FriendlyName
          if InStr(FriendlyName,name)
            return COMPort
        }
      }
    }
  }
}

Get_RS232_FileHandle(RS232_Port,RS232_Baud=9600,RS232_Parity="N",RS232_Data=8,RS232_Stop=1)
{
  sleep,1000
  RS232_Settings = %RS232_Port%:baud=%RS232_Baud% parity=%RS232_Parity% data=%RS232_Data% stop=%RS232_Stop% dtr=Off xon=off to=off odsr=off octs=off rts=off idsr=off
  return RS232_Initialize(RS232_Settings)
}

RS232_Initialize(RS232_Settings)
{
  ;###### Extract/Format the RS232 COM Port Number ######
  ;7/23/08 Thanks krisky68 for finding/solving the bug in which RS232 COM Ports greater than 9 didn't work.
  StringSplit, RS232_Temp, RS232_Settings, `:
  RS232_Temp1_Len := StrLen(RS232_Temp1)  ;For COM Ports > 9 \\.\ needs to prepended to the COM Port name.
  If (RS232_Temp1_Len > 4)                   ;So the valid names are
    RS232_COM = \\.\%RS232_Temp1%             ; ... COM8  COM9   \\.\COM10  \\.\COM11  \\.\COM12 and so on...
  Else                                          ;
    RS232_COM = %RS232_Temp1%

  ;8/10/09 A BIG Thanks to trenton_xavier for figuring out how to make COM Ports greater than 9 work for USB-Serial Dongles.
  StringTrimLeft, RS232_Settings, RS232_Settings, RS232_Temp1_Len+1 ;Remove the COM number (+1 for the semicolon) for BuildCommDCB.
  ;MsgBox, RS232_COM=%RS232_COM% `nRS232_Settings=%RS232_Settings%

  ;###### Build RS232 COM DCB ######
  ;Creates the structure that contains the RS232 COM Port number, baud rate,...
  VarSetCapacity(DCB, 28)
  BCD_Result := DllCall("BuildCommDCB"
       ,"str" , RS232_Settings ;lpDef
       ,"ptr", &DCB)        ;lpDCB
;  If (BCD_Result != 1)
;  {
;    MsgBox, There is a problem with Serial Port communication. `nFailed Dll BuildCommDCB, BCD_Result=%BCD_Result% `nThe Script Will Now COMFail.`n %DCB%
;    COMFail=1
;    return
;  }

  ;###### Create RS232 COM File ######
  ;Creates the RS232 COM Port File Handle
  RS232_FileHandle := DllCall("CreateFile"
       ,"Str" , RS232_COM    ;File Name
       ,"UInt", 0xC0000000   ;Desired Access
       ,"UInt", 3            ;Safe Mode
       ,"UInt", 0            ;Security Attributes
       ,"UInt", 3            ;Creation Disposition
       ,"UInt", 0            ;Flags And Attributes
       ,"ptr" , 0            ;Template File
       ,"Cdecl Int")

  If (!RS232_FileHandle)
  {
;;    MsgBox, There is a problem with Serial Port communication. `nFailed Dll CreateFile, RS232_FileHandle=%RS232_FileHandle% `nThe Script Will Now COMFail.
    COMFail=1
    return
  }

  ;###### Set COM State ######
  ;Sets the RS232 COM Port number, baud rate,...
  SCS_Result := DllCall("SetCommState"
       ,"ptr", RS232_FileHandle ;File Handle
       ,"ptr", &DCB)            ;Pointer to DCB structure
  If (SCS_Result!=1)
  {
;;    MsgBox, There is a problem with Serial Port communication. `nFailed Dll SetCommState, SCS_Result=%SCS_Result% `nThe Script Will Now COMFail.
    RS232_Close(RS232_FileHandle)
    COMFail=1
    return
  }

  ;###### Create the SetCommTimeouts Structure ######
  ReadIntervalTimeout        = 0x01000000
  ReadTotalTimeoutMultiplier = 0x00000000
  ReadTotalTimeoutConstant   = 0x00000010
  WriteTotalTimeoutMultiplier= 0x00000000
  WriteTotalTimeoutConstant  = 0x00000010

  VarSetCapacity(Data,20) ; 5 * sizeof(DWORD)
  NumPut(ReadIntervalTimeout,         Data,  0, "UInt")
  NumPut(ReadTotalTimeoutMultiplier,  Data,  4, "UInt")
  NumPut(ReadTotalTimeoutConstant,    Data,  8, "UInt")
  NumPut(WriteTotalTimeoutMultiplier, Data, 12, "UInt")
  NumPut(WriteTotalTimeoutConstant,   Data, 16, "UInt")

  ;###### Set the RS232 COM Timeouts ######
  SCT_result := DllCall("SetCommTimeouts"
     ,"ptr", RS232_FileHandle ;File Handle
     ,"ptr", &Data)         ;Pointer to the data structure
  If (SCT_result != 1)
  {
;;    MsgBox, There is a problem with Serial Port communication. `nFailed Dll SetCommState, SCT_result=%SCT_result% `nThe Script Will Now COMFail.
    RS232_Close(RS232_FileHandle)
    COMFail=1
    return
  }
  Return %RS232_FileHandle%
}

RS232_Close(RS232_FileHandle)
{
  return DllCall("CloseHandle","ptr",RS232_FileHandle)
}

RS232_Write(RS232_FileHandle,Data,Data_Length)
{
  if RS232_FileHandle
  WF_Result := DllCall("WriteFile"
       ,"ptr" , RS232_FileHandle ;File Handle
       ,"ptr" , Data          ;Pointer to string to send
       ,"UInt", Data_Length    ;Data Length
       ,"ptr*", Bytes_Sent     ;Returns pointer to num bytes sent
       ,"Int" , "NULL")
}

RS232_Read(RS232_FileHandle,Data_Length,ByRef RS232_Bytes_Received)
{
  Num_Bytes:=Data_Length+Data_Length//3
  SetFormat,Integer,HEX
  VarSetCapacity(Data,Num_Bytes,0xff)
  if RS232_FileHandle
  Read_Result := DllCall("ReadFile"
       ,"ptr" , RS232_FileHandle   ; hFile
       ,"ptr"  , &Data             ; lpBuffer
       ,"Int"  , Num_Bytes        ; nNumberOfBytesToRead
       ,"ptr*", RS232_Bytes_Received   ; lpNumberOfBytesReceived
       ,"Int"  , 0)               ; lpOverlapped
  If (Read_Result != 1)
  {
    RS232_Close(RS232_FileHandle)
    COMFail=1
    return
  }
  Loop,% RS232_Bytes_Received
  {
    t:=NumGet(Data,a_index-1,"UChar")
    StringTrimLeft,t,t,2
    If (StrLen(t)=1)
      t:="0" t
    Data_HEX.=t
  }
  SetFormat,Integer,DEC
  Return Data_HEX
}
Win 7 x64
AHK v1.1.24.00
                       Справка тебе в помощь.