#include // Library for the LPD8806 LED Strip #include // Library for the SD Card #include // Ligrary for the LCD Display #include // Library for the SPI Interface #define BACKLIGHT 10 // Pin used for the LCD Backlight #define SDssPin 53 // SD card CS pin #define STRIP_LENGTH 96 // Set the number of LEDs for BOTH Strips combined byte gamma(byte x); int dataPin1 = 31; // Data Pin for the first LED Strip int clockPin1 = 32; // Clock Pin for the first LED Strip int dataPin2 = 33; // Data Pin for the second LED Strip int clockPin2 = 34; // Clock Pin for the second LED Strip int frameDelay = 50; // default for the frame delay int dualdelay = 50; // default delay between strips (to make up for offset) LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //Init the LCD LPD8806 strip1 = LPD8806(STRIP_LENGTH, dataPin1, clockPin1); LPD8806 strip2 = LPD8806(STRIP_LENGTH, dataPin2, clockPin2); //BacklightControl to save battery Life boolean BackLightTimer = false; int BackLightTimeout = 400; int BackLightTemp = BackLightTimeout; //Stuff for the Keypad //int adc_key_val[5] ={ // 30, 150, 360, 535, 760 }; int adc_key_val[5] ={ 30, 150, 360, 600, 760 }; int NUM_KEYS = 5; int adc_key_in; int key=-1; int oldkey=-1; //AuxButton is a seperate button to send the image. Connect wires to these pins to use it. int AuxButton = 44; int AuxButtonGND = 45; //Up Button is a seperate button to move up the filenames. Connect wires to these pins to use it. int UpButton =42; int UpButtonGND = 43; //Down Button is a seperate button to move down the filenames. Connect wires to these pins to use it. int DownButton =40; int DownButtonGND =41; File root; File dataFile; String m_CurrentFilename = ""; int m_FileIndex = 0; int m_NumberOfFiles = 0; String m_FileNames[200]; //yep this is bad, but unless you are going to have over 200 images on your lightwand.. long buffer[STRIP_LENGTH]; void setup() { Serial.begin(115200); pinMode(AuxButton, INPUT); digitalWrite(AuxButton,HIGH); pinMode(AuxButtonGND, OUTPUT); digitalWrite(AuxButtonGND,LOW); pinMode(UpButton, INPUT); digitalWrite(UpButton,HIGH); pinMode(UpButtonGND, OUTPUT); digitalWrite(UpButtonGND,LOW); pinMode(DownButton, INPUT); digitalWrite(DownButton,HIGH); pinMode(DownButtonGND, OUTPUT); digitalWrite(DownButtonGND,LOW); setupLEDs(); setupLCDdisplay(); setupSDcard(); BackLightOn(); } void setupLEDs() { strip1.begin(); strip2.begin(); strip1.show(); strip2.show(); } void setupLCDdisplay() { lcd.begin(16,2); lcd.print("*** DLW V.07 ***"); lcd.setCursor(0, 1); lcd.print("Initializing..."); delay(1000); lcd.clear(); } void setupSDcard() { pinMode(SDssPin, OUTPUT); while (!SD.begin(SDssPin)) { BackLightOn(); lcd.print("SD init failed!"); delay(1000); lcd.clear(); delay(500); } lcd.clear(); lcd.print("SD init done."); delay(1000); root = SD.open("/"); lcd.clear(); lcd.print("Scanning files"); delay(500); GetFileNamesFromSD(root); isort(m_FileNames, m_NumberOfFiles); m_CurrentFilename = m_FileNames[0]; DisplayCurrentFilename(); } int ReadKeypad() { adc_key_in = analogRead(0); // read the value from the sensor digitalWrite(13, HIGH); key = get_key(adc_key_in); // convert into key press //Serial.print("key read = "); //Serial.println(adc_key_in,DEC); if (key != oldkey) { // if keypress is detected delay(50); // wait for debounce time adc_key_in = analogRead(0); // read the value from the sensor key = get_key(adc_key_in); // convert into key press if (key != oldkey) { oldkey = key; if (key >=0){ return key; } } } return key; } // Convert ADC value to key number int get_key(unsigned int input) { int k; for (k = 0; k < NUM_KEYS; k++) { if (input < adc_key_val[k]) { return k; } } if (k >= NUM_KEYS) k = -1; // No valid key pressed return k; } //The Main menu starts here... void loop() { int keypress = ReadKeypad(); if (( keypress == 1) || (digitalRead(UpButton) == LOW)) { //up key (step up through the filenames) BackLightOn(); if (m_FileIndex > 0) { m_FileIndex--; } else { m_FileIndex = m_NumberOfFiles -1; //wrap round to the last file } DisplayCurrentFilename(); delay(500); } if (( keypress == 2) || (digitalRead(DownButton) == LOW)) { //down key (step down through the filenames) BackLightOn(); if (m_FileIndex < m_NumberOfFiles -1) { m_FileIndex++; } else { m_FileIndex = 0;//wrap round to the 1st file again } DisplayCurrentFilename(); delay(500); } //Serial.print(digitalRead(AuxButton),DEC);//for displaying the key values if ((keypress == 4) || (digitalRead(AuxButton) == LOW)) { //select key (send out the selected file) SendFile(m_CurrentFilename); } if(keypress == 0) { //right key (frame delay +) BackLightOn(); if (frameDelay < 200) { frameDelay+=5; } ShowFrameDelay(); } if(keypress == 3) { //left key (frame delay -) BackLightOn(); if (frameDelay > 5) { frameDelay-=5; } ShowFrameDelay(); } if (BackLightTimer == true) BackLightTime(); } void BackLightOn() { analogWrite(BACKLIGHT,255); BackLightTimer = true; BackLightTemp = BackLightTimeout; } void BackLightTime() { if ((BackLightTemp <= 255) && (BackLightTemp >= 0)) { analogWrite(BACKLIGHT,BackLightTemp); delay(1); } if (BackLightTemp <= 0) { BackLightTimer = false; BackLightTemp = BackLightTimeout; analogWrite(BACKLIGHT,0); } else { BackLightTemp --; delay(1); } } void ShowFrameDelay() { lcd.clear(); lcd.print("Frame delay:"); lcd.setCursor(0,1); lcd.print(frameDelay); delay(500); DisplayCurrentFilename(); } void SendFile(String Filename) { lcd.clear(); lcd.print("Sending File"); lcd.setCursor(0, 1); lcd.print(Filename); char temp[14]; Filename.toCharArray(temp,14); dataFile = SD.open(temp); // if the file is available send it to the LED's if (dataFile) { ReadTheFile(); dataFile.close(); ClearStrip(100); } else { lcd.clear(); lcd.print(" Error reading"); lcd.setCursor(4, 1); lcd.print("file"); BackLightOn(); delay(1000); lcd.clear(); setupSDcard();//try to re-init the SD card...(this was failing, but a fix can be done below) //In the SD.CPP in the BEGIN class which starts // boolean SDClass::begin(uint8_t csPin) { // //it needs the line below to be added // // if (root.isOpen()) root.close(); // allows repeated calls // // Just before the line // return card.init(SPI_HALF_SPEED, csPin) && // // return; } DisplayCurrentFilename(); } void DisplayCurrentFilename() { m_CurrentFilename = m_FileNames[m_FileIndex]; lcd.clear(); lcd.print(m_CurrentFilename); } void GetFileNamesFromSD(File dir) { int fileCount = 0; String CurrentFilename = ""; while(1) { File entry = dir.openNextFile(); if (! entry) { // no more files m_NumberOfFiles = fileCount; entry.close(); break; } else { if (entry.isDirectory()) { //GetNextFileName(root); } else { CurrentFilename = entry.name(); if (CurrentFilename.endsWith(".bmp") || CurrentFilename.endsWith(".BMP") ) { //find files with our extension only m_FileNames[fileCount] = entry.name(); fileCount++; } } } entry.close(); } } void latchanddelay(int dur) { strip2.show(); delay(dualdelay); strip1.show(); delay(dur); } void ClearStrip(int duration) { int x; for(x=0;x STRIP_LENGTH) { displayWidth = STRIP_LENGTH;//only display the number of led's we have } /* compute the line length */ uint32_t lineLength = imgWidth * 3; if ((lineLength % 4) != 0) lineLength = (lineLength / 4 + 1) * 4; //Serial.println("Line Length"); //Serial.println(lineLength,DEC); for(int y=imgHeight;y>0 ;y--) { int bufpos=0; int m = 0; for(int x=0;x < displayWidth ;x ++) { uint32_t offset = (MYBMP_BF_OFF_BITS + (((y-1)* lineLength) + (x*3))) ; //Serial.print("x = "); //Serial.println(x,DEC); dataFile.seek(offset); int g=gamma(readByte()); int b=gamma(readByte()); int r=gamma(readByte()); strip1.setPixelColor(m,r,b,g); x++; g=gamma(readByte()); b=gamma(readByte()); r=gamma(readByte()); strip2.setPixelColor(m,r,b,g); m++; } latchanddelay(frameDelay); } //Serial.println("Finished"); ClearStrip(100); } //sort the filenames in alphabetical order void isort(String *filenames, int n) { for (int i = 1; i < n; ++i) { String j = filenames[i]; int k; for (k = i - 1; (k >= 0) && (j < filenames[k]); k--) { filenames[k + 1] = filenames[k]; } filenames[k + 1] = j; } } // Gamma correction compensates for our eyes' nonlinear perception of // intensity. It's the LAST step before a pixel value is stored, and // allows intermediate rendering/processing to occur in linear space. // The table contains 256 elements (8 bit input), though the outputs are // only 7 bits (0 to 127). This is normal and intentional by design: it // allows all the rendering code to operate in the more familiar unsigned // 8-bit colorspace (used in a lot of existing graphics code), and better // preserves accuracy where repeated color blending operations occur. // Only the final end product is converted to 7 bits, the native format // for the LPD8806 LED driver. Gamma correction and 7-bit decimation // thus occur in a single operation. PROGMEM prog_uchar gammaTable[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 21, 21, 21, 22, 22, 23, 23, 24, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 37, 37, 38, 38, 39, 40, 40, 41, 41, 42, 43, 43, 44, 45, 45, 46, 47, 47, 48, 49, 50, 50, 51, 52, 52, 53, 54, 55, 55, 56, 57, 58, 58, 59, 60, 61, 62, 62, 63, 64, 65, 66, 67, 67, 68, 69, 70, 71, 72, 73, 74, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,104,105,106,107,108, 109,110,111,113,114,115,116,117,118,120,121,122,123,125,126,127 }; inline byte gamma(byte x) { return pgm_read_byte(&gammaTable[x]); }