Read analog data, in Java Raspberry PI

The goal here is to read analog data from a Java program running on a Raspberry PI.
For this example, we will be using a potentiometer like this one.

When the user turns the knob of the potentiometer, its resistance will vary, and the output current will go from 0 Volt (0%) to 3.3 Volts (100%).
We want to catch those numbers from a Java program running on a Raspberry PI.
If we can do that, we can easily replace the potentiometer with a thermometer, a photovoltaic cell, a pressure sensor, and earthquake detector…, whatever can send an analog signal.

Read analog data, in Java Raspberry PI

The connectors

The Raspberry Pi has a General Purpose Input Output interface (GPIO), the programmable pins can be either on or off, but nothing in between. In (very) short, off means 0 Volt, on means 3.3 Volts.
This is why we need an Analog to Digital Converter (ADC), featured here.
We will connect the GPIO interface of the Raspberry Pi on a Cobbler pinned into a breadboard, next to the ADC.

The Software part

Talk to the MCP3008

The most important here is probably to understand how an ADC works.
Donald Norris gives a good explanation in his book Raspberry Pi Projects for the Evil Genius, but here is a quick summary.
In such a communication – like between the Raspberry Pi and the MCP3008, you need a Master and a Slave.

The Raspberry PI will play the Master.
The MCP3008 will play the Slave.

  1. The fisrt clock pulse (CLK) received by the MCP3008 with its CS pin held low and its DIN pin held high will constitute the start bit.
  2. The SLG/DIFF bit follows next, and the 3 bits that represent the selected channel(s).
  3. After those 5 (start, SLG/DIFF, 3 channel-bits) bits have been received, the MCP3008 will sample the analog voltage during the next clock cycle.
  4. The MCP3008 then outputs what’s known as a low null bit, disregarded by the Raspberry PI.
    The following 10 bits – each sent on a clock cycle – are the ADC values. Most Significant Bit (MSB) is sent first, Least Significant Bit (LSB) is sent last.
  5. The Raspberry PI will then put the MCP3008 CS pin high, ending the ADC process.

What we are interested in are those 10 bits mentioned just before (step 4).
On a 10-bit word, it is possible to represent 210 states, which is 1024. This way, 1024 states can be represented, ranging from 0 to 1023.
From the Raspberry PI, you send a clock pulse by turning the CLK pin on and off. This CLK pin is connected to the GPIO1, according to the table and wiring diagram mentioned above.
You will see in the code that we are using MISO and MOSI.
MISO stands for Master In Slave Out.
MOSI stands for Master Out Slave In.

How it translates in Java

Note: For clarity, we showcase here a simple, unique Java class. The code could be much better architected by implementing an Observer and a Listener. Such a code is also available, see in the repository the classes in the adc package, namely adc.ADCObserver, adc.ADCListener and adc.ADCContext. An example showing how to use them is featured in adc.sample.SampleMain.

The heart of this program is the method readAdc(). It uses the pins mentioned earlier, identified with the classes and methods provided by PI4J.

    77    private static int readAdc()
    78    {
    79      chipSelectOutput.high();
    81      clockOutput.low();
    82      chipSelectOutput.low();
    84      int adccommand = ADC_CHANNEL;
    85      adccommand |= 0x18; // 0x18: 00011000
    86      adccommand <<= 3;
    87      // Send 5 bits: 8 - 3. 8 input channels on the MCP3008.
    88      for (int i=0; i<5; i++) //
    89      {
    90        if ((adccommand & 0x80) != 0x0) // 0x80 = 0&10000000
    91          mosiOutput.high();
    92        else
    93          mosiOutput.low();
    94        adccommand <<= 1;      
    95        clockOutput.high();
    96        clockOutput.low();      
    97      }
    99      int adcOut = 0;
   100      for (int i=0; i<12; i++) // Read in one empty bit, one null bit and 10 ADC bits
   101      {
   102        clockOutput.high();
   103        clockOutput.low();      
   104        adcOut <<= 1;
   106        if (misoInput.isHigh())
   107        {
   108  //      System.out.println("    " + misoInput.getName() + " is high (i:" + i + ")");
   109          // Shift one bit on the adcOut
   110          adcOut |= 0x1;
   111        }
   112        if (DISPLAY_DIGIT)
   113          System.out.println("ADCOUT: 0x" + Integer.toString(adcOut, 16).toUpperCase() + 
   114                                   ", 0&" + Integer.toString(adcOut, 2).toUpperCase());  115      }
   116      chipSelectOutput.high();
   117     118      adcOut >>= 1; // Drop first bit
   119      return adcOut;
   120    }

Read analog data, in Java Raspberry PI Schematic

otice that the steps of the readAdc method are the ones we described in the MCP3008 section.
Bits are read one by one, appropraitely shifted in an int, and returned to the caller.
This readAdc() method is called in a loop from the main method. A SIGTERM (Ctrl+C) will terminate the program.
The value returned by the readAdc method is an int ranging from 0 to 1023, as we said before. This value is converted into a percentage (by dividing it by 10.23, which is 1023 / 100). This value will be sent to the output (displayed) only if it is different from the previous reading.
The loop waits for 100 ms (1/10 s) at its bottom.


For more detail: Read analog data, in Java Raspberry PI

Scroll to Top
Read previous post:
How to Use Signal Values and Messages to Read Multiple Inputs

Those who have worked on simple microcontrollers know how difficult it is to continuously check for an input pin status...