ESP8266/DHT: Difference between revisions

From Noisebridge
Jump to navigation Jump to search
(lightened code + library mod #0ff)
m (#0ff)
 
Line 1: Line 1:
Humidity/Temperature sensor with SD Card data logger.
Humidity/Temperature sensor with SD Card data logger.


Note: Requires modified Nokia library.
This code is for use with NUBCore #060 hardware and a DHT11 sensor.
 
The DHT11 sensor seems to return eroneous data when sampled quickly, here it seems to be stable at once a minute.
 
Note: Requires modified Nokia library (see below).


<pre>
<pre>
Line 38: Line 42:


DHT dht(PIN_DHT, DHTTYPE);
DHT dht(PIN_DHT, DHTTYPE);
void handleHumidity(void);


void setup() {
void setup() {
Line 61: Line 67:
   }
   }


   // WiFi.begin(ssid, password);
   WiFi.begin(); // Usese last configured settings
   WiFi.begin();
   // WiFi.begin("ssid", "password");
   unsigned long timeout = millis() + 10000;
   unsigned long timeout = millis() + 10000;
   while (WiFi.status() != WL_CONNECTED){
   while (WiFi.status() != WL_CONNECTED) {
     digitalWrite(5, HIGH);
     digitalWrite(5, HIGH);
     delay(50);
     delay(50);
     digitalWrite(5, LOW);
     digitalWrite(5, LOW);
     delay(450);
     delay(450);
    yield();
     if (millis() > timeout)
     if (millis() > timeout)
       break;
       break;
Line 76: Line 83:


   if (wifiEnabled) {
   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.onStart([]() {
    ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    if (DISPLAY_ENABLED) {
       static uint8_t lastProgress = 0;
       display.clearDisplay();
       static unsigned long nextTime = 0;
       display.setTextSize(1);
       uint8_t p = (progress / (total / 100));
      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) {
      if (p == 100 || (p != lastProgress && millis() > nextTime)) {
    static uint8_t lastProgress = 0;
        nextTime = millis() + 100;
    static unsigned long nextTime = 0;
        if (p < 100) {
    uint8_t p = (progress / (total / 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();
          }
        }
      }
    });


     if (p == 100 || (p != lastProgress && millis() > nextTime)) {
     ArduinoOTA.onError([](ota_error_t error) {
      nextTime = millis() + 100;
       if (DISPLAY_ENABLED) {
       if (p < 100) {
         display.println("ERROR: " + String(error));
         if (DISPLAY_ENABLED) {
        display.display();
          display.clearDisplay();
         delay(1000);
          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) {
    ArduinoOTA.begin();
 
     if (DISPLAY_ENABLED) {
     if (DISPLAY_ENABLED) {
       display.println("ERROR: " + String(error));
       display.println(WiFi.SSID());
      display.println(WiFi.localIP());
       display.display();
       display.display();
      delay(1000);
     }
     }
  });
 
  ArduinoOTA.begin();
    for (int i = 0; i < 10; i++) {
 
      ArduinoOTA.handle();
  if (DISPLAY_ENABLED) {
      delay(100);
    display.println(WiFi.localIP());
      yield();
     display.display();
     }
   }
   }


   for (int i = 0; i < 10; i++) {
   if (!SD.begin(PIN_SD_CS)) {
     ArduinoOTA.handle();
    // no SD found
     delay(100);
    display.clearDisplay();
    display.println("No SD found");
     display.display();
    // TODO: change delay to loop w/yield
     delay(1000);
     yield();
     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 {
   } else {
     //SD initialized
     // SD initialized
     sdEnabled = true;
     sdEnabled = true;
   }
   }
 
 
   dht.begin();
   dht.begin();
   delay(100);
   delay(100);
Line 173: Line 181:


void handleHumidity() {
void handleHumidity() {
   static unsigned long next = 15000;
   static unsigned long next = 10000; // Don't read for first 10 seconds
   unsigned long now = millis();
   unsigned long now = millis();


   if (now > next) {
   if (now > next) {
     next = now + 10000;
    bool validData = false;
     int h, c, f;
 
     next = now + 60000; // Read every 60 seconds
 
    // Blip LED
    digitalWrite(5, HIGH);
 
     float h, c, f;
     h = dht.readHumidity();
     h = dht.readHumidity();
     c = dht.readTemperature();
     c = dht.readTemperature();
     f = dht.readTemperature(true);
     f = dht.readTemperature(true);


     display.clearDisplay();
     validData = (h >= 0 && h <= 100);
    display.setCursor(0, 0);
 
    display.setTextSize(2);
    if (validData) {
    display.println(String(c) + "/" + String(f));
 
    display.setTextSize(3);
        display.clearDisplay();
    display.println(String(h) + "%");
        display.setCursor(0, 0);
    display.display();
        display.setTextSize(2);
        display.println(String(int(c)) + "/" + String(int(f)));
        display.setTextSize(3);
        display.println(String(int(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 (sdEnabled) {
          if (dataFile) {
      String data = String(millis()) + ",";
            dataFile.println(data);
      data += String(h) + ",";
            dataFile.close();
      data += String(c) + ",";
          }
      data += String(f);
        }
 
    } else {
      File dataFile = SD.open("HUMIDITY.TXT", FILE_WRITE);
         display.println("DATA ERROR");
 
         display.display();
      if (dataFile) {
         dataFile.println(data);
         dataFile.close();
      }
     }
     }


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

Latest revision as of 22:37, 7 July 2016

Humidity/Temperature sensor with SD Card data logger.

This code is for use with NUBCore #060 hardware and a DHT11 sensor.

The DHT11 sensor seems to return eroneous data when sampled quickly, here it seems to be stable at once a minute.

Note: Requires modified Nokia library (see below).

#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 handleHumidity(void);

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(); // Usese last configured settings
  // WiFi.begin("ssid", "password");
  unsigned long timeout = millis() + 10000;
  while (WiFi.status() != WL_CONNECTED) {
    digitalWrite(5, HIGH);
    delay(50);
    digitalWrite(5, LOW);
    delay(450);
    yield();
    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.SSID());
      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);
    yield();
  } else {
    // SD initialized
    sdEnabled = true;
  }

  dht.begin();
  delay(100);
}

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

  handleHumidity();

  delay(50);
}

void handleHumidity() {
  static unsigned long next = 10000; // Don't read for first 10 seconds
  unsigned long now = millis();

  if (now > next) {
    bool validData = false;

    next = now + 60000; // Read every 60 seconds

    // Blip LED
    digitalWrite(5, HIGH);

    float h, c, f;
    h = dht.readHumidity();
    c = dht.readTemperature();
    f = dht.readTemperature(true);

    validData = (h >= 0 && h <= 100);

    if (validData) {

        display.clearDisplay();
        display.setCursor(0, 0);
        display.setTextSize(2);
        display.println(String(int(c)) + "/" + String(int(f)));
        display.setTextSize(3);
        display.println(String(int(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();
          }
        }
    } else {
        display.println("DATA ERROR");
        display.display();
    }

    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);
    }     
    }

}

*/