I'm building a project that displays a random poem from an SD card to a LCD on button press. I reached the point where I wanted to enclose it and power it via batteries. I would like the Arduino to sleep until a button is pressed, wake up, display a random poem from the SD card, then return to sleep. So far I've been able to get the Arduino to go to sleep but on button press it prints out a poem too fast to read then returns to sleep. Any help is greatly appreciated.
// SPI
#include <SPI.h>
// interrupt library/pin
#include <avr/interrupt.h>
#include <avr/sleep.h>
// pin to for interrupt
int wakePin = 3;
// SD card chip select pin.
const byte chipSelect = 10;
// File system object. Make SdFat compatible with SD.
#include <SdFat.h>
SdFat SD;
// Directory file.
File root;
// Text file
File entry;
//number of files in root
int rootFileCount = 0;
// initialize the LCD library by associating any LCD interface pin
// with the arduino pin number it is connected to
#include <LiquidCrystal.h>
const int rs = 9, en = 2, d4 = 6, d5 = 7, d6 = 4, d7 = 8;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
// number of LCD columns and rows
const byte lcdCols = 20;
const byte lcdRows = 4;
// index of poetry file to read on SD card
int threshold;
void setup() {
Serial.begin(9600);
while (!Serial) {
SysCall::yield();
}
Serial.println("Serial initialized. Initializing LCD display...");
// set up the LCD's number of columns and rows:
lcd.begin(lcdCols, lcdRows);
// turn off LCD autoscrolling
lcd.noAutoscroll();
// set up switch pins
pinMode(wakePin, INPUT_PULLUP);
Serial.println("LCD initialized. Initializing SD card...");
//Initialize at the highest speed supported by the board that is
//not over 50 MHz. Try a lower speed if SPI errors occur.
delay(1000);
while (!SD.begin(chipSelect, SD_SCK_MHZ(50))) {
SD.initErrorHalt();
}
Serial.println("SD card initialized. Opening root directory...");
if (!root.open("/")) {
Serial.println("Opening root directory failed.");
}
while (root.openNextFile()) {
rootFileCount++;
}
Serial.print(rootFileCount);
Serial.println(" files counted.");
// generate a seed for the RNG and random starting colours
randomSeed(analogRead(0));
delay(1000);
}
void sleepNow()
{
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
noInterrupts (); // make sure we don't get interrupted before we sleep
sleep_enable (); // enables the sleep bit in the mcucr register
EIFR = bit (INTF0); // clear flag for interrupt 0
attachInterrupt (1, wakeUpNow, RISING); // wake up on rising edge
interrupts (); // interrupts allowed now, next instruction WILL be executed
sleep_cpu (); // here the device is put to sleep
detachInterrupt (1); // stop this interrupt until next time
}
void loop() {
Serial.println("going to sleep");
delay(150);
sleepNow();
}
void wakeUpNow()
{
Serial.println("waking up");
delay(1000);
displayPoem();
}
void displayPoem()
{
// move to root directory beginning
root.rewindDirectory();
//generate random number up to file count and open the corresponding file
threshold = random(0, rootFileCount);
//loop through directory to open selected random poem
int i = 0;
while (i < threshold) {
entry = root.openNextFile();
i++;
}
// arrays with characters to display on each row of lcd screen
char row0[lcdCols];
char row1[lcdCols];
char row2[lcdCols];
char row3[lcdCols];
// initialise as empty otherwise problems will occur when reading first line
memset(row0, ' ', lcdCols);
memset(row1, ' ', lcdCols);
memset(row2, ' ', lcdCols);
memset(row3, ' ', lcdCols);
// read the file byte by byte and display it on the LCD screen
byte b = 0;
byte le;
bool leFlag = false;
while (entry.available()) {
//if the next byte is a carriage return
if (entry.peek() == 13) {
leFlag = true;
//ignore carriage return and line end symbols
entry.read();
entry.read();
}
else {
// ignore any non basic ascii symbols
while (entry.peek() < 32 || entry.peek() > 126) {
entry.read();
}
//first row
if (b < lcdCols) {
row0[b] = entry.read();
// prevent words from splitting over lines
if (b == lcdCols - 1 && entry.peek() != ' ') {
//find the last instance of space in row0
le = lineEnd(row0, lcdCols);
//shift all text after the last space to the row beneath
for (byte c = le; c < lcdCols; c++) {
row1[c - le] = row0[c];
row0[c] = ' ';
}
//update the index position to account for the shift;
b = 2 * lcdCols - 1 - le;
}
//second row
} else if (b < lcdCols * 2) {
row1[b - lcdCols] = entry.read();
// prevent words from splitting over lines
if (b == lcdCols * 2 - 1 && entry.peek() != ' ') {
//find the last instance of space in row1
le = lineEnd(row1, lcdCols);
//shift all text after the last space to the row beneath
for (byte c = le; c < lcdCols; c++) {
row2[c - le] = row1[c];
row1[c] = ' ';
}
//update the index position to account for the shift;
b = 3 * lcdCols - 1 - le;
}
//third row
} else if (b < lcdCols * 3) {
row2[b - lcdCols * 2] = entry.read();
// prevent words from splitting over lines
if (b == lcdCols * 3 - 1 && entry.peek() != ' ') {
//find the last instance of space in row2
le = lineEnd(row2, lcdCols);
//shift all text after the last space to the row beneath
for (byte c = le; c < lcdCols; c++) {
row3[c - le] = row2[c];
row2[c] = ' ';
}
//update the index position to account for the shift;
b = 4 * lcdCols - 1 - le;
}
//fourth row
} else if (b < lcdCols * 4) {
row3[b - lcdCols * 3] = entry.read();
}
b++;
}
// write the row bytes to the display
if (b > lcdCols * 4 || leFlag == true) {
lcd.clear();
lcd.home();
lcd.write(row0);
lcd.setCursor(0, 1);
lcd.write(row1);
lcd.setCursor(0, 2);
lcd.write(row2);
lcd.setCursor(0, 3);
lcd.write(row3);
// time to wait between displaying lines
delay(3500);
memset(row0, ' ', lcdCols);
memset(row1, ' ', lcdCols);
memset(row2, ' ', lcdCols);
memset(row3, ' ', lcdCols);
b = 0;
leFlag = false;
}
}
// clear the screen and reset the cursor
lcd.clear();
lcd.home();
entry.close();
}
// determine the position of where to break the display in a row of characters
byte lineEnd(char row[], byte rowLength) {
byte le = 0;
for (byte c = 0; c < rowLength; c++) {
if (row[c] == ' ') {
le = c;
}
}
return le;
}