DS18B20Article
If you just have a single One Wire (OW) family type connected to your bus, it is pretty easy to access it using Find() - see the Swordfish example file "DS18B20 DisplayTemp.bas". However, what do you do if you have multiple devices connected to your bus?
Each OW device has a unique ROM ID, which enables you to target a specific device. The first thing you need to do is build and run the example program OWSearch.bas. This program not only serves to test your OW bus, but it also displays the ROM IDs for all devices connected to it. For example,
FAMILY $28 ($1D) ($0000002CDBAE) <- DS18B20 FAMILY $28 ($3F) ($0000002CD16E) <- DS18B20 FAMILY $05 ($F1) ($00000019F75D) FAMILY $05 ($90) ($0000001A20B7) FAMILY $23 ($CA) ($0000005C62EE) 5 device(s) found
As you can see, there are two DS18B20 temperature sensors connected to the bus. We can set these as constants in our program, like this
const Sensor_A(8) as byte = ($28, $AE, $DB, $2C, $00, $00, $00, $1D) const Sensor_B(8) as byte = ($28, $6E, $D1, $2C, $00, $00, $00, $3F)
Looking at the above code, the first byte is the family ID - you can view a list of device families here. The next 6 bytes are the ROM ID followed by the checksum.
Now, we just need to write a generic subroutine which will take a ROM ID and display the temperature...
sub DisplaySensor(byrefconst pID() as byte) dim TempA as shortint dim TempB as word RomID = pID Convert GetTemp(TempA, TempB) USART.Write(DecToStr(TempA),".",DecToStr(TempB,2), $BA, "C",13,10) end sub
Program Listing
// device and clock speed... device = 18F452 clock = 20 // import modules... include "DS18B20.bas" include "convert.bas" include "usart.bas" // FAMILY $28 ($1D) ($0000002CDBAE) <- DS18B20 // FAMILY $28 ($3F) ($0000002CD16E) <- DS18B20 const Sensor_A(8) as byte = ($28, $AE, $DB, $2C, $00, $00, $00, $1D) const Sensor_B(8) as byte = ($28, $6E, $D1, $2C, $00, $00, $00, $3F) // display a sensor value... sub DisplaySensor(byrefconst pID() as byte) dim TempA as shortint dim TempB as word RomID = pID Convert GetTemp(TempA, TempB) USART.Write(DecToStr(TempA),".",DecToStr(TempB,2), $BA, "C",13,10) end sub // program start... SetBaudrate(br115200) SetPin(PORTC.0) while true DisplaySensor(Sensor_A) DisplaySensor(Sensor_B) delayms(1000) wend
The output will look like this. I've clamped my finger to the second sensor, so you can see the value rising...
21.25ºC 22.50ºC 21.50ºC 23.25ºC 21.50ºC 24.75ºC 21.50ºC 24.00ºC 21.75ºC 25.00ºC 21.00ºC 25.75ºC 21.00ºC 26.25ºC
The above program sample uses a 20MHz clock, but you may have problems when using a slower clock. For example, 4MHz. This is because the OneWire (OW) library uses indirect addressing to access the OW port pin. If you don't know what indirect addressing means, don't worry - but it does cost many more processor clock cycles than if direct addressing was used. Luckily, the DS18B20 module allows you to use direct addressing. An additional benefit is that direct addressing will generate far less code than direct addressing. Here is how it's done...
// device and clock speed... device = 18F452 clock = 20 // import modules... #option OW_PIN = PORTC.0 include "DS18B20.bas" include "convert.bas" include "usart.bas" // FAMILY $28 ($1D) ($0000002CDBAE) <- DS18B20 // FAMILY $28 ($3F) ($0000002CD16E) <- DS18B20 const Sensor_A(8) as byte = ($28, $AE, $DB, $2C, $00, $00, $00, $1D) const Sensor_B(8) as byte = ($28, $6E, $D1, $2C, $00, $00, $00, $3F) // display a sensor value... sub DisplaySensor(byrefconst pID() as byte) dim TempA as shortint dim TempB as word RomID = pID Convert GetTemp(TempA, TempB) USART.Write(DecToStr(TempA),".",DecToStr(TempB,2), $BA, "C",13,10) end sub // program start... SetBaudrate(br115200) while true DisplaySensor(Sensor_A) DisplaySensor(Sensor_B) delayms(1000) wend
It's virtually identical to the previous code example, except I've removed the call to SetPin() and put
#option OW_PIN = PORTC.0
before the module includes. Notice the emphasis on before. Options should always be declared before you include a module so that the Swordfish pre-processor can calculate a value before it is used in a module.
Using the OW_PIN option is therefore the preferred method of assigning the OW bus pin, in terms of both execution speed and less program ROM being used. Unless there is a compelling reason to do so, do try and avoid the use of SetPin()