We do not take any responsibility for possible errors in the guide or errors that you might do wiring it up. Incorrect wiring can result in damaged sensor or damaged Raspberry Pi.
| Product | Version |
|---|---|
| IDE | Xojo 2023r4 |
| GPIO Library | Einhugur I2C Plugin 1.1 |
| Electronics board | ADS1115 |
| Raspberry Pi | 5 |
Install I2C Plugin for use with Xojo
It is presumed that a Raspberry PI 4B or 5 is being used with the latest Raspberry Pi OS, and the program is running in
64-bit mode. This project uses Björn Eiríksson’s I2C plugin, which can be downloaded here.
More documentation is available at Björn’s website.
On the Raspberry Pi, install the libi2c with the following command at a terminal:
sudo apt-get install i2c-tools
Copy the I2C Plugin.xojo_plugin and place it in the Xojo plugins folder.
On my system in Windows 11, its located at: C:\Program Files\Xojo\Xojo 2023r4\Plugins
ADS1115 Analogue-to-Digital Converter (ADC)
The ADS1115 analogue-to-digital sensor can measure analogue voltages and send the data through an I2C (Inter-Integrated-Circuit) communication protocol to be read by the Raspberry Pi and the data shown on the screen. The I2C (Inter-Integrated-Circuit) to allow many devices to be read and written with through same two-wires that are connected to other devices.
This sensor works well with the Raspberry Pi because it works well with the 3.3-volt power supplied by the motherboard. There is a rheostat which changes the voltage by spinning the control clockwise or counterclockwise.
The following screen grab shows the output when running the program on the Raspberry Pi.
Note: The voltage does not typically need to be calibrated.
Figure 1. Example ADS: Reading an analogue voltage screen grab.
This screen grab shows a voltage of 1.846. A range of 0.0-volts to 3.3-volts is available with the current settings placed in the program for this chip.
Pressing the button will start a timer that reads data from the ADS1115 and refreshes the output on the TextArea control.
The breadboard layout with connections to the MPL3115A2 are shown below.
Figure 2. ADS1115 Breadboard layout.
The ADS1115 board works with Raspberry Pi’s 3.3-volts and is connected to Vin, while the GND connection is wired to ground. The SCL and SDA connections are made from the motherboard to the ADS1115.
The last connection is to add a variable rheostat to change the voltage to be read by the ADS1115, and a 4.7k-ohm resistor to maximize the life of the ADS1115 by lowering the milliamps to the sensors input pin. That’s all the connections that are needed.
To identify the address of the ADS1115, type the following command in a terminal on the Raspberry Pi. The number one is the bus number 1.
I2cdetect -y 1
The hexadecimal address should appear in the terminal as shown below.
Figure 3. Detecting ADS1115 I2C Address.
The hexadecimal address is 48, or in Xojo terms this is &H48, and the decimal number is 72.
With the large number of constants for the ADS1115, a Xojo module has been created called ADS1115 with the many constants that can be used.
With the wiring complete, creation of the program which makes the Xojo program interact with the Raspberry Pi can begin. Start Xojo and create a Desktop program, and then save the program as ADS.
Add the following four controls to the Windows1 control.
| Control | Name | Settings |
|---|---|---|
| DesktopLabel | Label1 | Text: Measure Analogue Voltage |
| DesktopTextArea | TextArea1 | |
| DesktopButton | BtnReadADS1115 | Text: Read ADS1115 |
| Timer | Timer1 | Runmode: Off Period: 1000 |
To allow properties to be used across methods, create the following properties in Window1.
| Property | Type |
|---|---|
| adapter | I2C.Adapter |
The adapter property class will hold the location of the handle file that is in memory, and the bus integer property is the bus line number (usually 1 on Raspberry Pi) that is determined by using the number 1 when typing i2cdetect -y 1 <- this one
Create an Opening event in Window1 and add the following code to initialize the adapter.
Code 1. Window1 Opening Event
Sub Opening() Handles Opening
//Open the bus (1) and address (&H48)
adapter = I2C.Adapter.Open(1) // The the Adapter ID here (Bus)
adapter.SetAddress(&H48) /// Device ID here (your ADS1115)
End Sub
The global adapter property is initialized with the Bus adapter ID first, and then the address of the I2C communication is used. This is determined with the i2cdetect -y 1 command. The default setting is &H48 on my ADS1115 – I2C.
Conserving good programming form, there is a closing event which releases the adapter in the Closing event.
Code 2. Window1 Closing Event
Sub Closing() Handles Closing
//Close to release the gpio
adapter.Close
End Sub
When the button pressed event occurs, the timer is either started, or stopped.
Code 3. BtnReadADS1115 Pressed Event
Sub Pressed() Handles Pressed
//Start and Stop the timer by pressing the button
If Timer1.RunMode = timer.RunModes.Multiple Then
Timer1.RunMode = timer.RunModes.Off
BtnReadADS1115.Caption = "Stopped"
Else
Timer1.RunMode = timer.RunModes.Multiple
Timer1.Period = 1000
BtnReadADS1115.Caption = "Running"
End If
End Sub
And If-Else statement is used to determine text on the button and start or stop the timer by changing the RunMode of the timer. When the timer begins to run, the refresh time is set to 1000 milliseconds, or 1-second.
Most of the code to read and write the ADS1115 is in the Timer1 Action event, shown below.
Code 4. Timer1 Action Event
Sub Action() Handles Action
Var Data As UInt16
//&HB 1100 0011 1000 0000
//&HB ABBB CCCD EEEF GHII
//Address pointer register
//A = Operational Status
//BBB = Input Multiplexer configuration
//CCC = Programmable Gain Amplifier
//D = Device Operating Mode
//EEE = Data Rate - Samples Per second
//F = Comparator Mode
//G = Comparator Polarity
//H = Latching Comparitor
//II = Comparator queue and disable
//Clear the textarea control
TextArea1.Text = ""
//Create the ADS1115 settings
Var HighByte, LowByte as UInt8
HighByte = ONESHOT_ON + AI_Pin0 + V_GAIN2
LowByte = SPS128 + Comp_Mode_Trad + Comp_Lat_Non + Comp_Que_One
//Swap bytes
Var Setting1 as UInt16 = (LowByte*256)+HighByte
//Set ADS1115 with requested settings
adapter.WriteWord(ADS1115_REG_PTR_CONFIG, Setting1)
//Allow time for settings to take effect
Thread.SleepCurrent(10)
//Read the raw voltage from ADS1115
Data = adapter.ReadWord(ADS1115_REG_PTR_CONVERT)
//Swap bytes
Var result as int16
result = LSBToMSBWord(Data)
//Convert Raw answer to voltage
Var answer as Double
answer = (result * 4.096)/32768
//Show voltage in TextArea1
TextArea1.Text = TextArea1.Text + "Volt: " + Format(answer, "#.000") + EndOfLine
End Sub
The general process of this code is to determine the settings for the reading, such as the pin location to read the voltage, range of voltage, number of measurements per second, etc. Then take these settings, write them to the ADS1115, and then read the data based on these settings. If the incorrect settings are written, then wrong data will be returned.
//Conversions
Const ONESHOT_ON = &B10000001
Const ONESHOT_OFF = &B00000000
The constant ONESHOT_ON is a binary representation for setting a single conversion reading on demand, which allows the ADS1115 to save power between measurements. If the setting is ONESHOT_OFF, then power is continuously supplied to the chip to retrieve measurements.
//Input Pin Multiplexer
Const AI_Pin0 = &B01000000 //Single Pin 0 and GND
Const AI_Pin1 = &B01010000 //Single Pin 1 and GND
Const AI_Pin2 = &B01100000 //Single Pin 2 and GND
Const AI_Pin3 = &B01110000 //Single Pin 3 and GND
Const AI_Pin01 = &B00000000 //Pin 0 and Pin 1 Differential
Const AI_Pin03 = &B00010000 //Pin 0 and Pin 3 Differential
Const AI_Pin13 = &B00100000 //Pin 1 and Pin 3 Differential
Const AI_Pin23 = &B00110000 //Pin 2 and Pin 3 Differential
An input pin multiplexer is required to determine where and how the voltage is to be measured. This example will measure the voltage of power applied to the individual A0 pin, which uses the constant value AI_Pin0. If you want to measure the difference between two voltage pins, then use AI_Pin01. AI_Pin01 will measure the difference between Pin 0 (1.58 volts) and Pin 1 (0.48 volts) which will provide the value 1.10 volts.
//Voltage gain pin measurement
Const V_GAIN1 = &B00000000 //Full Scale Voltage is: 0-6.144 volts
Const V_GAIN2 = &B00000010 //FS 0-4.096 volts
Const V_GAIN3 = &B00000100 //FS 0-2.048 volts (default)
Const V_GAIN4 = &B00000110 //FS 0-1.024 volts
Const V_GAIN5 = &B00001000 //FS 0-0.512 volts
Const V_GAIN6 = &B00001010 //FS .256 (&Ha)
Const V_GAIN7 = &B00001100 //FS .256 (&Hc)
Const V_GAIN8 = &B00001110 //FS .256 (&He)
Voltage gain is the range of the input voltages to the pin. In our example we are measuring voltage for the Raspberry Pi, which is 3.3 volts, so the appropriate range is 0-4.096 volts, which uses the constant V_GAIN2. This is the most common voltage range used with the Raspberry Pi.
Const ADS1115_REG_PTR_CONVERT = &H00 //Read
Const ADS1115_REG_PTR_CONFIG = &H01 //Write
Const ADS1115_REG_LO_THRESH = &H02
Const ADS1115_REG_HI_THRESH = &H03
When the register reads the latest voltage reading on the ADS1115, the ADS1115_REG_PTR_CONVERT register is accessed. Register constant ADS1115_REG_PTR_CONFIG configures, or writes the requested settings to the ADS1115. Low and high thresholds are added for advanced options, such as when a voltage is above a higher threshold, such as 2.9 volts, then cause the trigger to fire and then do something with this information. Low threshold provides the same trigger, except with a low-voltage trigger, such as anything below 0.3 volts – for example.
//Sampling Rate
Const SPS8 = &B00000000 //8 samples per second
Const SPS16 = &B00100000 //16 samples per second
Const SPS32 = &B01000000 //32 samples per second
Const SPS64 = &B01100000 //64 samples per second
Const SPS128 = &B10000000 //128 samples per second (default)
Const SPS250 = &B10100000 //250 samples per second
Const SPS475 = &B11000000 //475 samples per second
Const SPS860 = &B11100000 //860 samples per second
SPS is the abbreviation for Samples-Per-Second the analogue-to-digital is able to read.
The lowest setting is 8 samples-per-second, while the fastest reading is at 860 samples per second. For our application, the default of 128 samples -per-second is used. High sample rates are typically used for alternating waves.
//Comparitors
Const Comp_Mode_Win = &B00010000 //Window comparitor
Const Comp_Mode_Trad = &B00000000 //Traditional comparitor (default)
The comparator mode uses a built-in comparison to be configured in two modes. A window comparator triggers an alert when the input voltage falls outside a specified range of a lower and upper threshold. A traditional (Trad) comparator mode triggers an alert when the input voltage crosses a single voltage, not a range. In our example, we are not using a trigger.
//Polarity
Const Comp_Pol_High = &B00001000 //Active High
Const Comp_Pol_Low = &B00000000 //Active Low (default)
When using a trigger, the active high value will trigger when the input voltage exceeds the upper limit. Using a low trigger is used when the input voltage decrease below a minimum value, which is when a low voltage indicates an alert condition.
//Latency
Const Comp_Lat_On = &B00000100 //Comparator latching
Const Comp_Lat_Non = &B00000000 //Comparator non-latching (default)
When the comparator latching is on, then the output will remain in an active state once the voltage crosses a voltage threshold. The ADS1115 will remain in the active state until the user clears the latch by reading from the register or resetting the comparator. Non-latching means that the output will only be active when the voltage is outside of the threshold parameters. Once the voltage is within the parameters then the trigger stops.
Const Comp_Que_One = &B00000000 //Assert after one conversion
Const Comp_Que_Two = &B00000001 //Assert after two conversions
Const Comp_Que_Four = &B00000010 //Assert after four conversions
Const Comp_Que_Disable = &B00000011 //Disable comparator and set Alert/Ready pin to high impedence (default)
These comparator constants configure the behaviour of the ADS1115, and this is in regards to how many conversions must be made before the comparator output occurs. This helps filter out noise and ensures a trigger occurs when there are consistent readings. As an example, Comp_Que_One will trigger an alert after a single conversion threshold occurs, which is the most immediate response to changes in the input voltage. Comp_Que_Four will create a trigger when the last four consecutive conversions meet the threshold triggers. If disabled with Comp_Que_Disable, then no alert triggers will be generated, which is our case.
What is REALLY IMPORTANT is that the high-bit and low-bits which are written and read from the ADS1115 must be swapped on the Raspberry Pi to work.
//16 bit configuration
//&HB ABBB CCCD EEEF GHII
//Address pointer register
//A = Operational Status
//BBB = Input Multiplexer configuration
//CCC = Programmable Gain Amplifier
//D = Device Operating Mode
//EEE = Data Rate - Samples Per second
//F = Comparator Mode
//G = Comparator Polarity
//H = Latching Comparitor
//II = Comparator queue and disable
Setting the ADS1115 to retrieve the specific data you would like requires these 16-bits of data to be configured using the above constants. These constants have been made to allow easy addition in Xojo 2023r4. The high and low bytes must be swapped before reading and writing with the ADS1115. This structure allows you to control how the ADS1115 behaves.
A slight time pause is required to ensure the settings have been written, and for some data to have been internally read from the ADS1115.
Data is read in 16-bits and then the high and low bytes are swapped. Converting the 16-bit value to a decimal voltage is performed with the equation, and finally the voltage is shown in the TextArea control.
The ADS1115 is a very common voltage reader. This example shows how to build a program that can read the analogue voltage using I2C communication on the Raspberry Pi with Xojo 2023r4.