ESP8266/DHT: Difference between revisions

From Noisebridge
Jump to navigation Jump to search
ESP8266 (talk | contribs)
#0ff
 
ESP8266 (talk | contribs)
lightened code + library mod #0ff
Line 20: Line 20:
#define PIN_CE    16  //Pin 2 on LCD
#define PIN_CE    16  //Pin 2 on LCD
#define PIN_DC    15  //Pin 3 on LCD
#define PIN_DC    15  //Pin 3 on LCD
#define PIN_PUSH  0  // Push Button Switch


#define PIN_SD_CS 10 // Make sure "DIO" is selected
#define PIN_SD_CS 10 // Make sure "DIO" is selected
#define PIN_SOUND 3 // Piezo, overlapped with Serial Rx
//You may find a different size screen, but this one is 84 by 48 pixels
#define LCD_X    84
#define LCD_Y    48
#define LINE_INTERVAL 200
#define PING_INTERVAL 1000
#define MODE_HUMIDITY 16
#define MODE_SOUND 1
#define MODE_PING 2
#define MODE_CARD 3
#define MODE_FILE 4
#define MODE_CONTRAST 5
#define MODE_FIRMWARE 6
#define MODE_INITIALIZE 255
#define SWITCH_DEBOUNCE_TIME 50 // Timeout for debouncing presses
#define SWITCH_MULTI_TIME 300  // Timeout for detecting multiple clicks
#define SWITCH_HOLD_TIME 2000  // Timeout for detecting press and hold
#define SWITCH_PRESS 1
#define SWITCH_RELEASE 2
#define SWITCH_MULTI 4
#define SWITCH_HOLD 8


#define DISPLAY_ENABLED true
#define DISPLAY_ENABLED true


// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;
bool sdEnabled = false;
bool sdEnabled = false;
unsigned long nextLineMillis = 0;
unsigned long nextPing = 0;
unsigned long pingMillis = 0;
unsigned long debounceMillis = 0;
unsigned long doubleMillis = 0;
unsigned long holdMillis = 0;
int lastPing = 0;
bool pushStateOn = false;
uint8_t activeMode = MODE_INITIALIZE;
uint8_t clickCount = 0;


WiFiClient client;
WiFiClient client;
Line 87: Line 40:


void setup() {
void setup() {
  pinMode(PIN_PUSH, INPUT_PULLUP);
  pinMode(PIN_SOUND, OUTPUT);
 
   pinMode(4, OUTPUT);
   pinMode(4, OUTPUT);
   pinMode(5, OUTPUT);
   pinMode(5, OUTPUT);
Line 109: Line 58:
     display.setTextSize(1);
     display.setTextSize(1);
     display.setTextColor(BLACK);
     display.setTextColor(BLACK);
    display.println("WiFi: " + String(ssid).substring(0, 7));
     display.display();
     display.display();
   }
   }
Line 121: Line 69:
     digitalWrite(5, LOW);
     digitalWrite(5, LOW);
     delay(450);
     delay(450);
//    Serial.printf(".\n");
     if (millis() > timeout)
     if (millis() > timeout)
       break;
       break;
Line 127: Line 74:


   wifiEnabled = WiFi.status() == WL_CONNECTED;
   wifiEnabled = WiFi.status() == WL_CONNECTED;


   if (wifiEnabled) {
   if (wifiEnabled) {
  // Port defaults to 8266
  // ArduinoOTA.setPort(8266);
  // Hostname defaults to esp8266-[ChipID]
  // ArduinoOTA.setHostname("myesp8266");
  // No authentication by default
  // ArduinoOTA.setPassword((const char *)"123");


   ArduinoOTA.onStart([]() {
   ArduinoOTA.onStart([]() {
//    Serial.println("Start");
     if (DISPLAY_ENABLED) {
     if (DISPLAY_ENABLED) {
       display.clearDisplay();
       display.clearDisplay();
Line 152: Line 89:
     }
     }
   });
   });
  ArduinoOTA.onEnd([]() {
 
//    Serial.println("\nEnd");
  });
   ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
   ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
     static uint8_t lastProgress = 0;
     static uint8_t lastProgress = 0;
     static unsigned long nextTime = 0;
     static unsigned long nextTime = 0;
     uint8_t p = (progress / (total / 100));
     uint8_t p = (progress / (total / 100));
//    Serial.printf("Progress: %u%%\r", p);
 
     if (p == 100 || (p != lastProgress && millis() > nextTime)) {
     if (p == 100 || (p != lastProgress && millis() > nextTime)) {
       nextTime = millis() + 100;
       nextTime = millis() + 100;
Line 176: Line 111:
         lastProgress = p;
         lastProgress = p;
       } else {
       } else {
//        Serial.println("Start");
         if (DISPLAY_ENABLED) {
         if (DISPLAY_ENABLED) {
           display.clearDisplay();
           display.clearDisplay();
Line 191: Line 125:
   });
   });
   ArduinoOTA.onError([](ota_error_t error) {
   ArduinoOTA.onError([](ota_error_t error) {
//    Serial.printf("Error[%u]: ", error);
//    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
//    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
//    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
//    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
//    else if (error == OTA_END_ERROR) Serial.println("End Failed");
     if (DISPLAY_ENABLED) {
     if (DISPLAY_ENABLED) {
       display.println("ERROR: " + String(error));
       display.println("ERROR: " + String(error));
Line 204: Line 132:
   });
   });
   ArduinoOTA.begin();
   ArduinoOTA.begin();
//  Serial.println("Ready");
//  Serial.print("IP address: ");
//  Serial.println(WiFi.localIP());
    
    
   if (DISPLAY_ENABLED) {
   if (DISPLAY_ENABLED) {
Line 221: Line 145:
}
}


//TODO - change delay to loop funtion


if(!SD.begin(PIN_SD_CS)) {
if(!SD.begin(PIN_SD_CS)) {
Line 228: Line 151:
   display.println("No SD found");
   display.println("No SD found");
   display.display();
   display.display();
  //TODO - change delay to loop w/yield
   delay(1000);
   delay(1000);
    
    
   } else {
   } else {
  //SD initialized
    //SD initialized
  sdEnabled = true;
    sdEnabled = true;
   }
   }
 
   dht.begin();
   dht.begin();
 
   delay(100);
   setMode(MODE_HUMIDITY);
}
}


Line 243: Line 167:
     ArduinoOTA.handle();
     ArduinoOTA.handle();


   unsigned long now = millis();
   handleHumidity();
  bool pushed = !digitalRead(PIN_PUSH);
  uint8_t buttonAction = 0;
 
  if (client.connected()) {
    bool got = checkGet();
    if (got) {
      lastPing = millis() - pingMillis;
      nextPing = millis() + PING_INTERVAL;
    }
  } else if (millis() > nextPing) {
    sendGet();
  }
 
  // Handle switch state(s)
  if (now > debounceMillis &&  pushed != pushStateOn) {
    // Push switch state change
    debounceMillis = now + SWITCH_DEBOUNCE_TIME;
    if (pushed) {
      // Switch pushed
      pushStateOn = true;
      if (doubleMillis < now) {
        doubleMillis = now + SWITCH_MULTI_TIME;
        clickCount = 1;
        // string2Line("Switch: ON", 4);
        buttonAction = SWITCH_PRESS;
      } else {
        // Multi-click, goto next mode
        setMode(activeMode < 5 ? activeMode + 1 : 0);
        clickCount++;
        // string2Line("Mode: " + String(activeMode), 2);
        // string2Line("Click: " + String(clickCount), 4);
        buttonAction = SWITCH_MULTI;
      }
      holdMillis = now + SWITCH_HOLD_TIME;
    } else {
      // Switch released
      pushStateOn = false;
      // string2Line("Switch: OFF", 4);
      holdMillis = 0;
      buttonAction = SWITCH_RELEASE;
    }
  } else if (pushed && holdMillis > 0 && now > holdMillis) {
    // Long press
    // string2Line("Switch: HOLD", 4);
    holdMillis = 0;
    buttonAction = SWITCH_HOLD;
  }
 
  if (activeMode == MODE_HUMIDITY) {
    handleHumidity();
  } else if (activeMode == MODE_PING) {
    handlePingMode(buttonAction);
  } else if (activeMode == MODE_CARD) {
    handleCardMode(buttonAction);
  } else if (activeMode == MODE_FILE) {
    handleFileMode(buttonAction);
  } else if (activeMode == MODE_FIRMWARE) {
    handleFirmwareMode(buttonAction);
  } else if (activeMode == MODE_CONTRAST) {
    handleContrastMode();
  } else if (activeMode == MODE_SOUND) {
    handleSoundMode(buttonAction);
  }
 
  int a = analogRead(A0) / 4;
  if (a > 255)
    a = 255;
  analogWrite(4, a);
  // analogWrite(5, digitalRead(0) ? 0 : 127);


   delay(50);
   delay(50);
}
void setMode(uint8_t newMode) {
  if (newMode != activeMode) {
    if (DISPLAY_ENABLED) {
      display.clearDisplay();
      display.setTextSize(1);
      display.setTextColor(BLACK);
      display.setCursor(28, 0);
      display.println("mode:");
      display.setCursor(32, 12);
      display.setTextSize(3);
      display.println(newMode);
      display.display();
      delay(300);
      yield();
    }
    if (newMode == MODE_PING) {
      handlePingMode(0);
    } else if (newMode == MODE_CARD) {
      handleCardMode(SWITCH_HOLD);
    } else if (newMode == MODE_FILE) {
      handleFileMode(SWITCH_PRESS);
    } else if (newMode == MODE_FIRMWARE) {
      handleFirmwareMode(0);
    } else if (newMode == MODE_CONTRAST) {
      handleContrastMode();
    } else if (newMode == MODE_SOUND) {
      handleSoundMode(SWITCH_RELEASE);
    }
    activeMode = newMode;
  } else {
    // Not a new mode selection
  }
}
}


void handleHumidity() {
void handleHumidity() {
   static unsigned long next = 5000;
   static unsigned long next = 15000;
   unsigned long now = millis();
   unsigned long now = millis();


   if (now > next) {
   if (now > next) {
     next = now + 2000;
     next = now + 10000;
     int h, c, f;
     int h, c, f;
     h = dht.readHumidity();
     h = dht.readHumidity();
Line 378: Line 197:
       data += String(f);
       data += String(f);
    
    
       File dataFile = SD.open("humidity.txt", FILE_WRITE);
       File dataFile = SD.open("HUMIDITY.TXT", FILE_WRITE);
    
    
       if (dataFile) {
       if (dataFile) {
Line 387: Line 206:


     digitalWrite(5, HIGH);
     digitalWrite(5, HIGH);
     delay(200);
     delay(100);
     digitalWrite(5, LOW);
     digitalWrite(5, LOW);
   }
   }
}
}
</pre>
Slightly modified version of Adafruit Nokia Display library (Adafruit_PCD8544.cpp)...
<pre>
/*********************************************************************
This is a library for our Monochrome Nokia 5110 LCD Displays
  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/338
These displays use SPI to communicate, 4 or 5 pins are required to 
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada  for Adafruit Industries. 
BSD license, check license.txt for more information
All text above, and the splash screen below must be included in any redistribution
Hacked for ESP8266 by thex #0ff
*********************************************************************/
//#include <Wire.h>
#if defined(ESP8266)
#include <pgmspace.h>
#else
#include <avr/pgmspace.h>
#endif
#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif
#ifdef __AVR__
  #include <util/delay.h>
#endif
#ifndef _BV
  #define _BV(x) (1 << (x))
#endif
#include <stdlib.h>
#include <Adafruit_GFX.h>
#include "Adafruit_PCD8544.h"
// the memory buffer for the LCD
uint8_t pcd8544_buffer[LCDWIDTH * LCDHEIGHT / 8] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFF, 0xFC, 0xE0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
0xF8, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, 0xC0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x7F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x87, 0x8F, 0x9F, 0x9F, 0xFF, 0xFF, 0xFF,
0xC1, 0xC0, 0xE0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, 0xFC, 0xFE, 0xFE, 0xFE,
0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xE0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0xC0, 0xE0, 0xF1, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x0F, 0x0F, 0x87,
0xE7, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0x3F, 0xF9, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xFD, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0x7E, 0x3F, 0x3F, 0x0F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFC, 0xF0, 0xE0, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFC, 0xF0, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01,
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x7F, 0x7F,
0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x1F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};


void handlePingMode(uint8_t action) {
  if (client.connected()) {
    bool got = checkGet();
    if (got) {
      lastPing = millis() - pingMillis;
      nextPing = millis() + PING_INTERVAL;
//      Serial.println("Ping: " + String(lastPing) + "ms");
    }
  } else if (action == SWITCH_PRESS && millis() > nextPing) {
    // Do new ping on switch press
    sendGet();
  }


  // Check/show signal strength
// reduces how much is refreshed, which speeds it up!
  if (millis() > nextLineMillis) {
// originally derived from Steve Evans/JCW's mod but cleaned up and
    int signalStrength = WiFi.RSSI() >= -50 ? 100 : 2 * (WiFi.RSSI() + 100);
// optimized
    String signalBars = " ";
//#define enablePartialUpdate


    nextLineMillis = millis() + LINE_INTERVAL;
#ifdef enablePartialUpdate
static uint8_t xUpdateMin, xUpdateMax, yUpdateMin, yUpdateMax;
#endif


    if (DISPLAY_ENABLED) {
      display.clearDisplay();
      display.setTextSize(1);
      display.setTextColor(BLACK);
      display.setCursor(0, 0);


      for (int i = 0; i < signalStrength / 10; i++)
        signalBars += "*";
      display.println(signalBars);
      display.println(String(WiFi.RSSI()) + "db/" + String(signalStrength) + "%");
      display.println();
      display.println("Ping: " + String(lastPing) + "ms");
      display.println();
      display.println("#007 " + String(millis() / 1000));


      display.display();
static void updateBoundingBox(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax) {
    }
#ifdef enablePartialUpdate
   }
  if (xmin < xUpdateMin) xUpdateMin = xmin;
  if (xmax > xUpdateMax) xUpdateMax = xmax;
  if (ymin < yUpdateMin) yUpdateMin = ymin;
   if (ymax > yUpdateMax) yUpdateMax = ymax;
#endif
}
}


void handleCardMode(uint8_t action) {
Adafruit_PCD8544::Adafruit_PCD8544(int8_t SCLK, int8_t DIN, int8_t DC,
   if (action == SWITCH_HOLD)
    int8_t CS, int8_t RST) : Adafruit_GFX(LCDWIDTH, LCDHEIGHT) {
    testSD();
   _din = DIN;
  _sclk = SCLK;
  _dc = DC;
  _rst = RST;
  _cs = CS;
}
}


void handleFileMode(uint8_t action) {
Adafruit_PCD8544::Adafruit_PCD8544(int8_t SCLK, int8_t DIN, int8_t DC,
   if (action == SWITCH_PRESS)
    int8_t RST) : Adafruit_GFX(LCDWIDTH, LCDHEIGHT) {
    getNextFile();
   _din = DIN;
  _sclk = SCLK;
  _dc = DC;
  _rst = RST;
  _cs = -1;
}
}


void handleFirmwareMode(uint8_t action) {
Adafruit_PCD8544::Adafruit_PCD8544(int8_t DC, int8_t CS, int8_t RST):
   digitalWrite(PIN_SD_CS, digitalRead(2));
   Adafruit_GFX(LCDWIDTH, LCDHEIGHT) {
  // -1 for din and sclk specify using hardware SPI
  _din = -1;
  _sclk = -1;
  _dc = DC;
  _rst = RST;
  _cs = CS;
}
}


void handleContrastMode() {
  static uint8_t contrast = 50;
  uint8_t analog = analogRead(A0) / 8;


   if (!DISPLAY_ENABLED)
// the most basic function, set a single pixel
void Adafruit_PCD8544::drawPixel(int16_t x, int16_t y, uint16_t color) {
   if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height))
     return;
     return;


   if (analog != contrast) {
   int16_t t;
     contrast = analog;
  switch(rotation){
    display.clearDisplay();
     case 1:
     display.setCursor(0, 0);
      t = x;
    display.setTextSize(1);
      x = y;
    display.println("  Contrast:");
      y =  LCDHEIGHT - 1 - t;
     display.setTextSize(3);
      break;
    display.println(contrast);
     case 2:
    display.setContrast(contrast);
      x = LCDWIDTH - 1 - x;
    display.display();
      y = LCDHEIGHT - 1 - y;
      break;
     case 3:
      t = x;
      x = LCDWIDTH - 1 - y;
      y = t;
      break;
   }
   }


   yield();
   if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT))
  delay(50);
    return;
}


void handleSoundMode(uint8_t action) {
  // x is which column
  static bool soundOn = false;
  if (color)  
   static int frequency = 1000;
    pcd8544_buffer[x+ (y/8)*LCDWIDTH] |= _BV(y%8);
  static int duty = 512;
   else
    pcd8544_buffer[x+ (y/8)*LCDWIDTH] &= ~_BV(y%8);  


   bool refresh = action != 0;
   updateBoundingBox(x,y,x,y);
 
}
  if (action == SWITCH_HOLD) {
    // Toggle sound on
    soundOn = !soundOn;
    if (soundOn) {
      analogWrite(PIN_SOUND, duty);
    } else {
      analogWrite(PIN_SOUND, 0);
    }
  } else if (action == SWITCH_PRESS) {
    frequency = analogRead(A0) * 4;
    // Crash if set to 0, espressif PWM defined as 100Hz-1Khz
    if (frequency < 10) frequency = 10;
    analogWriteFreq(frequency);
  }


  if (!digitalRead(2)) {
    // Right switch pressed
    duty = analogRead(A0);
    if (soundOn)
      analogWrite(PIN_SOUND, duty);
    refresh = true;
  }


  if (refresh) {
// the most basic function, get a single pixel
    display.clearDisplay();
uint8_t Adafruit_PCD8544::getPixel(int8_t x, int8_t y) {
    display.setCursor(0, 0);
  if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT))
    display.setTextSize(1);
     return 0;
    display.println(" Sound: " + String(soundOn ? "ON" : "OFF") + "\r\n");
    display.setTextSize(2);
    display.println((frequency < 100 ? " " : "") + String(frequency) + "Hz");
    display.println("  " + String(int(duty / 10.24)) + "%");
     display.display();
  }


   yield();
   return (pcd8544_buffer[x+ (y/8)*LCDWIDTH] >> (y%8)) & 0x1;
  delay(50);
}
}


void sendGet() {
  pingMillis = millis();


   if (!client.connect("void-local.tablesugar.info", 80)) {
void Adafruit_PCD8544::begin(uint8_t contrast, uint8_t bias) {
     // Error
   if (isHardwareSPI()) {
     return;
    // Setup hardware SPI.
    SPI.begin();
#ifdef ESP8266
     // Datasheet says 4 MHz is max SPI clock speed
     SPI.setFrequency(400000);
#else
    SPI.setClockDivider(PCD8544_SPI_CLOCK_DIV);
#endif
    SPI.setDataMode(SPI_MODE0);
    SPI.setBitOrder(MSBFIRST);
   }
   }
  else {
    // Setup software SPI.


  client.print("GET /none.html HTTP/1.1\r\nHost: void-local.tablesugar.info\r\nConnection: close\r\n\r\n");
    // Set software SPI specific pin outputs.
}
    pinMode(_din, OUTPUT);
    pinMode(_sclk, OUTPUT);


bool checkGet() {
#ifndef ESP8266
  if (client.available()) {
     // Set software SPI ports and masks.
     // Got something
     clkport    = portOutputRegister(digitalPinToPort(_sclk));
     client.stop();
     clkpinmask  = digitalPinToBitMask(_sclk);
     return true;
    mosiport    = portOutputRegister(digitalPinToPort(_din));
  } else if (millis() - pingMillis > 2000) {
     mosipinmask = digitalPinToBitMask(_din);
    // Timeout
#endif
     client.stop();
    return true;
   }
   }
  return false;
}


void testSD() {
  // Set common pin outputs.
//  Serial.print("\nInitializing SD card...");
  pinMode(_dc, OUTPUT);
  if (_rst > 0)
      pinMode(_rst, OUTPUT);
  if (_cs > 0)
      pinMode(_cs, OUTPUT);


   if (DISPLAY_ENABLED) {
  // toggle RST low to reset
     display.clearDisplay();
   if (_rst > 0) {
     display.setTextSize(1);
     digitalWrite(_rst, LOW);
    display.setTextColor(BLACK);
     delay(500);
     display.setCursor(0, 0);
     digitalWrite(_rst, HIGH);
    display.println("*Testing SD*");
    display.display();
   }
   }


   // we'll use the initialization code from the utility libraries
   // get into the EXTENDED mode!
  // since we're just testing if the card is working!
   command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION );
  // if (!card.init(SPI_HALF_SPEED, PIN_SD_CS)) {
   if (!card.init(400000, PIN_SD_CS)) {
//    Serial.println("initialization failed. Things to check:");
//    Serial.println("* is a card inserted?");
//    Serial.println("* is your wiring correct?");
//    Serial.println("* did you change the PIN_SD_CS pin to match your shield or module?");
    if (DISPLAY_ENABLED) {
      display.println("NO CARD!!!");
      display.display();
    }
    return;
  } else {
//    Serial.println("Wiring is correct and a card is present.");
    // string2Line("Card found", 1);
    nextLineMillis = nextPing = 5000;
  }


   // print the type of card
   // LCD bias select (4 is optimal?)
//  Serial.print("\nCard type: ");
   command(PCD8544_SETBIAS | bias);
   String cardType;
  switch (card.type()) {
    case SD_CARD_TYPE_SD1:
      cardType = "SD1";
      break;
    case SD_CARD_TYPE_SD2:
      cardType = "SD2";
      break;
    case SD_CARD_TYPE_SDHC:
      cardType = "SDHC";
      break;
//    default:
//      Serial.println("????");
  }


   // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
   // set VOP
   if (!volume.init(card)) {
   if (contrast > 0x7f)
//    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
     contrast = 0x7f;
//    Serial.println(cardType);
     if (DISPLAY_ENABLED) {
      display.println("No partition\r\nFAT16/FAT32\r\nfmt needed.");
      display.display();
    }
    return;
  }


  command( PCD8544_SETVOP | contrast); // Experimentally determined


  // print the type and size of the first FAT-type volume
  uint32_t volumesize;
//  Serial.print("\nVolume type is FAT");
//  Serial.println(volume.fatType(), DEC);
//  Serial.println();


// Serial.println(cardType);
  // normal mode
  command(PCD8544_FUNCTIONSET);


   if (DISPLAY_ENABLED)
   // Set display to Normal
    display.println(cardType + "/FAT" + String(volume.fatType()));
  command(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL);


   volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
   // initial display line
   volumesize *= volume.clusterCount();      // we'll have a lot of clusters
   // set page address
   volumesize *= 512;                            // SD card blocks are always 512 bytes
   // set column address
//  Serial.print("Volume size (bytes): ");
   // write display data
//  Serial.println(volumesize);
//  Serial.print("Volume size (Kbytes): ");
  volumesize /= 1024;
//  Serial.println(volumesize);
//  Serial.print("Volume size (Mbytes): ");
   volumesize /= 1024;
// Serial.println(volumesize);


   if (volumesize < 1000) {
   // set up a bounding box for screen updates
    if (DISPLAY_ENABLED)
      display.println("Size: " + String(volumesize) + "MB");
  } else {
    if (DISPLAY_ENABLED)
      display.println("Size: " + String(round(volumesize / 100) / 10) + "GB");
  }


   if (DISPLAY_ENABLED)
   updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1);
    display.display();
  // Push out pcd8544_buffer to the Display (will show the AFI logo)
  display();
}




// Serial.println("\nFiles found on the card (name, date and size in bytes): ");
inline void Adafruit_PCD8544::spiWrite(uint8_t d) {
  root.openRoot(volume);
  if (isHardwareSPI()) {
    // Hardware SPI write.
    SPI.transfer(d);
  }
  else {
#ifdef ESP8266
    // Software SPI write with bit banging.
    for(uint8_t bit = 0x80; bit; bit >>= 1) {
      digitalWrite(_sclk, LOW);
      if (d & bit) digitalWrite(_din, HIGH);
      else        digitalWrite(_din, LOW);
      digitalWrite(_sclk, HIGH);
    }
#else
    // Software SPI write with bit banging.
    for(uint8_t bit = 0x80; bit; bit >>= 1) {
      *clkport &= ~clkpinmask;
      if(d & bit) *mosiport |=  mosipinmask;
      else        *mosiport &= ~mosipinmask;
      *clkport |=  clkpinmask;
    }
#endif
  }
}


  // list all files in the card with date and size
bool Adafruit_PCD8544::isHardwareSPI() {
   root.ls(LS_R | LS_DATE | LS_SIZE);
   return (_din == -1 && _sclk == -1);
}
}


void getNextFile() {
void Adafruit_PCD8544::command(uint8_t c) {
   static bool inited = false;
   digitalWrite(_dc, LOW);
   static int fileCount = 0;
  if (_cs > 0)
    digitalWrite(_cs, LOW);
  spiWrite(c);
   if (_cs > 0)
    digitalWrite(_cs, HIGH);
}


//  Serial.println("Get files...");
void Adafruit_PCD8544::data(uint8_t c) {
  digitalWrite(_dc, HIGH);
  if (_cs > 0)
    digitalWrite(_cs, LOW);
  spiWrite(c);
  if (_cs > 0)
    digitalWrite(_cs, HIGH);
}


  if (DISPLAY_ENABLED) {
void Adafruit_PCD8544::setContrast(uint8_t val) {
    display.clearDisplay();
  if (val > 0x7f) {
     display.setTextSize(1);
     val = 0x7f;
    display.setTextColor(BLACK);
    display.setCursor(0, 0);
    display.print("SD: " + String(fileCount) + " ");
    display.display();
   }
   }
  command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION );
  command( PCD8544_SETVOP | val);
  command(PCD8544_FUNCTIONSET);
 
}


   if (!inited && !SD.begin(PIN_SD_CS)) {
 
//   Serial.println("Initialization failed!");
 
     if (DISPLAY_ENABLED) {
void Adafruit_PCD8544::display(void) {
       display.println("Initializat-\r\nion failed!");
  uint8_t col, maxcol, p;
      display.display();
 
   for(p = 0; p < 6; p++) {
#ifdef enablePartialUpdate
    // check if this page is part of update
    if ( yUpdateMin >= ((p+1)*8) ) {
      continue;  // nope, skip it!
    }
     if (yUpdateMax < p*8) {
       break;
     }
     }
     return;
#endif
  }
 
     command(PCD8544_SETYADDR | p);


  inited = true;


  File files = SD.open("/");
#ifdef enablePartialUpdate
  File file;
    col = xUpdateMin;
  unsigned long fileSize;
    maxcol = xUpdateMax;
#else
    // start at the beginning of the row
    col = 0;
    maxcol = LCDWIDTH-1;
#endif


  int index = 0;
    command(PCD8544_SETXADDR | col);
  while (true) {
 
     file = files.openNextFile();
     digitalWrite(_dc, HIGH);
     if (!file) {
     if (_cs > 0)
      // end
       digitalWrite(_cs, LOW);
//      Serial.println("end of files");
     for(; col <= maxcol; col++) {
       if (DISPLAY_ENABLED)
      spiWrite(pcd8544_buffer[(LCDWIDTH*p)+col]);
        display.println("end of files");
        display.display();
      fileCount = 0;
      return;
     }
    if (!file.isDirectory()) {
      if (index == fileCount) {
        // name of next file
//        Serial.print(String(file.name()));
        fileSize = file.size();
        if (fileSize < 1024) {
          if (DISPLAY_ENABLED)
            display.print(String(fileSize) + "Bytes");
        } else if (fileSize < 100000) {
          if (DISPLAY_ENABLED)
            display.print(String(round(file.size() / 1024)) + "KB");
        } else {
          if (DISPLAY_ENABLED)
            display.print(String(round(file.size() / 1024 / 10.24) / 100.0) + "MB");
        }
        if (DISPLAY_ENABLED)
          display.println("\r\n" + String(file.name()));
        fileCount++;
        break;
      }
      index++;
     }
     }
    if (_cs > 0)
      digitalWrite(_cs, HIGH);
   }
   }


   String fileContent = "";
   command(PCD8544_SETYADDR );  // no idea why this is necessary but it is to finish the last byte?
   while (file.available() && fileContent.length() < 36) {
#ifdef enablePartialUpdate
    fileContent += char(file.read());
  xUpdateMin = LCDWIDTH - 1;
   }
   xUpdateMax = 0;
  yUpdateMin = LCDHEIGHT-1;
   yUpdateMax = 0;
#endif


  while (fileContent.length() < 64)
}
    fileContent += " ";


   if (DISPLAY_ENABLED)
// clear everything
     display.println(fileContent);
void Adafruit_PCD8544::clearDisplay(void) {
  memset(pcd8544_buffer, 0, LCDWIDTH*LCDHEIGHT/8);
   updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1);
  cursor_y = cursor_x = 0;
}
 
/*
// this doesnt touch the buffer, just clears the display RAM - might be handy
void Adafruit_PCD8544::clearDisplay(void) {
 
  uint8_t p, c;
 
  for(p = 0; p < 8; p++) {
 
     st7565_command(CMD_SET_PAGE | p);
    for(c = 0; c < 129; c++) {
      //uart_putw_dec(c);
      //uart_putchar(' ');
      st7565_command(CMD_SET_COLUMN_LOWER | (c & 0xf));
      st7565_command(CMD_SET_COLUMN_UPPER | ((c >> 4) & 0xf));
      st7565_data(0x0);
    }   
    }


  display.display();
}
}
*/
</pre>
</pre>

Revision as of 20:56, 7 July 2016

Humidity/Temperature sensor with SD Card data logger.

Note: Requires modified Nokia library.

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <SPI.h>
#include <SD.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <DHT.h>

#define DHTTYPE DHT11

#define PIN_DHT   1

#define PIN_CE    16  //Pin 2 on LCD
#define PIN_DC    15  //Pin 3 on LCD

#define PIN_SD_CS 10 // Make sure "DIO" is selected

#define DISPLAY_ENABLED true

bool sdEnabled = false;

WiFiClient client;

#if defined(DISPLAY_ENABLED)
Adafruit_PCD8544 display = Adafruit_PCD8544(PIN_DC, PIN_CE, -1);
#else
Adafruit_PCD8544 display = Adafruit_PCD8544(4, 5, 2, -1);
#endif

bool wifiEnabled = false;

DHT dht(PIN_DHT, DHTTYPE);

void setup() {
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);

  if (DISPLAY_ENABLED) {
    display.begin();
    display.setContrast(55);

    display.clearDisplay();

    display.setTextSize(1);
    display.setTextColor(BLACK);
    display.setCursor(0, 0);
    display.println("#0FF DHT");
    display.setTextColor(WHITE, BLACK); // 'inverted' text
    display.setTextSize(2);
    display.println(" void ");
    display.setTextSize(1);
    display.setTextColor(BLACK);
    display.display();
  }

  // WiFi.begin(ssid, password);
  WiFi.begin();
  unsigned long timeout = millis() + 10000;
  while (WiFi.status() != WL_CONNECTED){
    digitalWrite(5, HIGH);
    delay(50);
    digitalWrite(5, LOW);
    delay(450);
    if (millis() > timeout)
      break;
  }

  wifiEnabled = WiFi.status() == WL_CONNECTED;

  if (wifiEnabled) {

  ArduinoOTA.onStart([]() {
    if (DISPLAY_ENABLED) {
      display.clearDisplay();
      display.setTextSize(1);
      display.setTextColor(BLACK);
      display.setCursor(0, 0);
      display.println("*OTA Update*");
      display.println("");
      display.setTextSize(2);
      display.display();
    }
  });

  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    static uint8_t lastProgress = 0;
    static unsigned long nextTime = 0;
    uint8_t p = (progress / (total / 100));

    if (p == 100 || (p != lastProgress && millis() > nextTime)) {
      nextTime = millis() + 100;
      if (p < 100) {
        if (DISPLAY_ENABLED) {
          display.clearDisplay();
          display.setTextSize(1);
          display.setCursor(0, 0);
          display.println("*OTA Update*");
          display.println("");
          display.setTextSize(2);
          display.setCursor(24, 24);
          display.println(String(p) + "%");
          display.display();
        }
        lastProgress = p;
      } else {
        if (DISPLAY_ENABLED) {
          display.clearDisplay();
          display.setTextSize(1);
          display.setTextColor(BLACK);
          display.setCursor(0, 0);
          display.println("*OTA Success*");
          display.println("");
          display.println("rebooting...");
          display.display();
        }
      }
    }
  });
  ArduinoOTA.onError([](ota_error_t error) {
    if (DISPLAY_ENABLED) {
      display.println("ERROR: " + String(error));
      display.display();
      delay(1000);
    }
  });
  ArduinoOTA.begin();
  
  if (DISPLAY_ENABLED) {
    display.println(WiFi.localIP());
    display.display();
  }

  for (int i = 0; i < 10; i++) {
    ArduinoOTA.handle();
    delay(100);
    yield();
  }
}


if(!SD.begin(PIN_SD_CS)) {
  //no SD found
  display.clearDisplay();
  display.println("No SD found");
  display.display();
  //TODO - change delay to loop w/yield
  delay(1000);
  
  } else {
    //SD initialized
    sdEnabled = true;
  }
  
  dht.begin();
  delay(100);
}

void loop() {
  if (wifiEnabled)
    ArduinoOTA.handle();

  handleHumidity();

  delay(50);
}

void handleHumidity() {
  static unsigned long next = 15000;
  unsigned long now = millis();

  if (now > next) {
    next = now + 10000;
    int h, c, f;
    h = dht.readHumidity();
    c = dht.readTemperature();
    f = dht.readTemperature(true);

    display.clearDisplay();
    display.setCursor(0, 0);
    display.setTextSize(2);
    display.println(String(c) + "/" + String(f));
    display.setTextSize(3);
    display.println(String(h) + "%");
    display.display();

    if (sdEnabled) {
      String data = String(millis()) + ",";
      data += String(h) + ",";
      data += String(c) + ",";
      data += String(f);
  
      File dataFile = SD.open("HUMIDITY.TXT", FILE_WRITE);
  
      if (dataFile) {
        dataFile.println(data);
        dataFile.close();
      }
    }

    digitalWrite(5, HIGH);
    delay(100);
    digitalWrite(5, LOW);
  }
}


Slightly modified version of Adafruit Nokia Display library (Adafruit_PCD8544.cpp)...

/*********************************************************************
This is a library for our Monochrome Nokia 5110 LCD Displays

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/338

These displays use SPI to communicate, 4 or 5 pins are required to  
interface

Adafruit invests time and resources providing this open source code, 
please support Adafruit and open-source hardware by purchasing 
products from Adafruit!

Written by Limor Fried/Ladyada  for Adafruit Industries.  
BSD license, check license.txt for more information
All text above, and the splash screen below must be included in any redistribution

Hacked for ESP8266 by thex #0ff
*********************************************************************/

//#include <Wire.h>
#if defined(ESP8266)
#include <pgmspace.h>
#else
#include <avr/pgmspace.h>
#endif
#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

#ifdef __AVR__
  #include <util/delay.h>
#endif

#ifndef _BV
  #define _BV(x) (1 << (x))
#endif

#include <stdlib.h>

#include <Adafruit_GFX.h>
#include "Adafruit_PCD8544.h"

// the memory buffer for the LCD
uint8_t pcd8544_buffer[LCDWIDTH * LCDHEIGHT / 8] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFF, 0xFC, 0xE0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
0xF8, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, 0xC0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x7F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x87, 0x8F, 0x9F, 0x9F, 0xFF, 0xFF, 0xFF,
0xC1, 0xC0, 0xE0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, 0xFC, 0xFE, 0xFE, 0xFE,
0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xE0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0xC0, 0xE0, 0xF1, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x0F, 0x0F, 0x87,
0xE7, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0x3F, 0xF9, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xFD, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0x7E, 0x3F, 0x3F, 0x0F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFC, 0xF0, 0xE0, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFC, 0xF0, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01,
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x7F, 0x7F,
0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x1F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
};


// reduces how much is refreshed, which speeds it up!
// originally derived from Steve Evans/JCW's mod but cleaned up and
// optimized
//#define enablePartialUpdate

#ifdef enablePartialUpdate
static uint8_t xUpdateMin, xUpdateMax, yUpdateMin, yUpdateMax;
#endif



static void updateBoundingBox(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax) {
#ifdef enablePartialUpdate
  if (xmin < xUpdateMin) xUpdateMin = xmin;
  if (xmax > xUpdateMax) xUpdateMax = xmax;
  if (ymin < yUpdateMin) yUpdateMin = ymin;
  if (ymax > yUpdateMax) yUpdateMax = ymax;
#endif
}

Adafruit_PCD8544::Adafruit_PCD8544(int8_t SCLK, int8_t DIN, int8_t DC,
    int8_t CS, int8_t RST) : Adafruit_GFX(LCDWIDTH, LCDHEIGHT) {
  _din = DIN;
  _sclk = SCLK;
  _dc = DC;
  _rst = RST;
  _cs = CS;
}

Adafruit_PCD8544::Adafruit_PCD8544(int8_t SCLK, int8_t DIN, int8_t DC,
    int8_t RST) : Adafruit_GFX(LCDWIDTH, LCDHEIGHT) {
  _din = DIN;
  _sclk = SCLK;
  _dc = DC;
  _rst = RST;
  _cs = -1;
}

Adafruit_PCD8544::Adafruit_PCD8544(int8_t DC, int8_t CS, int8_t RST):
  Adafruit_GFX(LCDWIDTH, LCDHEIGHT) {
  // -1 for din and sclk specify using hardware SPI
  _din = -1;
  _sclk = -1;
  _dc = DC;
  _rst = RST;
  _cs = CS;
}


// the most basic function, set a single pixel
void Adafruit_PCD8544::drawPixel(int16_t x, int16_t y, uint16_t color) {
  if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height))
    return;

  int16_t t;
  switch(rotation){
    case 1:
      t = x;
      x = y;
      y =  LCDHEIGHT - 1 - t;
      break;
    case 2:
      x = LCDWIDTH - 1 - x;
      y = LCDHEIGHT - 1 - y;
      break;
    case 3:
      t = x;
      x = LCDWIDTH - 1 - y;
      y = t;
      break;
  }

  if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT))
    return;

  // x is which column
  if (color) 
    pcd8544_buffer[x+ (y/8)*LCDWIDTH] |= _BV(y%8);  
  else
    pcd8544_buffer[x+ (y/8)*LCDWIDTH] &= ~_BV(y%8); 

  updateBoundingBox(x,y,x,y);
}


// the most basic function, get a single pixel
uint8_t Adafruit_PCD8544::getPixel(int8_t x, int8_t y) {
  if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT))
    return 0;

  return (pcd8544_buffer[x+ (y/8)*LCDWIDTH] >> (y%8)) & 0x1;  
}


void Adafruit_PCD8544::begin(uint8_t contrast, uint8_t bias) {
  if (isHardwareSPI()) {
    // Setup hardware SPI.
    SPI.begin();
#ifdef ESP8266
    // Datasheet says 4 MHz is max SPI clock speed
    SPI.setFrequency(400000);
#else
    SPI.setClockDivider(PCD8544_SPI_CLOCK_DIV);
#endif
    SPI.setDataMode(SPI_MODE0);
    SPI.setBitOrder(MSBFIRST);
  }
  else {
    // Setup software SPI.

    // Set software SPI specific pin outputs.
    pinMode(_din, OUTPUT);
    pinMode(_sclk, OUTPUT);

#ifndef ESP8266
    // Set software SPI ports and masks.
    clkport     = portOutputRegister(digitalPinToPort(_sclk));
    clkpinmask  = digitalPinToBitMask(_sclk);
    mosiport    = portOutputRegister(digitalPinToPort(_din));
    mosipinmask = digitalPinToBitMask(_din);
#endif
  }

  // Set common pin outputs.
  pinMode(_dc, OUTPUT);
  if (_rst > 0)
      pinMode(_rst, OUTPUT);
  if (_cs > 0)
      pinMode(_cs, OUTPUT);

  // toggle RST low to reset
  if (_rst > 0) {
    digitalWrite(_rst, LOW);
    delay(500);
    digitalWrite(_rst, HIGH);
  }

  // get into the EXTENDED mode!
  command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION );

  // LCD bias select (4 is optimal?)
  command(PCD8544_SETBIAS | bias);

  // set VOP
  if (contrast > 0x7f)
    contrast = 0x7f;

  command( PCD8544_SETVOP | contrast); // Experimentally determined


  // normal mode
  command(PCD8544_FUNCTIONSET);

  // Set display to Normal
  command(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL);

  // initial display line
  // set page address
  // set column address
  // write display data

  // set up a bounding box for screen updates

  updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1);
  // Push out pcd8544_buffer to the Display (will show the AFI logo)
  display();
}


inline void Adafruit_PCD8544::spiWrite(uint8_t d) {
  if (isHardwareSPI()) {
    // Hardware SPI write.
    SPI.transfer(d);
  }
  else {
#ifdef ESP8266
    // Software SPI write with bit banging.
    for(uint8_t bit = 0x80; bit; bit >>= 1) {
      digitalWrite(_sclk, LOW);
      if (d & bit) digitalWrite(_din, HIGH);
      else         digitalWrite(_din, LOW);
      digitalWrite(_sclk, HIGH);
    }
#else
    // Software SPI write with bit banging.
    for(uint8_t bit = 0x80; bit; bit >>= 1) {
      *clkport &= ~clkpinmask;
      if(d & bit) *mosiport |=  mosipinmask;
      else        *mosiport &= ~mosipinmask;
      *clkport |=  clkpinmask;
    }
#endif
  }
}

bool Adafruit_PCD8544::isHardwareSPI() {
  return (_din == -1 && _sclk == -1);
}

void Adafruit_PCD8544::command(uint8_t c) {
  digitalWrite(_dc, LOW);
  if (_cs > 0)
    digitalWrite(_cs, LOW);
  spiWrite(c);
  if (_cs > 0)
    digitalWrite(_cs, HIGH);
}

void Adafruit_PCD8544::data(uint8_t c) {
  digitalWrite(_dc, HIGH);
  if (_cs > 0)
    digitalWrite(_cs, LOW);
  spiWrite(c);
  if (_cs > 0)
    digitalWrite(_cs, HIGH);
}

void Adafruit_PCD8544::setContrast(uint8_t val) {
  if (val > 0x7f) {
    val = 0x7f;
  }
  command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION );
  command( PCD8544_SETVOP | val); 
  command(PCD8544_FUNCTIONSET);
  
 }



void Adafruit_PCD8544::display(void) {
  uint8_t col, maxcol, p;
  
  for(p = 0; p < 6; p++) {
#ifdef enablePartialUpdate
    // check if this page is part of update
    if ( yUpdateMin >= ((p+1)*8) ) {
      continue;   // nope, skip it!
    }
    if (yUpdateMax < p*8) {
      break;
    }
#endif

    command(PCD8544_SETYADDR | p);


#ifdef enablePartialUpdate
    col = xUpdateMin;
    maxcol = xUpdateMax;
#else
    // start at the beginning of the row
    col = 0;
    maxcol = LCDWIDTH-1;
#endif

    command(PCD8544_SETXADDR | col);

    digitalWrite(_dc, HIGH);
    if (_cs > 0)
      digitalWrite(_cs, LOW);
    for(; col <= maxcol; col++) {
      spiWrite(pcd8544_buffer[(LCDWIDTH*p)+col]);
    }
    if (_cs > 0)
      digitalWrite(_cs, HIGH);

  }

  command(PCD8544_SETYADDR );  // no idea why this is necessary but it is to finish the last byte?
#ifdef enablePartialUpdate
  xUpdateMin = LCDWIDTH - 1;
  xUpdateMax = 0;
  yUpdateMin = LCDHEIGHT-1;
  yUpdateMax = 0;
#endif

}

// clear everything
void Adafruit_PCD8544::clearDisplay(void) {
  memset(pcd8544_buffer, 0, LCDWIDTH*LCDHEIGHT/8);
  updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1);
  cursor_y = cursor_x = 0;
}

/*
// this doesnt touch the buffer, just clears the display RAM - might be handy
void Adafruit_PCD8544::clearDisplay(void) {
  
  uint8_t p, c;
  
  for(p = 0; p < 8; p++) {

    st7565_command(CMD_SET_PAGE | p);
    for(c = 0; c < 129; c++) {
      //uart_putw_dec(c);
      //uart_putchar(' ');
      st7565_command(CMD_SET_COLUMN_LOWER | (c & 0xf));
      st7565_command(CMD_SET_COLUMN_UPPER | ((c >> 4) & 0xf));
      st7565_data(0x0);
    }     
    }

}

*/