Feedback!

Arduino

Arduino is a very awesome micro-controller platform which we use extensively here at LucidTronix. The Arduino team did a wonderful job creating a smooth, beginner-friendly suite of software and hardware for programming interactive electronics. Below check out our tutorials tagged with Arduino. We often make Arduino-clones, using the software of the Arduino community and our own custom artisanal Printed Circuit Boards.
RGB Flashlight, wearable sound art, rainbow lamp....
Think of it like a shift register for Pulse Width Modulation (PWM)....
Wall-ter is a wall following robot....
Rainbow flower necklace using the TLC5940....
Play pong on a little LCD screen with two big joysticks....
Control a 120v outlet with a 5V arduino....
Control the hue, value and saturation on this pocket-sized joystick drawing machine....
This PCB controls a camera and an SD card so you can make automatic time lapse videos. ...
Two proximity sensors help this bot avoid cliffs....
Light sensors guids this robot towards the light....
Here is another arduino library to handle Hue, Saturation, and Brightness as well as Red, Green, and ...
Display bitmap images and text files and folders with this TFT LCD screen and SD Card navigator....
Mixing pixels from two face images together....
Print bitmaps, cellular automata, drawings and text.....
A wearable real-time clock with vibrant color display....
Coupling the HMC5883L Compass with our color library turns the Wearable Wayfinder into a handy naviga...
3d view of a face using an SD card, accelerometer and a TFT LCD Screen...
Control the Heart Matrix LED display wirelessly, using XBEE radio modules....
The heartduino is a heart-shaped arduino clone complete with onboard sensors and a 70 pixel LED matri...
Combine an electret microphone, Arduino and a heart matrix for a sound-sensitive wearable device....
Connecting the MCP79410 real-time clock chip and our Heart Matrix you can show the time with love....
Wearable digital compass displays the direction in green LEDs....
Servo motor, JPEG camera, and Arduino Leonardo combine to make a panoramic camera....
An introduction to programming Arduinos using In-system programming...
Write messages on Liquid Crystal Displays with potentiometers or keyboards....
Arduino-powered spherical camera with 2 Servo Motors and an SD Card....
Handheld gaming machine, based on the Arduino Leonardo, equipped with joystick, SD card and more....
32 buttons for a fully-functioning hand-held USB keyboard....
Build your own clock with the MCP79410 chip and 4 7-Segment LED modules....
Our take on the classic bouncing ball, paddle game....
The Wearable Wayfinder is a totally programmable, beautiful little computer for your wrist packed wit...
Standalone programmable Heart-Shaped LED display....
A hackable Human interface device in 3 dimensions....
An arduino library for the MMA8453 Triple Axis Accelerometer...
How to upload code to an Arduino Leonardo clone....
A library to interface Arduino code with the 3 Axis L3G4200D gyroscope....

Assets

Arduino Code

This whole project basically boils down to these three lines of code:
      float avg_b = ((float)b*ratio )+ ((float)b2*(1-ratio));
      float avg_g = ((float)g*ratio )+ ((float)g2*(1-ratio));
      float avg_r = ((float)p*ratio )+ ((float)p2*(1-ratio));
the floating point variable 'ratio' controls the weight of each pixel. Notice that ratio is always between 0 and 1. So if ratio is 0.3 then 1-ratio = 0.7 and we will take 70% of the second pixel and 30% of the first. The code below is for the Joy Gamer so you will need to download the necessary libraries available at our basic Joy Gamer tutorial.
/* LucidTronix Joy Gamer SD Navigator
 * If the compiler gives you an error about sketch being too big make sure to
 * COMMENT OUT both the USE_ACCELEROMETER and the USE COLOR defines in the JoyGamer.h file.  
 * They should look like this:
 //#define USE_ACCELEROMETER
 //#define USE_COLOR
 * For more instructions, details and schematic, See:
 * http://www.lucidtronix.com/tutorials/27
 */

#include <JoyGamer.h>
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#include <SD.h>

Adafruit_ST7735  tft = Adafruit_ST7735(SS, 9, 8);
JoyGamer jg = JoyGamer(&tft);

File bmpFile1;
File bmpFile2;

// information we extract about the bitmap file
int bmpWidth, bmpHeight;
int bmpWidth2, bmpHeight2;
uint8_t bmpDepth, bmpImageoffset;
uint8_t bmpDepth2, bmpImageoffset2;
float ratio = 0.5;

int img_index1 = 12;
int img_index2 = 16;
int num_images = 60;

void setup(void) {
  jg.initialize();
  jg.start_sd_card();
  bmp_load_and_draw_2_images("face36.bmp","face34.bmp");
}

void loop() {
  bmpdraw_2_images();
}

void bmp_load_and_draw_2_images(char* filename1, char* filename2) {
  bmpFile1 = SD.open(filename1);
  bmpFile2 = SD.open(filename2);
  if (!bmpFile1) {
    jg.draw_string(12,62, "Coodn't find image", ST7735_RED);
  }

  if (!bmpReadHeader(bmpFile1,0)) { 
    jg.draw_string(12,82, "Bad image" , ST7735_RED);
  }
  if (!bmpFile2) {
    jg.draw_string(12,62, "Coodn't find image 2" , ST7735_RED);
  }
  if (!bmpReadHeader(bmpFile2,1)) { 
    jg.draw_string(12,82, "Bad image 2" , ST7735_RED);
  }
  bmpdraw_2_images();
}

/*********************************************/
// This procedure reads 2 bitmaps and draws an average to the screen
// its sped up by reading many pixels worth of data at a time
// instead of just one pixel at a time. increading the buffer takes
// more RAM but makes the drawing a little faster. 20 pixels' worth
// is probably a good place

#define BUFFPIXEL 20
void bmpdraw_2_images() {
  bmpFile1.seek(bmpImageoffset);
  bmpFile2.seek(bmpImageoffset2);
  uint32_t time = millis();
  uint16_t p, p2; 
  uint8_t g, b;
  uint8_t g2, b2;
  int i, j;
  unsigned int file_pos = bmpImageoffset;

  uint8_t sdbuffer[3 * BUFFPIXEL];  // 3 * pixels to buffer
  uint8_t buffidx = 3*BUFFPIXEL;
  uint8_t sdbuffer2[3 * BUFFPIXEL];  // 3 * pixels to buffer
  //set up the 'display window'
  tft.setAddrWindow(0, 0, bmpWidth-1, bmpHeight-1);

  for (i=0; i< bmpHeight; i++) {
    // bitmaps are stored with the BOTTOM line first so we have to move 'up'

    for (j=0; j<bmpWidth; j++) {
      // read more pixels
      if (buffidx >= 3*BUFFPIXEL) {
        bmpFile1.read(sdbuffer, 3*BUFFPIXEL);
        bmpFile2.read(sdbuffer2, 3*BUFFPIXEL);
        buffidx = 0;
      }
      // convert pixel from 888 to 565
      b = sdbuffer[buffidx++];     // blue
      g = sdbuffer[buffidx++];     // green
      p = sdbuffer[buffidx++];     // red
      // convert pixel from 888 to 565
      buffidx -= 3;  

      b2 = sdbuffer2[buffidx++];     // blue
      g2 = sdbuffer2[buffidx++];     // green
      p2 = sdbuffer2[buffidx++];     // red

      file_pos += 3;

      float avg_b = ((float)b*ratio )+ ((float)b2*(1-ratio));
      float avg_g = ((float)g*ratio )+ ((float)g2*(1-ratio));
      float avg_r = ((float)p*ratio )+ ((float)p2*(1-ratio));

      b = (int) avg_r;
      g = (int) avg_g;
      p = (int) avg_b;

      p >>= 3;
      p <<= 6;

      g >>= 2;
      p |= g;
      p <<= 5;

      b >>= 3;
      p |= b;

      tft.drawPixel(j, bmpHeight - i, p);
    }
    if( digitalRead(jg.joystick_btn_pin) == HIGH){
      reset_image(&img_index1, &bmpFile1, file_pos); 
    }
    if(digitalRead(jg.btn_pin) == LOW) {
      reset_image(&img_index2, &bmpFile2, file_pos); 
    }
    float cur_val = analogRead(0);
    ratio = cur_val / 1024.0;
  }
}

void reset_image(int *index, File *a_file, int file_pos)
{
  *index = ++*index % num_images;
  a_file->close();
  String img2 = "face";
  img2 += String(*index);
  img2 += ".bmp";
  char  img2c[11] ;
  for(int i = 0; i < 10; i++){
    img2c[i] = img2.charAt(i);
  }
  if (*index < 10 ) {
    for(int i = 10; i >= 5; i--){
      img2c[i] = img2c[i-1];
    }
    img2c[4] = '0';
  }
  img2c[10] = 0;
  *a_file = SD.open(img2c);
  a_file->seek(file_pos); 
}

boolean bmpReadHeader(File f, int mode) {
  // read header
  uint32_t tmp;

  if (read16(f) != 0x4D42) {
    // magic bytes missing
    return false;
  }

  // read file size
  tmp = read32(f);  
  //Serial.print("size 0x"); Serial.println(tmp, HEX);

  // read and ignore creator bytes
  read32(f);

  if (mode == 0 ) bmpImageoffset = read32(f); 
  else if (mode == 1 ) bmpImageoffset2 = read32(f);  
  //Serial.print("offset "); Serial.println(bmpImageoffset, DEC);

  // read DIB header
  tmp = read32(f);
  //Serial.print("header size "); Serial.println(tmp, DEC);
  if (mode == 0 ) {
    bmpWidth = read32(f);
    bmpHeight = read32(f);
  } 
  else if (mode == 1 ) {
    bmpWidth2 = read32(f);
    bmpHeight2 = read32(f);
  }

  if (read16(f) != 1)
    return false;

  if (mode == 0 ) bmpDepth = read16(f);
  else if (mode == 1 ) bmpDepth2 = read16(f);
  //Serial.print("bitdepth "); Serial.println(bmpDepth, DEC);

  if (read32(f) != 0) {
    // compression not supported!
    return false;
  }
  return true;
}

/*********************************************/

// These read data from the SD card file and convert them to big endian 
// (the data is stored in little endian format!)

// LITTLE ENDIAN!
uint16_t read16(File f) {
  uint16_t d;
  uint8_t b;
  b = f.read();
  d = f.read();
  d <<= 8;
  d |= b;
  return d;
}

// LITTLE ENDIAN!
uint32_t read32(File f) {
  uint32_t d;
  uint16_t b;

  b = read16(f);
  d = read16(f);
  d <<= 16;
  d |= b;
  return d;
}

Display a Bitmap on the Joy Gamer Arduino Code

Here is Arduino Code to show a bitmap image on the Joy Gamer. Our library does almost all the work for you :) Just call the function:
  jg.bmp_load_and_draw_image("sample.bmp");
Make sure you have the SD card inserted properly, and loaded with the bitmap file "sample.bmp". You can of course load whatever images you want. The images do have to be in bitmap format and at largest 128 by 160 pixels. We wrote a little program to convert images into the bmp format, you can download it below.
/* LucidTronix Joy Gamer
 * For instructions, details and schematic, See:
 * http://www.lucidtronix.com/tutorials/48
 */

#include <JoyGamer.h>
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#include <Color.h>
#include <I2C.h>
#include <MMA8453Q.h>
#include <SD.h>

Adafruit_ST7735  tft = Adafruit_ST7735(SS, 9, 8);
JoyGamer jg = JoyGamer(&tft);

void setup(){
  jg.initialize();
  jg.start_sd_card();
  jg.bmp_load_and_draw_image("sample.bmp");
}

void loop() {

}

SD Navigator Arduino Code

Here is the Arduino code behind the SD card navigator on the Joy Gamer. We are pushing right up against the edge of what the little Atmega32u4 chip can handle so we had to hack a bit to make this work. First in the JoyGamer.h file you have to comment out the defines like this:
//#define USE_ACCELEROMETER
//#define USE_COLOR
This way we don't load libraries we won't use and we can fit all the SD navigator code on the device. Otherwise you will get the nasty sketch too big error.
Okay now that the code compiles let's have a bit of explanation. This code has 3 modes: display a directory, display a bitmap or display a text file. There is a global variable cur_file which is either the directory, bitmap or text file we are currently viewing. We keep track of the modes using an enum defined at the top of the file. This is a little cleaner and easier to read than just using an int for the mode:
enum modes_t{
  DISPLAY_DIRECTORY,
  DISPLAY_BITMAP,
  DISPLAY_TEXT
};

modes_t mode = DISPLAY_DIRECTORY;
Then in the main loop we have switch statement on the current mode. In the setup function we open the root directory and set it as the cur_file in the function open_file(). This function sets the mode appropriately given the type of file fed in as an argument.
Throughout the code we check if jg.btn_pin is pressed and if so we jump back to displaying the root directory. Links to all the necessry libraries can be found at the Joy Gamer Tutorial. See the whole file below:
/* LucidTronix Joy Gamer SD Navigator
 * If the compiler gives you an error about sketch being too big make sure to
 * COMMENT OUT both the USE_ACCELEROMETER and the USE COLOR defines in the JoyGamer.h file.  
 * They should look like this:
 //#define USE_ACCELEROMETER
 //#define USE_COLOR
 * For more instructions, details and schematic, See:
 * http://www.lucidtronix.com/tutorials/21
 */

#include <JoyGamer.h>
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#include <SD.h>

Adafruit_ST7735  tft = Adafruit_ST7735(SS, 9, 8);
JoyGamer jg = JoyGamer(&tft);

enum modes_t{
  DISPLAY_DIRECTORY,
  DISPLAY_BITMAP,
  DISPLAY_TEXT
};

modes_t mode = DISPLAY_DIRECTORY;

int cursor_x = 64;
int cursor_y = 64;

File cur_file;
File selected_file;
int cur_dir_files;
const int max_files = 12;
String files[max_files];

int line_height = 12;
int char_width = 6;
unsigned long last_switch = 0;

void setup(){
  jg.initialize();
  jg.start_sd_card();
  open_file("/");
}

void loop(){
  switch(mode){
    case DISPLAY_DIRECTORY:
      handle_cursor();
      for(int i = 0; i < cur_dir_files; i++){
        if(cursor_y > i*10+ 10 && cursor_y < i*10 + 20){
          jg.draw_string(10, i*10 + 10, files[i], ST7735_MAGENTA);
          if(digitalRead(jg.joystick_btn_pin) == HIGH) {
            open_file(files[i]);
            break;
          }
        } 
        else {
          jg.draw_string(10, i*10 + 10, files[i], ST7735_BLACK);
        }
        if(digitalRead(jg.btn_pin) == LOW && millis() - last_switch > 500) {
          open_file("/");
          break;
        }
      }
      break;
    case DISPLAY_TEXT:
      jg.clear_screen(ST7735_WHITE);
      jg.clear_screen();
      display_text_file();
      break;
    case DISPLAY_BITMAP:
      jg.bmpdraw(cur_file);
      delay(2000);
      open_file("/");
      break;
  }
}

void handle_cursor(){
  tft.fillCircle(cursor_x, cursor_y, 5, ST7735_WHITE);
  int delta_x = map(analogRead(0), 0, 1024, -6, 6); 
  int delta_y = map(analogRead(1), 0, 1024, -8, 8);
  cursor_x = constrain(cursor_x + delta_x, 5, 123);
  cursor_y = constrain(cursor_y + delta_y, 5, 155); 
  tft.fillCircle(cursor_x, cursor_y, 5, ST7735_GREEN);
}

void open_file(String filename){
  jg.clear_screen(ST7735_WHITE);
  cur_file.seek(0);
  cur_file.close();
  delay(100);
  char buffer[13];
  filename.toCharArray(buffer, 13);
  cur_file = SD.open(buffer);
  filename.toLowerCase();
  if(cur_file.isDirectory()){
    mode = DISPLAY_DIRECTORY;
    load_dir(cur_file);
  }
  else if(filename.lastIndexOf(".bmp") != -1){
    mode = DISPLAY_BITMAP;
  }
  else {
    mode = DISPLAY_TEXT;
  }
  last_switch = millis();
}

void load_dir(File dir){
  for(int i = 0; i < max_files; i++) files[i] = "";
  jg.clear_screen(ST7735_WHITE);
  dir.rewindDirectory();
  File entry =  dir.openNextFile();
  cur_dir_files = 0;
  while(entry && SD.exists(entry.name()) && max_files > cur_dir_files){
    String filename = entry.name();
    if(filename[0] != '.' && filename[0] != '_' && filename.lastIndexOf('~') == -1){ // don't show hidden files
      files[cur_dir_files] = filename;
      cur_dir_files++;
    }
    entry.close();
    entry = dir.openNextFile();
  }
  dir.rewindDirectory();
}

void display_text_file(){
  int aax = 2;
  int aay = 3;
  tft.setTextColor(ST7735_BLACK);
  while(cur_file && cur_file.available() && aay < 150){
    char cur_c = cur_file.read();
    if(cur_c == 10 || cur_c == 13 || (cur_c == ' ' && aax > 85)){
      aay += line_height;
      aax = 2;
    }
    else {   
      tft.setCursor(aax, aay);
      tft.print(cur_c);
      aax += char_width;
      if (aax >= 118) {
        aax = 2;
        aay += line_height;
      }
    }
    delay(10);
    if(digitalRead(jg.btn_pin) == LOW && millis() - last_switch > 500) {
      open_file("/");
      break;
    }
  }
  delay(1500);
}
List All Tags

Open Interactive Tag Tree