Wednesday, April 23, 2014

Adding Analog Pins to Arduino pt.2

Don't forget part 1: http://jazz-disassemblies.blogspot.com/2014/01/adding-analog-pins-to-arduino-pt1.html

The first step in part 2 of adding analog pins to an arduino is by getting rid of the MCP3008! Yes, I am sorry but that particular IC is overly complicated and too expensive for what it offers.

Since I wrote that first part, I began looking for alternatives because of the price of the MCP3008. Even in quantities of 10 or more, the IC was still more expensive than a bare Atmel microcontroller! At first I thought that I could buy another microcontroller for less than the MCP3008 at a fraction of the cost and even be able to simplify the methods of communication to my own liking.

After looking for the cheapest, yet adequately powerful uC, I came across the ATtiny48 which has several Analog inputs and even more digital IO's. The Analog inputs would in theory, be read, stored in variables and then transferred to the master microcontroller across an 8-bit wide data bus. The particular analog value that would be transferred would be selected by the master uC via three other pins; select bits. The pins were going to offer a binary value which would select the current pot to be transferred.

This method would allow for me to read many many more pots than the master microcontroller was equipped with, but at a large cost; the cost of many digital IO pins. One way to get those digital IOs back would be to use analogWrite on one of the PWM outputs and connect that pin to an analog input on the master uC. Considering that, I could sacrifice one analog input for 8 more. HOWEVER, the AT48 has no PWM outsputs. :(

After mulling over it for a long time, I realized what I had actually designed. The program I had spent an hour writing... The program that utilized the exact methods of communication to suite my exact needs...was, you guessed it: An analog multiplexer which decodes 3-to-8 inputs. They have an app...I mean IC for that. The 74HC4052 accepts two sets of 4 analog inputs and connects them to one of two outputs respectively. Two select bits, choose the analog input to transfer to the output.

The 4052 is a mere 50 cents, requires no external programming, runs on a large voltage range and comes in a variety of packages!

I will simply import photos and descriptions of my project, so that I can describe how to use the 4052.
Analog pins A0-A3 are used for higher priority data, so that leaves A4-A7 open. Again, we will also need two digital IO to use as select bits on the 4052.

// ***************************************************************
// define pin connections
// ***************************************************************

int pSelect0 = 3;
int pSelect1 = 4;

// ***************************************************************
// define variables
// ***************************************************************

// locate the delay between the select bits and the updated output
// of your 4052 IC and update this value:
int latency = 100; 

byte aVal00 = 0; // analog Value, 4052 # 0, input 0
byte aVal01 = 0; // analog Value, 4052 # 0, input 1
byte aVal10 = 0; // analog Value, 4052 # 1, input 0
byte aVal11 = 0; // analog Value, 4052 # 1, input 1

byte aVal02 = 0; // analog Value, 4052 # 0, input 2
byte aVal03 = 0; // analog Value, 4052 # 0, input 3
byte aVal12 = 0; // analog Value, 4052 # 1, input 2
byte aVal13 = 0; // analog Value, 4052 # 1, input 3

byte aVal04 = 0; // analog Value, 4052 # 0, input 4
byte aVal05 = 0; // analog Value, 4052 # 0, input 5
byte aVal14 = 0; // analog Value, 4052 # 1, input 4
byte aVal15 = 0; // analog Value, 4052 # 1, input 5

byte aVal06 = 0; // analog Value, 4052 # 0, input 6
byte aVal07 = 0; // analog Value, 4052 # 0, input 7
byte aVal16 = 0; // analog Value, 4052 # 1, input 6
byte aVal17 = 0; // analog Value, 4052 # 1, input 7

// ***************************************************************
// Setup
// ***************************************************************

void setup()
{
Serial.begin(9600);
// define pin modes   
pinMode(pSelect0, OUTPUT);
pinMode(pSelect1, OUTPUT);
}  

// ***************************************************************
// Main Loop
// ***************************************************************

void loop()
{
getAnalog();
processAnalog();
}

// ***************************************************************
// Get Analog Values
// ***************************************************************

void getAnalog()
{

  // read the first set of four
  // part 1 of 4
  digitalWrite(pSelect0, LOW), digitalWrite(pSelect1, LOW); // 00
    delayMicroseconds(latency);
  
aVal00 = map(analogRead(A4), 0, 1023, 0, 255),
aVal01 = map(analogRead(A5), 0, 1023, 0, 255),
aVal10 = map(analogRead(A6), 0, 1023, 0, 255),
aVal11 = map(analogRead(A7), 0, 1023, 0, 255);
  
  // read the second set of four
  // part 2 of 4
  digitalWrite(pSelect0, LOW), digitalWrite(pSelect1, HIGH); // 01
    delayMicroseconds(latency);
  
aVal02 = map(analogRead(A4), 0, 1023, 0, 255),
aVal03 = map(analogRead(A5), 0, 1023, 0, 255),
aVal12 = map(analogRead(A6), 0, 1023, 0, 255),
aVal13 = map(analogRead(A7), 0, 1023, 0, 255);
  
  // read the third set of four
  // part 3 of 4
  digitalWrite(pSelect0, HIGH), digitalWrite(pSelect1, LOW); // 10
    delayMicroseconds(latency);
  
aVal04 = map(analogRead(A4), 0, 1023, 0, 255),
aVal05 = map(analogRead(A5), 0, 1023, 0, 255),
aVal14 = map(analogRead(A6), 0, 1023, 0, 255),
aVal15 = map(analogRead(A7), 0, 1023, 0, 255);
  
  // read the last set of four
  // part 4 of 4
  digitalWrite(pSelect0, HIGH), digitalWrite(pSelect1, HIGH); // 11
    delayMicroseconds(latency);
  
aVal06 = map(analogRead(A4), 0, 1023, 0, 255),
aVal07 = map(analogRead(A5), 0, 1023, 0, 255),
aVal16 = map(analogRead(A6), 0, 1023, 0, 255),
aVal17 = map(analogRead(A7), 0, 1023, 0, 255);  
  
  
  return; // return to main loop    
return;
}

// ***************************************************************
// Process the values
// ***************************************************************

void processAnalog()
{
// Do whatever you would like to do with the values here
return;
}

// ***************************************************************

That is all. I realize that the getAnalog function could be simplified using an array, but I did it quickly. If anyone wants to make that change, please share it! Also, I used the map function to change the analog value that was read from 10-bits to 8-bits. I have my reasons, but anyone may remove that if they want a higher resolution. 

There you have it. 16 independent analog values on top of the 4 I needed for something else. With all of the analog pins at our disposal, you could have 32 analog values! I am using this for 16 pots and the other 4 for external control voltages. Just imagine, 32 analog values with a simple Atmega168. 

Keep up with future posts to see when I actually breadboard this out.