Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses

Perl interface to analog inputs on the Raspberry Pi

by stevieb (Abbot)
on Jan 11, 2017 at 16:16 UTC ( #1179406=CUFP: print w/replies, xml ) Need Help??

Over the last few months, I've been writing Perl modules/distributions to interact with a Raspberry Pi, its GPIO, and external hardware/devices. My primary objective is to create a complete indoor grow room automation system.

The past week and a half, I have been focusing on writing a distribution that provides Perl users a way to interact with Adafruit's ADS1xxx Analog to Digital Converters (ADC), so that I could communicate with analog devices via the Pi which does not have any analog inputs. Hence, RPi::ADC::ADS was born.

The vast majority of functionality specified in the unit's datasheet has been incorporated into this XS-based module, and the documentation outlays all of the critical pieces from the hardware docs.


  • operates on the i2c bus, can connect four units simultaneously for a total of 16 analog inputs
  • ability to access all four channels on each ADC
  • continuous and single conversion modes
  • all eight Data Rate settings available
  • ability to change comparator polarity
  • ability to modify the comparator queue
  • all programmable gain amplifier modes available
  • ability to operate in single-ended mode or differential mode**
  • ability to return either the input data as raw, as a percentage, or as voltage
  • very easy to configure and run; most users won't have to set any parameters or call any configuration methods; the defaults are very sane
  • the documentation is extensive and detailed, but easy to understand and laid out reasonably well (I hope)
  • it has zero dependencies, Perl or otherwise (well, other than the need for a C compiler for the XS file)
  • works with any ADS1xxx model, and will properly bit-shift according to whether we're on a 16-bit wide resolution model, or a 12-bit one

** - single-ended mode is the measurement of voltage of a single input relative to ground. Differential mode retrieves the voltage difference between two separate inputs.

Here's a basic example, and for the most part, exactly how I use the software. Say I have a moisture sensor connected to analog input A0 (0 as far as the software is concerned) and I want to get the moisture level from it:

use warnings; use strict; use RPi::ADC::ADS; my $adc = RPi::ADC::ADS->new; my $v = $adc->volts; my $p = $adc->percent; my $r = $adc->raw;

Volts is a floating point number, percent is a float chopped at .2f and raw is the raw 16-bit unsigned int.

If you have more than one channel active at a time, specify which channel you want to fetch from:

# A0, A1 and A3 input channels for (0, 1, 3){ print $adc->percent($_) ."\n"; }

All configuration register options can be changed on the fly, as they each have their own setter/getter. Say you are using two inputs (eg: A0 and A3) as single-ended inputs and at one point in code, you need to retrieve the value of the difference in levels between them. The documentation has a map for parameter value to hardware functionality for all settings. All fetch methods allow you to send in the channel to retrieve on the fly, so we don't have to do anything special here. Per the map in the docs above, either of these will work:

my $diff_a0_a3 = $adc->percent(5); # or $adc->channel(5); my $diff_a0_a3 = $adc->percent;

The software is quite complete, and I have tested the vast majority of the configuration settings. I'm about 85% test coverage so there's a bit more work to do there, but I digress.

My next project is to write a Perl distribution for a BMP 180 barometric and altimiter sensor which I just bought and soldered yesterday, and an MCP3008 analog-digital converter. The 3008 has 10 input channels whereby the ADS only has four, but the ADS has 12-bit or 16-bit of resolution accuracy, where the MCP3008 only has 10-bit, so I decided I'd write code for both.

See also:

WiringPi::API, my original and nearly feature complete wrapper for the WiringPi libraries.

RPi::WiringPi, OO interface for the above wrapper with error detection, safe exit on unexpected terminations, and more.

RPi::DHT11, module to access the DHT11 temperature and humidity sensor.

App::RPi::EnvUI, my Dancer2 and jQuery one-page app for indoor grow room control (not yet fully completed).

RPi::WiringPi::Constant, module that contains commonly used names in the Raspberry Pi/electrical/electronics realm.

Replies are listed 'Best First'.
Re: Perl interface to analog inputs on the Raspberry Pi
by Discipulus (Monsignor) on Jan 12, 2017 at 08:51 UTC
    Congratulations! is big jump in just 6 months!

    Continue sharing please; one day I hope I'll have enough spare time to jump on Perl's electronic point of view.


    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Perl interface to analog inputs on the Raspberry Pi
by Anonymous Monk on Jan 11, 2017 at 21:31 UTC
    Congratulations. You may have posted the most valuable piece of content to this site in nearly 10 years. Great job!

      I wouldn't go near that far, but thanks nonetheless!

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: CUFP [id://1179406]
Approved by haukex
Front-paged by Corion
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (6)
As of 2018-01-20 23:04 GMT
Find Nodes?
    Voting Booth?
    How did you see in the new year?

    Results (227 votes). Check out past polls.