Skip to Main Content

Embedded Technologies

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Interested in getting your voice heard by members of the Developer Marketing team at Oracle? Check out this post for AppDev or this post for AI focus group information.

Java ME 8 + Raspberry Pi + Sensors = IoT World (Part 3)

Yolande Poirier-OracleJun 24 2015 — edited Oct 6 2015

by Jose Cruz

Learn how to connect sensors to the Raspberry Pi and control them with Java.

Part 1 of this series explained how to connect electronic sensors to the Raspberry Pi Model B using general-purpose input/output (GPIO) interfaces. Part 2 focused on using inter-integrated circuit bus (I2C) interfaces to connect sensors.

This article focuses on using universal asynchronous receiver/transmitter (UART) interfaces to connect new modules that do the following:

In addition, because we won't have all UART interfaces you need, this article describes how to convert an I2C interface to UART using the SparkFun I2C/SPI-to-UART breakout board (SC16IS750). We'll also use a little mono audio amplifier, the SparkFun module TPA2005D1.

Note: The complete example code for this NetBeans IDE 8.0.2 project can be downloaded from the attached zip file at the bottom of this article.

Enabling UART on the Raspberry Pi

UART is a serial port that consists of two signals—a transmit signal (TxD) and a receive signal (RxD)—made available on pin 8 (BCM or GPIO 14) and pin 10 (BCM or GPIO 15), respectively, on the GPIO header. You can view the Raspberry pinout here.

Remember that all GPIO pins operate at 0 and 3.3 V logic levels, not the common RS-232 serial port level of +/- 12 V. If you wish to connect a UART device, you need a board or adapter to convert the higher signal levels to the lower GPIO signal levels. For example, you can use a MAX3232CPE transceiver and some capacitors. See this tutorial.

By default, the Raspberry Pi uses its built-in UART interface as the serial console. To have control of it, we need to run a few commands to release it.

First, back up the /boot/cmdline.txt file by running the following command:

|

$ sudo cp /boot/cmdline.txt /boot/cmdline_backup.txt

|

Then, enter the following command from the command line to edit the file.

|

$ sudo nano /boot/cmdline.txt

|

Change the following line in the file, from this:

|

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200
console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

|

to this:

|

dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4
elevator=deadline rootwait

|

Next, enter the following command from the command line to edit the /etc/inittab file:

|

$ sudo nano /etc/inittab

|

Then change the following line in the file from this:

|

#spawn a getty on Raspberry Pi serial line
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

|

to this (to comment out the second line):

|

#spawn a getty on Raspberry Pi serial line
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

|

As the last step, reboot the Raspberry Pi.

 

Circuits We Will Create

Based on the block diagram shown in Figure 1 and the components shown Figure 2, we create the circuits shown in Figure 3.

image001.gif

Figure 1. Block diagram of the circuits we will create

image002.gif

Figure 2. Components we will use

image003.gif

Figure 3. Schematic of the circuits we will create

 

Connecting the GPS Receiver Engine Board

The EM-406a is a compact, high-performance, low power consumption GPS engine board. It uses the SiRF Star III LP Single GPS chipset, which can track up to 20 satellites at a time, and has the following features:

  • Very high sensitivity (tracking sensitivity: -159 dBm)
  • Extremely fast TTFF (Time To First Fix) at low signal levels
  • Support for the NMEA 0183 data protocol
  • Built-in SuperCap to maintain system data for rapid satellite acquisition
  • Built-in patch antenna
  • Foliage lock for weak signal tracking
  • All-in-view 20-channel parallel processing
  • Snap lock 100ms reacquisition time

Let's now connect the device to the Raspberry Pi's GND, GPS Tx to UART RxD, GPS Rx to UART TxD, and VCC 5v pins, as shown in Figure 3, and create a Java ME 8 class called GPSEM406ADevice to control the GPS device. See Listing 1.

|

public class GPSEM406ADevice {

private UARTConfig config=null; //UART config parameters object
private UART uart = null;       //UART object

private static String nmea = ""; //NMEA protocol data read from UART event listener

private String time = null; //Time from GPS
private final String longitude\[\] ={null, null};     //Longitude read from GPS
private final String latitude\[\] = {null, null};     //Latitude read from GPS
private final String altitude\[\] = {null, null};     //Altitude read from GPS

|

Listing 1. Creating the GPSEM406ADevice class

Next, create a class constructor that initializes and activates UART using the DeviceManager API and the UARTConfig class (see Listing 2) to establish the following conditions for serial communication and activate the input data listener to receive status from the GPS device.

  • Controller Number: DeviceConfig.DEFAULT
  • Channel Number: DeviceConfig.DEFAULT
  • Baud Rate: 4800
  • Data Bits: DATABITS_8
  • Parity: PARITY_NONE
  • Stop Bits: STOPBITS_1
  • Flow control: FLOWCONTROL_NONE

|

public GPSEM406ADevice() throws IOException {
//Config UART
config = new UARTConfig(DeviceConfig.DEFAULT, DeviceConfig.DEFAULT, 4800,
DATABITS_8, PARITY_NONE, STOPBITS_1, FLOWCONTROL_NONE);
//Create UART object
uart = (UART) DeviceManager.open(UART.class, config);
// Initialize GPS to talk NMEA protocol
GPS_Switch_Mode_To_NMEA();
//Create read data listener to UART
uart.setEventListener(UARTEvent.INPUT_DATA_AVAILABLE, new MyUARTListener());
}

|

Listing 2. Establishing the initial conditions for the GPS device and UART

The GPS_Switch_Mode_To_NMEA method (see Listing 3) initializes the GPS device to talk the NMEA protocol by using several byte commands (see explanation here) that establishes this type of text protocol.

|

private static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}

private void GPS_Switch_Mode_To_NMEA() {
byte[] data = hexStringToByteArray("A0A20018810201010001010105010101000100010001000100012580013AB0B3");
ByteBuffer buffer = ByteBuffer.allocateDirect(data.length);
buffer.put(data);
buffer.clear();
...
uart.write(buffer);
I2CUtils.I2Cdelay(10000);
Logger.getGlobal().log(Level.FINE, "GPS Config Ok...");
...
}

|

Listing 3. Method to initialize the GPS device to talk the NMEA protocol

Then create the following format and get methods (see Listing 4):

  • formatTime: Format read time
  • formatLat: Format read latitude
  • formatLong: Format read longitude
  • formatAlt: Format read altitude
  • getTime: Read time
  • getLatitude: Read latitude
  • getLongitude: Read longitude
  • getAltitude: Read altitude

|

private String formatTime(String time) {
return (time != null) ? time.substring(0, 2) + ":" + time.substring(2, 4) + ":" +
time.substring(4, 6) : "";
}

private String formatLat(String[] pos) {
return ((pos[0] != null) && (pos[1] != null)) ? pos[0].substring(0, 2) +
"* " + pos[0].substring(2, 4) + "' " + pos[0].substring(5, 9) + "\" " + pos[1] : "";
}

private String formatLong(String[] pos) {
return ((pos[0] != null) && (pos[1] != null)) ? pos[0].substring(0, 3) +
"* " + pos[0].substring(3, 5) + "' " + pos[0].substring(6, 10) + "\" " + pos[1] : "";
}

private String formatAlt(String[] alt) {
return ((alt[0] != null) && (alt[1] != null)) ? alt[0] + " " + alt[1] : "";
}

public String getTime() {
return formatTime(time);
}

public String getLongitude() {
return formatLong(longitude);
}

public String getLatitude() {
return formatLat(latitude);
}

public String getAltitude() {
return formatAlt(altitude);
}

|

Listing 4. Format and get methods

To read all UART data, we need to create a listener class called MyUARTListener that implements UARTEventListener with a synchronized method eventDispatched (see Listing 5).

|

class MyUARTListener implements UARTEventListener {
@Override
public synchronized void eventDispatched(UARTEvent event) {
if (event.getID() == INPUT_DATA_AVAILABLE) {
ByteBuffer buffer = ByteBuffer.allocateDirect(10);
try {
int nrocar = uart.read(buffer);
char c;

                for (int i = 0; i \< nrocar; i++) {
                    c = (char) buffer.get(i);
                    nmea = nmea.concat(String.valueOf(c));
                }

                if (nmea.contains("\\r\\n")) {
                    //System.out.println(nmea);
                    if (nmea.contains("$GPGGA")) {
                        processNMEA(nmea);
                    }
                    nmea = "";
                }
            } catch (IOException ex) {
                Logger.getGlobal().log(Level.WARNING, ex.getMessage());
            }
        }
    }

}

|

Listing 5. Listener class MyUARTListener

When data is available, we parse it with the processNMEA method (see Listing 6). We use this method to read all the GPS data into a special String that begins with the $GPGGA tag.

|

private void processNMEA(String message) {
try {
StringTokenizer tokens = new StringTokenizer(message, ",");
// pull off the first token and check if it is the message we want
//$GPGGA,130612.255,,,,,0,00,,,M,0.0,M,,00 (no info)
//$GPGGA,161229.487,3723.2475,N,12158.3416,W,1,07,1.0,9.0,M,,,,0000*18 (with info)

    tokens.nextToken(); // $GPGGA position
    // Next token is the time
    time = tokens.nextToken();
    latitude\[0\] = tokens.nextToken();
    latitude\[1\] = tokens.nextToken();
    if ((latitude\[0\].equals("0")) || (latitude\[1\].equals("00"))) {
        Logger.getGlobal().log(Level.FINE, "Time: " + formatTime(time) + " - No GPS satellite link...");
    } else {
        longitude\[0\] = tokens.nextToken();
        longitude\[1\] = tokens.nextToken();
        // Skip the next three tokens
        tokens.nextToken(); // Position indicator
        tokens.nextToken(); // Satellites used
        tokens.nextToken(); // Horizontal Dilution of precision
        altitude\[0\] = tokens.nextToken();
        altitude\[1\] = tokens.nextToken();
        Logger.getGlobal().log(Level.FINE, "Time: " + getTime() + "\\n"
            + " Latitude: " + getLatitude() + " Longitude: " + getLongitude() + "\\n"
            + " Altitude: " + getAltitude() + "\\n");
    }
} catch (Exception ex) {
}

}

|

Listing 6. Parser method processNMEA

Finally, free all resources by closing the UART object (see Listing 7).

|

public void close() {
...
uart.setEventListener(UARTEvent.INPUT_DATA_AVAILABLE, null);
uart.close();
...
}

|

Listing 7. Closing the UART object and freeing the listener

Let's now create the Test MIDlet class called TestGPSEM406A to receive the time, latitude, longitude, and altitude from satellites, as shown in Listing 8.

|

public class TestGPSEM406A extends MIDlet {

private LoggingHandler loggerHandler = LoggingHandler.getInstance();
private GPSEM406ADevice gps;

@Override
public void startApp() {
    loggerHandler.start();
    Logger.getGlobal().setLevel(Level.ALL);
    try {
        gps = new GPSEM406ADevice();

    } catch (IOException ex) {
        ex.printStackTrace();
    }
}
@Override
public void destroyApp(boolean unconditional) {
    gps.close();
}

}

|

Listing 8. Test MIDlet for the EM-406a GPS device

Converting I2C Interface to UART by Connecting the I2C/SPI-to-UART Breakout Board

This is a breakout board for the SC16IS750, which is a handy chip used to convert I2C or SPI serial signals to a single-channel, high-performance UART interface. The input pins of the SC16IS750 are 5.5 V–tolerant, so this board should work with both 3.3 V and 5 V controllers. The following are some of its general features:

  • Single full-duplex UART interface
  • Selectable I2C-bus or SPI interface
  • 64-byte first-in, first-out (FIFO) transmitter and receiver
  • Full compatibility with industrial standard 16C450 and equivalent
  • Baud rates up to 5 Mb/sec in 16x clock mode
  • Auto hardware flow control using RTS/CTS
  • Auto software flow control with programmable Xon/Xoff characters
  • Single or double Xon/Xoff characters
  • Receive and transmit FIFO levels
  • Programmable special character detection
  • Line break generation and detection
  • Software reset

This chip has the following registers (addresses are shown in hexadecimal):

When LCR bit 7 = 0:

  • 00h: XHR (Receive/transmit holding register)
  • 02h: FCR (FIFO control register)
  • 03h: LCR (line control register)
  • 04h: MCR (Modem control register)
  • 05h: LSR (line status register)
  • 06h: MSR (modem status register)
  • 08h: XLVL (transmit FIFO level register)
  • 09h: RXLVL (receive FIFO level register)

When LCR bit 7 = 1:

  • 00h: DLL
  • 01h: DLH (division register)

To support these registers, create an enumeration called SC16IS750, as shown in Listing 9.

|

public enum SC16IS750 {
XHR(0x00),
FCR(0x02),
LCR(0x03),
MCR(0x04),
LSR(0x05),
MSR(0x06),
TXLVL(0x08),
RXLVL(0x09),
DLL(0x00),
DLH(0x01);

public int cmd;

private SC16IS750(int cmd) {
    //SC16IS740 expects a R/W bit first, 
    //followed by the 4 bit register address of the byte.
    //So shift the bits left by three bits:
    this.cmd = cmd \<\< 3;
}
...

}

|

Listing 9. Enumeration that defines all SC16IS750 registers

Let's now connect the SC16IS750 breakout board to the Raspberry Pi's 3.3 V, SCL, SDA, and GND pins, as shown in Figure 3, and create a Java ME 8 class called SC16IS750Device with its constructor using the control address to initialize the converter registers, as shown in Listing 10.

|

public class SC16IS750Device extends I2CRpi {

private static final int SC16IS750\_write = 0x48;

public SC16IS750Device() throws IOException {
    super(SC16IS750\_write);
    configUARTregs();
}

|

Listing 10. SC16IS750Device class with its constructor establishing the control address

Then create the following operation methods (see Listing 11):

  • configUARTregs: Configure all registers to establish I2C-to-UART conversion
  • write: Write a String to buffer data
  • bytesToRead: Bytes at buffer to be read
  • read: Read all bytes at buffer

|

private void configUARTregs() {
...
//Line Control Register: Enable Writing DLH & DLL
//& set no Parity, 1 stop bit, and 8 bit word length
SC16IS750.LCR.write(device, (byte) 0b10000011);

 //Division registers DLL & DLH
 // Write '96' to get 9600 baud rate
 // Assumes you have the version with the ~14MHz crystal
 // (16x9600 = 153600 = 14.7456Mhz/96)
 SC16IS750.DLL.write(device, (byte) 96);
 SC16IS750.DLH.write(device, (byte) 00);
 
 //Line Control Register: Disable Writing DLH & DLL
 //Same setup 
 SC16IS750.LCR.write(device, (byte) 0b00000011);

 //Modem Control Register
 //Normal Operating Mode
 SC16IS750.MCR.write(device, (byte) 0b00000000);

 //FIFO Control Register: Enable the FIFO and no other features
 SC16IS750.FCR.write(device, (byte) 0b00000111);

...
}

public void write(String cad) {
ByteBuffer buffer = ByteBuffer.allocateDirect(cad.length());
buffer.put(cad.getBytes());
buffer.clear();
try {
device.write(SC16IS750.XHR.cmd, 1, buffer);
} catch (IOException ex) {
Logger.getGlobal().log(Level.WARNING,ex.getMessage());
}
}

public int bytesToRead(){
return SC16IS750.RXLVL.read(device);
}

public int read(){
return SC16IS750.XHR.read(device);
}

|

Listing 11. Operation methods

Connecting the Text-to-Speech Module to the I2C/SPI-to-UART Breakout Board

The Emic 2 text-to-speech module is a multilanguage voice synthesizer that converts a stream of digital text into natural sounding speech. Its simple command-based interface makes it easy to integrate into any embedded system.

Here are some of its general features.

  • High-quality speech synthesis for English and Spanish languages
  • Nine predefined voice styles comprising male, female, and child
  • Dynamic control of speech and voice characteristics, including pitch, speaking rate, and word emphasis
  • Industry-standard DECtalk text-to-speech synthesizer engine (5.0.E1)
  • Communication: Asynchronous 9600 b/sec serial (8N1)
  • On-board audio power amplifier and 1/8-inch (3.5 mm) audio jack

Let's now connect the Emic 2 module's GND, SOUT, and SIN pins to the SC16IS750 breakout board's GND, RX, and TX pins, respectively, and connect its 5 V pin to the Raspberry Pi's 5 V pin, as shown in Figure 3. Then, create a Java ME 8 class called EMIC2Device with its constructor that creates an SC16IS750 object using class SC16IS750Device, as shown in Listing 12.

|

public class EMICI2CDevice {

private SC16IS750Device sc;

// Define all messages for Emic
private final String\[\] emic2Msgs = {
    "Emic 2 Ok.", //0
    "Hello my friends.", //1
    "I am testing I2C to UART converter.", //2
    "See you later.", //3
    "Bye.", //4
    "Hola como estan.", //5
    "Ahora hablo Espanol.", //6
    "Adios amigos."//7    
};

public EMICI2CDevice() throws IOException {
    //I2C Emic interface using SC16IS750
    sc = new SC16IS750Device();
}

|

Listing 12. EMIC2Device class with its constructor creating an SC16IS750 object

Create the following operation methods (see Listing 13):

  • msg: Write a predefined message
  • getMsg: Get a predefined message
  • write: Write a String
  • writeCommand: Send a command
  • waitResponse: Wait for Emic 2 response characters
  • close: Close UART communication

|

public void msg(int msgnum) {
write(emic2Msgs[msgnum]);
Logger.getGlobal().log(Level.FINE, emic2Msgs[msgnum]);
}

public String getMsg(int num) {
return emic2Msgs[num];
}

public void write(String cad) {
cad = "S " + cad.concat("\r\n");
sc.write(cad);
// Wait for response from Emic-2. It responds to all commands with :
waitResponse(2);
}

public void writeCommand(String cad) {
cad = cad.concat("\r\n");
sc.write(cad);
// Wait for response from Emic-2.
waitResponse(5);
}

private void waitResponse(int nrobytes) {
int work = 0;
//wait two chars :\n
while (work != nrobytes) {
work = sc.bytesToRead();
}
for (; 0 < work; work--) {
sc.read();
}
}

public void close() {
sc.close();
}

|

Listing 13. Operation methods

We can connect an headphone to the onboard 1/8-inch (3.5 mm) audio jack, but if we want to use a little speaker, the SparkFun mono audio amplifier module TPA2005D1 is recommended, as shown in Figure 3, with an additional 10K volume control potentiometer. We must connect SP- and SP+ from the Emic 2 to IN- and IN+ on the amplifier module's connector.

Let's now create the test MIDlet class called TestEMIC2 to hear the Emic 2 speak predefined messages in English and Spanish, as shown in Listing 14.

|

public class TestEMIC2 extends MIDlet {

@Override
public void startApp() {

...
EMICI2CDevice sc = new EMICI2CDevice();

        sc.writeCommand("W200");
        sc.writeCommand("L0"); //Set English
        sc.writeCommand("N0");
        sc.msg(0);
        sc.msg(1);
        sc.msg(2);
        sc.msg(3);
        sc.msg(4);
        sc.write("End of English Test.");
        
        sc.writeCommand("W200");
        sc.writeCommand("L1"); //Set Spanish
        sc.writeCommand("N0");
        sc.msg(5);
        sc.msg(6);
        sc.msg(7);
        sc.write("Fin de la prueba en Espanol.");

        sc.close();
...
}

...
}

|

Listing 14. Test MIDlet for Emic 2

Performing Some Additional Configuration

Before running our TestEM406A MIDlet using NetBeans IDE 8.0.2, it is important to establish the appropriate API permissions. To do this, in the IDE, select project JavaMEDemos, and then right-click and select Properties to show the Project Properties window. Select Application Descriptor, and then select the API Permissions tab. Include the following permission, as shown in Figure 4:

|

jdk.dio.uart.UARTPermission *:* , open

|

Figure4.jpeg

Figure 4. Establishing API permissions

Conclusion

The Raspberry Pi has a UART port that can be used for serial communication with some devices such as the EM-406a GPS device, but remember that it is very important to check voltage levels, because this port works at 3.3 V, not at the classic serial level of +/- 12 V.

By default, the UART port is used by the serial console and it must be released before you can manipulate it.

If you need to connect additional serial devices, you can use SC16IS750 modules that convert the I2C or SPI protocols to UART. You can use up to fifteen modules with distinct I2C addresses, and you can manipulate up to fifteen serial devices.

In the next article in this series, we will examine other types of sensors using other types of interfaces, such as serial peripheral interface bus (SPI).

See Also

About the Author

Jose Cruz (@joseacruzp) is a software engineer who has been working with Java since 1998. He is a lead developer of Java, Java ME, and Java EE at Ferreteria EPA C.A. in Venezuela. From an early age, his hobby has been electronics. This has led him to combine computing with electronics and develop projects where Java and embedded devices such as Arduino and Raspberry Pi are used.

Join the Conversation

Join the Java community conversation on Facebook, Twitter, and the Oracle Java Blog!

Comments

Post Details

Added on Jun 24 2015
0 comments
17,233 views