A TINI digital thermometer

10 May

Example: A TINI digital thermometer: The Digits class can be used in conjunction with the Thermometer class from an earlier example to make a simple thermometer that uses TINI, a DS1920 temperature iButton or a DS1820 1-Wire thermometer, and the SAA1064 display driver. Simply implement the previous example, and connect a thermometer iButton or 1-Wire device to TINI via the 1-Wire bus. We’ll call the new class LEDTherm.

Listing 11-2: LEDTherm.java

import java.io.*;
public   class LEDTherm {
public static void main (String[] args) {
Thermometer therm = new Thermometer();
Digits LEDs = new Digits();
while (true) {
try {
therm.measureT();
LEDs.setValue((byte)(therm.degF));
Thread.sleep(1000);
} catch(Exception e) {System.out.println(e);}
}
}
}
C:\> cd src
C:\> javac -bootclasspath %TINI_HOME%\bin\tiniclasses.jar
-classpath                                                                               %TINI_HOME%\bin\owapi_dependencies_TINI.jar;.
-d ..\bin   Digits.java
C:\> cd ..
C:\> java -classpath %TINI_HOME%\bin\tini.jar;. BuildDependency
-p                                                                                       %TINI_HOME%\bin\owapi_dependencies_TINI_001.jar
-f bin
-x                                                                                       %TINI_HOME%\bin\owapi_dep.txt
-o bin
-d %TINI_HOME%\bin\tini.db

When you run the program on your TINI you can watch the LED digits display the temperature.

Example: Extending TINI’s parallel I/O
In the previous two examples we were writing to an I2C device. We could read back a status byte from the SA1064 LED driver, but this is not particularly interesting. This status byte contains a single 1-bit field that indicates that there was a power failure since the last time you read the status byte. A more interesting example is using a Philips PCF85743, remote 8-bit I/O expander, for adding 8-bit parallel I/O to your TINI.

Figure 11-12: I2C 8-bit parallel I/O schematic
Listing 11-3: Parallel_IO.java

You can connect the switches and LEDs to any of the pins that you like. For the example Java program listed here, switches are connected to P0-P3 and LEDs are connected to P4-P7.

import com.dalsemi.system.*;
import java.io.*;
public class Parallel_IO {
byte[] data = new byte[1];
I2CPort PioPort;
public Parallel_IO() {
PioPort = new I2CPort();
PioPort.setAddress((byte)0×27);
PioPort.setClockDelay((byte)0×7F);
data[0] = 0×00;
}
private static char[] hexChars =
{ ‘0’,’1′,’2′,’3′,’4′,’5′,’6′,’7′,’8′,’9′,’A’,’B’,’C’,’D’,’E’,’F’ };
public static String toHex( byte data )
{
StringBuffer output = new StringBuffer();
int firstNibble, secondNibble;
firstNibble = ( data >> 4 ) & 0×0F;
secondNibble = data & 0×0F;
output.append( hexChars[ firstNibble ] );
output.append( hexChars[ secondNibble ] );
return output.toString();
}
public void Blinky() {
int stat=0;
for (int i=1; i<10; i++) {
System.out.print( “Write: “ + i );
try {
data[0] = (byte)(0×1A);
stat = PioPort.write( data, 0, 1);
System.out.print( “ [ “ + toHex(data[0]) + “ “ + stat + “ ]” );
TINIOS.sleepProcess(250);
data[0] = (byte)(0×2A);
stat = PioPort.write( data, 0, 1);
System.out.print( “ [ “ + toHex(data[0]) + “ “ + stat + “ ]” );
TINIOS.sleepProcess(250);
data[0] = (byte)(0×4A);
stat = PioPort.write( data, 0, 1);
System.out.print( “ [ “ + toHex(data[0]) + “ “ + stat + “ ]” );
TINIOS.sleepProcess(250);
System.out.println();
}
catch(Exception e){
System.out.println( “Error in I2C write…” );
System.out.println( e );
}
}
for (int i=1; i<10; i++ ) {
System.out.println( i );
try {
data[0] = (byte)(0×00);
System.out.print( “read: “ + i );
stat = PioPort.read( data, 0,1 );
System.out.println( “ [ “ + toHex(data[0]) + “ “ + stat + “ ]” );
TINIOS.sleepProcess(250);
}
catch(Exception e) {
System.out.println( “Error in I2C read…” );
System.out.println( e );
}
}
}
public static void main(String[] args) {
Parallel_IO myPio = new Parallel_IO();
myPio.Blinky();
}
}

As with previous programs, the first few lines declare a data buffer for storing the data to be sent to, or received from, the I2C device, in this case a single byte. We have also created a single constructor that creates a new I2CPort object and assigns the address and clock delay.

import com.dalsemi.system.*;
import java.io.*;
public class Parallel_IO {
byte[] data = new byte[1];
I2CPort PioPort;
public Parallel_IO() {
PioPort = new I2CPort();
PioPort.setAddress((byte)0×27);
PioPort.setClockDelay((byte)0×7F);
data[0] = 0×00;
}

We also have a toHex() method for displaying the contents read from, or written to, the I2C device. This is entirely for our convenience, so we don’t have to read decimal and determine if the output is proper. Then we have the bulk of the class in the blinky() method.

try {
data[0] = (byte)(0×1A);
stat = PioPort.write( data, 0, 1);
System.out.print( “ [ “ + toHex(data[0]) + “ “ + stat + “ ]” );
TINIOS.sleepProcess(250);

System.out.println();
}
catch(Exception e){
System.out.println( “Error in I2C write…” );
System.out.println( e );
}
for (int i=1; i<10; i++ ) {
System.out.println( i );
try {
data[0] = (byte)(0×00);
System.out.print( “read: “ + i );
stat = PioPort.read( data, 0,1 );
System.out.println( “ [ “ + toHex(data[0]) + “ “ + stat + “ ]” );
TINIOS.sleepProcess(250);
}
catch(Exception e) {
System.out.println( “Error in I2C read…” );
System.out.println( e );
}
}

The blinky() method does two things. First it writes various bytes to the PCF8574 to turn on and off some of the LEDs. Then it reads from the PCF8574 and displays the results of the various switch settings. We have liberally filled this program with lots of print statements so we can see what’s happening along the way. Compile the program and run it on TINI and watch the results.

C:\> javac -bootclasspath %TINI_HOME%\bin\tiniclasses.jar
-classpath                                                                               %TINI_HOME%\bin\owapi_dependencies_TINI.jar;.
-d bin   src\Parallel_IO.java
C:\> java -classpath %TINI_HOME%\bin\tini.jar;. BuildDependency
-p                                                                                       %TINI_HOME%\bin\owapi_dependencies_TINI_001.jar
-f bin
-x                                                                                       %TINI_HOME%\bin\owapi_dep.txt
-o bin
-d %TINI_HOME%\bin\tini.db

This next example is a slight extension of the last one. Instead of reading or writing from the same device, we will be reading inputs from one PC8574 and writing outputs to a second one. This will also demonstrate connecting several devices to an I2C bus at the same time. We will be using the first remote 8-bit I/O expander to read the position of eight push buttons and then writing this value to the second I/O expander to turn on or off eight LEDs. We will also use the interrupt feature of the first PCF8574 to trigger an external interrupt on a TINI stick when any of the buttons is pressed.

Listing 11-04: InOut.java

import  java.util.TooManyListenersException;
import com.dalsemi.system.*;
import java.io.*;
class InOut implements ExternalInterruptEventListener {
int i;
byte[] data = new byte[1];
I2CPort PioPort_I;
I2CPort PioPort_O;
private static char[] hexChars =
{ ‘0’,’1′,’2′,’3′,’4′,’5′,’6′,’7′,’8′,’9′,’A’,’B’,’C’,’D’,’E’,’F’ };
public static String toHex( int data )
{
StringBuffer output = new StringBuffer();
int firstNibble, secondNibble;
firstNibble = ( data >> 4 ) & 0×0F;
secondNibble = data & 0×0F;
output.append( hexChars[ firstNibble ] );
output.append( hexChars[ secondNibble ] );
return output.toString();
}
public void init() throws TooManyListenersException
{
int stat=0;
// This is the signal to which we will add an event listener
ExternalInterrupt myInterrupt = new ExternalInterrupt();
// Add the event listener
myInterrupt.addEventListener(this);
// Set this to EDGE triggering
try {
myInterrupt.setTrigger( true, this );
}
catch (Exception e){
System.out.println( e );
}
// Set the addresses and clock delay
PioPort_I = new I2CPort();
PioPort_I.setAddress((byte)0×21);
PioPort_I.setClockDelay((byte)0×7F);
PioPort_O = new I2CPort();
PioPort_O.setAddress((byte)0×22);
PioPort_O.setClockDelay((byte)0×7F);
// Set all outputs low
try {
data[0] = (byte)(0×00);
stat = PioPort_I.write( data, 0,1 );
stat = PioPort_O.write( data, 0, 1);
}
catch (Exception e) {
System.out.println( e );
}
}
public void externalInterruptEvent(ExternalInterruptEvent ev)
{
int stat = 0;
System.out.println( “Interrupt Caught: “ + ++i );
try {
// Fetch the Input states
data[0] = (byte)(0×00);
stat = PioPort_I.read( data, 0,1 );
System.out.println( “Read [ “ + toHex(data[0]) + “ “ + stat + “ ]” );
// Write the states to the Outputs on the other device
stat = PioPort_O.write( data, 0, 1);
System.out.println( “Write [ “ + toHex(data[0]) + “ “ + stat + “ ]” );
// Reset inputs
data[0] = (byte)0×00;
stat = PioPort_I.write( data, 0,1 );
System.out.println( “Reset [ “ + toHex(data[0]) + “ “ + stat + “ ]” );
}
catch (Exception e) {
System.out.println( e );
}
// Die after 10 pushes
if (i > 9) { System.exit(0); }
}
public static void main(String[] args) throws TooManyListenersException
{
// Start up the InterruptListender
InOut interrupt = new InOut();
// Initialize everything
interrupt.init();
// Hang out for awhile
while (true) {
// do nothing
}
}
}

Figure 11-13: I2C 8-bit dual parallel I/O schematic

The program for this schematic is a slight modification of the previous, combined with what we learned in Chapter 8 for setting up an ExternalInterruptEventListener. We will spend much less time going through this program, as it’s very much like the program from Chapter 8, ExtInt.java. We have created the init() method to create the ExternalInterrupt object and set the EventListener. We also needed to set the interrupt triggering to “edge triggering” so we can catch which button was pressed when we trigger an interrupt. Edge triggering will trigger an interrupt every time the button changes state. This is in contrast to “level triggering,” the other form of interrupt trigger, where the ExternalInterruptEventListener is called continually until the button is released. In this method we also create two I2CPort objects, one for each of the I2C devices, and we initialize them to all bits off.

public void init() throws TooManyListenersException
{
int stat=0;
// This is the signal to which we will add an event listener
ExternalInterrupt myInterrupt = new ExternalInterrupt();
// Add the event listener
myInterrupt.addEventListener(this);
// Set this to EDGE triggering
try {
myInterrupt.setTrigger( true, this );
}
catch (Exception e){
System.out.println( e );
}
// Set the addresses and clock delay
PioPort_I = new I2CPort();
PioPort_I.setAddress((byte)0×21);
PioPort_I.setClockDelay((byte)0×7F);
PioPort_O = new I2CPort();
PioPort_O.setAddress((byte)0×22);
PioPort_O.setClockDelay((byte)0×7F);
// Set all outputs low
try {
data[0] = (byte)(0×00);
stat = PioPort_I.write( data, 0,1 );
stat = PioPort_O.write( data, 0, 1);
}
catch (Exception e) {
System.out.println( e );
}
}

The last thing before our main starts the whole thing running is the externalInterruptEvent() method. Each time the first PCF8574 fires an interrupt, this method is called. In this method we read the byte from the input device and write this to the output device to turn on or off the corresponding LEDs to match the buttons pushed. As with the previous example, this program is quite verbose so we can see what is going on in case the LEDs don’t work as expected.

public void externalInterruptEvent(ExternalInterruptEvent ev)
{
int stat = 0;
System.out.println( “Interrupt Caught: “ + ++i );
try {
// Fetch the Input states
data[0] = (byte)(0×00);
stat = PioPort_I.read( data, 0,1 );
System.out.println( “Read [ “ + toHex(data[0]) + “ “ +
stat + “ ]” );
// Write the states to the Outputs on the other device
stat = PioPort_O.write( data, 0, 1);
System.out.println( “Write [ “ + toHex(data[0]) + “ “ +
stat + “ ]” );
// Reset inputs
data[0] = (byte)0×00;
stat = PioPort_I.write( data, 0,1 );
System.out.println( “Reset [ “ + toHex(data[0]) + “ “ +
stat + “ ]” );
}
catch (Exception e) {
System.out.println( e );
}
// Die after 10 pushes
if (i > 9) { System.exit(0); }
}

To compile this:
C:\> javac -bootclasspath %TINI_HOME%\bin\tiniclasses.jar
-classpath                                                                               %TINI_HOME%\bin\owapi_dependencies_TINI.jar;.
-d bin   src\InOut.java
C:\> java -classpath %TINI_HOME%\bin\tini.jar;. BuildDependency
-p                                                                                       %TINI_HOME%\bin\owapi_dependencies_TINI_001.jar
-f bin
-x                                                                                       %TINI_HOME%\bin\owapi_dep.txt

-o bin
-d %TINI_HOME%\bin\tini.db

After you compile this and FTP it to your TINI, give it a test run. If you see lots of -1s printed in the output, this is probably because there is something not quite right with the way you have connected your I2C bus or devices, so check the schematics again. While it’s hard to show the LEDs lighting, the screen output looks like this:

Interrupt Caught: 1
Read [ 01 0 ]
Write [ 01 0 ]
Reset [ 00 0 ]
Interrupt Caught: 2
Read [ 00 0 ]
Write [ 00 0 ]
Reset [ 00 0 ]
Interrupt Caught: 6
Read [ 81 0 ]
Write [ 81 0 ]
Reset [ 00 0 ]
Interrupt Caught: 7
Read [ 00 0 ]
Write [ 00 0 ]
Reset [ 00 0 ]
Interrupt Caught: 10
Read [ 80 0 ]
Write [ 80 0 ]
Reset [ 00 0 ]

Here you can see that we press the first button (01), then both the first and last button (81 is button 8 and button 1), then just the last button (80). Notice that each interrupt is followed with another that reads 00. This is the button release (it’s changing state on the device and so it triggers another interrupt). All of the examples in this chapter have used the microprocessor port driver for I2C communication. If you wish to use memory-mapped I2C then you simply need to use an alternate form of the constructor given in the discussion of the API. The rest of the example programs do not need any further modification.

Summary
The section has provided a very brief look at the I2C bus protocol and how to use it with TINI. There are a number of aspects of I2C and TINI that we have not attempted to cover here. The Dallas Semiconductor TINI archives are a rich source of information, in a question-and-answer format, for those interested in more information. Additionally, the Philips web site provides the complete I2C specification, free of charge.

References
1. Philips Semiconductors, About the I2C-bus,

http://www-us.semiconductors.philips.com/i2c/facts/

2. Philips Semiconductors, I2C Bus Specification,

http://www-us.semiconductors.philips.com/acrobat/various/

I2C_BUS_SPECIFICATION_3.pdf
3. I2C FAQ,

http://perso.club-internet.fr/mbouget/i2c-faq.html

4. The I2C-bus and how to use it (including specification),

http://www.semiconductors.philips.com/acrobat/various/

I2C_BUS_SPECIFICATION_1995.pdf

Random Posts

Comments are closed.