Тема: 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)
; читаем ответ от порта в переменную In_Data
varsetcapacity(In_Data,Receive_Data_Size)
RS232_Read(RS232_FileHandle,Receive_Data_Size,RS232_Bytes_Received,In_Data)
; если длина запрошенных и полученных байт одинакова выполняем присвоение переменным
if (RS232_Bytes_Received==Receive_Data_Size)
{
; пишем полученные данные в свои переменные
b0:=numget(In_Data,0,"uchar") ; 1 байт
b1:=numget(In_Data,1,"uchar") ; 1 байт
b2:=numget(In_Data,2,"uchar") ; 1 байт
b3:=numget(In_Data,3,"uchar") ; 1 байт
b4:=numget(In_Data,4,"uchar") ; 1 байт
b5:=numget(In_Data,5,"uchar") ; 1 байт
b6:=numget(In_Data,6,"uchar") ; 1 байт
b7:=numget(In_Data,7,"uchar") ; 1 байт
w0:=numget(In_Data,8,"ulong") ; 4 байта
}
else ; если не одинакова - увеличиваем интервал между запросами
{
tie_interval+=1
if tie_interval>500 ; максимально возможный интервал
tie_interval=100
}
if DebugMode ; показывать отладочную информацию
{ ; перечислять все полученные байты, независимо от типов данных
v=
loop,% RS232_Bytes_Received
{
tmp:=numget(In_Data,a_index-1,"uchar")
v.=a_index-1 "`t" format("0x{:02x}",tmp) " " tmp "`n"
}
tooltip,
(
COMPort=%COMPort%
COM handle=%RS232_FileHandle%
Bytes Received=%RS232_Bytes_Received%/%Receive_Data_Size%
Recieved data:
%v%
),400,0,2
}
; выводим на экран
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,Byref D)
{
Num_Bytes:=Data_Length*2
; 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
}
D:=Data
}
Скажите, если стоит добавить в коллекцию и что для этого нужно изменить.