Added support to Mac OS X. Now it supports all (Windows, Linux and Mac OS X).
Code: Select all
DeclareModule OWire
;-DeclareModule
Enumeration OW_ErrCode
#OW_Err_OK ; Ошибок нет.
#OW_Err_Port ; Нет открытого порта (для OpenPort() - ошибка открытия порта).
#OW_Err_NoDevice ; Не найдены 1-Wire устройства.
#OW_Err_IO ; Ошибка при обмене данными с 1-Wire устройством.
#OW_Err_BaudRate ; Ошибка при изменении скорости порта.
#OW_Err_Search ; Ошибка происходит если во время поиска ни одно 1-Wire устройство не ответило.
#OW_Err_BadParam ; Неккоректный параметр.
#OW_Err_NoData ; Нет данных.
EndEnumeration
#OW_PortOnly = -10 ; Идентификатор порта по умолчанию.
#OW_Mode_CPU_MinUsage = 1 ; Уменьшить загрузку процессора (снизится скорость обмена данными).
#OW_Mode_Invert = 2 ; Инвертирование сигналов DTR и RTS.
#OW_Mode_NoControlPin = 4 ; Не изменять состояние управляющих выходов DTR и RTS.
Structure OW_RAM ; Копия содержимого ОЗУ датчика DS18B20 ($BE).
L_Termo.a ; Младший байт температуры
H_Termo.a ; Старший байт температуры
Max_Termo.a ; Верхний предел температуры
Min_Termo.a ; Нижний предел температуры
Config.a ; Байт конфигурации
x.a[3] ; Резерв 3 байта (в датчике не реализовано)
CRC.a ; Контрольная сумма
EndStructure
;
Structure OW_Buff
Byte.a[0]
EndStructure
Structure OW_SN ; Идентификатор датчика ($33).
Type.a ; Тип устройства (код семейства)
Number.a[6] ; Серийный номер.
CRC.a ; Контрольная сумма.
EndStructure
Declare OW_GetMode()
Declare OW_SetMode(Mode)
Declare OW_GetPortDefID()
Declare OW_GetLastError() ; Код ошибки (см. константы #OW_Err_xxxx)
Declare OW_SetLastError(ErrCode)
Declare OW_ClosePort(Port=#OW_PortOnly) ; Закрытие порта.
Declare OW_OpenPort(ComPort.s, Port=#OW_PortOnly) ; Открытие порта.
Declare OW_PortID(Port=#OW_PortOnly)
Declare OW_Reset(Port=#OW_PortOnly) ; Сброс датчика.
Declare.a OW_ByteRW(Byte.a=$FF, Port=#OW_PortOnly) ; Чтение/запись байта.
Declare OW_ReadMultiByte(*Buff.OW_Buff, Count, Port=#OW_PortOnly) ; Чтение массива байт.
Declare OW_WriteMultiByte(*Buff.OW_Buff, Count, Port=#OW_PortOnly) ; Запись массива байт.
Declare.a OW_GetCRC(*Buff, Count) ; Вычислене контрольной суммы.
; Термометр передает 8-битный код семейства (10h для DS18S20 и 28h для DS18B20),
; затем 48-битный серийный номер, а затем 8-битную CRC для проверки правильности принятой информации.
Declare OW_ReadROM(*Info.OW_SN, Port=#OW_PortOnly)
; Эта процедура позволяет адресовать на шине конкретный термометр.
; Необходимо передать 64-битный код датчика (считанный процедурой ReadROM()),
; и только тот, который имеет такой код, будет «откликаться» до следующего импульса сброса.
Declare OW_SelectROM(*Info.OW_SN, Port=#OW_PortOnly)
; Вызов процедуры позволит пропустить процедуру сравнения серийного номера
; и тем самым сэкономить время в системах, где на шине имеется всего одно устройство.
Declare OW_SkipROM(Port=#OW_PortOnly)
; Поиск датчиков, идентификаторы которых будут помещены в список.
Declare OW_SearchROM_Reset()
Declare OW_SearchROM_Enum(*Sensor.OW_SN, Port=#OW_PortOnly)
; Поиск датчиков у которых результат последнего измерения температуры
; выходит за предустановленные пределы TH и TL.
Declare OW_SearchAlarm_Reset()
Declare OW_SearchAlarm_Enum(*Sensor.OW_SN, Port=#OW_PortOnly)
; Чтение данных из промежуточного ОЗУ датчика.
Declare OW_ReadRAM(*Info.OW_RAM, Port=#OW_PortOnly)
; Запись данных в промежуточное ОЗУ датчика
Declare OW_WriteRAM(*Info.OW_Buff, Port=#OW_PortOnly)
; Копирование данных из промежуточного ОЗУ в энергонезависимую память датчика.
; Эта операция требует около 10мс.
Declare OW_CopyRAM(Port=#OW_PortOnly)
; Запуск процесса преобразования температуры.
Declare OW_ConvertT(Wait=0, Port=#OW_PortOnly)
; Эта процедура действует обратным образом по отношению к процедуре OW_CopyRAM(),
; т.е. она позволяет считать байты TH и TL из энергонезависимой памяти в промежуточное ОЗУ.
Declare OW_Recall(Port=#OW_PortOnly)
; Проверка, использует ли 1-Wire устройство паразитное питание.
Declare OW_ReadPowerSupply(Port=#OW_PortOnly)
EndDeclareModule
Module OWire
EnableExplicit
;- Private
#wbf_WaitByte = 1
#wbf_ClearByte = 2
#wbf_Slot = 4
CompilerIf #PB_Compiler_OS = #PB_OS_Linux Or #PB_Compiler_OS = #PB_OS_MacOS
#NCCS = 32
#TCSANOW = 0
Structure termios Align #PB_Structure_AlignC
c_iflag.l
c_oflag.l
c_cflag.l
c_lflag.l
c_line.a
c_cc.a[#NCCS]
c_ispeed.l
c_ospeed.l
EndStructure
Global gModuleModeLin=0
CompilerEndIf
Structure sSearch
LastDiscrepancy.l
Done.a
Search.a[8]
EndStructure
CompilerIf #PB_Compiler_Thread
Threaded tLastErr=0, tSearchROM.sSearch, tSearchAlarm.sSearch
CompilerElse
Global tLastErr=0, tSearchROM.sSearch, tSearchAlarm.sSearch
CompilerEndIf
Global gCurrent_ComPort_ID=-2, gModuleMode=0
Macro TestPortID(pID)
If pID=#OW_PortOnly
pID=gCurrent_ComPort_ID
EndIf
EndMacro
Macro Odd(xx)
((xx) & 1)
EndMacro
Procedure ClearInBuf(Port) ; Очистка приёмного буфера.
Protected Count, *Mem
Count = AvailableSerialPortInput(Port)
If Count>0
*Mem=AllocateMemory(Count+2, #PB_Memory_NoClear)
If *Mem
ReadSerialPortData(Port, *Mem, Count)
FreeMemory(*Mem)
EndIf
EndIf
EndProcedure
Procedure TestPort(Port)
TestPortID(Port)
If IsSerialPort(Port)
tLastErr=#OW_Err_OK
ClearInBuf(Port)
Else
tLastErr=#OW_Err_Port
EndIf
ProcedureReturn Port
EndProcedure
Procedure SetBaudRate(Port, Rate)
Protected Result=#False, PortID
If IsSerialPort(Port)
PortID = SerialPortID(Port)
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Protected dcb.DCB
If PortID
If GetCommState_(PortID, @dcb)
dcb\BaudRate = Rate ; Требуемая скорость.
If gModuleMode & #OW_Mode_NoControlPin = 0
dcb\fbits & ~%0010000000100000
If gModuleMode & #OW_Mode_Invert = 0
dcb\fbits | %0001000000010000
Else
dcb\fbits & ~%0001000000010000
EndIf
EndIf
If SetCommState_(PortID, @dcb)
Result = #True
EndIf
EndIf
EndIf
CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux Or #PB_Compiler_OS = #PB_OS_MacOS
Protected options.termios, Sp
If Rate=9600 Or Rate=115200
CompilerIf #PB_Compiler_OS = #PB_OS_Linux
Select Rate
Case 9600 : Sp = 13
Case 115200 : Sp = 4098
EndSelect
CompilerElse
Sp = Rate
CompilerEndIf
If tcgetattr_(PortID, @options) = 0 ; читает параметры порта.
If cfsetispeed_(@options, Sp) = 0 ; установка скорости порта.
If cfsetospeed_(@options, Sp) = 0 ; установка скорости порта.
If tcsetattr_(PortID, #TCSANOW, @options) = 0
Result=#True
EndIf
EndIf
EndIf
EndIf
EndIf
If gModuleMode & #OW_Mode_NoControlPin = 0
If gModuleMode&#OW_Mode_Invert <> gModuleModeLin&#OW_Mode_Invert
If gModuleMode & #OW_Mode_Invert=0
SetSerialPortStatus(Port, #PB_SerialPort_DTR, 1)
SetSerialPortStatus(Port, #PB_SerialPort_RTS, 1)
Else
SetSerialPortStatus(Port, #PB_SerialPort_DTR, 0)
SetSerialPortStatus(Port, #PB_SerialPort_RTS, 0)
EndIf
EndIf
gModuleModeLin=gModuleMode
EndIf
CompilerEndIf
If Result=#False : tLastErr=#OW_Err_BaudRate : EndIf
EndIf
ProcedureReturn Result
EndProcedure
Procedure.a ReadBit(Port, Flag=#wbf_WaitByte|#wbf_ClearByte|#wbf_Slot)
Protected Bit.a, x.l
tLastErr=#OW_Err_OK
If Flag&#wbf_ClearByte
ClearInBuf(Port)
EndIf
Bit=$FF
If Flag&#wbf_Slot
If WriteSerialPortData(Port, @Bit, 1)<>1
tLastErr=#OW_Err_IO
ProcedureReturn 0
EndIf
EndIf
If Flag&#wbf_WaitByte
x = ElapsedMilliseconds()
Repeat
If gModuleMode & #OW_Mode_CPU_MinUsage : Delay(1) : EndIf
Until AvailableSerialPortInput(Port)>0 Or Int(ElapsedMilliseconds()-x)>=36
EndIf
If AvailableSerialPortInput(Port)=1
x=0
If ReadSerialPortData(Port, @x, 1) = 1
Bit = Bool(x=$FF)
Else
tLastErr=#OW_Err_IO
EndIf
Else
tLastErr=#OW_Err_IO
EndIf
ProcedureReturn Odd(Bit)
EndProcedure
Procedure WriteBit(Bit.a, Port, Flag=#wbf_WaitByte|#wbf_ClearByte)
Bit=Odd(Bit)*$FF
WriteSerialPortData(Port, @Bit, 1)
If Flag & #wbf_WaitByte
Protected x.l = ElapsedMilliseconds()
Repeat
If gModuleMode & #OW_Mode_CPU_MinUsage : Delay(1) : EndIf
Until AvailableSerialPortInput(Port)>0 Or Int(ElapsedMilliseconds()-x)>=36
If Flag & #wbf_ClearByte And AvailableSerialPortInput(Port)>0
ReadSerialPortData(Port, @Bit, 1)
EndIf
EndIf
EndProcedure
; Код на основе материала. http://www.maximintegrated.com/app-notes/index.mvp/id/187
Procedure SearchDevice(*Sensor.OW_SN, *Search.sSearch, Port, Code.a)
Protected Result=#False
Protected.l id_bit_number, last_zero
Protected.l rom_byte_number
Protected.l id_bit, cmp_id_bit
Protected.a rom_byte_mask, search_direction
If *Search\Done = #False
ClearInBuf(Port)
id_bit_number = 1
last_zero = 0
rom_byte_number = 0
rom_byte_mask = 1
If OW_Reset(Port)
OW_WriteMultiByte(@Code, 1, Port)
If tLastErr=#OW_Err_OK
Repeat
id_bit = ReadBit(Port)
If tLastErr<>#OW_Err_OK : Break : EndIf
cmp_id_bit = ReadBit(Port)
If tLastErr<>#OW_Err_OK : Break : EndIf
If id_bit And cmp_id_bit ; Ни один датчик не ответил!
tLastErr=#OW_Err_Search
Break
ElseIf id_bit <> cmp_id_bit
search_direction = id_bit
Else ; Произошла коллизия (больше одного датчика и у них разные ID).
If id_bit_number < *Search\LastDiscrepancy
search_direction = Bool((*Search\Search[rom_byte_number] & rom_byte_mask))
Else
search_direction = Bool(id_bit_number=*Search\LastDiscrepancy)
EndIf
If search_direction = 0
last_zero = id_bit_number
EndIf
EndIf
If search_direction
*Search\Search[rom_byte_number] | rom_byte_mask
Else
*Search\Search[rom_byte_number] & ~rom_byte_mask
EndIf
WriteBit(search_direction, Port)
id_bit_number+1
rom_byte_mask<<1
If rom_byte_mask=0
rom_byte_number+1
rom_byte_mask = 1
EndIf
Until rom_byte_number >= 8
If Not id_bit_number < 65
*Search\LastDiscrepancy = last_zero
If *Search\LastDiscrepancy = 0
*Search\Done = #True
EndIf
CopyMemory(@*Search\Search[0], *Sensor, 8)
Result=#True
EndIf
EndIf
EndIf
Else
tLastErr=#OW_Err_NoData
EndIf
ProcedureReturn Result
EndProcedure
;-Public
Procedure OW_GetMode()
ProcedureReturn gModuleMode
EndProcedure
Procedure OW_SetMode(Mode)
CompilerIf #PB_Compiler_OS = #PB_OS_Linux Or #PB_Compiler_OS = #PB_OS_MacOS
gModuleModeLin=gModuleMode
CompilerEndIf
gModuleMode = Mode
EndProcedure
Procedure OW_GetPortDefID()
ProcedureReturn gCurrent_ComPort_ID
EndProcedure
Procedure OW_GetLastError()
ProcedureReturn tLastErr
EndProcedure
Procedure OW_SetLastError(ErrCode)
tLastErr = ErrCode
EndProcedure
Procedure OW_ClosePort(Port=#OW_PortOnly)
Protected Result = #False, OldPort
OldPort=Port
TestPortID(Port)
If IsSerialPort(Port)
If gModuleMode & #OW_Mode_NoControlPin = 0
If gModuleMode & #OW_Mode_Invert = 0
SetSerialPortStatus(Port, #PB_SerialPort_DTR, 0)
SetSerialPortStatus(Port, #PB_SerialPort_RTS, 0)
Else
SetSerialPortStatus(Port, #PB_SerialPort_DTR, 1)
SetSerialPortStatus(Port, #PB_SerialPort_RTS, 1)
EndIf
EndIf
CloseSerialPort(Port)
If OldPort=#OW_PortOnly
gCurrent_ComPort_ID=-2
EndIf
Result = #True
tLastErr = #OW_Err_OK
Else
tLastErr = #OW_Err_Port
EndIf
ProcedureReturn Result
EndProcedure
Procedure OW_OpenPort(ComPort.s, Port=#OW_PortOnly)
Protected ID=0, PortID=-2
If Port>=0 And Port<1000
OW_ClosePort(Port)
PortID=Port
ElseIf Port=#OW_PortOnly
OW_ClosePort(Port)
PortID=#PB_Any
ElseIf Port=#PB_Any
PortID=#PB_Any
Else
tLastErr=#OW_Err_BadParam ; Неправильный идентификатор порта
ProcedureReturn 0
EndIf
ID = OpenSerialPort(PortID, ComPort, 115200, #PB_SerialPort_NoParity,
8, 1, #PB_SerialPort_NoHandshake, 255, 255)
If ID
If Port<0
If Port=#OW_PortOnly
gCurrent_ComPort_ID = ID
EndIf
Port=ID
EndIf
If gModuleMode & #OW_Mode_NoControlPin = 0
If gModuleMode & #OW_Mode_Invert = 0
SetSerialPortStatus(Port, #PB_SerialPort_DTR, 1)
SetSerialPortStatus(Port, #PB_SerialPort_RTS, 1)
Else
SetSerialPortStatus(Port, #PB_SerialPort_DTR, 0)
SetSerialPortStatus(Port, #PB_SerialPort_RTS, 0)
EndIf
Delay(20)
EndIf
;SerialPortTimeouts(Port, 10, 10, 2, 2, 10)
OW_ByteRW($FF, Port)
ClearInBuf(Port)
tLastErr = #OW_Err_OK
Else
tLastErr=#OW_Err_Port
EndIf
ProcedureReturn ID
EndProcedure
Procedure OW_PortID(Port=#OW_PortOnly)
Protected ID=0
Port=TestPort(Port)
If tLastErr = #OW_Err_OK
ID = SerialPortID(Port)
EndIf
ProcedureReturn ID
EndProcedure
Procedure OW_Reset(Port=#OW_PortOnly) ; Подаём команду "Сброс" датчику температуры.
Protected x.l, Result=#False
Port=TestPort(Port)
If tLastErr = #OW_Err_OK
If SetBaudRate(Port, 9600)
ClearInBuf(Port)
x=$F0
If WriteSerialPortData(Port, @x, 1)=1
x = ElapsedMilliseconds()
Repeat
Delay(2)
Until AvailableSerialPortInput(Port)>0 Or Int(ElapsedMilliseconds()-x)>=32
If AvailableSerialPortInput(Port)=1
x=0
If ReadSerialPortData(Port, @x, 1) = 1
Result=Bool(x<>$F0)
If Result=#False : tLastErr=#OW_Err_NoDevice : EndIf
Else
Goto M1:
EndIf
Else
M1:
tLastErr=#OW_Err_IO
ClearInBuf(Port)
EndIf
Else
tLastErr=#OW_Err_IO
EndIf
SetBaudRate(Port, 115200)
EndIf
EndIf
ProcedureReturn Result
EndProcedure
Procedure.a OW_ByteRW(Byte.a=$FF, Port=#OW_PortOnly)
Protected Result.a, x.a, i
Port=TestPort(Port)
If tLastErr=#OW_Err_OK
For i= 1 To 8
WriteBit(Odd(Byte), Port, #wbf_WaitByte)
Byte>>1
x=ReadBit(Port, 0)
If tLastErr=#OW_Err_OK
Result>>1
Result|(x<<7)
Else
Result = $FF
Break
EndIf
Next i
EndIf
ProcedureReturn Result
EndProcedure
Procedure OW_ReadMultiByte(*Buff.OW_Buff, Count, Port=#OW_PortOnly) ; Чтение массива байт.
Protected Result=#False, Time, WaitTime
Protected RealCount, i, x, Byte.a, Pos, *Mem.OW_Buff
If *Buff And Count>0 And Count<1000000
Port=TestPort(Port)
If tLastErr=#OW_Err_OK
RealCount=Count*8
WaitTime=36+(Count*2)
Time = ElapsedMilliseconds()
*Mem=AllocateMemory(RealCount+2, #PB_Memory_NoClear)
If *Mem
FillMemory(*Mem, RealCount, $FF, #PB_Ascii)
If WriteSerialPortData(Port, *Mem, RealCount)=RealCount
Repeat
If gModuleMode & #OW_Mode_CPU_MinUsage : Delay(2) : EndIf
Until Int(ElapsedMilliseconds()-Time)>=WaitTime Or AvailableSerialPortInput(Port)>=RealCount
If AvailableSerialPortInput(Port)=RealCount
FillMemory(*Mem, RealCount, 0, #PB_Ascii)
If ReadSerialPortData(Port, *Mem, RealCount) = RealCount
Pos=0
For i=0 To Count-1
Byte=0
For x=0 To 7
Byte>>1
Byte | (Bool(*Mem\Byte[Pos]=$FF)<<7)
Pos+1
Next x
*Buff\Byte[i]=Byte :
Next i
Result=#True
Else
tLastErr=#OW_Err_IO
EndIf
Else
ClearInBuf(Port)
tLastErr=#OW_Err_IO
EndIf
Else
tLastErr=#OW_Err_IO
EndIf
FreeMemory(*Mem)
Else
tLastErr=#OW_Err_BadParam
EndIf
Else
tLastErr=#OW_Err_Port
EndIf
Else
tLastErr=#OW_Err_BadParam
EndIf
ProcedureReturn Result
EndProcedure
Procedure OW_WriteMultiByte(*Buff.OW_Buff, Count, Port=#OW_PortOnly) ; Запись массива байт.
Protected Result=#False, i, x, Byte.a, RealCount
Protected Pos, *Mem.OW_Buff
If (*Buff And Count>0 And Count<1000000) Or (*Buff=0 And Count=1)
Port=TestPort(Port)
If tLastErr=#OW_Err_OK
RealCount=Count*8
*Mem=AllocateMemory(RealCount+2, #PB_Memory_NoClear)
If *Mem
Pos=0
For x=0 To Count-1
If Count=1 And *Buff&~$FF=0
Byte=*Buff
Else
Byte=*Buff\Byte[x]
EndIf
For i=1 To 8
*Mem\Byte[Pos]=Odd(Byte)*$FF
Pos+1
Byte>>1
Next i
Next x
If WriteSerialPortData(Port, *Mem, RealCount)=RealCount
x=36+(Count*2)
i = ElapsedMilliseconds()
Repeat
If gModuleMode & #OW_Mode_CPU_MinUsage : Delay(2) : EndIf
Until Int(ElapsedMilliseconds()-i)>=x Or AvailableSerialPortInput(Port)>=RealCount
If AvailableSerialPortInput(Port)=RealCount
If ReadSerialPortData(Port, *Mem, RealCount) = RealCount
Result=#True
Else
tLastErr=#OW_Err_IO
EndIf
Else
ClearInBuf(Port)
tLastErr=#OW_Err_IO
EndIf
Else
ClearInBuf(Port)
tLastErr=#OW_Err_IO
EndIf
FreeMemory(*Mem)
Else
tLastErr=#OW_Err_BadParam
EndIf
EndIf
Else
tLastErr=#OW_Err_BadParam
EndIf
ProcedureReturn Result
EndProcedure
Procedure.a OW_GetCRC(*Buff.OW_Buff, Count)
Protected CRC.a, Byte.a, i, x
If *Buff And Count>0
tLastErr=#OW_Err_OK
Count-1
For i=0 To Count
Byte=*Buff\Byte[i]
For x=1 To 8
If (Byte ! CRC) & 1
CRC = ((CRC!$18)>>1)|$80
Else
CRC >> 1
EndIf
Byte>>1
Next x
Next i
Else
tLastErr=#OW_Err_BadParam
EndIf
ProcedureReturn CRC
EndProcedure
; Датчик передает 8-битный код семейства (10h для DS18S20 и 28h для DS18B20),
; затем 48-битный серийный номер, а затем 8-битную CRC для проверки правильности принятой информации.
Procedure OW_ReadROM(*Info.OW_Buff, Port=#OW_PortOnly)
Protected i, Result=#False
Port=TestPort(Port)
If tLastErr=#OW_Err_OK
If *Info
If OW_Reset(Port)
If OW_WriteMultiByte($33, 1, Port)
If OW_ReadMultiByte(@*Info\Byte[0], 8, Port)
Result=#True
EndIf
EndIf
EndIf
Else
tLastErr=#OW_Err_BadParam
EndIf
EndIf
ProcedureReturn Result
EndProcedure
; Эта процедура позволяет адресовать на шине конкретный датчик температуры.
; Необходимо передать 64-битный код датчика (считанный процедурой OW_ReadROM()),
; и только тот, который имеет такой код, будет «откликаться» до следующего импульса сброса.
Procedure OW_SelectROM(*Info.OW_Buff, Port=#OW_PortOnly)
Protected i, Result=#False
Port=TestPort(Port)
If tLastErr=#OW_Err_OK
If *Info
If OW_Reset(Port)
If OW_WriteMultiByte($55, 1, Port)
If OW_WriteMultiByte(*Info, 8, Port)
Result=#True
EndIf
EndIf
EndIf
Else
tLastErr=#OW_Err_BadParam
EndIf
EndIf
ProcedureReturn Result
EndProcedure
; Вызов процедуры позволит пропустить процедуру сравнения серийного номера
; и тем самым сэкономить время в системах, где на шине имеется всего одно устройство.
Procedure OW_SkipROM(Port=#OW_PortOnly)
Protected Result=#False
Port=TestPort(Port)
If tLastErr=#OW_Err_OK
If OW_Reset(Port)
If OW_WriteMultiByte($CC, 1, Port)
Result=#True
EndIf
EndIf
EndIf
ProcedureReturn Result
EndProcedure
Procedure OW_SearchROM_Reset()
tLastErr=#OW_Err_OK
FillMemory(@tSearchROM, SizeOf(sSearch))
ProcedureReturn #True
EndProcedure
Procedure OW_SearchROM_Enum(*Sensor.OW_SN, Port=#OW_PortOnly)
Protected Result=#False
If *Sensor
Port=TestPort(Port)
If tLastErr=#OW_Err_OK
Result=SearchDevice(*Sensor, @tSearchROM, Port, $F0)
EndIf
Else
tLastErr=#OW_Err_BadParam
EndIf
ProcedureReturn Result
EndProcedure
Procedure OW_SearchAlarm_Reset()
tLastErr=#OW_Err_OK
FillMemory(@tSearchAlarm, SizeOf(sSearch))
ProcedureReturn #True
EndProcedure
Procedure OW_SearchAlarm_Enum(*Sensor.OW_SN, Port=#OW_PortOnly)
Protected Result=#False
If *Sensor
Port=TestPort(Port)
If tLastErr=#OW_Err_OK
Result=SearchDevice(*Sensor, @tSearchAlarm, Port, $EC)
EndIf
Else
tLastErr=#OW_Err_BadParam
EndIf
ProcedureReturn Result
EndProcedure
; Чтение данных из промежуточного ОЗУ датчика.
Procedure OW_ReadRAM(*Info.OW_Buff, Port=#OW_PortOnly)
Protected i, Result=#False
Port=TestPort(Port)
If tLastErr=#OW_Err_OK
If *Info
If OW_WriteMultiByte($BE, 1, Port)
If OW_ReadMultiByte(*Info, 9, Port) : Result=#True : EndIf
EndIf
Else
tLastErr=#OW_Err_BadParam
EndIf
EndIf
ProcedureReturn Result
EndProcedure
; Запись данных в промежуточное ОЗУ датчика
Procedure OW_WriteRAM(*Info.OW_Buff, Port=#OW_PortOnly)
Protected i, Result=#False
Port=TestPort(Port)
If tLastErr=#OW_Err_OK
If *Info
If OW_WriteMultiByte($4E, 1, Port)
For i=0 To 2
OW_ByteRW(*Info\Byte[i], Port)
If tLastErr<>#OW_Err_OK : Break : EndIf
Next
If tLastErr=#OW_Err_OK : Result=#True : EndIf
EndIf
Else
tLastErr=#OW_Err_BadParam
EndIf
EndIf
ProcedureReturn Result
EndProcedure
; Копирование данных из промежуточного ОЗУ в энергонезависимую память датчика.
; Это требует около 10мс.
Procedure OW_CopyRAM(Port=#OW_PortOnly)
Protected Result=#False
Port=TestPort(Port)
If tLastErr=#OW_Err_OK
If OW_WriteMultiByte($48, 1, Port)
Delay(20)
Result=#True
EndIf
EndIf
ProcedureReturn Result
EndProcedure
; Запуск процесса преобразования температуры.
Procedure OW_ConvertT(Wait=0, Port=#OW_PortOnly)
Protected Result=#False
Port=TestPort(Port)
If tLastErr=#OW_Err_OK
If OW_WriteMultiByte($44, 1, Port)
Result=#True
If Wait>0
Delay(Wait)
EndIf
EndIf
EndIf
ProcedureReturn Result
EndProcedure
; Эта процедура действует обратным образом по отношению к процедуре OW_CopyRAM(),
; т.е. она позволяет считать байты TH и TL из энергонезависимой памяти в промежуточное ОЗУ.
Procedure OW_Recall(Port=#OW_PortOnly)
Protected Result=#False
Port=TestPort(Port)
If tLastErr=#OW_Err_OK
If OW_WriteMultiByte($B8, 1, Port) : Result=#True : EndIf
EndIf
ProcedureReturn Result
EndProcedure
; Проверка, использует ли 1-Wire устройство "паразитное" питание.
Procedure OW_ReadPowerSupply(Port=#OW_PortOnly)
Protected Result=#False
Port=TestPort(Port)
If tLastErr=#OW_Err_OK
If OW_WriteMultiByte($B4, 1, Port)
Result=ReadBit(Port)
EndIf
EndIf
ProcedureReturn Result
EndProcedure
EndModule
Code: Select all
XIncludeFile "OWire_Module.pbi"
UseModule OWire
CompilerIf #PB_Compiler_Thread = 0
CompilerError "Please enable thread-safe"
CompilerEndIf
EnableExplicit
Enumeration Window
#WinMain
EndEnumeration
Enumeration Menu
#Menu_Main
EndEnumeration
Enumeration Gadget
#ComboPort
#SpinThermoInterval
#CheckThermoControl
#ContainerThermoControl
#SpinThermoMin
#SpinThermoMax
#Table
EndEnumeration
Enumeration
#MItem_Log
#MItem_Exit
#MItem_Mode_CPU_MinUsage
#MItem_Mode_Invert
#MItem_ConvertOnly
#MItem_Shem
#MItem_About
EndEnumeration
Enumeration StatusBar
#StatusBar_Main
EndEnumeration
Enumeration
#StatusBar_Main_Status
EndEnumeration
Enumeration
#Table_Type
#Table_SN
#Table_Power
#Table_Thermo
#Table_Status
EndEnumeration
Enumeration Image
#ImageShem
EndEnumeration
Enumeration File
#LogFileID
EndEnumeration
#Table_Color_Err = $8888FD
#Table_Color_Warn = $ABF9FF
#DI_ErrFlag_CRC_ROM = 1
#DI_ErrFlag_CRC_RAM = 1<<1
#DI_ErrFlag_Thermo = 1<<2
#DI_ErrFlag_OW = 1<<3
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
#PortName = "COM"
CompilerElse
#PortName = "/dev/ttyS"
CompilerEndIf
Structure ThreadParam
BreakTh.a ; Если #True, то нужно завершить работу потока.
PortChange.a ; Если #True, то выбран другой порт.
ThermoControl.a
ConvertOnly.a
ThermoInterval.u ; Интервал в секундах опроса датчиков.
ThermoMin.w
ThermoMax.w
Log.a
EndStructure
Structure DevicesInfo
SN.OW_SN
Thermo.f
ErrFlag.a
EndStructure
Define Thread_OW_ID, Event, Window, x
Global gOW_Thread.ThreadParam
gOW_Thread\BreakTh = #False
gOW_Thread\PortChange = #True
Procedure.s GetLastErrorString(Err)
Protected String.s
Select Err
Case #OW_Err_OK : String = "Нет ошибок"
Case #OW_Err_Port : String = "Нет открытого COM порта"
Case #OW_Err_NoDevice : String = "Нет ответа от '1-Wire' устройств"
Case #OW_Err_IO : String = "Ошибка обмена данными"
Case #OW_Err_BaudRate : String = "Ошибка изменения скорости порта"
Case #OW_Err_Search : String = "Ошибка при поиске '1-Wire' устройств"
Case #OW_Err_BadParam : String = "Ошибка в аргументе функции"
Case #OW_Err_NoData : String = "Нет данных"
EndSelect
ProcedureReturn String
EndProcedure
Procedure WriteLog(String.s)
If IsFile(#LogFileID)=0
If OpenFile(#LogFileID, "DS18B20_ThermoMon.log")
If Lof(#LogFileID)<=0
WriteStringFormat(#LogFileID, #PB_UTF8)
Else
FileSeek(#LogFileID, Lof(#LogFileID))
EndIf
Goto _next
EndIf
Else
_next:
If String<>""
ReplaceString(String, Chr($a), " ", #PB_String_InPlace)
ReplaceString(String, Chr($d), " ", #PB_String_InPlace)
String = FormatDate("[%dd/%mm/%yyyy %hh:%ii:%ss] ", Date())+ String
EndIf
WriteStringN(#LogFileID, String, #PB_UTF8)
FlushFileBuffers(#LogFileID)
EndIf
EndProcedure
Procedure.s wordform(num.i, form_one.s, form_two.s, form_three.s)
num % 100
Protected num_two.i = num % 10
If num > 10 And num < 20
ProcedureReturn form_three
EndIf
If num_two > 1 And num_two < 5
ProcedureReturn form_two
EndIf
If num_two = 1
ProcedureReturn form_one
EndIf
ProcedureReturn form_three
EndProcedure
Procedure.s SN_Text(*x.OW_SN)
Protected String.s, i
String = RSet(Hex(*x\Type), 2, "0")+"-"
For i=5 To 0 Step -1
String + RSet(Hex(*x\Number[i]), 2, "0")
Next i
String + "-"+RSet(Hex(*x\CRC), 2, "0")
ProcedureReturn String
EndProcedure
Procedure UpdateTableAll(List Devices.DevicesInfo())
Protected String.s, i=0, Err
ClearGadgetItems(#Table)
ForEach Devices()
Select Devices()\SN\Type
Case $10
String="DS1820 / DS18S20"
Case $28
String="DS18B20"
Default
String="Неизвестное устройство"
EndSelect
Err=#False
;Devices()\SN\crc+2
String + Chr(10)+SN_Text(@Devices()\SN)
If OW_GetCRC(Devices()\SN, 7) <> Devices()\SN\CRC
String+" ОШИБКА CRC" : Err=#True
Devices()\ErrFlag | #DI_ErrFlag_CRC_ROM
EndIf
String+Chr(10)
If OW_SelectROM(Devices()\SN)
If OW_ReadPowerSupply()
String+"3 вывода"
Else
String+"2 вывода ('паразитное' питание)"
EndIf
Else
String+"Ошибка"
EndIf
If Devices()\SN\Type=$10 Or Devices()\SN\Type=$28
String+Chr(10)+"Измерение"+Chr(10)+"Инициализация"
EndIf
AddGadgetItem(#Table, i, String)
If Err=#True
SetGadgetItemColor(#Table, i, #PB_Gadget_BackColor, #Table_Color_Err, #Table_SN)
EndIf
i+1
Next
EndProcedure
Procedure SearchSensor(List Devices.DevicesInfo(), Port.s)
Protected Sensor.OW_SN, x=0
StatusBarText(#StatusBar_Main, #StatusBar_Main_Status, "Поиск '1-Wire' устройств...")
If ListSize(Devices())>0
ClearList(Devices())
EndIf
OW_SearchROM_Reset()
While OW_SearchROM_Enum(@Sensor)=#True
x+1
If AddElement(Devices())
CopyStructure(@Sensor, @Devices()\SN, OW_SN)
EndIf
Wend
If x>0
UpdateTableAll(Devices())
StatusBarText(#StatusBar_Main, #StatusBar_Main_Status,
"Найдено "+x+" '1-Wire' "+wordform(x, "устройство", " устройства", " устройств")+".")
Else
ClearGadgetItems(#Table)
StatusBarText(#StatusBar_Main, #StatusBar_Main_Status,
"На порту "+Port+", '1-Wire' устройства не найдены.")
EndIf
EndProcedure
Procedure SelectPort(List Devices.DevicesInfo())
Protected Port.s
Port = GetGadgetText(#ComboPort)
OW_ClosePort()
If Port<>""
If OW_OpenPort(Port)
StatusBarText(#StatusBar_Main, #StatusBar_Main_Status, "Порт открыт")
Else
StatusBarText(#StatusBar_Main, #StatusBar_Main_Status,
"Не удалось открыть порт '"+Port+
"' Возможно он зянят или отстуствует в системе")
EndIf
EndIf
ClearList(Devices())
If OW_GetLastError() = #OW_Err_OK ; Ошибок нет.
SearchSensor(Devices(), Port)
EndIf
EndProcedure
Procedure Thread_OW(*Bool)
Protected NewList Devices.DevicesInfo()
Protected String.s, Count, i, Err, OldPos, z
Protected x.w, Thermo.f, RAM.OW_RAM
Protected CountErr, OldCountErr
Protected WarnCount, OldWarnCount
Repeat
Delay(100)
If gOW_Thread\PortChange
SelectPort(Devices())
Count = ListSize(Devices())
If Count>0
ResetList(Devices())
i=0
OldPos=0
EndIf
gOW_Thread\PortChange = #False
EndIf
If Count>0
Repeat
If NextElement(Devices())=0
i=0
If gOW_Thread\ConvertOnly=0 ; Раздельный опрос отключен
ResetList(Devices())
Break
Else ; Раздельный опрос включен
If FirstElement(Devices())=0
Break
EndIf
EndIf
EndIf
If gOW_Thread\ConvertOnly=0 ; Раздельный опрос отключен
If i=0
If OW_SkipROM()=#False
String = GetLastErrorString(OW_GetLastError())
StatusBarText(#StatusBar_Main, #StatusBar_Main_Status, String)
Err=#True
Goto M1
EndIf
EndIf
Else ; Раздельный опрос включен
If OW_SelectROM(@Devices()\SN)=#False
String = GetLastErrorString(OW_GetLastError())
StatusBarText(#StatusBar_Main, #StatusBar_Main_Status, String)
Err=#True
Goto M1
EndIf
EndIf
If i=0 Or gOW_Thread\ConvertOnly
If OW_ConvertT()=#False
String = GetLastErrorString(OW_GetLastError())
StatusBarText(#StatusBar_Main, #StatusBar_Main_Status, String)
Err=#True
Goto M1
EndIf
CountErr=0
WarnCount=0
For z=1 To 8 ; Ждем окончания измерения температуры.
Delay(100)
If gOW_Thread\PortChange
Break
ElseIf gOW_Thread\BreakTh
Break 2
EndIf
Next z
EndIf
If Devices()\SN\Type = $10 Or ; DS1820 / DS18S20
Devices()\SN\Type = $28 ; DS18B20
If OW_SelectROM(@Devices()\SN)
If OW_ReadRAM(@RAM)
x=(RAM\H_Termo<<8)|RAM\L_Termo
If Devices()\SN\Type = $28 ; DS18B20
Thermo=x/16
Else
Thermo=x/2
EndIf
Devices()\Thermo = Thermo
SetGadgetItemText(#Table, i, StrF(Thermo, 1)+" °C", #Table_Thermo)
If gOW_Thread\Log
WriteLog(SN_Text(@Devices()\SN)+" — "+StrF(Thermo, 1)+" °C")
EndIf
If Thermo<-55 Or Thermo>127
Devices()\ErrFlag | #DI_ErrFlag_Thermo
SetGadgetItemColor(#Table, i, #PB_Gadget_BackColor, #Table_Color_Warn, #Table_Thermo)
Else
Devices()\ErrFlag & ~#DI_ErrFlag_Thermo
x/16
If gOW_Thread\ThermoControl=0 Or
(gOW_Thread\ThermoMin<=x And x<=gOW_Thread\ThermoMax)
SetGadgetItemColor(#Table, i, #PB_Gadget_BackColor, -1, #Table_Thermo)
Else
WarnCount+1
SetGadgetItemColor(#Table, i, #PB_Gadget_BackColor, #Table_Color_Warn, #Table_Thermo)
EndIf
EndIf
If OW_GetCRC(@RAM, 8)=RAM\CRC
Devices()\ErrFlag & ~#DI_ErrFlag_CRC_RAM
SetGadgetItemText(#Table, i, "OK", #Table_Status)
SetGadgetItemColor(#Table, i, #PB_Gadget_BackColor, -1, #Table_Status)
Else
Devices()\ErrFlag | #DI_ErrFlag_CRC_RAM
SetGadgetItemText(#Table, i, "Ошибка CRC", #Table_Status)
SetGadgetItemColor(#Table, i, #PB_Gadget_BackColor, #Table_Color_Err, #Table_Status)
EndIf
EndIf
EndIf
If OW_GetLastError()<>#OW_Err_OK
Devices()\ErrFlag | #DI_ErrFlag_OW
SetGadgetItemText(#Table, i, GetLastErrorString(OW_GetLastError()), #Table_Status)
SetGadgetItemColor(#Table, i, #PB_Gadget_BackColor, #Table_Color_Err, #Table_Status)
ElseIf Devices()\ErrFlag & #DI_ErrFlag_CRC_RAM = 0
Devices()\ErrFlag & ~#DI_ErrFlag_OW
SetGadgetItemColor(#Table, i, #PB_Gadget_BackColor, -1, #Table_Status)
EndIf
Else
Continue
EndIf
If Devices()\ErrFlag
CountErr+1
If Devices()\ErrFlag & ~#DI_ErrFlag_CRC_ROM = 0
SetGadgetItemText(#Table, i, "", #Table_Thermo)
EndIf
EndIf
If gOW_Thread\ConvertOnly ; Раздельный опрос включен
SetGadgetItemColor(#table, OldPos, #PB_Gadget_BackColor, -1, #Table_Type)
SetGadgetItemColor(#table, i, #PB_Gadget_BackColor, RGB(128, 255, 128), #Table_Type)
EndIf
OldPos=i
i+1
If gOW_Thread\ConvertOnly ; Раздельный опрос включен
Break
EndIf
ForEver
If Err=#True Or CountErr<>OldCountErr Or OldWarnCount<>WarnCount
If CountErr>0
String=". "+wordform(CountErr, "Обнаружен ", "Обнаружено ", "Обнаружены ")+
CountErr+wordform(CountErr, " датчик", " датчика", " датчиков")+
" с ошибками в работе"
Else
String="."
EndIf
If WarnCount>0
String+" В "+WarnCount+wordform(WarnCount, " датчике", " датчиках", " датчиках")+
" зафиксирован выход за пределы допустимой температуры"
EndIf
StatusBarText(#StatusBar_Main, #StatusBar_Main_Status,
"Найдено "+Count+" '1-Wire' "+
wordform(Count, "устройство", " устройства", " устройств")+String)
Err=#False
OldCountErr = CountErr
OldWarnCount=WarnCount
EndIf
If gOW_Thread\ThermoInterval>1
For z=1 To gOW_Thread\ThermoInterval-1
For x=1 To 10
Delay(100)
If gOW_Thread\PortChange Or gOW_Thread\BreakTh
Break 2
EndIf
Next x
Next z
EndIf
Else
M1:
If WarnCount<>-1
x=CountGadgetItems(#Table)-1
For i=0 To x
SetGadgetItemText(#Table, i, "", #Table_Thermo)
SetGadgetItemText(#Table, i, String, #Table_Status)
SetGadgetItemColor(#Table, i, #PB_Gadget_BackColor, -1, #Table_Thermo)
SetGadgetItemColor(#Table, i, #PB_Gadget_BackColor, #Table_Color_Err, #Table_Status)
Next
WarnCount=-1
EndIf
CountErr+1
If CountErr>=10
Count=0
If OW_Reset()
SearchSensor(Devices(), GetGadgetText(#ComboPort))
Count = ListSize(Devices())
EndIf
CountErr=0
EndIf
EndIf
Until gOW_Thread\BreakTh
EndProcedure
Procedure EnumPorts(Gadget)
Protected i, ID
ClearGadgetItems(Gadget)
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
AddGadgetItem(Gadget, -1, "/dev/tty.usbserial")
CompilerElse
For i=0 To 10
ID = OpenSerialPort(#PB_Any, #PortName+i, 9600, #PB_SerialPort_NoParity,
8, 1, #PB_SerialPort_NoHandshake, 255, 255)
If ID
AddGadgetItem(Gadget, -1, #PortName+i)
CloseSerialPort(ID)
EndIf
Next
CompilerEndIf
EndProcedure
Procedure OpenWinMain()
Protected x
CompilerIf #PB_Compiler_OS = #PB_OS_Linux
SetGadgetFont(#PB_Default, FontID(LoadFont(#PB_Any,"Liberation Mono",10)))
CompilerEndIf
OpenWindow(#WinMain, 0, 0, 590, 400, "DS18B20 термо-мониторинг v1.1",
#PB_Window_MinimizeGadget|#PB_Window_Invisible|#PB_Window_ScreenCentered)
CreateMenu(#Menu_Main, WindowID(#WinMain))
MenuTitle("Файл")
MenuItem(#MItem_Log, "Записывать в лог-файл")
MenuBar()
MenuItem(#MItem_Exit, "Выход")
MenuTitle("Режим")
MenuItem(#MItem_Mode_CPU_MinUsage, "Снизить нагрузку на CPU")
MenuItem(#MItem_Mode_Invert, "Инвертировать DTR и RTS")
MenuItem(#MItem_ConvertOnly, "Раздельный опрос")
MenuTitle("Справка")
MenuItem(#MItem_About, "О программе")
x=TextGadget(#PB_Any, 4, 8, 100, 16, "Порт:")
ResizeGadget(x, #PB_Ignore, #PB_Ignore, GadgetWidth(x, #PB_Gadget_RequiredSize)+4, #PB_Ignore)
ComboBoxGadget(#ComboPort, GadgetX(x)+GadgetWidth(x), 4, 100, 22)
EnumPorts(#ComboPort)
x=TextGadget(#PB_Any, GadgetX(#ComboPort)+GadgetWidth(#ComboPort)+10, 8, 350, 16, "Интервал опроса:")
ResizeGadget(x, #PB_Ignore, #PB_Ignore, GadgetWidth(x, #PB_Gadget_RequiredSize)+4, #PB_Ignore)
SpinGadget(#SpinThermoInterval, GadgetX(x)+GadgetWidth(x), 4, 50, 22, 1, 60,
#PB_Spin_ReadOnly|#PB_Spin_Numeric)
GadgetToolTip(#SpinThermoInterval, "Интервал в секундах опроса датчиков")
CheckBoxGadget(#CheckThermoControl, GadgetX(#SpinThermoInterval)+GadgetWidth(#SpinThermoInterval)+16,
8, 100, 16, "Термо контроль")
ResizeGadget(#CheckThermoControl, #PB_Ignore, #PB_Ignore,
GadgetWidth(#CheckThermoControl, #PB_Gadget_RequiredSize)+2, #PB_Ignore)
; CheckBoxGadget(#CheckConvertOnly, GadgetX(#CheckThermoControl),
; GadgetY(#CheckThermoControl)+GadgetHeight(#CheckThermoControl)+2, 100, 16, )
; ResizeGadget(#CheckConvertOnly, #PB_Ignore, #PB_Ignore,
; GadgetWidth(#CheckConvertOnly, #PB_Gadget_RequiredSize)+2, #PB_Ignore)
; GadgetToolTip(#CheckConvertOnly, "Опрос датчиков по одному. Необходимо для работы с множеством датчиков с 'паразитным' питанием. Внимание! Скорость считывания уменьшается по мере увеличения количества датчиков")
ContainerGadget(#ContainerThermoControl, GadgetX(#CheckThermoControl)+GadgetWidth(#CheckThermoControl),
2, 200, 28, #PB_Container_Single)
x=TextGadget(#PB_Any, 4, 7, 350, 16, "Мин:")
ResizeGadget(x, #PB_Ignore, #PB_Ignore, GadgetWidth(x, #PB_Gadget_RequiredSize)+4, #PB_Ignore)
SpinGadget(#SpinThermoMin, GadgetX(x)+GadgetWidth(x), 2, 50, 22, -55, 125,
#PB_Spin_ReadOnly|#PB_Spin_Numeric)
GadgetToolTip(#SpinThermoMin, "Минимальная допустимая температура")
x=TextGadget(#PB_Any, GadgetX(#SpinThermoMin)+GadgetWidth(#SpinThermoMin)+10, 7, 350, 16, "Макс:")
ResizeGadget(x, #PB_Ignore, #PB_Ignore, GadgetWidth(x, #PB_Gadget_RequiredSize)+4, #PB_Ignore)
SpinGadget(#SpinThermoMax, GadgetX(x)+GadgetWidth(x), 2, 50, 22, -55, 125,
#PB_Spin_ReadOnly|#PB_Spin_Numeric)
GadgetToolTip(#SpinThermoMax, "Максимальная допустимая температура")
CloseGadgetList()
ResizeGadget(#ContainerThermoControl, #PB_Ignore, #PB_Ignore,
GadgetX(#SpinThermoMax)+GadgetWidth(#SpinThermoMax)+10, #PB_Ignore)
ResizeWindow(#WinMain, #PB_Ignore, #PB_Ignore,
GadgetX(#ContainerThermoControl)+GadgetWidth(#ContainerThermoControl)+2, #PB_Ignore)
x=ListIconGadget(#Table, 2, GadgetY(#ContainerThermoControl)+GadgetHeight(#ContainerThermoControl)+2,
WindowWidth(#WinMain)-4, 304, "Тип", 80,
#PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection)
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
SendMessage_(x, #LVM_SETEXTENDEDLISTVIEWSTYLE,
#LVS_EX_LABELTIP|#LVS_EX_GRIDLINES|#LVS_EX_DOUBLEBUFFER,
#LVS_EX_LABELTIP|#LVS_EX_GRIDLINES|#LVS_EX_DOUBLEBUFFER)
CompilerEndIf
AddGadgetColumn(#Table, #Table_SN, "Серийный номер", 150)
AddGadgetColumn(#Table, #Table_Power, "Подключение", 100)
AddGadgetColumn(#Table, #Table_Thermo, "Температура", 100)
AddGadgetColumn(#Table, #Table_Status, "Статус", 120)
CreateStatusBar(#StatusBar_Main, WindowID(#WinMain))
AddStatusBarField(#PB_Ignore)
ResizeGadget(#Table, #PB_Ignore, #PB_Ignore, #PB_Ignore,
WindowHeight(#WinMain)-StatusBarHeight(#StatusBar_Main)-GadgetY(#Table)-MenuHeight()-2)
HideWindow(#WinMain, #False)
EndProcedure
Procedure ReadSetting()
Protected String.s, x,Flag, p
x=OpenPreferences("ThermoMon.ini")
String=ReadPreferenceString("Port", "")
If String
SetGadgetText(#ComboPort, String)
Else
SetGadgetState(#ComboPort, -1)
EndIf
gOW_Thread\ThermoInterval = ReadPreferenceLong("Interval", 1)
If gOW_Thread\ThermoInterval<=0 Or gOW_Thread\ThermoInterval>100
gOW_Thread\ThermoInterval=1
EndIf
SetGadgetState(#SpinThermoInterval, gOW_Thread\ThermoInterval)
SetGadgetText(#SpinThermoInterval, Str(gOW_Thread\ThermoInterval))
gOW_Thread\ThermoControl = ReadPreferenceLong("ThermoControl", 0)&1
SetGadgetState(#CheckThermoControl, gOW_Thread\ThermoControl)
gOW_Thread\ConvertOnly = ReadPreferenceLong("ConvertOnly", 0)&1
SetMenuItemState(#Menu_Main, #MItem_ConvertOnly, gOW_Thread\ConvertOnly)
gOW_Thread\ThermoMin = ReadPreferenceLong("ThermoMin", 0)
gOW_Thread\ThermoMax = ReadPreferenceLong("ThermoMax", 10)
gOW_Thread\Log = ReadPreferenceLong("Log", 0)&1
SetMenuItemState(#Menu_Main, #MItem_Log, gOW_Thread\Log)
Flag = OW_GetMode()
p = ReadPreferenceLong("CPU_MinUsage", 0)&1
If p
Flag|#OW_Mode_CPU_MinUsage
EndIf
SetMenuItemState(#Menu_Main, #MItem_Mode_CPU_MinUsage, p)
p=ReadPreferenceLong("Invert", 0)
If p
Flag|#OW_Mode_Invert
EndIf
SetMenuItemState(#Menu_Main, #MItem_Mode_Invert, p)
OW_SetMode(Flag)
If gOW_Thread\ThermoMin<=-55 Or gOW_Thread\ThermoMin>130
gOW_Thread\ThermoMin=0
EndIf
If gOW_Thread\ThermoMax<=-55 Or gOW_Thread\ThermoMax>130
gOW_Thread\ThermoMax=10
EndIf
If gOW_Thread\ThermoMin>=gOW_Thread\ThermoMax
gOW_Thread\ThermoMin=gOW_Thread\ThermoMax-1
EndIf
SetGadgetState(#SpinThermoMin, gOW_Thread\ThermoMin)
SetGadgetText(#SpinThermoMin, Str(gOW_Thread\ThermoMin))
SetGadgetState(#SpinThermoMax, gOW_Thread\ThermoMax)
SetGadgetText(#SpinThermoMax, Str(gOW_Thread\ThermoMax))
PostEvent(#PB_Event_Gadget, #WinMain, #ComboPort, #PB_EventType_Change)
PostEvent(#PB_Event_Gadget, #WinMain, #CheckThermoControl)
If x
ClosePreferences()
EndIf
EndProcedure
Procedure WriteSetting()
If CreatePreferences("ThermoMon.ini")
WritePreferenceString("Port", GetGadgetText(#ComboPort))
WritePreferenceLong("Interval", GetGadgetState(#SpinThermoInterval))
WritePreferenceLong("ThermoControl", GetGadgetState(#CheckThermoControl))
WritePreferenceLong("ConvertOnly", GetMenuItemState(#Menu_Main, #MItem_ConvertOnly))
WritePreferenceLong("ThermoMin", GetGadgetState(#SpinThermoMin))
WritePreferenceLong("ThermoMax", GetGadgetState(#SpinThermoMax))
WritePreferenceLong("Log", gOW_Thread\Log)
WritePreferenceLong("CPU_MinUsage", GetMenuItemState(#Menu_Main, #MItem_Mode_CPU_MinUsage))
WritePreferenceLong("Invert", GetMenuItemState(#Menu_Main, #MItem_Mode_Invert))
ClosePreferences()
EndIf
EndProcedure
Procedure PortChange()
gOW_Thread\PortChange = #True
WriteSetting()
EndProcedure
SetCurrentDirectory(GetPathPart(ProgramFilename()))
OpenWinMain()
BindGadgetEvent(#ComboPort, @PortChange(), #PB_EventType_Change)
ReadSetting()
Thread_OW_ID=CreateThread(@Thread_OW(), 0)
Repeat
Event = WaitWindowEvent()
Window = EventWindow()
If Window = #WinMain
If Event = #PB_Event_Menu
Select EventMenu()
Case #MItem_Log
gOW_Thread\Log = GetMenuItemState(#Menu_Main, #MItem_Log)!1
SetMenuItemState(#Menu_Main, #MItem_Log, gOW_Thread\Log)
WriteSetting()
Case #MItem_Exit : Break
Case #MItem_Mode_CPU_MinUsage
x=GetMenuItemState(#Menu_Main, #MItem_Mode_CPU_MinUsage)!1
SetMenuItemState(#Menu_Main, #MItem_Mode_CPU_MinUsage, x)
If x
OW_SetMode(OW_GetMode()|#OW_Mode_CPU_MinUsage)
Else
OW_SetMode(OW_GetMode()&~#OW_Mode_CPU_MinUsage)
EndIf
Case #MItem_Mode_Invert
x=GetMenuItemState(#Menu_Main, #MItem_Mode_Invert)!1
SetMenuItemState(#Menu_Main, #MItem_Mode_Invert, x)
If x
OW_SetMode(OW_GetMode()|#OW_Mode_Invert)
Else
OW_SetMode(OW_GetMode()&~#OW_Mode_Invert)
EndIf
Case #MItem_ConvertOnly
x = GetMenuItemState(#Menu_Main, #MItem_ConvertOnly) ! 1
gOW_Thread\ConvertOnly = x
SetMenuItemState(#Menu_Main, #MItem_ConvertOnly, x)
If x=0
SetGadgetItemColor(#table, -1, #PB_Gadget_BackColor, -1, #Table_Type)
EndIf
Case #MItem_About
MessageRequester("О программе", "Мониторинг температуры с использованием DS18x20."+Chr(10)+
"E-Mail: pure-basic@yandex.ru")
EndSelect
ElseIf Event = #PB_Event_Gadget
Select EventGadget()
Case #SpinThermoInterval
gOW_Thread\ThermoInterval = GetGadgetState(#SpinThermoInterval)
WriteSetting()
Case #CheckThermoControl
gOW_Thread\ThermoControl = GetGadgetState(#CheckThermoControl)
WriteSetting()
Case #SpinThermoMin
x=GetGadgetState(#SpinThermoMin)
Select EventType()
Case #PB_EventType_Change
gOW_Thread\ThermoMin = x
WriteSetting()
Case #PB_EventType_Up
If x>=GetGadgetState(#SpinThermoMax)
x=GetGadgetState(#SpinThermoMax)-1
SetGadgetState(#SpinThermoMin, x)
SetGadgetText(#SpinThermoMin, Str(x))
EndIf
EndSelect
Case #SpinThermoMax
x=GetGadgetState(#SpinThermoMax)
Select EventType()
Case #PB_EventType_Change
gOW_Thread\ThermoMax = x
WriteSetting()
Case #PB_EventType_Down
If x=<GetGadgetState(#SpinThermoMin)
x=GetGadgetState(#SpinThermoMin)+1
SetGadgetState(#SpinThermoMax, x)
SetGadgetText(#SpinThermoMax, Str(x))
EndIf
EndSelect
EndSelect
EndIf
EndIf
Until Event = #PB_Event_CloseWindow And Window = #WinMain
gOW_Thread\BreakTh=#True
HideWindow(#WinMain, #True)
WriteSetting()
WaitThread(Thread_OW_ID, 400)
If IsThread(Thread_OW_ID)
KillThread(Thread_OW_ID)
EndIf
If IsFile(#LogFileID)
CloseFile(#LogFileID)
EndIf
End
Screenshot.
If you use a USB to COM adapter like this (chip PL2303).
scheme is very simple.