Shop OBEX P1 Docs P2 Docs Learn Events
Having fun with analog — Parallax Forums

Having fun with analog

iseriesiseries Posts: 1,540
edited 2026-04-19 22:42 in Propeller 2

I had a project that needed to read the voltage value from a device.

The P2 has this function but it not straight forward as using a voltmeter.

Each pin on the P2 has different calibration values so you need to determine what the low and high reading are. So, 0 volts and 3.3 volts have different value based on what pin you decide to use.

At first, I tried using a 5K pot to see how the values changed. Trying to set an exact voltage level on the pin is tedious at best.

I then remembered I had an AD5220 chip laying around somewhere if only I could remember where.

After finding it I wired it up and built a program to adjust the voltage programmatically from low to high and then some voltage I wanted to measure. I thought this was so neat that I had a board made so I could just plug this in and find the values of whatever pin I needed.

The AD5220 has 128 positions available and the only way to set it is start at the bottom or top and could each position. The newer variable resistor unit now use I2C or SPI to set what position you want but they are not bread board friendly.

By programming the AD5220 to a value I need to apply a voltage to a pin I can load a test program and test that voltage without having to touch a pot. Look ma no hands!

#include <stdio.h>
#include <propeller.h>
#include "smartpins.h"

void Check(void);
void Set(int, int);
int Status(void);


#define CK 22
#define CS 20
#define UD 21
#define POWER 36


int Low;
int High;
int Middle;
int Factor;
volatile int wait;


int main(int argc, char** argv)
{
    int i;
    int j;

    _pinh(CS);
    _pinl(CK);
    _pinl(UD);
    _pinl(CS);

    _pinstart(POWER, P_ADC | P_ADC_1X, 13, 0);

    printf("Starting\n");

    Check();

    printf("Low: %d, Middle: %d, High: %d\n", Low, Middle, High);

    Set(128, 0);

    Factor = (High - Low) * 10 / 33;

    printf("Per Volt Factor: %d\n", Factor);

    j = (High - Low) / 128;
    j = (Factor * 205) / j / 100; // ten amps = 2.5 + .4 / 2

    //j = 49;
    printf("Setting to 2V --> %d\n", j);

    Set(j, 1);

    _waitms(500);

    i = _rdpin(POWER) - Low;

    printf("Adjusted Reading: %d, %dV X 100\n", i, i * 100 / Factor);

    i = Status();

    printf("Read Time: %d useconds X 10\n", i);

    _pinh(CS);

    while (1)
    {
        _waitms(5000);
    }
}

void Check()
{
    int i;

    Set(128, 0);

    _waitms(500);
    Low = _rdpin(POWER);

    Set(128, 1);

    _waitms(500);
    High = _rdpin(POWER);

    Set(64, 0);

    _waitms(500);
    Middle = _rdpin(POWER);

}

void Set(int x, int ud)
{
    if (ud == 0)
        _pinl(UD);
    else
        _pinh(UD);

    _waitx(250);

    for (int i=0;i<x;i++)
    {
        _pinh(CK);
        _waitx(250);
        _pinl(CK);
        _waitx(250);
    }
}

int Status()
{
    int i;
    int useconds = 0;
    int v;
    int t;

    while (_pinr(POWER) == 0);

    for (i=0;i<10;i++)
    {
        t = _getus();
        while (_pinr(POWER) == 0);
        v = _rdpin(POWER);
        useconds += _getus() - t;
    }

    return useconds;
}

By running this program, it will give me the low, high and conversion factor for any given pin.

Mike

Comments

  • Hi,
    if 8 bit resolution is fine, you can also use EVANH's SAR https://obex.parallax.com/obex/8-bit-sar-adc/ which does not need calibration.
    Cheers Christof

  • I've written a simple driver for analogue IO that is handy if you just need to read some potentiometers or measure a voltage and no special timing requirements have to be met and ~12 bits resolution and 8..10 bits accuracy is sufficient.

    You can simply call InitAdcPins() and it handles the calibration. Offset and gain is calibrated only once so thermal drift is not compensated over time. For most applications this is OK as pin-to-pin and IC-to-IC variations are usually much greater than thermal drift.

    By default, values are given in millivolts ranging from 0 to 3300. If required you can use different units by changing a constant. If anybody finds this useful I can put it into OBEX.

Sign In or Register to comment.