Bruno Deletre
Joined: 30 Mar 2009
Posts: 4
|
|
Posted: 04 April 2009, 9:56 AM Post subject: |
|
|
Don,
Forgive me for my last post. It was very early in the morning and I should have done my own reset first. It was actually a problem of reset and data collision. I finally managed to have up to 6 sensors in the same line, thank you.
I added the PEC calculation inspired from the forum and the MLX datasheet.
I post it in case somebody would search such a strange thing.
| Code: | '####################################################################################################################################
'####################################################################################################################################
'
' FUNCTIONS TO READ AND WRITE MLX90614 PARALLAX SENSORS SHARING THE SAME DATA LINE
'
'####################################################################################################################################
'####################################################################################################################################
Const PECERROR as single=-1000.0
Const MULTIPURPOSE_COM as Byte=3
Const MLX_count as integer =4
Const MLX_DATA_PIN as Byte = 8 '
Const MLX_RST_PIN as Byte= 7 '
Const MLX_COM_SPEED as long =9600
Dim MLX_Addresses(1 to 4) as Byte
Public MLX_Temp(1 to 4) as single
#define VERBOSE_DEBUG
#define INCLUDE_MLX_TEST_MAIN
'######################################################################################################################################
#ifdef INCLUDE_MLX_TEST_MAIN
Sub Main()
dim count as integer
dim cycles as long
dim temp as single
MLX_Addresses(1)=&H05
MLX_Addresses(2)=&H15
MLX_Addresses(3)=&H25
MLX_Addresses(4)=&H35
Call MLX_InitAtHighPower()
for cycles =1 to 1000
for count =1 to MLX_count
temp=MLX_Read(MLX_Addresses(count))
while temp=PECERROR
delay(0.01) 'Putting this delay at 0.05 enables to avoid almost any data collision with 6 sensors.
'In case it is too low, the PEC Check catches the error and resend the request
temp=MLX_Read(MLX_Addresses(count))
wend
MLX_Temp(count)=temp
Console.WriteLine( Cstr(cycles) & " -->MLX# " & Cstr(MLX_Addresses(count)) & " --> " & Cstr(MLX_Temp(count)) & "°C")
delay(1.0)
Next count
next cycles
End Sub
#endif
'######################################################################################################################################
Public Function MLX_Read(byval sensor_address as byte) as Single
' As the MLX shares RX and TX lines, the solution proposed by Donald KINZER is to permanently
' define and destroy software COM ports and set them alternatively in single TX or single RX
' Prepare the queue
Dim MLX_q(1 to 40) as Byte
Call OpenQueue(MLX_q)
Call Putpin(MLX_RST_PIN,zxOutputLow)
Call Putpin(MLX_RST_PIN,zxOutputHigh)
Call Putpin(MLX_RST_PIN,zxInputPullUp)
Delay(0.05)
' Prepare the channel for transmitting, send command
Call DefineCom(MULTIPURPOSE_COM, 0, MLX_DATA_PIN, &H08)
Call OpenCom(MULTIPURPOSE_COM, MLX_COM_SPEED, 0, MLX_q)
Call PutQueueStr(MLX_q, Chr(0) & "!TEMR" & Chr(sensor_address) & Chr(&H07))
' wait until the data is transmitted
Do While CBool(StatusCom(MULTIPURPOSE_COM) And &H04)
Loop
' Reconfigure the channel for receiving
Call CloseCom(MULTIPURPOSE_COM, 0, 0)
Call DefineCom(MULTIPURPOSE_COM, MLX_DATA_PIN, 0, &H08)
Call OpenCom(MULTIPURPOSE_COM, MLX_COM_SPEED, MLX_q, 0)
' Wait for data to arrive
Do While (GetQueueCount(MLX_q) < 3) ' Waiting for tempLow,tempHigh and PEC Values Loop ' Extract the returned value from the queue Dim Temp as UnsignedInteger dim PEC as byte dim OK as boolean Call GetQueue(MLX_q, Temp, SizeOf(Temp)) Call GetQueue(MLX_q, PEC, SizeOf(PEC)) 'PEC Check OK = Check_RW_PEC(sensor_address, &H07,Temp, PEC) if OK=True then MLX_Read = (Csng(Temp) *0.02)-273.0 else MLX_Read = PECERROR end if ' Close the channel Call CloseCom(MULTIPURPOSE_COM, 0, 0) #ifdef VERBOSE_DEBUG Debug.print "MLX_Read("; Cstr(sensor_address) ; ")" #endif End Function '###################################################################################################################################### Public sub MLX_InitAtHighPower() dim count as integer #ifdef VERBOSE_DEBUG Debug.print "MLX_InitAtHighPower()" #endif 'Initialise the bus Call Putpin(MLX_RST_PIN,zxOutputLow) Call Putpin(MLX_RST_PIN,zxOutputHigh) Call Putpin(MLX_RST_PIN,zxInputPullUp) Delay(0.05) 'set all sensors at low power continuous reading without output for count =1 to MLX_count call MLXSendCmd("!TEMC",MLX_Addresses(count),&H07) Next count end sub '###################################################################################################################################### Public sub MLX_InitAtLowPower() dim count as integer #ifdef VERBOSE_DEBUG Debug.print "MLX_InitAtLowPower()" #endif 'Initialise the bus Call Putpin(MLX_RST_PIN,zxOutputLow) Call Putpin(MLX_RST_PIN,zxOutputHigh) Call Putpin(MLX_RST_PIN,zxInputPullUp) Delay(0.05) 'set all sensors at low power continuous reading without output for count =1 to MLX_count call MLXSendCmd("!TEMZ",MLX_Addresses(count),&H07) Next count end sub '###################################################################################################################################### Public Sub MLXSendCmd(byval CMD as string,byval sensor_address as byte, byval Lowbyte as byte=0, byval Highbyte as byte=0) 'Set Sensor reading intervals [0,"!TEMI",slaveaddr,intervalnonsleep,intervalsleep] 'Set Sensor alarm level [0,"!TEMA",slaveaddr,alarmlowbyte,alarmhighbyte] 'Set sensor for continuous data reading at low power [0,"!TEMZ",slaveaddr,$07] 'Set sensor for continuous data reading at low power & output [0,"!TEMz",slaveaddr,$07] Needs to be followed by data reception 'Set sensor for continuous data reading [0,"!TEMC",slaveaddr,$07] 'Set sensor for continuous data reading & output [0,"!TEMc",slaveaddr,$07] Needs to be followed by data reception 'Stop continuous reading mode [0,"!TEMS",slaveaddr] ' Prepare the queue Dim MLX_q(1 to 40) as Byte Call OpenQueue(MLX_q) Call Putpin(MLX_RST_PIN,zxOutputLow) Call Putpin(MLX_RST_PIN,zxOutputHigh) Call Putpin(MLX_RST_PIN,zxInputPullUp) Delay(0.05) ' Prepare the channel for transmitting, send command Call DefineCom(MULTIPURPOSE_COM, 0, MLX_DATA_PIN, 8) Call OpenCom(MULTIPURPOSE_COM, MLX_COM_SPEED, 0, MLX_q) 'Debug.print Cstr(Highbyte);"-";Cstr(Lowbyte) if Highbyte=0 and Lowbyte=0 then Call PutQueueStr(MLX_q, Chr(0) & CMD & Chr(sensor_address)) elseif Highbyte=0 and Lowbyte>-->0 then
Call PutQueueStr(MLX_q, Chr(0) & CMD & Chr(sensor_address) & Chr(Lowbyte))
else
Call PutQueueStr(MLX_q, Chr(0) & CMD & Chr(sensor_address) & Chr(Lowbyte) & Chr(Highbyte))
end if
' wait until the data is transmitted
Do While CBool(StatusCom(MULTIPURPOSE_COM) And &H04)
Loop
' Close the channel
Call CloseCom(MULTIPURPOSE_COM, 0, 0)
#ifdef VERBOSE_DEBUG
Debug.print "MLXSendCmd(" ; Cstr(CMD); "," ;Cstr(sensor_address); "," ; Cstr(Lowbyte); "," ;Cstr(Highbyte); ")"
#endif
End Sub
'#####################################################################################################################################
'#####################################################################################################################################
Public function Check_RW_PEC(byval slaveadrr as byte, byval CMD as byte,byval Temp as unsignedinteger, byval PEC as byte) as boolean
' PEC verification according to MELIXIS spec for MLX90614 Read word commands (page 15-16).
' The Write word command is slightly different and is not implemented.
dim Current_CRC as byte
dim Data as byte
Check_RW_PEC=True
Current_CRC=0
Data = shl(slaveadrr,1)+0
Current_CRC=Calc_CRC8(Current_CRC,Data)
Data = CMD
Current_CRC=Calc_CRC8(Current_CRC,Data)
Data = shl(slaveadrr,1)+1
Current_CRC=Calc_CRC8(Current_CRC,Data)
Data = Lobyte(Temp)
Current_CRC=Calc_CRC8(Current_CRC,Data)
Data = Hibyte(Temp)
Current_CRC=Calc_CRC8(Current_CRC,Data)
IF Current_CRCPEC then
#ifdef VERBOSE_DEBUG
Debug.print "--------------------------- PEC failed"
#endif
Check_RW_PEC=False
end if
end function
'-------------------------------------------------------
' Calc_CRC8_T adapted from "Tony"'s code on the Zbasic Forum
' Uses a look-up table to determine the new CRC Value
'-------------------------------------------------------
Private Function Calc_CRC8(ByVal Current_CRC as byte, ByVal Data as byte) as byte
Calc_CRC8 = crcTable((Current_CRC xor DATA) + 1) 'add 1 to use ZX 1-based indexing
End Function
' polynominal lookup table for CRC calculation
Private crcTable as ByteVectorData ({
&H00,&H07,&H0E,&H09,&H1C,&H1B,&H12,&H15,&H38,&H3F,&H36,&H31,&H24,&H23,&H2A,&H2D,
&H70,&H77,&H7E,&H79,&H6C,&H6B,&H62,&H65,&H48,&H4F,&H46,&H41,&H54,&H53,&H5A,&H5D,
&HE0,&HE7,&HEE,&HE9,&HFC,&HFB,&HF2,&HF5,&HD8,&HDF,&HD6,&HD1,&HC4,&HC3,&HCA,&HCD,
&H90,&H97,&H9E,&H99,&H8C,&H8B,&H82,&H85,&HA8,&HAF,&HA6,&HA1,&HB4,&HB3,&HBA,&HBD,
&HC7,&HC0,&HC9,&HCE,&HDB,&HDC,&HD5,&HD2,&HFF,&HF8,&HF1,&HF6,&HE3,&HE4,&HED,&HEA,
&HB7,&HB0,&HB9,&HBE,&HAB,&HAC,&HA5,&HA2,&H8F,&H88,&H81,&H86,&H93,&H94,&H9D,&H9A,
&H27,&H20,&H29,&H2E,&H3B,&H3C,&H35,&H32,&H1F,&H18,&H11,&H16,&H03,&H04,&H0D,&H0A,
&H57,&H50,&H59,&H5E,&H4B,&H4C,&H45,&H42,&H6F,&H68,&H61,&H66,&H73,&H74,&H7D,&H7A,
&H89,&H8E,&H87,&H80,&H95,&H92,&H9B,&H9C,&HB1,&HB6,&HBF,&HB8,&HAD,&HAA,&HA3,&HA4,
&HF9,&HFE,&HF7,&HF0,&HE5,&HE2,&HEB,&HEC,&HC1,&HC6,&HCF,&HC8,&HDD,&HDA,&HD3,&HD4,
&H69,&H6E,&H67,&H60,&H75,&H72,&H7B,&H7C,&H51,&H56,&H5F,&H58,&H4D,&H4A,&H43,&H44,
&H19,&H1E,&H17,&H10,&H05,&H02,&H0B,&H0C,&H21,&H26,&H2F,&H28,&H3D,&H3A,&H33,&H34,
&H4E,&H49,&H40,&H47,&H52,&H55,&H5C,&H5B,&H76,&H71,&H78,&H7F,&H6A,&H6D,&H64,&H63,
&H3E,&H39,&H30,&H37,&H22,&H25,&H2C,&H2B,&H06,&H01,&H08,&H0F,&H1A,&H1D,&H14,&H13,
&HAE,&HA9,&HA0,&HA7,&HB2,&HB5,&HBC,&HBB,&H96,&H91,&H98,&H9F,&H8A,&H8D,&H84,&H83,
&HDE,&HD9,&HD0,&HD7,&HC2,&HC5,&HCC,&HCB,&HE6,&HE1,&HE8,&HEF,&HFA,&HFD,&HF4,&HF3}) |
Once again thank you for your help ,
Bruno
|
|