Mapping Analog Data to Shift Register

Hello,

I'm attempting to map analog data to 8 LEDs via a 7HC595 shift register to control the overall brightness of the lights. Is this possible? I'm specifically confused how to map the analog input data to the shift register and control the light illumination. I hope to achieve a PWM-eqsue effect based on the variation in the analog input.

These are three sketches I'm working to combine:

Sketch 1:

//Analog read pins
const int xPin = 0;

int minVal = 265;
int maxVal = 402;

//to hold the caculated values
double x;

void setup(){
  Serial.begin(9600);
}

void loop(){

  //read the analog values from the accelerometer
  int xRead = analogRead(xPin);

  //convert read values to degrees -90 to 90 - Needed for atan2
  int xAng = map(xRead, minVal, maxVal, -90, 90);

  x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI);

  Serial.print("x: ");
  Serial.print(x);

  delay(100);
}

SKETCH 2:

//Pin connected to ST_CP of 74HC595
int latchPin = 2;
//Pin connected to SH_CP of 74HC595
int clockPin = 1;
////Pin connected to DS of 74HC595
int dataPin = 3;
int xRead = analogRead(A0);

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
  //set pins to output so you can control the shift register
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void loop() {
  // read the analog in value:
  sensorValue = analogRead(A0);            
  // map it to the range of the analog out:
  outputValue = map(sensorValue, 0, 525, 0, 654);  
  // change the analog out value:
  analogWrite(latchPin, outputValue);

  // print the results to the serial monitor:
  Serial.print("sensor = " );                      
  Serial.println(sensorValue);      
  Serial.print("\t output = ");      
  Serial.println(outputValue);  
  
  delay(250);
}

SKETCH 3:

const int Xdata = A2;  
const int greenPin1 = 3;
const int greenPin2 = 4;
const int greenPin3 = 5;
const int greenPin4 = 6;
const int greenPin5 = 7;
const int greenPin6 = 8;
const int greenPin7 = 9;
const int greenPin8 = 10;

int sensorValue = 0;     
int outputValue = 0;       

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
}

void loop() {
  // read the analog in value:
  sensorValue = analogRead(Xdata);            
  // map it to the range of the analog out:
  outputValue = map(sensorValue, 0, 525, 0, 654);  
  // change the analog out value:
  analogWrite(greenPin1, outputValue);
  analogWrite(greenPin2, outputValue);
  analogWrite(greenPin3, outputValue);
  analogWrite(greenPin4, outputValue);
  analogWrite(greenPin5, outputValue);
  analogWrite(greenPin6, outputValue);
  analogWrite(greenPin7, outputValue);
  analogWrite(greenPin8, outputValue);

  // print the results to the serial monitor:
  Serial.print("sensor = " );                      
  Serial.println(sensorValue);      
  Serial.print("\t output = ");      
  Serial.println(outputValue);  

  delay(50);                    
}

(code tags added by moderator)

Any advice is greatly appreciated....

Please edit your post, select the code, and put it between [code] ... [/code] tags.

You can do that by hitting the # button above the posting area.

Lo siento! Nonetheless, the three sketches I'm working to combine:

Sketch 1:

//Analog read pins
const int xPin = 0;

int minVal = 265;
int maxVal = 402;

//to hold the caculated values
double x;

void setup(){
  Serial.begin(9600);
}

void loop(){

  //read the analog values from the accelerometer
  int xRead = analogRead(xPin);

  //convert read values to degrees -90 to 90 - Needed for atan2
  int xAng = map(xRead, minVal, maxVal, -90, 90);

  x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI);

  Serial.print("x: ");
  Serial.print(x);

  delay(100);
}




SKETCH 2:

//Pin connected to ST_CP of 74HC595
int latchPin = 2;
//Pin connected to SH_CP of 74HC595
int clockPin = 1;
////Pin connected to DS of 74HC595
int dataPin = 3;
int xRead = analogRead(A0);

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
  //set pins to output so you can control the shift register
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void loop() {
  // read the analog in value:
  sensorValue = analogRead(A0);           
  // map it to the range of the analog out:
  outputValue = map(sensorValue, 0, 525, 0, 654); 
  // change the analog out value:
  analogWrite(latchPin, outputValue);

  // print the results to the serial monitor:
  Serial.print("sensor = " );                     
  Serial.println(sensorValue);     
  Serial.print("\t output = ");     
  Serial.println(outputValue); 
 
  delay(250);
}




SKETCH 3:

const int Xdata = A2; 
const int greenPin1 = 3;
const int greenPin2 = 4;
const int greenPin3 = 5;
const int greenPin4 = 6;
const int greenPin5 = 7;
const int greenPin6 = 8;
const int greenPin7 = 9;
const int greenPin8 = 10;

int sensorValue = 0;     
int outputValue = 0;       

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
}

void loop() {
  // read the analog in value:
  sensorValue = analogRead(Xdata);           
  // map it to the range of the analog out:
  outputValue = map(sensorValue, 0, 525, 0, 654); 
  // change the analog out value:
  analogWrite(greenPin1, outputValue);
  analogWrite(greenPin2, outputValue);
  analogWrite(greenPin3, outputValue);
  analogWrite(greenPin4, outputValue);
  analogWrite(greenPin5, outputValue);
  analogWrite(greenPin6, outputValue);
  analogWrite(greenPin7, outputValue);
  analogWrite(greenPin8, outputValue);

  // print the results to the serial monitor:
  Serial.print("sensor = " );                     
  Serial.println(sensorValue);     
  Serial.print("\t output = ");     
  Serial.println(outputValue); 

  delay(50);                   
}

You want all 8 lights to vary in brightness? But all 8 have the same brightness at a given moment?

I don't think you can control the brightness of an LED with a 595 shift register. With the 595, the LED will either be ON or OFF. There is no in-between.

Certainly, but you could pulse them. Assuming for the moment that you want them all the same brightness, you could send out the required pattern, wait a few milliseconds, and then send out "all off" and wait a few more milliseconds. That way you get a dimming effect.

EXACTLY! And I want the brightness level to correspond to mapped analog input data.
For example: using an accelerometer, map tilt data to a 1x8 array of LEDs so that the "brightness" corresponds with the tilt angle.

In the example above, I want to use a 595 in place of a single LED so that the effect can be on a larger scale (instead of one LED, shifting the effect to 8 LEDs making the total 64 controlled LEDs and potentially more depending on how many are registers are daisy chained).

Can this be done?

This project is similar to what I want to achieve but it doesn't use a shift register.

Instead I want to use the analog input from an accelerometer and map it to control brightness of several LEDs via a 595, so all LEDs will brighten or dim dependent on the angle of tilt.

I think I would do this instead, if I understand the requirement:
Map the analog brightness to a PWM pin, use that to drive a transistor to control the LEDs.

CrossRoads:
I think I would do this instead, if I understand the requirement:
Map the analog brightness to a PWM pin, use that to drive a transistor to control the LEDs.

Thanks for the response!!!
I've never worked with transistors before but I just read up a bit and watched this vid to try and understand (about 8:50 on is the most relevant part):

From this explanation, it seems like your suggestion would be the easiest solution but do you have any examples of multiplexing with transistors and pwm like you're describing?
Thanks again.

CrossRoads:
I think I would do this instead, if I understand the requirement:
Map the analog brightness to a PWM pin, use that to drive a transistor to control the LEDs.

CR - would he be able to control "the other side" that way perhaps? For example, have the 595s connected, via a resistor, to each anode, and then instead of connecting the common cathodes to ground, connect them via a current sink (MOSFET?) which itself is PWM driven. So the anode is constant, but you vary brightness at the cathode end.

This shows the software way:

#include <SPI.h>

const byte LATCH = 10;

void setup ()
{
  SPI.begin ();
}  // end of setup

const byte maxDimIterations = 30;

byte c;
void loop ()
{
  c++;
  
  for (byte bright = 0; bright < maxDimIterations; bright++)
    {
    digitalWrite (LATCH, LOW);
    SPI.transfer (c);    // wanted bit pattern
    digitalWrite (LATCH, HIGH);
    delay (bright);

    digitalWrite (LATCH, LOW);
    SPI.transfer (0);   // all LEDs off
    digitalWrite (LATCH, HIGH);
    delay (maxDimIterations - bright);
    }
    
}  // end of loop

What this is doing is sending out the pattern we want to see (c in this case) and then alternating that with sending 0. So we see desired pattern some of the time, and nothing the rest of the time. This makes them seem to brighten.

This particular test has some flicker though. A bit of rejigging of the loop should fix that.

#include <SPI.h>

const byte LATCH = 10;

void setup ()
{
  SPI.begin ();
}  // end of setup

const byte maxDimIterations = 30;

byte c;
void loop ()
{
  c++;
  
  for (byte bright = 0; bright < maxDimIterations; bright++)
    {
    digitalWrite (LATCH, LOW);
    SPI.transfer (c);    // wanted bit pattern
    digitalWrite (LATCH, HIGH);
    delay (bright);

    digitalWrite (LATCH, LOW);
    SPI.transfer (0);   // all LEDs off
    digitalWrite (LATCH, HIGH);
    delay (maxDimIterations - bright);
    }
    
}  // end of loop

Great sketch! My final goal is to map analog data to this output.
SO from here, is it possible to map analog values to control LATCH HIGH and LOW values using something like this sketch....

//Analog read pins
const int xPin = 0;

int minVal = 265;
int maxVal = 402;

//to hold the caculated values
double x;

void setup(){
  Serial.begin(9600);
}

void loop(){

  //read the analog values from the accelerometer
  int xRead = analogRead(xPin);

  //convert read values to degrees -90 to 90 - Needed for atan2
  int xAng = map(xRead, minVal, maxVal, -90, 90);

  x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI);

  Serial.print("x: ");
  Serial.print(x);

  delay(100);
}

...Or would it just be easier to use a transistor and connect all LEDs in series without a 595 and control them using just use one PWM pin from the Arduino?

Well if you want them all to show the same thing, a 595 is hardly necessary. The whole point of the shift register is you can have (say) 8 LEDs and have them all showing different things from time to time. However in case this is what you want, I tested the idea of the MOSFET:

I made it up and it actually works. I haven't shown every LED, but you get the picture. The "ground" side of all the LEDs goes through the transistor, and the transistor is connected to a PWM output, so you can vary the brightness of all of them. This sketch demonstrates:

#include <SPI.h>

const byte LATCH = 10;

void setup ()
{
  SPI.begin ();
}  // end of setup

const byte maxDimIterations = 63;

byte c;
void loop ()
{
  c++;
  
  for (byte bright = 0; bright < maxDimIterations; bright++)
    {
    analogWrite (5, bright * 4);
    digitalWrite (LATCH, LOW);
    SPI.transfer (c);
    digitalWrite (LATCH, HIGH);
    delay (10);
    }  // end of for
    
}  // end of loop

But as I say, if you just want 8 LEDs always on, skip the 595 part, and just use the transistor. (The output pin won't be powerful enough to drive dozens of LEDs).

THANKS NICK!

This seems like a great solution. Any suggestions on the better transistor for this application?

A: Transistor - NPN, 60V 200mA (2N3904) - COM-00521 - SparkFun Electronics
B: Transistor - NPN (BC547) - COM-08928 - SparkFun Electronics

As I read the datasheets those are 100/200 mA transistors. I was using a N-channel MOSFET RFP30N06LE. That can handle 30 amps (might need a heat sink though).

The electronics experts here might have a better suggestion.

For example:

In the bildr.org tutorial for the RFP30N06LE there's the following quote under Limitations:

"The RFP30N06LE can handle switching up to 60V, and the amperage is limited to 30A (with heat sink and proper wiring). Anything over a few amps, especially when the current is constant (like in a motor) and not short pulses, I would recommend using a heat-sink. I usually just solder a bent pice of metal to the back, just something to help dissipate the heat. Just note, if you are using more than one of the RFP30N06LEs, you can not solder them to the same heat-sink as the back is connected to the drain of the MOSFET, not the source."

So how many correctly wired 20mA LEDs could a transistor reliably power on 5V?
Are there any power supply and wiring issues I should be aware of if I connect 16-20 20mA LEDs to the RFP30N06LE?
AND what is this heat sink business? How does that work exactly? It sounds slightly dangerous...tell me more!

THANKS AGAIN!!!!

So how many correctly wired 20mA LEDs could a transistor reliably power on 5V?

Well, 30 amps is 30000 milliamps. So you are asking how many times 20 goes into 30000?

AND what is this heat sink business? How does that work exactly?

The transistor in question has a big hole at the back. The idea is to bolt on a bit of metal called a heat sink to help conduct away the heat.

I'm attempting to map analog data to 8 LEDs ...

You probably won't need the heat sink for 8 LEDs.