0
Offline
Newbie
Karma: 1
Posts: 13
Arduino rocks
|
 |
« on: November 01, 2009, 10:17:03 am » |
Here's a Siemens DL2416 intelligent LED alphanumeric display being run by a Boarduino: /* DL2416T intelligent 16-segment display test
version: 0.2 author: Alex Davis hardware: Atmega168 or Atmega328 Arduino Sends text to a directly-connected DL2416T 16-segment four-character alphanumeric display. There are probably enough pins to do four displays without external logic. As is the code does just one. If you debug using Serial you will set d0 high and throw off every other character. */
#include <avr/pgmspace.h>
// strings to display stored in EEPROM // don't put spaces at the start - the code assumes there won't be any // do put a space on the end prog_char string0[] PROGMEM = "SING WHILE YOU MAY "; prog_char string1[] PROGMEM = "LIKE A FLY THAT'S TRAPPED ON A WINDOW "; prog_char string2[] PROGMEM = "SING WHILE YOU MAY "; prog_char string3[] PROGMEM = "THOUGH THERE'S NOTHING IN THE WORLD "; prog_char string4[] PROGMEM = "THAT YOU CAN CHANGE "; prog_char string5[] PROGMEM = "SING WHILE YOU MAY "; prog_char string6[] PROGMEM = "'CAUSE IT MAY NOT BE VERY LONG ";
#define NUM_STRINGS 7 #define MAX_SIZE 81
// an array of strings // if you change the number of strings above // update this as well to match PROGMEM const char *stringSet[] = {string0, string1, string2, string3, string4, string5, string6 };
// function prototypes void formatStr(char []); void displayChar(char, int, byte);
// set ports and pins void setup() { byte pinLoop; // set port d to all outputs, except serial in // then set them low DDRD = B11111110; PORTD = B00000000; // set pins 8-16 to outputs for (pinLoop = 8; pinLoop < 17; pinLoop++) { pinMode(pinLoop, OUTPUT); } // set the pin states // use 8 for BL and set to HIGH digitalWrite(8, HIGH); // use 9 for AO and set to LOW digitalWrite(9, LOW); // use 10 for A1 and set to LOW digitalWrite(10, LOW); // if you tie C1 and C2 on each display // then 11 can be for display0 // and 12 can be for display1 // use 11 for C1 and set to HIGH digitalWrite(11, HIGH); // use 12 for C2 and set to HIGH digitalWrite(12, HIGH); // use 13 for CLR and set to HIGH digitalWrite(13, HIGH); // use 14 for CU and set to HIGH digitalWrite(14, HIGH); // use 15 for WR and set to HIGH digitalWrite(15, HIGH); // use 16 for CUE and set to LOW digitalWrite(16, LOW); }
// main void loop() { byte i; // buffer string stored in RAM char currentString[MAX_SIZE]; for (i = 0; i < NUM_STRINGS; i++) { // copy a string from the array of strings in the EEPROM // to a local buffer string in RAM strcpy_P(currentString, (char*)pgm_read_word(&(stringSet[i]))); // parse the string for display formatStr(currentString); // pause a bit delay(1000); } }
/* ------------------------------------------------------------ function formatStr purpose: formats a string for display on a DL2416T expects: a pointer to a string returns: nothing ------------------------------------------------------------ */
void formatStr(char toDisplay[]) { int wStart = 0, // start of word in string wEnd = 0; // end of word in string int count = 0, // string position counter x = 0, // string position counter for word < 5 n = 0, // display counter for word > 5 mid-word wordLen = 0, // length of string d = 0, // display counter for word >5 end word dLen = 0; // length - 1 for display purposes byte displayNum = 0; // selects display 0 or 1
byte setChar; int segCount = 0; // loop until the end of the string while (toDisplay[count] != '\0') { // assume string begins a word and not with a space wStart = count; wordLen = 0; // find the length of the word until we reach a space // or the end of the string while ((toDisplay[count] != ' ') && (toDisplay[count] != '\0')) { // set the end to the current location // when we drop out of the loop this will be // the last character in the word wEnd = count; // move to the next position in the string count++; // increment the character count wordLen++; } // display directly if it fits on the display if (wordLen < 5) { // write the characters between wStart and wEnd directly // to the display // back through the buffer array and set one character // on the display at a time // blank the display digitalWrite(8, LOW); delay(1); // go through the buffer array backwards and write the // characters to the display segCount = 0; for (n = wEnd; n > (wStart - 1); n--) { // send the character, display position and display displayChar(toDisplay[n], segCount, displayNum); segCount++; } // unblank the display digitalWrite(8, HIGH); // a pause to read the word delay(750); // clear the display digitalWrite(13, LOW); delay(2); digitalWrite(13, HIGH); } // if it is more than four characters long // display using the scrolling method if (wordLen > 4) { dLen = wordLen - 1; // write the characters between wStart and wEnd so they // appear to scroll from left to right // it takes length + 2 iterations to scroll // all the way to the last character // we will use x to keep track of where we are in the // scrolling process for (x = 0; x < (wordLen + 3); x++) { // clear the display digitalWrite(13, LOW); delay(2); digitalWrite(13, HIGH); // scroll until the fourth character in the word // read the buffer backwards if (x < 4) { segCount = 0; for (d = (wEnd - (dLen - x)); d > (wStart - 1) ; d--) { // send the character, display position and display displayChar(toDisplay[d], segCount, displayNum); segCount++; } } // after the fourth character scroll on // until the end of the word if ((x > 3) && (x < wordLen)) { segCount = 0; for (d = wEnd - (dLen - x); d > ((wStart + (x - 3)) - 1); d--) { // send the character, display position and display displayChar(toDisplay[d], segCount, displayNum); segCount++; } } // once we get to the end of the word // scroll off by reading forwards in the array // while counting backwards in the display position if (x > dLen) { segCount = 3; for (d = (wStart + (x - 3)); d < (wEnd + 1); d++) { // send the character, display position and display displayChar(toDisplay[d], segCount, displayNum); segCount--; } } // a small delay between scroll delay(200); } // clear the display digitalWrite(13, LOW); delay(2); digitalWrite(13, HIGH); } count++; } } // end function formatStr
/* ------------------------------------------------------------ function displayChar purpose: displays a character on a DL2416T expects: a character, a position and a display (0,1,2 etc...) returns: nothing ------------------------------------------------------------ */
void displayChar(char myChar, int myPos, byte myDisp) { /* here's how to set a character: 1. select an address using a0-a1 which here are arduino pins 9-10 2. pull WR to LOW to enable loading 3. send the bit-shifted character to the data lines d0-d6 all at once using PORTD 4. set the WR pin back to HIGH 5. repeat for next character */ // right now we only do one display // but logic for more would be added here // using a case if more than one were used if (myDisp == 0) { // enable display 0 by setting C1-C2 LOW digitalWrite(11, LOW); // disable display 1 by setting C1-C2 HIGH digitalWrite(12, HIGH); delay(2); } // we are going to set the ASCII character all at once on PORTD // but we must avoid pin 0, which is serial RX // so we will shift one bit to the left myChar = myChar << 1; // the segment position is the opposite of the array // eg. seg0 is array[3] // set the character pin state // cheap binary conversion of setChar switch (myPos) { case 0: digitalWrite(9, LOW); digitalWrite(10, LOW); break; case 1: digitalWrite(9, HIGH); digitalWrite(10, LOW); break; case 2: digitalWrite(9, LOW); digitalWrite(10, HIGH); break; case 3: digitalWrite(9, HIGH); digitalWrite(10, HIGH); break; } // set the WR pin LOW to enable loading digitalWrite(14, LOW); delay(2); // set the shifted character to PORTD PORTD = myChar; delay(2); // set WR pin HIGH to finish loading digitalWrite(14, HIGH); delay(2); } // end function displayChar
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 1
Posts: 13
Arduino rocks
|
 |
« Reply #1 on: November 01, 2009, 10:22:02 am » |
here's the link to the video: It's a small display, so the code takes an array of strings, breaks them down into words, and then displays them all at once if they fit or scrolls them if they don't. I did it all using just the array index so as to conserve RAM.
|
|
|
|
|
Logged
|
|
|
|
|
North York, Ontario
Offline
Full Member
Karma: 0
Posts: 142
Arduino rocks!
|
 |
« Reply #2 on: November 02, 2009, 10:35:56 am » |
Awesome, Ive been contemplating figuring out how to hook these up, and youve done the work for me! Looks good, thanks!
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 2
Arduino rocks
|
 |
« Reply #3 on: November 03, 2009, 10:15:34 pm » |
Where did you get that display at? I can't seem to find a good 4 digit 14 segment display.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 1
Posts: 13
Arduino rocks
|
 |
« Reply #4 on: November 04, 2009, 11:28:23 am » |
I pulled them out of some surplus lab gear I bought for a few dollars. I wouldn't recommend trying to buy them online. They exist, but the prices are outrageous. Too bad, I do like how they look.
|
|
|
|
|
Logged
|
|
|
|
|
Manchester (England England)
Online
Brattain Member
Karma: 274
Posts: 25480
Solder is electric glue
|
 |
« Reply #5 on: November 05, 2009, 08:44:05 am » |
|
|
|
|
« Last Edit: November 05, 2009, 08:46:14 am by Grumpy_Mike »
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 1
Posts: 13
Arduino rocks
|
 |
« Reply #6 on: November 06, 2009, 10:56:15 pm » |
Here's an update to the functions to support a second display: /* ------------------------------------------------------------ function formatStr purpose: formats a string for display on a DL2416T expects: a pointer to a string returns: nothing ------------------------------------------------------------ */
void formatStr(char toDisplay[]) { int wStart = 0, // start of word in string wEnd = 0; // end of word in string int count = 0, // string position counter x = 0, // string position counter for word < 5 n = 0, // display counter for word > 5 mid-word wordLen = 0, // length of string d = 0, // display counter for word >5 end word dLen = 0, // length - 1 for display purposes offset = 0; // an offset to center the word on the display byte displayNum; // selects display 0 or 1
byte setChar; int segCount = 0;
// loop until the end of the string
while (toDisplay[count] != '\0') { // assume string begins a word and not with a space wStart = count; wordLen = 0;
// find the length of the word until we reach a space // or the end of the string while ((toDisplay[count] != ' ') && (toDisplay[count] != '\0')) { // set the end to the current location // when we drop out of the loop this will be // the last character in the word wEnd = count; // move to the next position in the string count++; // increment the character count wordLen++; } // start with 1st display, displayNum = 0 displayNum = 0;
// display directly if it fits on the display if (wordLen < 9) { // write the characters between wStart and wEnd directly // to the display
// back through the buffer array and set one character // on the display at a time
// blank the display digitalWrite(8, LOW); delay(1);
// go through the buffer array backwards and write the // characters to the display segCount = 0;
// calculate an offset to center the word if ((wordLen > 0 ) && (wordLen < 4)) { offset = 3; } if ((wordLen > 3) && (wordLen < 6)) { offset = 2; } if ((wordLen > 5) && (wordLen < 8)) { offset = 1; } // apply the offset to the segCount segCount = segCount + offset;
for (n = wEnd; n > (wStart - 1); n--) { // move to 2nd display if segCount > 3 // eg. displayNum = 1 if (segCount > 3) { displayNum = 1; } // send the character, display position and display displayChar(toDisplay[n], segCount, displayNum); segCount++;
} // unblank the display digitalWrite(8, HIGH);
// a pause to read the word delay(750);
// clear the display digitalWrite(13, LOW); delay(2); digitalWrite(13, HIGH); }
// if it is more than eight characters long // display using the scrolling method if (wordLen > 8) { dLen = wordLen - 1;
// write the characters between wStart and wEnd so they // appear to scroll from left to right
// it takes length + 2 iterations to scroll // all the way to the last character
// we will use x to keep track of where we are in the // scrolling process for (x = 0; x < (wordLen + 3); x++) {
// clear the display digitalWrite(13, LOW); delay(2); digitalWrite(13, HIGH);
// scroll until the eighth character in the word // read the buffer backwards if (x < 7) { // start with the first display displayNum = 0;
segCount = 0; for (d = (wEnd - (dLen - x)); d > (wStart - 1) ; d--) { // move to 2nd display if segCount > 3 // eg. displayNum = 1 if (segCount > 3) { displayNum = 1; } // send the character, display position and display displayChar(toDisplay[d], segCount, displayNum); segCount++; } } // after the eighth character scroll on // until the end of the word if ((x > 7) && (x < wordLen)) { segCount = 0; displayNum = 0;
for (d = wEnd - (dLen - x); d > ((wStart + (x - 3)) - 1); d--) { // move to 2nd display if segCount > 3 // eg. displayNum = 1 if (segCount > 3) { displayNum = 1; } // send the character, display position and display displayChar(toDisplay[d], segCount, displayNum); segCount++; } }
// once we get to the end of the word // scroll off by reading forwards in the array // while counting backwards in the display position if (x > dLen) { segCount = 7; for (d = (wStart + (x - 3)); d < (wEnd + 1); d++) { // move to 1st display if segCount < 4 // eg. displayNum = 0 if (segCount < 4) { displayNum = 0; } // send the character, display position and display displayChar(toDisplay[d], segCount, displayNum); segCount--; } } // a small delay between scroll delay(200);
} // clear the display digitalWrite(13, LOW); delay(2); digitalWrite(13, HIGH); } count++; } } // end function formatStr
/* ------------------------------------------------------------ function displayChar purpose: displays a character on a DL2416T expects: a character, a position and a display (0,1,2 etc...) returns: nothing ------------------------------------------------------------ */
void displayChar(char myChar, int myPos, byte myDisp) {
/* here's how to set a character: 1. select an address using a0-a1 which here are arduino pins 9-10 2. pull WR to LOW to enable loading 3. send the bit-shifted character to the data lines d0-d6 all at once using PORTD 4. set the WR pin back to HIGH 5. repeat for next character
*/
// enable the correct display if (myDisp == 0) { // enable display 0 by setting C1-C2 LOW digitalWrite(11, LOW); // disable display 1 by setting C1-C2 HIGH digitalWrite(12, HIGH); delay(2);
} if (myDisp == 1) { // enable display 1 by setting C1-C2 LOW digitalWrite(12, LOW); // disable display 0 by setting C1-C2 HIGH digitalWrite(11, HIGH); delay(2); // convert the 7-0 word frame position to the // actual position on display 1 myPos = myPos - 4; }
// we are going to set the ASCII character all at once on PORTD // but we must avoid pin 0, which is serial RX // so we will shift one bit to the left myChar = myChar << 1; // the segment position is the opposite of the array // eg. seg0 is array[3] // set the character pin state // cheap binary conversion of setChar switch (myPos) { case 0: digitalWrite(9, LOW); digitalWrite(10, LOW); break; case 1: digitalWrite(9, HIGH); digitalWrite(10, LOW); break; case 2: digitalWrite(9, LOW); digitalWrite(10, HIGH); break; case 3: digitalWrite(9, HIGH); digitalWrite(10, HIGH); break; }
// set the WR pin LOW to enable loading digitalWrite(14, LOW); delay(2);
// set the shifted character to PORTD PORTD = myChar; delay(2);
// set WR pin HIGH to finish loading digitalWrite(14, HIGH); delay(2); } // end function displayChar
I wanted to have my words centered (more or less). It would not be hard to left-justify instead - just adjust the offset section. Next stop for this project is to move it beyond the breadboard and add in support for an SD card. The ultimate goal is a handheld speed-reader. Reading one word at a time you can read more than 600 WPM. But I'll need a source for a modern, available display. It'll need to be an OLED or VFD. I don't think an STN LCD will be fast enough.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 1
Posts: 13
Arduino rocks
|
 |
« Reply #7 on: November 08, 2009, 10:23:18 am » |
Auugh! The above code does not work, but this does: /* ------------------------------------------------------------ function formatStr purpose: formats a string for display on a DL2416T expects: a pointer to a string returns: nothing ------------------------------------------------------------ */
void formatStr(char toDisplay[]) { int wStart = 0, // start of word in string wEnd = 0; // end of word in string int count = 0, // string position counter x = 0, // string position counter for word < 5 n = 0, // display counter for word > 5 mid-word wordLen = 0, // length of string d = 0, // display counter for word >5 end word dLen = 0, // length - 1 for display purposes offset = 0; // an offset to center the word on the display byte displayNum; // selects display 0 or 1
byte setChar; int segCount = 0;
// loop until the end of the string
while (toDisplay[count] != '\0') { // assume string begins a word and not with a space wStart = count; wordLen = 0;
// find the length of the word until we reach a space // or the end of the string while ((toDisplay[count] != ' ') && (toDisplay[count] != '\0')) { // set the end to the current location // when we drop out of the loop this will be // the last character in the word wEnd = count; // move to the next position in the string count++; // increment the character count wordLen++; } // start with 1st display, displayNum = 0 displayNum = 0;
// display directly if it fits on the display if (wordLen < 9) { // write the characters between wStart and wEnd directly // to the display
// back through the buffer array and set one character // on the display at a time
// blank the display digitalWrite(8, LOW); delay(1);
// go through the buffer array backwards and write the // characters to the display segCount = 0;
// calculate an offset to center the word if (wordLen < 2) { offset = 4; } if ((wordLen > 1 ) && (wordLen < 4)) { offset = 3; } if ((wordLen > 3) && (wordLen < 6)) { offset = 2; } if ((wordLen > 5) && (wordLen < 8)) { offset = 1; } // apply the offset to the segCount segCount = segCount + offset;
for (n = wEnd; n > (wStart - 1); n--) { // move to 2nd display if segCount > 3 // eg. displayNum = 1 if (segCount > 3) { displayNum = 1; } // send the character, display position and display displayChar(toDisplay[n], segCount, displayNum); segCount++;
} // unblank the display digitalWrite(8, HIGH);
// a pause to read the word delay(750);
// clear the display digitalWrite(13, LOW); delay(2); digitalWrite(13, HIGH);
// reset offset offset = 0; }
// if it is more than eight characters long // display using the scrolling method if (wordLen > 8) { dLen = wordLen - 1;
// write the characters between wStart and wEnd so they // appear to scroll from left to right
// it takes length + 2 iterations to scroll // all the way to the last character
// we will use x to keep track of where we are in the // scrolling process for (x = 0; x < (wordLen + 7); x++) {
// clear the display digitalWrite(13, LOW); delay(2); digitalWrite(13, HIGH);
// scroll until the eighth character in the word // read the buffer backwards if (x < 8) { // start with the first display displayNum = 0;
segCount = 0; for (d = (wEnd - (dLen - x)); d > (wStart - 1) ; d--) { // move to 2nd display if segCount > 3 // eg. displayNum = 1 if (segCount > 3) { displayNum = 1; } // send the character, display position and display displayChar(toDisplay[d], segCount, displayNum); segCount++; } } // after the eighth character scroll on // until the end of the word if ((x > 7) && (x < wordLen)) { segCount = 0; displayNum = 0;
for (d = wEnd - (dLen - x); d > ((wStart + (x - 7)) - 1); d--) { // move to 2nd display if segCount > 3 // eg. displayNum = 1 if (segCount > 3) { displayNum = 1; } // send the character, display position and display displayChar(toDisplay[d], segCount, displayNum); segCount++; } }
// once we get to the end of the word // scroll off by reading forwards in the array // while counting backwards in the display position if (x > dLen) { segCount = 7; displayNum = 1; for (d = (wStart + (x - 7)); d < (wEnd + 1); d++) { // move to 1st display if segCount < 4 // eg. displayNum = 0 if (segCount < 4) { displayNum = 0; } // send the character, display position and display displayChar(toDisplay[d], segCount, displayNum); segCount--; } } // a small delay between scroll delay(200);
} // clear the display digitalWrite(13, LOW); delay(2); digitalWrite(13, HIGH); } count++; } } // end function formatStr
/* ------------------------------------------------------------ function displayChar purpose: displays a character on a DL2416T expects: a character, a position and a display (0,1,2 etc...) returns: nothing ------------------------------------------------------------ */
void displayChar(char myChar, int myPos, byte myDisp) {
/* here's how to set a character: 1. select an address using a0-a1 which here are arduino pins 9-10 2. pull WR to LOW to enable loading 3. send the bit-shifted character to the data lines d0-d6 all at once using PORTD 4. set the WR pin back to HIGH 5. repeat for next character
*/
// enable the correct display if (myDisp == 0) { // enable display 0 by setting C1-C2 LOW digitalWrite(11, LOW); // disable display 1 by setting C1-C2 HIGH digitalWrite(12, HIGH); delay(2);
} if (myDisp == 1) { // enable display 1 by setting C1-C2 LOW digitalWrite(12, LOW); // disable display 0 by setting C1-C2 HIGH digitalWrite(11, HIGH); delay(2); // convert the 7-0 word frame position to the // actual position on display 1 myPos = myPos - 4; }
// we are going to set the ASCII character all at once on PORTD // but we must avoid pin 0, which is serial RX // so we will shift one bit to the left myChar = myChar << 1; // the segment position is the opposite of the array // eg. seg0 is array[3] // set the character pin state // cheap binary conversion of setChar switch (myPos) { case 0: digitalWrite(9, LOW); digitalWrite(10, LOW); break; case 1: digitalWrite(9, HIGH); digitalWrite(10, LOW); break; case 2: digitalWrite(9, LOW); digitalWrite(10, HIGH); break; case 3: digitalWrite(9, HIGH); digitalWrite(10, HIGH); break; }
// set the WR pin LOW to enable loading digitalWrite(14, LOW); delay(1);
// set the shifted character to PORTD PORTD = myChar; delay(1);
// set WR pin HIGH to finish loading digitalWrite(14, HIGH); delay(1); } // end function displayChar
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 1
Arduino rocks
|
 |
« Reply #8 on: November 27, 2009, 02:25:57 am » |
I am an absolute Arduino newbie. I have been trying to connect the HDPL 1414 display to an Arduino Duemilanove. This is slightly different from to your situation and I am confused about the pin assignment. Could you please post a quick scheme of the connections in this case? Thank you very much for your help.
|
|
|
|
|
Logged
|
|
|
|
|
Rural Arizona
Offline
Edison Member
Karma: 7
Posts: 1712
Incorrigible tinkerer
|
 |
« Reply #9 on: November 27, 2009, 04:27:07 pm » |
The one featured in the video is no longer manufactured but I beleve it is this one It's similar, but not the same: the 2416 has larger digits, and a couple of extra chip select lines. Probably brighter, too, since it came along a little later. The big difference between those and the "starburst" displays you mentioned is the on-chip decoder/driver logic that makes them more convenient to use if you just need a few characters of alphanumeric display for a hobby project. The tiny characters and limited set kinda limit their appeal to young geeks with good eyesight and old geeks with excessive levels of nostalgia, though: not so interesting to a generation that expects even a $5 wristwatch to display an animated, full-color image of a crowing rooster when that alarm goes off  Ran
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 1
Posts: 13
Arduino rocks
|
 |
« Reply #10 on: November 27, 2009, 08:58:28 pm » |
Datasheet here: http://www.avagotech.com/docs/5988-3271ENLooks similar but the pins assignments are moved around a bit. It should be easy to get this working.
|
|
|
|
|
Logged
|
|
|
|
|
|