Go Down

Topic: LEDS and 74HC595 shift register (Read 10 times) previous topic - next topic

John_Ryan

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:-

http://www.arduino.cc/en/Tutorial/ShiftOut

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?



Digger450

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.

John_Ryan

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 :)

John_Ryan

#3
Jul 28, 2007, 12:25 pm Last Edit: Jul 28, 2007, 12:54 pm by John_Ryan Reason: 1
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

Code: [Select]

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

Code: [Select]

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
Code: [Select]

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



LedValues.pde
Code: [Select]

/**
* 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!

John_Ryan

#4
Jul 28, 2007, 10:59 pm Last Edit: Jul 29, 2007, 04:17 am by John_Ryan Reason: 1
*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

Code: [Select]

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

Code: [Select]

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
Code: [Select]

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



LedValues.pde
Code: [Select]

/**
* 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();
           }

     }

}



John_Ryan

#5
Jul 29, 2007, 04:35 am Last Edit: Jul 29, 2007, 04:36 am by John_Ryan Reason: 1
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:-

http://www.arduino.cc/en/Tutorial/ShftOut23

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 :)  

John_Ryan

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

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

John_Ryan

#7
Jul 29, 2007, 06:43 pm Last Edit: Jul 29, 2007, 06:45 pm by John_Ryan Reason: 1
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 :)

Code: [Select]


//  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

Code: [Select]

/**
* 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.

Code: [Select]

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

Digger450

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

John_Ryan

Thanks :) 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.


John_Ryan

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.

Daniel

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

John_Ryan

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" :)


John_Ryan

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!  

John_Ryan

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.

Code: [Select]

 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  :-?

Go Up