LEDS and 74HC595 shift register

Hi Guys

I've read lots about using the 595 to control LED's. I bought ten chips, and set up the board from this tutorial page:-

I've only ever seen diagrams, so here's a pic of one set up with two chips powering 16 LED's. It works perfectly, very easy to wire, components are cheap, and easy to program from the examples provided.

I was wondering, can the Arduino read a value from a flat file?

In the third example, values are assigned to an array "dataArray[0] = 0xAA;" Is it possible to store the "0xAA" part in a flat file on a pc and have the Arduino get the value every (x) number of seconds?

I want to be able to set a value for the LED's and store it in a file on a pc, and then have the board read it to determine which LED's are on and off.

I'm sure I can figure out a long way around the problem, is there a shortish or quick solution to having Arduino read a value from a .txt file for example?

You'd have to have an application on the PC to read the file and feed the value back to the Ardunio when polled. Another option might be to store the value in EEPROM.

I can probably throw together an app in processing to do that, that's the part I'm trying to bypass since reading from a .txt file opens up the number of methods of passing an array value to control LED's. A .txt file could be set up manually, or pretty much any other application can write values to a .txt file.

I thought it worth asking :slight_smile:

So, I've thrown together some code (LedValues.pde) for reading a .txt file, and then sending the two values to the board. But I've encountered a small problem.

The settings.txt file contains 5 rows of two values separated by TABS. This all works fine.

But when I added this code

import processing.serial.*; 
Serial port;

It only reads the first 4 rows? Are there any processing gurus here who might have an idea of why that is?

Also, this

port.write(new byte[]{thecolor[0], thecolor[1]}); // Send the two LED array values.

Doesn't work - does anyone know the correct format for sending the two values? Support over at processing is quite thrifty - and I noticed the examples over at K3 are entirely one-way conversations "from" the board, and I don't usually code in processing.

settings.txt

AAAA      0xFF
0xFE      0x7F
0xFC      0x3F
0xF8      0x1F
0xF0      0x0F

LedValues.pde

/**
 * Read LED Settings from .txt file
 * 
 * Load .txt file that contains values for RED and GREEN LEDs separated by a tab ('\t').
* If the .txt file contains a [sequence] of values, then the pairs are loaded until eof.

 */

import processing.serial.*; 
Serial port; 

String[] colorrows;
int myindex = 0;
PFont body;

void setup() {
  size(200, 200);
  background(0);
  stroke(255);
  frameRate(10);
  body = loadFont("TheSans-Plain-12.vlw");
  textFont(body);
  colorrows = loadStrings("settings.txt");
  // Open the port that the board is connected to and use the same speed (9600 bps)
  port = new Serial(this, Serial.list()[0], 9600); // port #0  

}

void draw() {

            if (myindex < colorrows.length) {
            String[] thecolor = split(colorrows[myindex], '\t');

            if (thecolor.length == 2) {
                  text("Red " + thecolor[0] + " Green " + thecolor[1], 20, 20 + myindex*20); // Print LED settings to console

                  port.write(thecolor[0], thecolor[1]); // Send the two LED array values.

                  delay(250);  // Delay of 250 milliseconds between changing values
            }

            myindex = myindex + 1; // Grab the next pair

            if (myindex == colorrows.length) { // if EOF - do it all over again
                  colorrows = loadStrings("settings.txt");
                  myindex=0;
                  delay(500);  // Delay of 500 milliseconds before redrawing
                  background(0);
                  redraw();
            }

      }

}

NB: The code reads the values, when it reaches the end, it reads the file all over again. That is so the values can be changed dynamically by another application, or for example, a .txt file updated via timed ftp where the contents of the .txt file are determined by a script, like php and a web based interface.

Thanks!

REVISIONS

  • Removed 0x from values stored in .txt file
  • Added converter for HEX to DEC
  • Added converter for DEC to Char

The following problem still persists.

The settings.txt file contains 5 rows of two values separated by TABS. This all works fine.

But when I added this code

import processing.serial.*; 
Serial port;

It only reads the first 4 rows? Are there any processing gurus here who might have an idea of why that is?

These

port.write(myredcharval); // Send the character for the Red LEDs.
port.write(mygreencharval); // Send the character for the Green LEDs.

Work in processing.

settings.txt

AA      FF
FE      7F
FC      3F
F8      1F
F0      0F

LedValues.pde

/**
 * Read LED Settings from .txt file
 * 
 * Load .txt file that contains values for RED and GREEN LEDs separated by a tab ('\t').
* If the .txt file contains a [sequence] of values, then the pairs are loaded until eof.

 */

import processing.serial.*; 
Serial port; 

String[] colorrows;
int myindex = 0;
PFont body;

void setup() {
  size(200, 200);
  background(0);
  stroke(255);
  frameRate(10);
  body = loadFont("TheSans-Plain-12.vlw");
  textFont(body);
  colorrows = loadStrings("settings.txt");
  // Open the port that the board is connected to and use the same speed (9600 bps)
  port = new Serial(this, Serial.list()[1], 9600); // COM4 port #1  

}

void draw() {

            if (myindex < colorrows.length) {
            String[] thecolor = split(colorrows[myindex], '\t');

            if (thecolor.length == 2) {
                  text("Red " + thecolor[0] + " Green " + thecolor[1], 20, 20 + myindex*20); // Print LED settings to console

                  int myredintval = unhex(thecolor[0]); // convert the Red hex value to it's decimal value
                  int mygreenintval = unhex(thecolor[1]); // convert the Green hex value to it's decimal value

                  char myredcharval = char(myredintval); // convert the decimal to character for Red
                  char mygreencharval = char(mygreenintval); // convert the decimal to character for Green

                  port.write(myredcharval); // Send the character for the Red LEDs.

                  port.write(mygreencharval); // Send the character for the Green LEDs.

                  delay(250);  // Delay of 250 milliseconds between changing values
            }

            myindex = myindex + 1; // Grab the next pair

            if (myindex == colorrows.length) { // if EOF - do it all over again
                  colorrows = loadStrings("settings.txt");
                  myindex=0;
                  delay(500);  // Delay of 500 milliseconds before redrawing
                  background(0);
                  redraw();
            }

      }

}

I've tested the board and it's receiving the characters sent to it quite nicely. Still only 4 lines (4 pairs of values) so I'm rather puzzled by that.

I'll post the Arduino code for receiving the values and integrating them with this:-

Other uses would include creating animated sequences for christmas tree lights by changing the HEX values stored in the settings.txt file, and you don't need an app or script to alter the contents of a .txt file, that can be done in any text editor.

Same with the LED matrix's people have been experimenting with, the sequencing can be done in a .txt file and processed by Arduino, rather than a purpose built application.

I'll add a 3rd value for each pair, so a delay between changing the LED's can be added dynamically to the .txt file, rather than the arbitrary 250 milliseconds.

Any clues on why (import processing.serial.*; ) is causing the last pair in the settings.txt file to be skipped, would be greatly appreciated :slight_smile:

SOLVED A carriage return after the last value, and Processing reads all 5 pairs :slight_smile:

AA FF
FE 7F
FC 3F
F8 1F
F0 0F

So here's the final Arduino code - works perfectly. I'll post a movie of the sequences functioning with the .txt file and output from processing when I get a chance.

I guess this could be used for turning relays on and off, or driving servo's. The data stored in the .txt file doesn't necessarily need to be in sequence.

I'll add a delay variable to the .txt file as well - but for what it does already, suits my needs :slight_smile:

//  Adapted Code for using a 74HC595 Shift Register
//  to Read values for LED's from .txt file sent from processing


//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
////Pin connected to DS of 74HC595
int dataPin = 11;

int firstByte; // value for Red Leds
int secondByte; // value for Green LEDs - all mine are Red but I refer to the second group of 8 Red LEDs, Green LEDs
int val;
int serialInArray[3]; // array for storing 3 bytes as they arrive from processing
int serialCount = 0; // for counting the number of bytes received


void setup() {
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {

  if (Serial.available() > 0) {

    serialInArray[serialCount] = Serial.read(); // read a byte sent by processing
    serialCount++;  // increment number of bytes received

    if (serialCount > 2 ) {  // when 3 bytes received
      firstByte = serialInArray[1]; // get value for Red LEDs
      secondByte = serialInArray[2]; // get value for Green LEDs

      //ground latchPin and hold low for as long as you are transmitting

      digitalWrite(latchPin, 0);
      shiftOut(dataPin, clockPin, firstByte); 
      shiftOut(dataPin, clockPin, secondByte);

      //return the latch pin high to signal chip that it 
      //no longer needs to listen for information
      digitalWrite(latchPin, 1);
      serialCount = 0; // reset byte counter to zero
    }
  }
}

// the following code from the original tutorial (http://www.arduino.cc/en/Tutorial/ShftOut23 )

void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
  // This shifts 8 bits out MSB first, 
  //on the rising edge of the clock,
  //clock idles low

  //internal function setup
  int i=0;
  int pinState;
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, OUTPUT);

  //clear everything out just in case to
  //prepare shift register for bit shifting
  digitalWrite(myDataPin, 0);
  digitalWrite(myClockPin, 0);

  //for each bit in the byte myDataOutÉ
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that %00000001 or "1" will go through such
  //that it will be pin Q0 that lights. 
  for (i=7; i>=0; i--)  {
    digitalWrite(myClockPin, 0);

    //if the value passed to myDataOut and a bitmask result 
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000 
    // and proceeds to set pinState to 1.
    if ( myDataOut & (1<<i) ) {
      pinState= 1;
    }
    else {      
      pinState= 0;
    }

    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(myDataPin, pinState);
    //register shifts bits on upstroke of clock pin  
    digitalWrite(myClockPin, 1);
    //zero the data pin after shift to prevent bleed through
    digitalWrite(myDataPin, 0);
  }

  //stop shifting
  digitalWrite(myClockPin, 0);
}

Final revision for processing

/**
 * Load LED Settings
 * 
 * Load .txt file that contains values for RED and GREEN LEDs separated by a tab ('\t').
 * If the .txt file contains a sequence of values, the pairs are loaded until eof.
 * 
 */

import processing.serial.*; 
Serial port; 

String[] colorrows;
String[] myhexstr;
int myindex = 0;
PFont body;


void setup() {
  size(200, 200);
  background(0);
  stroke(255);
  frameRate(10);
  body = loadFont("TheSans-Plain-12.vlw");
  textFont(body);
  colorrows = loadStrings("settings.txt");
  // Open the port that the board is connected to and use the same speed (9600 bps)
  println(Serial.list());
  port = new Serial(this, Serial.list()[1], 9600); // port #1 COM4  

}

void draw() {

  if (myindex < colorrows.length) {
    String[] thecolor = split(colorrows[myindex], '\t');

    if (thecolor.length == 2) {
      text("Red " + thecolor[0] + " Green " + thecolor[1], 20, 20 + myindex*20); // Print LED settings to console

      int myredintval = unhex(thecolor[0]);
      int mygreenintval = unhex(thecolor[1]);
      char myredcharval = char(myredintval);
      char mygreencharval = char(mygreenintval);

      port.write('A');// send A as first byte

      delay(10); // small delay so we don't choke

      port.write(myredcharval); // send red

      delay(10); // small delay so we don't choke

      port.write(mygreencharval); // send green

    }

    myindex = myindex + 1; // Grab the next pair

    if (myindex == colorrows.length) {
      colorrows = loadStrings("settings.txt");
      myindex=0;
      delay(500);  // Delay of 500 milliseconds before redrawing
      background(0);
      redraw();
    }

  }

}

My settings.txt file ended up looking like this, it was fun to play with.

FF    FF // turn them all on
0     0  // turn them all off
6     12 // turn Red LEDs 2&3 on - turn Green LEDs 3&4 on
10    18 // etc
12    22 // etc
14    25 // etc

Looks good. Just thought I'd point out that the ShiftOut function is now incorporated into Arduino. Check it out here.

Thanks :slight_smile: Here's the video

Top screen is processing running through the values picked from settings.txt

The bottom screen is NotePad with settings.txt loaded.

The movie demonstrates how values can be changed in the text editor (Notepad) and then updated by processing to change which LEDs Arduino turns on or off.

http://video.google.com/videoplay?docid=-2403153345259867570

I built this so the values in settings.txt file can be determined using a number of methods independently or cooperatively, including php, processing, and manually.

In addition to changing the values, php can determine what processing has been doing with the settings and vice versa. Arduino shows real time results of web based applications and additional hardware interactions dealt with locally by processing, such as, a number of switches and sensors changing the values in settings.txt.

At the very least, it's an easy way of creating and storing Christmas tree LED sequences without needing to upload directly to Arduino, or recode them in processing.

I have another eight 595's to add once a longer board arrives. So, initially, 80 LED's in total will be controlled this way.

Here's another fascinating video:-

http://video.google.com/videoplay?docid=2647922083218837117&hl=en

An array of 16 LEDs running a sequence determined by settings.txt

I produced this one to show the manufacturers of these UltraBright LED a failure after 5 hours of use. Two LED's had failed earlier within an hour, so I ran another test hoping it was just a coincidence.

These LEDs had been purchased as part of a bulk lot from a Power Seller at eBay. Name withheld as I'm not interested in slinging mud, it's worth a headsup mention for anyone that might experience similar issues. They attempted to place the blame on static, until I showed them the application - now they're offering free LED's which I'm not interested in.

Standard 5mm green LED's were working fine after 5 days of continuous use. These UltraBrights will be a problem in a commercial setting, given the frequency they would need to be replaced.

So I'm interested in understanding the nature of the problem, if it's coincidence, or a genuine manufacturing fault.

hey

what value resistor are you suing in series with the LEDs? Did you get any manufacturer's data with them? I have had bad LEDs too sometimes... they call them "floor sweepings"... they were cheap too.

D

hey daniel

Using the 220ohm resistors per the tutorial.

The LED supplier said "The work current can never be over 20mA continuous or 60mA peak"

The LEDs were cheap, I'll see if they've heard of the term "floor sweeps" :slight_smile:

Actually I've done some quick math, and according to my calculations the LEDs are getting a constant 22.72 mA. Since there's only ever one LED on at a time, I probably need to double up on resistors - bummer!

I discovered processing can read a text file directly from a website, so a small modification to the code, and the LED settings can be determined by a php script writing values to settings.txt.

  colorrows = loadStrings("http://www.yourserver.com/settings.txt");

The settings.txt values can also be changed manually via ftp.

This is good news for me, it means the php application, and the computer operating the LED's, don't need to be on the same machine, and it means multiple remote machines and users can manipulate the settings.txt values.

The supplier of the LEDs is now refusing to discuss the problem via the eBay messaging application, aside from the three which have stopped working, the rest appear to be holding up fine.

I guess the Chinese have got their hands full with people returning product at the moment :-?

Here's a sample php script that toggles the value of LED7 in the left (1st) group of 8 LED's

<?php

// php demo script - toggle LED 7 on and off via www

// runs on yourwww.com - save it as toggle.php

// All LEDs on = FF FF
// LED 7 off = FF BF
// LED 7 on = FF FF

// Read the current values

$file = fopen("settings.txt","r"); // open settings.txt
$settings=fread($file,filesize("settings.txt")); // read whole file

// split pairs into strings
$myhex1 = substr($settings, 0, 2);
$myhex3 = substr($settings, 3, 2);

// show user what the present values are
echo $myhex1;
echo "
";
echo $myhex3;
echo "
";

fclose($file);

// toggle LED 7


// if LED 7 is on - turn it off
if ($myhex3=="FF") {
      $newhex3="BF";
}

// if LED 7 is off - turn it on
if ($myhex3=="BF") {
      $newhex3="FF";
}

$towrite=$myhex1; // restore right settings 
$towrite .=chr(9); // add in tab delimiter used by processing
$towrite .=$newhex3; // store new value for left settings - LED 7

// show the user what the new values are
echo "
";
echo $towrite;

// write values to settings.txt
$file = fopen("settings.txt","w");
fwrite($file,"$towrite\n");
$file = fclose($file);

?>

To toggle the LED status, press the refresh button on the browser. Response time's really good, about 1 second - so I could be sitting in France turning a LED on and off in the US via www.myserver.com/toggle.php

I know there's ways of doing this using other hardware and software. But I haven't seen anything Arduino like that I could recreate, plus, I like being able to add an indefinite number of 595's so the number of LED's, or relay's, one can control, is unlimited.

595's are cheap too - 4 bucks for 10 off eBay if you don't mind the dodgy sellers and their "floor sweeps".

If you want to have all LEDs off, and only toggle LED 7 on and off, change the hex values from

// All LEDs on = FF FF
// LED 7 off = FF BF
// LED 7 on = FF FF

to

// All LEDs off = 00 00
// LED 7 on = 00 40
// LED 7 off = 00 00

It's actually LED 2, not 7, depending from which direction you look at the LEDs on the board.

I've got all the LEDs fired up to determine how long they'll last, but others may just want turn individual LEDs on and off, while leaving the rest off.

Here's an online binary to hex converter script I stumbled across, it's handy for visualizing if your not a binary to hex guru.

Now I want to add the 4021's - can anyone see a problem with this layout ?

I want the board to multiplex inputs and outputs at the same time, and use a hacked version of the code from both examples, but, before I go destroying the board I thought I'd check with you guru's first :slight_smile:

I'd been sifting through some of Tom's code and came across a processing/php solution to sending values from Arduino, via processing, to php, and then php writing the values to a .txt file on a web server.

This is significant for me, because I have a means of sending values from a .txt file stored on a web server to Arduino via processing, and now I have a way of Arduino talking back to the server via processing via php.

For example, I might like to have a digital input for each LED, so if a switch is turned on or off, the server side script can decide if it's going to turn a LED on or off.

code for processing

/* http client
 original code by Tom Igoe
 Starts a network client that connects to a server on port 80,
 sends an HTTP 1.1 GET request.
 Sends an input value to php
 php writes the value to a text file on a web server 
  */
import processing.net.*;
Client client;
int inputValue = 33;                    // number representing the input switch - this would be determined by the value Arduino sends to processing

void setup()
{
  // open a TCP socket to the host:
  client = new Client(this, "yourserver.com", 80);
  // send the HTTP GET request:
  client.write("GET /~youraccount/switch.php?receivedValue=" + inputValue + " HTTP/1.1\n");
  client.write("HOST: yourserver.com\n\n");
   println("\n\nSend complete\n");
}

php - switch.php

<?php
$filename = 'switched.txt';
// create string from the POST
  $dataString = $dataString.$_REQUEST['receivedValue'];
  // add a linefeed and carriage return
  $dataString = $dataString."\r\n";

//  make sure the file exists and is writable first:
if (is_writable($filename)) {

   // Open $filename in write mode
   if (!$handle = fopen($filename, 'w')) {
         echo "Can't open file $filename";
         exit;
   }

   // Write $dataString to the opened file.
   if (fwrite($handle, $dataString) == FALSE) {
       echo "Can't write to file $filename";
       exit;
   }
  // data successfully written:
   echo "Wrote $dataString to file $filename";
   // send a 0 to tell the remote side we're done:
  echo "\0";
  // close the file
   fclose($handle);

} else {
   echo "The file $filename is not write-enabled.";
}
end;
?>

So, depending on what processing receives from Arduino, the value gets stored in the file switched.txt, located on the web server.

Once I've integrated the 4021's - I'll provide a more thorough explanation of how the Arduino sends and receives data from a web based php script, via processing.

I can think of a number of reasons why you would want web based communications like this, home security springs to mind, remote sensor monitoring via a web based interface, and being able to send data to Arduino over the internet.

So, the layout (above) with both 595 and 4021's works fine - nothing blew up, I'll post pic's when I get time.

The 595's still respond, so the LED switching works perfectly. And the serial window in Arduino echo's which input switch is on when a button is pushed.

In processing, I used port.read(); to collect the value of the switch sent by Arduino.

So now I'm writing a method to debounce the switch, once that's done - I'll incorporate the method of writing the input value from processing, to a .txt file on the server.

Then, I'll publish the php code for reading the values of switches, and changing which LED's are displayed, via a web based interface, without using Xport or any other device for handling web based communications with Arduino, just, USB Arduino and an internet connection, processing, php, 2 x .txt files, and a trusty Linux server :slight_smile: