Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // Arduino Digital Light Wand + SD + LCD V1.06 (LPD8806)
- // by Is0-Mick 2012
- //
- //This version can use dual strips for double the resolution
- //
- //This version supports direct reading of a 24bit BMP from the SD card.
- //You need to rotate the image 90 degrees right, due to lack of memory / speed to process
- //this on the fly...
- //
- // Added Gamma Table from ada fruit code which gives better conversion of 24 bit to 21 bit
- // instead of just bitshifting values.
- // Also added version number to display on start up.
- //
- // Fixed a strange problem with 1 green pixel being left on if the last line of the image
- // or last pixel was not black. Apparently seems to be a known hardware / library bug...
- //
- // Tidied up code
- //
- // Fixed Backlight Problem
- //
- // Fixed the SD init problem (removing card, trying to send a file (which fails) now re-inits the card.
- // Backlight now fades out, instead of just switching off.
- //
- // Changed one of the original values of the shields key values, as it was thinking you were pressing a different
- // button sometimes, so changed the 535 value to 600 which seems to fix that :)
- //
- // Added code for an external switch to show the bitmap so you don't have fiddle with the small button on the shield
- // Pins are defined as aux button. I pulled one low as a GND, and the other is the trigger.(pins 44,45 currently)
- #include <LPD8806.h>
- #include <SD.h>
- #include <LiquidCrystal.h>
- #include <SPI.h>
- #define BACKLIGHT 10
- #define SDssPin 53 //SD card CS pin
- int frameDelay = 10; // default for the frame delay
- LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //Init the LCD
- int dataPin = 31;
- int clockPin = 32;
- byte gamma(byte x);
- #define STRIP_LENGTH 104
- boolean dualstrip = true;
- LPD8806 strip = LPD8806(STRIP_LENGTH, dataPin, clockPin);
- //BacklightControl to save battery Life
- boolean BackLightTimer = false;
- int BackLightTimeout = 2000;
- 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;
- 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);
- setupLEDs();
- setupLCDdisplay();
- setupSDcard();
- BackLightOn();
- }
- void setupLEDs()
- {
- strip.begin();
- strip.show();
- }
- void setupLCDdisplay()
- {
- lcd.begin(16,2);
- lcd.print("*** DLW V.05 ***");
- 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) //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) //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;
- 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++;
- }
- }
- }
- }
- }
- void latchanddelay(int dur)
- {
- strip.show();
- delay(dur);
- }
- void ClearStrip(int duration)
- {
- int x;
- for(x=0;x<STRIP_LENGTH;x++)
- {
- strip.setPixelColor(x, 0);
- }
- strip.show();// Had to add this extra show, otherwise if you were displaying an image
- // and the last line / pixel were white, a green pixel would remain lit!
- latchanddelay(duration);
- }
- uint32_t readLong()
- {
- uint32_t retValue;
- byte incomingbyte;
- incomingbyte=readByte();
- retValue=(uint32_t)((byte)incomingbyte);
- incomingbyte=readByte();
- retValue+=(uint32_t)((byte)incomingbyte)<<8;
- incomingbyte=readByte();
- retValue+=(uint32_t)((byte)incomingbyte)<<16;
- incomingbyte=readByte();
- retValue+=(uint32_t)((byte)incomingbyte)<<24;
- return retValue;
- }
- uint16_t readInt()
- {
- byte incomingbyte;
- uint16_t retValue;
- incomingbyte=readByte();
- retValue+=(uint16_t)((byte)incomingbyte);
- incomingbyte=readByte();
- retValue+=(uint16_t)((byte)incomingbyte)<<8;
- return retValue;
- }
- int readByte()
- {
- int retbyte=-1;
- while(retbyte<0) retbyte= dataFile.read();
- return retbyte;
- }
- void ReadTheFile()
- {
- #define MYBMP_BF_TYPE 0x4D42
- #define MYBMP_BF_OFF_BITS 54
- #define MYBMP_BI_SIZE 40
- #define MYBMP_BI_RGB 0L
- #define MYBMP_BI_RLE8 1L
- #define MYBMP_BI_RLE4 2L
- #define MYBMP_BI_BITFIELDS 3L
- uint16_t bmpType = readInt();
- uint32_t bmpSize = readLong();
- uint16_t bmpReserved1 = readInt();
- uint16_t bmpReserved2 = readInt();
- uint32_t bmpOffBits = readLong();
- bmpOffBits = 54;
- Serial.println("bmpType = ");
- Serial.println(bmpType,HEX);
- Serial.println("bmpSize");
- Serial.println(bmpSize,DEC);
- Serial.println("bmpReserved1");
- Serial.println(bmpReserved1,DEC);
- Serial.println("bmpReserved2");
- Serial.println(bmpReserved2,DEC);
- Serial.println("bmpOffBits");
- Serial.println(bmpOffBits,DEC);
- /* Check file header */
- if (bmpType != MYBMP_BF_TYPE || bmpOffBits != MYBMP_BF_OFF_BITS)
- {
- lcd.setCursor(0, 0);
- lcd.print("not a bitmap");
- delay(1000);
- return;
- }
- /* Read info header */
- uint32_t imgSize = readLong();
- uint32_t imgWidth = readLong();
- uint32_t imgHeight = readLong();
- uint16_t imgPlanes = readInt();
- uint16_t imgBitCount = readInt();
- uint32_t imgCompression = readLong();
- uint32_t imgSizeImage = readLong();
- uint32_t imgXPelsPerMeter = readLong();
- uint32_t imgYPelsPerMeter = readLong();
- uint32_t imgClrUsed = readLong();
- uint32_t imgClrImportant = readLong();
- Serial.println("bitmap height");
- Serial.println(imgHeight,DEC);
- Serial.println("bitmap Width");
- Serial.println(imgWidth,DEC);
- Serial.println("bitmap bpp");
- Serial.println(imgBitCount,DEC);
- /* Check info header */
- if( imgSize != MYBMP_BI_SIZE || imgWidth <= 0 ||
- imgHeight <= 0 || imgPlanes != 1 ||
- imgBitCount != 24 || imgCompression != MYBMP_BI_RGB ||
- imgSizeImage == 0 )
- {
- lcd.setCursor(0, 0);
- lcd.print("Unsupported");
- lcd.setCursor(0, 1);
- lcd.print("Bitmap Use 24bpp");
- delay(1000);
- return;
- }
- int displayWidth = imgWidth;
- if (imgWidth > 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);
- int x = 0;
- for(int y=imgHeight;y>0 ;y--) {
- int bufpos=0;
- if ( dualstrip == true)
- {
- int pos = 0;
- for(int x=0;x <((displayWidth)/2) ;x ++) {
- uint32_t offset = (MYBMP_BF_OFF_BITS + (((y-1)* lineLength) + (pos*3))) ;
- //Serial.println("x = ");
- //Serial.println(x,DEC);
- dataFile.seek(offset+3);
- int g=gamma(readByte());
- int b=gamma(readByte());
- int r=gamma(readByte());
- strip.setPixelColor(x,r,g,b);
- g=gamma(readByte());
- b=gamma(readByte());
- r=gamma(readByte());
- strip.setPixelColor((STRIP_LENGTH-x)-1,r,g,b);
- pos+=2;
- }
- latchanddelay(frameDelay/2);
- }
- else
- {
- for(int x=0;x <displayWidth ;x++) {
- uint32_t offset = (MYBMP_BF_OFF_BITS + (((y-1)* lineLength) + (x*3))) ;
- dataFile.seek(offset);
- int g=gamma(readByte());
- int b=gamma(readByte());
- int r=gamma(readByte());
- strip.setPixelColor(x,r,g,b);
- }
- 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]);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement