Measuring temperature with a DS1920

10 May

Example: Measuring temperature with a DS1920
temperature iButton
Let’s now go through a similar exercise making a Java class that will return the temperature measured from a DS1920 temperature iButton. As with the switch example, we’ll make a simple, reusable class that provides a basic thermometer object, with methods that return the current temperature. We’ll start by looking at the relevant class in the 1-Wire API, the OneWireContainer10 class.
The OneWireContainer10 class
The OneWireContainer10 class represents and encapsulates devices with a family code of 10h. These are thermometer devices such as the DS1820 and DS1820. We’re not going to list all of the methods here, as they can be completely explored in the Javadocs that come with the API, but we will look at some of the more important methods. Some of the methods come from classes that we’ve already seen, but we’re going to list them here for review.

Class OneWireAccessProvider
• public static DSPortAdapter getDefaultAdapter()
• public static DSPortAdapter getAdapter( String port_adapter, String port )

Class DSPortAdapter
• public abstract boolean beginExclusive( boolean blocking )
• public abstract int reset( )
• public OneWireContainer getFirstDeviceContainer()
• public abstract void endExclusive()
• public void targetFamily( int family )

Class OneWireContainer10
• public String getAddressAsString()
• public byte[] readDevice()
• public void doTemperatureConvert(   byte[] state )
• public double getTemperature( byte[] state )
• public static double convertToFahrenheit(   double celciusT )
• public void writeDevice(   byte[]   state )

Our thermometer class will consist of the following:
1. An overloaded constructor, thermometer(), that can take anywhere from zero to three arguments, depending on how specific you want to be when creating the object.

2. A measureT() method that causes the DS1920 thermometer iButton to make a measurement and place the temperature in both Celsius and Fahrenheit into the object’s data members.

3. A main() method that provides us with a way of testing our class. We’ll use it to create a couple of thermometer objects, on different computer I/O ports, and print the results.

The complete program is presented below, then presented in dissected and explained fashion, followed by a sample run of the program.

Listing 10-5: Thermometer.java

import com.dalsemi.onewire.*;
import  com.dalsemi.onewire.adapter.*;
import  com.dalsemi.onewire.container.*;
import java.io.*;
public class Thermometer {
// also get ALL thermometers not just container 10
DSPortAdapter adapter;
OneWireContainer10 container;
byte[] state;
String ROM_ID;
double degC;
double degF;
public Thermometer() {
try {
adapter = (DSPortAdapter)OneWireAccessProvider.getDefaultAdapter();
Init(“”);
} catch (Exception e) {
System.out.println(“problem in constructor”);
System.out.println(e);
}
}
public Thermometer( String PAadapt, String Port) {
try {
adapter = (DSPortAdapter)OneWireAccessProvider.getAdapter(PAadapt,Port);
Init(“”);
} catch (Exception e) {
System.out.println(“problem in constructor”);
System.out.println(e);
}
}
public Thermometer( String ROM, String PAadapt, String Port) {
try {
adapter = (DSPortAdapter)OneWireAccessProvider.getAdapter(PAadapt, Port);
Init(ROM);
} catch (Exception e) {
System.out.println(“problem in constructor”);
System.out.println(e);
}
}
public void Init(String ROM) {
try {
adapter.beginExclusive(true);
adapter.reset();
adapter.targetFamily(0×10);
// If we specified a specific device, get it else get the first one
if (ROM.length()<1) {
container =
(OneWireContainer10)adapter.getFirstDeviceContainer();
}
else {
container =
(OneWireContainer10)adapter.getDeviceContainer(ROM);
}
// cast the generic container into a TemperatureContainer
ROM_ID=  container.getAddressAsString();
state = container.readDevice();
container.doTemperatureConvert(state);
degC = container.getTemperature(state);
degF = container.convertToFahrenheit(degC);
adapter.endExclusive();
} catch (Exception e) {
System.out.println(“problem in constructor”);
System.out.println(e);
}
}
public void measureT() {
try {
adapter.beginExclusive(true);
adapter.reset();
state = container.readDevice();
container.doTemperatureConvert(state);
degC = container.getTemperature(state);
degF = container.convertToFahrenheit(degC);
container.writeDevice(state);
adapter.endExclusive();
} catch(Exception e) {
System.out.println(“problem in measure”);
System.out.println(e);
}
}
public static void main (String[] args) {
Thermometer myTherm;
// port_name should be like:     COM1, LPT1, /dev/ttyS0, or serial1
// portAdapter should be like: {DS1410E}, DS9097U, TINIExternalAdapter
if (args.length==2) {
myTherm = new Thermometer( args[0], args[1] );
}
else {
myTherm = new Thermometer();
}
// Read the temp sensor
myTherm.measureT();
// Display what we know (temoerature) in C and F
System.out.println(“The device ROM ID: “ + myTherm.ROM_ID);
System.out.println(“The measured temperature: “ + myTherm.degC
+ “ Deg C” + “, or “ + myTherm.degF + “ Deg F”);
}
}

Our Java program starts with the class declaration and the declaration of object data members, or instance variables. There is a port adapter that represents the communication interface, a OneWireContainer10 object, that represents the individual device, and an 8-element array of bytes called state that holds the current information on the raw sensor data before it’s been parsed into an actual temperature reading. A string containing the ROM_ID and two doubles, each holding the last measured temperature is also present.

public   class Thermometer {
DSPortAdapter adapter;
OneWireContainer10 container;
byte[] state;
String ROM_ID;
double degC;
double degF;

Next, there is the first of three constructors. As with the Switch program, each constructor calls the Init() method, which takes care of all the things that are common to each constructor. It attempts to use the default port adapter and attempts to find the first 1-Wire device with a family code of 10h to be identified. Most of this is creating the data members that were previously declared, but a couple of the actions are responsible for other functions. The targetFamily(10) is actually telling the 1-Wire bus that we’re going to limit the underlying 1-Wire bus searches (Search ROM passes) to devices with a family code of 10h. The beginExclusive() method and the reset() method prepares the 1-Wire bus and prevent other possible 1-Wire threads from interrupting the current communication. This seems to be particularly important when communicating via the DS1410E parallel port adapter. When using the COM port adapters, it doesn’t seem as important. After completing those methods, we create objects that were declared earlier, in a similar fashion to our switch example. First, we read the state array from the device with readDevice(), then we pass that array to a temperature conversion method, doTemperatureConvert(). After the conversion is complete, we can read the actual temperature using the getTemperature() method. That temperature is in Celsius, and can be converted to Fahrenheit with the convertToFarhenheit() method. Lastly, we release the 1-Wire bus from the exclusive control with the endExclusive() method. Those steps form the pattern for all of our temperature measurement. Since several of the methods throw exceptions, we enclosed the code in a try/catch block.

public Thermometer() {
try {
adapter = (DSPortAdapter)OneWireAccessProvider.getDefaultAdapter();
Init(“”);
} catch (Exception e) {
System.out.println(“problem in constructor”);
System.out.println(e);
}
}
public void Init(String ROM) {
try {
adapter.beginExclusive(true);
adapter.reset();
adapter.targetFamily(0×10);
// If we specified a specific device, get it else get the first one
if (ROM.length()<1) {
container =
(OneWireContainer10)adapter.getFirstDeviceContainer();
}
else {
container =
(OneWireContainer10)adapter.getDeviceContainer(ROM);
}
// cast the generic container into a TemperatureContainer
ROM_ID=  container.getAddressAsString();
state = container.readDevice();
container.doTemperatureConvert(state);
degC = container.getTemperature(state);
degF = container.convertToFahrenheit(degC);
adapter.endExclusive();
} catch (Exception e) {
System.out.println(“problem in constructor”);
System.out.println(e);
}
}
The second constructor is similar to the first, except that it accepts a specific port
adapter name and port as arguments.
public Thermometer( String PAadapt, String Port) {
try {
adapter = (DSPortAdapter)OneWireAccessProvider.getAdapter(PAadapt,Port);
Init(“”);
} catch (Exception e) {
System.out.println(“problem in constructor”);
System.out.println(e);
}
}

The third and final constructor takes the port adapter, port name, and ROM ID of a specific device as arguments.
public Thermometer( String ROM, String PAadapt, String Port) {
try {
adapter =
(DSPortAdapter)OneWireAccessProvider.getAdapter(PAadapt,  Port);
Init(ROM);
} catch (Exception e) {
System.out.println(“problem in constructor”);
System.out.println(e);
}
}

Each of our constructors performs a temperature measurement that initializes the data members. Subsequent temperature measurements require a repeat of the temperature measurement process. That’s what the measureT() method does. It grabs exclusive control of the 1-Wire bus, reads the state, converts it to a temperature, gets the temperature, converts it to Fahrenheit, returns control. Any time we need an updated temperature, we simply invoke this method and read the temperatures from the instance variables, degC and degF.

public void measureT() {
try {
adapter.beginExclusive(true);
adapter.reset();
state = container.readDevice();
container.doTemperatureConvert(state);
degC = container.getTemperature(state);
degF = container.convertToFahrenheit(degC);
container.writeDevice(state);
adapter.endExclusive();
} catch(Exception e) {
System.out.println(“problem in measure”);
System.out.println(e);
}
}

The main() method tests our thermometer class. The first thing it does is examine the command line arguments. If there are two arguments, then it assumes we specified a PortAdapter and CommPort to access and it calls that constructor. If we didn’t supply any arguments, then it uses the constructor that gets the default PortAdapter.

public static void main (String[] args) {
Thermometer myTherm;
// port_name should be like:     COM1, LPT1, /dev/ttyS0, or serial1
// portAdapter should be like: {DS1410E}, DS9097U, TINIExternalAdapter
if (args.length==2) {
myTherm = new Thermometer( args[0], args[1] );
}
else {
myTherm = new Thermometer();
}
// Read the temp sensor
myTherm.measureT();
// Display what we know (temoerature) in C and F
System.out.println(“The device ROM ID: “ + myTherm.ROM_ID);
System.out.println(“The measured temperature: “ + myTherm.degC
+ “ Deg C”+ “, or “ + myTherm.degF + “ Deg F”);
}
}

This sample program doesn’t make use of all the features of the DS1920 temperature iButton, by any stretch of the imagination, but it illustrates the highlights of how to talk to the device using the OneWireContainer10 class. A sample run is below.

Note: We don’t show the compile command-line options (like CLASSPATH, etc.) here because they might be confusing if you don’t put your files in the same folder names that we did. If you use the CDROM, the build.bat will compile the code for you.

C:\> java Thermometer
The device ROM ID: D40000004B996410
The measured temperature: 24.0 Deg C, or 75.2 Deg F

The device ROM ID: 700000004B8F1010
The measured temperature: 24.5 Deg C, or 76.1 Deg F

C:\> java Thermometer DS9097U COM1
The device ROM ID: D40000004B996410
The measured temperature: 21.5 Deg C, or 70.7 Deg F

The arguments are just a little different for Linux:
$ java Thermometer DS9097U /dev/ttyS0
The device ROM ID: D40000004B996410
The measured temperature: 22.0 Deg C, or 71.6 Deg F

The preceding sections have discussed how the 1-Wire bus works, how to interface a PC to the 1-Wire bus, and how to use the Java 1-Wire API to communicate with 1- Wire devices. The next section is going to examine how to use TINI to communicate with the 1-Wire bus.

Random Posts

Comments are closed.