January 31

Jewelry Box: The Sum of Its Parts

All the parts are coming together, and it’s best to keep each working sketch separate along the way, until it’s time to piece them together. Using the example sketches, which already perform the tasks I want, I’ll strip the parts I need, and put it to use in my final sketch.

 

 

Sketch Book

DS3231 Real-Time Clock (RTC)

The DS3231 library that I used provides an active time keeper, but not a counter of time, which is what I need. Yet again, Adafruit has a solution for this sketch. Using the RTClib for the DS3231 RTC module, I can count the amount of time that has passed, from 2016-07-17-00-00-00 (July 17, 2016 at midnight). Unix time is 0 (zero) for January 1, 1970 at midnight GMT (+000). Since I was in Daylight Saving Time (-0700) on July 17, this makes it 7AM GMT, and the Unix time that I’m using for my calculations is 1468738800.

In obtaining the date, I want to either pass on an anniversary message, or the amount of days. If today is July 17, subtract the current year from 2016, and display “X-year anniversary” in the SSD1306 OLED display. Otherwise, count the days since July 17, 2016, and show it as “X days” on the display. Due to size constraints I cannot cleanly fit a numeric line with year and months, and a footer for the “Years Months” text. That said, I may revisit the idea once I pick up another 128×64 OLED display for testing.

DS3231 Sketch

#include "RTClib.h"

RTC_DS3231 rtc;

void setup() {
  Serial.begin(9600);

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
}

void loop() {
  DateTime now = rtc.now();
  if ((now.month() == 7) && (now.day() == 17)) {
    int anniversary = (now.year() - 2016);
    Serial.print("Happy ");
    Serial.print(anniversary);
    Serial.println("-year");
    Serial.println("Anniversary!");
  }
  else {
    Serial.print("My happiness for ");
    Serial.print((now.unixtime() - 1468738800) / 86400L);
    Serial.println(" days!");
  }
  delay(5000);
}

I’m sending the text to the Serial display for testing. Once verified that it works as expected, I can have the text sent to the SSD1306 OLED display. When first testing the display, I noted the position for the text in the yellow and blue parts of the screen, and can set the text position accordingly. This sketch works, and ready for use, moving forward.

 

 

SSD1306 128×64 OLED Display

The example sketch from Adafruit is will show all the different things you can do, and display, given the display size: 128×32, or 128×64. In my particular case, it’s 128×64, with a top portion being in yellow, and the rest in blue. I’m making use of this split to keep a static message in yellow, and placing the RTC module’s output in blue; dynamic content will happen later.

In the example sketch from Adafruit, there is a section which displays text. I’m using that part of the example sketch to piece together my message.

SSD1306 Sketch

#include <Adafruit_SSD1306.h>
#include <Wire.h>

#define OLED_RESET 3
Adafruit_SSD1306 display(OLED_RESET);

void setup() {
  Serial.begin(9600);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println("     I LOVE YOU");
  display.println("     <3 OLGA <3");
  display.println("   My happiness for");
  display.println("");
  display.setTextSize(3);
  display.println("   7");
  display.setTextSize(1);
  display.println("       MONTHS");
  display.display();
}

void loop() {
}

There isn’t anything to loop, since the display is static; only needs to run once. This is true for our testing, but won’t be true for the bottom portion, which will be set by the date determined by the DS3231. Due to the TFT display using pin 4 for Card Chip Selector (CCS), I set the OLED_RESET pin to 3 in this sketch.

 

 

ILI9341 TFT Display

The last, but certainly not the least, part of the puzzle. This one is by far the most complicated part, due to the microSD card, image formatting and manipulation, and sketch setup. The best part of the Adafruit TFT display was the simplicity in the setup: virtually a plug-and-play setup. One issue I’ve encountered was the images not displaying when I first upload the sketch, but if I press the reset button, or power cycle the Uno R3, it starts to work as expected. Since this only happened when I uploaded the sketch the first time, it’s a minor inconvenience that doesn’t impact continued use.

ILI9341 Sketch

#include <Adafruit_GFX.h>
#include "Adafruit_ILI9341.h"
#include <SPI.h>
#include <SD.h>

#define SD_CS 4
#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
#define BUFFPIXEL 20

void setup(void) {
  tft.begin();
  tft.fillScreen(ILI9341_BLUE);
}

void loop() {
  bmpDraw("olga01.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga02.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga03.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga04.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga05.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga06.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga07.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga08.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga09.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga10.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga11.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga12.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga13.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga14.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga15.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga16.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga17.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga18.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga19.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga20.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga21.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga22.bmp", 0, 0);
  delay(1000);
  bmpDraw("olga23.bmp", 0, 0);
  delay(1000);
}

void bmpDraw(char *filename, uint8_t x, uint16_t y) {

  File bmpFile;
  int bmpWidth, bmpHeight;
  uint8_t bmpDepth;
  uint32_t bmpImageoffset;
  uint32_t rowSize;
  uint8_t sdbuffer[3*BUFFPIXEL];
  uint8_t buffidx = sizeof(sdbuffer);
  boolean goodBmp = false;
  boolean flip = true;
  int w, h, row, col;
  uint8_t r, g, b;
  uint32_t pos = 0, startTime = millis();

  if(read16(bmpFile) == 0x4D42) {
    (void)read32(bmpFile);
    bmpImageoffset = read32(bmpFile);
    bmpWidth = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if(read16(bmpFile) == 1) {
      bmpDepth = read16(bmpFile);
      if((bmpDepth == 24) && (read32(bmpFile) == 0)) {

        goodBmp = true;
        rowSize = (bmpWidth * 3 + 3) & ~3;

        if(bmpHeight < 0) {
          bmpHeight = -bmpHeight;
          flip = false;
        }

        w = bmpWidth;
        h = bmpHeight;
        if((x+w-1) >= tft.width()) w = tft.width() - x;
        if((y+h-1) >= tft.height()) h = tft.height() - y;

        tft.setAddrWindow(x, y, x+w-1, y+h-1);

        for (row=0; row<h; row++) {
          if(flip)
            pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
          else
            pos = bmpImageoffset + row * rowSize;
            if(bmpFile.position() != pos) {
              bmpFile.seek(pos);
              buffidx = sizeof(sdbuffer);
            }

            for (col=0; col<w; col++) {
            if (buffidx >= sizeof(sdbuffer)) {
              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0;
            }

            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            tft.pushColor(tft.color565(r,g,b));
          }
        }
      }
    }
  }

  bmpFile.close();
}

uint16_t read16(File &f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read();
  ((uint8_t *)&result)[1] = f.read();
  return result;
}

uint32_t read32(File &f) {
  uint32_t result;
  ((uint8_t *)&result)[0] = f.read();
  ((uint8_t *)&result)[1] = f.read();
  ((uint8_t *)&result)[2] = f.read();
  ((uint8_t *)&result)[3] = f.read();
  return result;
}

This will show the pictures that I have on the microSD card, which I’ve named “olga##.bmp”. Due to the FAT32 format, the filename must be less than 8.3 characters long; 8 for the filename, then 3 for the extension. The file ‘123456789.bmp’ cannot be used, as it exceeds the 8.3 filename length.

The drawback to this sketch design is that if I add more pictures, I will need to name each image in the sketch, taking up more space. As it is currently written, I am nearing the maximum 32kB space on the Uno R3 microcontroller. Depending on the size of the other two sketches, I may be cutting it close. This could have a negative, unstable effect on my microcontroller. I’ll have to look into upgrading from the Uno R3, to the Mega board.

Tags: , , ,
Copyright 2025. All rights reserved.

Posted 2017-01-31 by Draik in category "Arduino", "Jewelry Box