Programming the pcDuino

This Tutorial is Retired!

This tutorial covers concepts or technologies that are no longer current. It's still here for you to read and enjoy, but may not be as useful as our newest tutorials.

Pages
Contributors: SFUptownMaker
Favorited Favorite 3

Analog Input and Output

Unlike the Raspberry Pi, the pcDuino does have some analog input and output functionality. Here are examples of using the analog circuitry in your projects.

Hardware

Analog pin mapping on the pcDuino

Analog output on the pcDuino is accomplished via PWM. There are six PWM enabled pins in the Arduino-ish headers: 3, 5, 6, 9, 10, and 11. These, of course, correspond to the PWM pins on Arduino boards. Pins 5 and 6 are true 520Hz 8-bit PWM; the others are limited to a range of 0-20 at 5Hz. The high-level output for all the pins is 3.3V.

Analog input on the pcDuino is done through six dedicated pins labeled A0-A5 on the Arduino-ish headers. A0 and A1 are six-bit inputs, returning a value from 0-63 over a range from 0-2V; A2-A5 are 12-bit inputs operating across the full 3.3V range. Setting an analog reference on the AREF pin is not supported as of the time of this writing.

Analog in C++

Analog input is handled through standard file stream input: simply open the appropriate file and read the value. Values are read as a string, so an atoi() conversion is necessary to get an integer value to work with.

Analog output is handled through a command line interface. Piping a value into a particular file via the system() call allows you to set the PWM level on the appropriate pins; file streams do not work for this. Again, the file expects a string, not an integer, so you must format the output appropriately.

This example program fades the PWM pins from off to on, slowly, then prints the output of each analog input.

language:cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include "analog.h"

int adc[6];     // Array for file descriptors for the adc pins
int PWMMaxVal[6]; // Store the max values for the PWM outputs
char path[64];  // Nice big buffer for constructing file paths

int main(void)
{
  // For starters, let's create file descriptors for all the ADC pins. PWM is
  //   handled differently; see the analogWrite() function for details.
  for(int i = 0; i<= 5; i++)
  {
    memset(path, 0, sizeof(path));
    sprintf(path, "%s%s%d", ADC_IF_PATH, ADC_IF_FILE , i);
    adc[i] = open(path, O_RDONLY);
    memset(path, 0, sizeof(path));
    sprintf(path, "%s%s%d/%s", PWM_IF_PATH, PWM_IF_FILE , i, PWM_MAX);
    int PWMMaxFD = open(path, O_RDONLY);
    char PWMMaxStr[4];
    read(PWMMaxFD, PWMMaxStr, sizeof(PWMMaxStr));
    PWMMaxVal[i] = atoi(PWMMaxStr);
  }

  // Now, we'll blast all the PWM pins to zero. 
  for(int j = 0; j<=5; j++)
  {
    analogWrite(j, 0);
  }

  // Now we can go about the business of dimming some LEDs. 
  for(int j = 0; j<=5; j++)
  {
    for(int i = 0; i<=255; i++)
    {
      analogWrite(j, i);
      usleep(10000);
    }
    analogWrite(j, 0);
  }

  // Analog input is handled by file streams.
  for (int i = 0; i <= 5; i++)
  {
    char ADCBuffer[16];
    lseek(adc[i], 0, SEEK_SET);
    int res = read(adc[i], ADCBuffer, sizeof(ADCBuffer));
    int ADCResult = atoi(ADCBuffer);
    printf("ADC Channel: %d Value: %s", i, ADCBuffer);
  }
}

  // PWM pin access is handled by
  //   using the system() command to invoke the command process to execute a
  //   command. We assemble the command using sprintf()- the command takes
  //   the form
  //   echo <value> > /sys/class/leds/pwmX/brightness
  //   where <value> should be replaced by an integer from 0-255 and X should
  //   be replaced by an index value from 0-5
void analogWrite(int pin, int value)
{
  memset(path, 0, sizeof(path));
  value = (PWMMaxVal[pin] * value)/255;
  sprintf(path, "echo %d > %s%s%d/%s", value, PWM_IF_PATH, PWM_IF_FILE, \
    pin, PWM_IF);
  system(path);
}

Analog in Python

As usual, the Python code mirrors C++ functionally, but is somewhat simpler. The code performs a very similar operation to the C++ program--fade the PWM pins, then spit out the analog inputs.

language:python
#!/usr/bin/env python

import time, os

## For simplicity's sake, we'll create a strings and filenames for our paths
ADC_PATH= os.path.normpath('/proc/')
ADC_FILENAME = "adc"
PWM_PATH= os.path.normpath('/sys/class/leds/')
PWM_DIR = "pwm"
PWM_FILENAME = "brightness"
PWM_MAX = "max_brightness"

## create empty arrays to store the pointers for our files
adcFiles = []
pwmFiles = []
pwmMaxFiles = []

## create an empty array to store the maximum value for each channel of PWM
pwmMaxVal = []

## Populate the arrays with paths that we can use later.
for i in range(0,6):
  adcFiles.append(os.path.join(ADC_PATH, ADC_FILENAME+str(i)))
  pwmFiles.append(os.path.join(PWM_PATH, PWM_DIR+str(i), PWM_FILENAME))
  pwmMaxFiles.append(os.path.join(PWM_PATH, PWM_DIR+str(i), PWM_MAX))

## Now, let's scan the PWM directories and pull out the values we should use
##   for the maximum PWM level.
for file in pwmMaxFiles:
  fd = open(file, 'r')
  pwmMaxVal.append(int(fd.read(16)))
  fd.close()

## Let's dim some LEDs! The method for controlling a PWM pin on the pcDuino is
##   to send to the command interpreter (via os.system() this command:
##   echo <value> > /sys/class/leds/pwmX/brightness
##   where <value> varies from 0 to the maximum value found in the
##   max_brightness file, and X can be from 0-5.
for file in pwmFiles:
  j = pwmFiles.index(file)  ## extract the PWM limit for this LED
  for i in range (0,pwmMaxVal[j]):
    os.system("echo " + str(i) + " >" + file)
    time.sleep(.01)
  os.system("echo 0 >" + file)

## Reading ADC values is a little more straightforward than PWM- it's just
##   classic OS file reads. Note that the value that comes out of the file is
##   a string, so you'll need to format it with int() if you want to do math
##   with that value later on!
for file in adcFiles:
  fd = open(file, 'r')
  fd.seek(0)
  print "ADC Channel: " + str(adcFiles.index(file)) + " Result: " + fd.read(16)
  fd.close()