Introduction.
This discussion focuses on the Dallas DS2423 device. It is a member of the Dallas 1-W family and provides 512 bytes of RAM and two 32 bit externally triggered counters.
This work was performed by Garth Austin of Tobago as his capstone design project at Morgan State University. Garth has worked with me for some three years and I will miss him.
Our initial interest in the DS2423 was the two 32-bit counters which might be used in a tipping bucket to measure rainfall or as a part of an anemometer to measure wind speed or in virtually any application requiring an inexpensive counter.
However, Garth went further to implement writing to and reading from memory. With the advent of flash PICs where variables may be written to flash memory, there is some skepticism in my mind as to the utility of this RAM, but it may be of use to someone.
The DS2423 is interesting in that it uses an eight bit CRC for some data transfers and a 16-bit CRC for others and both of these were implemented using table lookup. This is contained in a separate discussion.
The DS2423 is packaged in a small 6-pin TSOC package and my initial reaction was that I just couldn't solder those leads to a DIP adaptor without damaging the device. However, it proved to be quite easy.
Detailed Discussion.
Reading the Counter.
Each RAM memory page as 32 bytes. Thus, referring to a specific page is a bit awkward as it is not to do the mental arithmetic of dropping off the five least significant bits of a specific memory address. Thus, in this discussion, the 32-bit pages are identified using the two 16-bit memory blocks within the 32 byte page. For example, page &01C - &01D identifies the page associated with memory locations &01C0 - &01DF
The external counters are associated with RAM pages &01C - &01D and &01E - &01F. They are read by issuing the read memory plus counter command (&Ha5) followed by the memory address of the start of the page (low byte, high byte) and then reading the 32 memory bytes followed by the four bytes associated with the counter. Note that these bytes are arranged least significant byte first.
This is illustrated in program DS2423_1.Bas.
' DS2423_1.Bas ' ' Reads 32 bytes in RAM page 01c0 and displays to the terminal. ' Reads four byte counter and displays the result ' ' BX24 DS2423 ' ' term 13 -------------- DQ ' ' Note there is a 4.7K pull up resistor to +5 VDC on the data lead. ' ' copyright, Garth Austin, Peter H Anderson, Baltimore, MD, Dec, '03 Public Sub Main() Dim X as Byte, C(1 to 4) as Byte, N as Integer Dim Count_2423 as Long Do Call Init_1W(13) Call OutByte_1W(13, &Hcc) ' skip ROM Call OutByte_1W(13, &Ha5) ' read memory page plus counter Call OutByte_1W(13, &Hc0) ' beginning at &H01c0 Call OutByte_1W(13, &H01) For N = 1 to 32 ' read the 32 bytes X = InByte_1W(13) Debug.Print CStr(X) Next For N = 1 to 4 ' read the counter C(N) = InByte_1W(13) Next Debug.Print "****************" For N = 1 to 4 Debug.Print CStr(C(N)) ' display the four counter bytes Next Count_2423 = CLng(C(4)) * 256 * 256 * 256 + CLng(C(3)) * 256 * 256 + CLng(C(2)) * 256 + CLng(C(1)) Debug.Print CStr(Count_2423) ' display as a long Call Sleep(10.0) Loop End Sub Sub Init_1W(ByVal Pin as Byte) ' bring Pin low for 500 usecs and then back ' high Dim N as Integer Call PutPin(Pin, 2) ' be sure DQ is a high Z Call PutPin(Pin, 0) For N = 1 to 3 ' adjust for 500 usec delay Next Call PutPin(Pin, 2) For N = 1 to 3 Next End Sub Function InByte_1W(ByVal Pin as Byte) as Byte Dim N as Integer, IByte as Byte, Mask as Byte Mask = bx0000_0001 ' least sig bit first IByte = 0 For N =1 to 8 If Get1Wire(Pin) = 1 Then IByte = IByte OR Mask End If Mask = Mask * 2 ' shift mask left for next bit Next InByte_1W = IByte End Function Sub OutByte_1W(ByVal Pin as Byte, ByVal OByte as Byte) Dim N as Integer, Mask as Byte Mask = bx0000_0001 For N = 1 to 8 If (Mask AND OByte) <>0 Then Call Put1Wire(Pin, 1) Else Call Put1Wire(Pin, 0) End If Mask = Mask * 2 Next End SubThe counters are set to zero on application of power. There is no other way to do this
Note that the external counters increment with every low going pulse. To avoid noise toggling the counters, I suggest the input not be left floating. That is, if a tipping bucket using a reed type relay is used, the two states are open and GRD. To avoid the float situation when the relay is open, use a pull up resistor to Vbat.
To avoid counting multiple events due to switch bounce, either an RC network or a MAX6817 switch de bouncer is suggested.
Writing to and Reading from Memory.
I was somewhat disappointed to find that the memory associated with the DS2423 is not non-volatile. Dallas indicates NV memory, but it is non-volatile in the sense that the data is held if Vbat is present. Thus, I have some difficulty in appreciating the value of the memory associated with the DS2423.
Data is first written to the 32 byte scratch pad memory by issuing the &H0f command followed by the target address of the start of the memory, least significant byte first which is written to registers TA1 and TA2 followed by the data bytes. Note that in theory, only the low five bytes of the address are required to identify a location in the 32 byte scratch pad memory. However, the full address is required as it is used as a password when writing scratch pad to memory.
The scratch pad is then transferred to memory by issuing the &H5a command, followed by the low and high byte of the target address, followed by the lowest five bits associated with the last scratch pad address.
In program DS2423_2.Bas, the data is then directly read from memory using the &Hf0 command, followed by the two byte address, followed by reading the data.
The following program then prompts the user to momentarily remove power from the DS2423 and after thirty seconds, the memory is again read and displayed to the terminal. The point is to vividly illustrate that the data is not retained.
' Program DS2423_2.Bas ' ' Illustrates how to write to and read from memory. ' ' Writes 31, 30, ... 0 to scratch pad memory and then copies the scratch pad to page &H0C0 - &H0D0. ' Reads from the page and displays to the terminal. ' ' Prompts the user to momentarily remove power from the DS2423 and after 30 seconds, reads from memory ' and displays. This illustrates that the data is not retained. ' ' copyright, Garth Austin and Peter H Anderson, Baltimore, MD, Jan, '04 Sub Main() Dim N as Byte, X as Byte ' write to scratch pad Init_1W(13) 'gets the devices attention Call OutByte_1W(13, &Hcc) 'skip ROM Call OutByte_1W(13, &H0f) ' write to scratchpad command Call OutByte_1W(13, &Hc0) ' low byte of target address Call OutByte_1W(13, &H01) ' high byte of target address For N = 0 to 31 Call OutByte_1W(13,31-N) Next Init_1W(13) Call OutByte_1W(13, &Hcc) Call OutByte_1W(13, &H5a) ' copy scratch pad Call OutByte_1W(13, &Hc0) ' low byte of target address Call OutByte_1W(13, &H01) ' high byte of target address Call Outbyte_1W(13, &H1f) 'E/S register ending offset (5 least significant bits) Init_1W(13) ' read memory Call OutByte_1W(13, &Hcc) Call OutByte_1W(13, &Hf0) ' read memory command Call OutByte_1W(13, &Hc0) ' low byte of target address Call OutByte_1W(13, &H01) ' high byte of target address For N = 0 to 31 X = InByte_1W(13) Debug.Print CStr(N); " "; CStr(X) Next Debug.Print "Briefly remove power from the DS2423" Debug.Print "30 sec delay" Call Sleep(30.0) Init_1W(13) ' again read memory Call OutByte_1W(13, &Hcc) Call OutByte_1W(13, &Hf0) ' read memory command Call OutByte_1W(13, &Hc0) ' low bite of target address Call OutByte_1W(13, &H01) ' high bite of target address For N = 0 to 31 X = InByte_1W(13) Debug.Print CStr(N); " "; CStr(X) Next Do Debug.Print "Done" Call Sleep(5.0) Loop End Sub Sub Init_1W(ByVal Pin as Byte) ' bring Pin low for 500 usecs and then back ' high Dim N as Integer Call PutPin(Pin, 2) ' be sure DQ is a high Z Call PutPin(Pin, 0) For N = 1 to 3 ' adjust for 500 usec delay Next Call PutPin(Pin, 2) For N = 1 to 3 Next End Sub Function InByte_1W(ByVal Pin as Byte) as Byte Dim N as Integer, IByte as Byte, Mask as Byte Mask = bx0000_0001 ' least sig bit first IByte = 0 For N =1 to 8 If Get1Wire(Pin) = 1 Then IByte = IByte OR Mask End If Mask = Mask * 2 ' shift mask left for next bit Next InByte_1W = IByte End Function Sub OutByte_1W(ByVal Pin as Byte, ByVal OByte as Byte) Dim N as Integer, Mask as Byte Mask = bx0000_0001 For N = 1 to 8 If (Mask AND OByte) <>0 Then Call Put1Wire(Pin, 1) Else Call Put1Wire(Pin, 0) End If Mask = Mask * 2 Next End Sub