Introduction: Simulated Analog/digital Converter for RaspberryPi

About: Jack passed away May 20, 2018 after a long battle with cancer. His Instructables site will be kept active and questions will be answered by our son-in-law, Terry Pilling. Most of Jack's instructables are tuto…

It is hard to get numeric data into a RaspberryPi through the GPIO because it does not have an analog to digital converter. This instructable shows how to time the charging and discharging of a capacitor to read a resistive sensor. The demonstration uses a photocell and a force sensitive resistor to control the brightness and blink rate of an LED, and it shows how to use millis() so changes happen instantly instead of having to wait for delay().

This is not a true analog to digital converter.

You will need a RaspberryPi, a breadboard, and a way to run wires from the RaspberryPi to the breadboard. You can use male/female jumper wires but one of the Pi Cobblers listed on this page from Adafruit will make it a lot easier: http://www.adafruit.com/search?q=cobbler

You will also need:

* This is a very handy assortment of resistors https://www.sparkfun.com/products/10969

.

This project uses the wiringPi libraries, written by Gordon Henderson, for programming the GPIO in C in a style similar to the Arduino IDE.

wiringPi must be installed.

Instructions for download, install and use are located at http://wiringpi.com

wiringPi uses it's own pin numbering scheme.

All pin numbers mentioned in the program or in the text are wiringPi numbers unless otherwise specified.

After installing wiringPi you can obtain a list showing the pin numbering for your specific model of RaspberryPi by opening a command terminal and typing:

gpio readall

.

This is my first attempt at reading the time it takes to charge a capacitor. In my latest attempt I use a better method counting microseconds instead of times through a loop. It gives much more stable results:

https://www.instructables.com/id/RaspberryPi-Multip...

Step 1: LED and Resistor

This is optional, but I found that having a bunch of these made up makes breadboarding a lot easier.

Solder a resistor to the cathode lead of some LEDs. The cathode lead is the shorter negative (ground) lead.

270 - 560 ohms works good for on the RaspberryPi, for an Arduino use 330 - 680 ohm resistors. I usually make them with 470 - 560 ohm resistors so they will work with both.

Step 2: Building the Circuit

Build the circuit as shown in the diagram.

Note that the pin marked DNC in the first photo is a ground.

Step 3: The Program

The RCtime() function does the reading of the sensors. I tried to write it as generic as possible so it can be lifted out and used in other programs. You might find some times where some adjustments will need to be made for calibration. Example, in the loop function in this line "if(toggle) pwmWrite(ledPin, photocellReading*4);" I multiply the photocell reading by 4. Your results may vary, I have two of the same photocells and they behave differently.

When I first started working on the project I did my first experimenting on an Arduino. When I had it working I transferred it to the RaspberryPi, and it didn't work. It took me a long time to figure out what was wrong. The RaspberryPi is no hot rod but it is many times faster than an Arduino. The solution was to add the "delay(2)" in the RCtime() function to give the capacitor time to discharge.

The code for the blink rate uses millis() instead of delay() because the whole program stops running during a delay(). By using millis() the program keeps running and changes are immediate. "time" is a global variable defined just below the program heading and the includes. It is initialized in the setup() function. Notice the use of the time, and toggle variables as well as the millis() function in the loop() function to see how this is done.

/***********************************************************************       
 * Filename ResCap.c
 * This program demonstrates a way to simulate an analog read by measuring 
 * the time it takes to charge a capacitor through a variable resistor.
 * It uses a photocell and a force sensitive resistor but the technique will 
 * work to read a potentiometer or any resistive sensor.
 ***********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wiringPi.h>

int photocellPin = 0;   // Photocell and capacitor connected to pin zero.
int fsrPin = 2;         // Force sensitive resistor and capacitor connected to pin two.
int ledPin = 1;         // The LED connected to pin one.
int toggle = 1;            // On/off state of LED.

unsigned long time;     // Save the time to set the blink rate.
/***********************************************************************        
 * RCtime() - Function, uses a digital pin to measure a resistive sensor
 * by first discharging capacitor then measuring the time it takes to 
 * charge the capacitor through a variable resistor. When the voltage 
 * rises to Vcc/2 the pin will go high.
 ***********************************************************************/
int RCtime(int RCpin)
{
  int PinVal = 0;                     // Start with zero.
                                      
  pinMode(RCpin, OUTPUT);             // Set pin to output and pull to LOW. (ground)
  digitalWrite(RCpin, LOW);

  delay(2);                           // Allow time to let capacitor discharge.
                          
  pinMode(RCpin, INPUT);              // Now set the pin to an input and...
  while (digitalRead(RCpin) == LOW) 
  {                                   // Count how long it takes to rise up to HIGH.
    PinVal++;                         // Increment to keep track of time.
    if (PinVal == 30000) 
    {
      break;                          // if we got this far, the resistance is to high,
    }                                 // no input to sensor, leave the loop.
  }                                   
  PinVal = PinVal/25;                 // Divide by 25 for calibration.

  if(PinVal > 1023) PinVal = 1023;    // Cap The value at 1023.

  return PinVal;                      // Returns zero - 1023.
}
/**************************************************************************        
 * loop() - function runs in a continuous loop until program is stopped.
 *
 * More presure on the force sensitive resistor makes the LED blink faster.
 * More light on the photocell makes the light dimmer.
 **************************************************************************/
void loop(void)
{
  int photocellReading = RCtime(photocellPin); // Read photocell.
  int fsrReading = RCtime(fsrPin);             // Read force sensitive resistor.

  if(millis()-time > (fsrReading))
  {
    toggle = !toggle;          //If true not toggle 
    time = millis();           //and reset time.
  }
 
  if(toggle) pwmWrite(ledPin, photocellReading*4);
  else pwmWrite(ledPin, 0);

//  printf("photocell %d - fsr %d\n", photocellReading, fsrReading); // uncomment for debugging.
}
/***********************************************************************        
 * setup() - function is run by main() one time when the program starts.
 ***********************************************************************/
void setup(void)
{
  wiringPiSetup();   // Required.

  pinMode(ledPin, PWM_OUTPUT);

  time = millis();   // Save the time to set the blink rate.
}
/***********************************************************************        
 * main() - required
 ***********************************************************************/
int main(void)
{
  setup();

  while(1)
  {
    loop();
  }
}

Attachments