Monthly Archives: August 2016

DHT 22 or AM2302 – Temperature and Humidity sensor

Mostly made by Aosong. Here is the datasheet. The library from Adafruit on GIT works  fine.  The library has been attached here also in case the GIT one is not available for any reason.

There are example codes in the library. Wiring the module is pretty simple.

DH-11

The module works on 3.3v – 5v and uses I2C for communication.

As per the datasheets the module will malfunction under harsh conditions and contamination. But it may recover if left for sometime.

DHT 11 – Temperature and Humidity sensor

Mostly made by Aosong. Here is the datasheet. Libraries are little rare and seems to be bit old. But this one on GIT is working fine.  The library has been attached here also in case the GIT one is not available for any reason.

There are example codes in the library. Wiring the module is pretty simple.

DH-11

The module works on 3.3v – 5v and uses I2C for communication.

As per the datasheets the module will malfunction under harsh conditions and contamination. But it may recover if left for sometime.

Using a 1.44″ Color LCD with Arduino as a display

Recently purchased a cheap color LCD from Ebay (http://www.ebay.com/itm/1-44-Red-Serial-128X128-SPI-Color-TFT-LCD-Module-Display-Replace-Nokia-5110-LCD-/310876068105?hash=item4861a85909:g:9LoAAOSwpzdWqdY~). They are really good for displaying anything (from an Arduino perspective) in color.

Though the are cheap and nice, but finding the proper library for them can be a pain. It would be wise to check the details of the LCD and availability of it’s library first before buying.

What I found so far is there are mainly two types of LCDs that are cheaply available on Ebay. One based on the ILI9163 chipset and another based on the ST7735 chipset.

Arduino IDE from version 1.0.5 onwards comes with a LCD library, which is based on the ST7735 chipset and an advancement of the Adafruit Libraries. Please see this article for more details.

Using the LCD is not much complicated but only thing to remember is there is a huge lot of confusion with which one supports what voltage and I/O levels. So with mine I started with 3.3v and things are working fine.

LED         Connect to +ve supply through a resistor
SCK         13 (fixed as per library)
SDA         11 (fixed as per library)
A0/DC        7 (can be any)
RESET        4   (can be any)
CS           5 (can be any)
GND         GND   
VCC         3.3v

There is one limitation to all libraries (I tested) at the moment, updating the texts on the display. The only way to clear the LCD is by calling the background function and painting the LCD with a color. This gives flicker, as a full screen text takes a bit time to get written fully. Yet to find a solution to this. In the below code only the area that needs to be updated is being cleared.

#include <SFE_BMP180.h> //from sparkfun 
#include <Wire.h>
#include <SoftwareSerial.h>

//#include <Adafruit_GFX.h>
#include <TFT.h> //comes with Arduino IDE 1.0.5 onwards
#include <SPI.h>

// Define pins for ILI9163 SPI myDisplay
#define __CS 5
#define __DC 7 // Labeled as A0 in some modules
#define __RST 6
// Connect SDA to Arduino pin 11 (MOSI), and SCK to 13 (SCK)

char printBuffer[32];

// Color definitions
#define BLACK 0,0,0
#define BLUE 0,0,255
#define RED 255,0,0
#define GREEN 0,255,0
#define CYAN 0,255,255
#define MAGENTA 255,0,255
#define YELLOW 255,255,0 
#define WHITE 255,255,255
#define TRANSPARENT -1
TFT myDisplay = TFT(__CS, __DC, __RST);


//#include <dht11.h>
//dht11 DHT11;


#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);


#define _SS_MAX_RX_BUFF 128 // RX buffer size //BEFORE WAS 64


SoftwareSerial esp8266(8,7); //RX,TX

String inputBuffer = "";
String slength;
String sTemp;
boolean stringComplete = false;
int inputBufferIndex;

String data1 = ""; 
String data2 = "";
String data3 = "";
String data5 = "";

SFE_BMP180 pressure;

char status;
double T,P,temp,paH,paM, tempHighest = 0.00, tempLowest = 100.00;

float humHighest = 0.00, humTemp = 0.00, humMin = 100.00;

float lmHighest = 0.00, lmTemp = 0.00, lmMin = 100.00;

unsigned long startTimeDataCapture = 0;
unsigned long lastCapture = 0;

void setup() {
  // put your setup code here, to run once:  
  inputBuffer.reserve(256); //to be optimized
  
  pressure.begin();

  dht.begin();

  pinMode(A0,INPUT);
  analogReference(INTERNAL);

 myDisplay.begin();
 myDisplay.setRotation(4);
 myDisplay.setTextSize(1);
 //myDisplay.setBitrate(24000000);
 //myDisplay.clearScreen();
 myDisplay.background(0,0,0);

 myDisplay.stroke(CYAN);
 myDisplay.setCursor(5,40);
 myDisplay.print("Cur :");
 myDisplay.setCursor(5,50);
 myDisplay.print("Min :");
 myDisplay.setCursor(5,60);
 myDisplay.print("Max :");

 myDisplay.stroke(YELLOW);
 myDisplay.setCursor(5,75);
 myDisplay.print("Hum :");
 myDisplay.setCursor(5,85);
 myDisplay.print("Min :");
 myDisplay.setCursor(5,95);
 myDisplay.print("Max :");

 myDisplay.stroke(WHITE); 
 myDisplay.setCursor(5,110);
 myDisplay.print("PAH :");
 myDisplay.setCursor(5,120);
 myDisplay.print("PAM :");

 myDisplay.stroke(GREEN); 
 myDisplay.setCursor(5,135);
 myDisplay.print("L_C :");
 myDisplay.setCursor(5,145);
 myDisplay.print("L_M :");
  
  Serial.begin(9600);

  esp8266.begin(115200);
  esp8266.println("AT");  delay(100);
  esp8266.println("AT+UART_CUR=4800,8,1,0,0"); esp8266.flush(); delay(100);
  while(esp8266.available())
  {
      //Serial.write(esp8266.read());
      esp8266.read();
      delay(80);
  }
  esp8266.end();

  esp8266.begin(4800);
  esp8266.println("AT"); delay(100);
  
  esp8266.println("AT+CIPMUX=1"); delay(100);
  esp8266.println("AT+CWMODE=1"); delay(100);
  //esp8266.println("AT+CWJAP="xxxxxxxxxxxxx","xxxxxxxxxxxxx""); esp8266.flush(); delay(1000);  
  //esp8266.println("AT+CWJAP="xxxxxxxxxxxxxxxx","xxxxxxxxxxxxxx""); esp8266.flush();  delay(1000);  
  
  while(esp8266.available())
  {
      //Serial.write(esp8266.read());
      esp8266.read();
      delay(80);
  }
    
  delay(1000);
}



void loop() {

  //myDisplay.setCursor(0,40);
  
  while(esp8266.available())
  {
      //Serial.write(esp8266.read());
      esp8266.read();
      delay(10);
  }

  inputBuffer = "";
  stringComplete = false;
  
  status = pressure.startTemperature();
  if (status != 0)
  {
    // Wait for the measurement to complete:
    delay(status);

    // Retrieve the completed temperature measurement:
    // Note that the measurement is stored in the variable T.
    // Function returns 1 if successful, 0 if failure.

    status = pressure.getTemperature(T);
    if (status != 0)
    {
      // Print out the measurement:
      temp = T;
            
      // Start a pressure measurement:
      // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait).
      // If request is successful, the number of ms to wait is returned.
      // If request is unsuccessful, 0 is returned.

      status = pressure.startPressure(3);
      if (status != 0)
      {
        // Wait for the measurement to complete:
        delay(status);

        // Retrieve the completed pressure measurement:
        // Note that the measurement is stored in the variable P.
        // Note also that the function requires the previous temperature measurement (T).
        // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.)
        // Function returns 1 if successful, 0 if failure.

        status = pressure.getPressure(P,T);
        if (status != 0)
        {
          // Print out the measurement:
          paM = P;
          paH = P*0.0295333727;
        }
        else
        {
          paM = -1;
          paH = -1;
        }
      }
      else
      {
          paM = -1;
          paH = -1;
      }
    }
    else
    {
      temp = -1;
    }
  }
  else
  {
    temp = -1;
  }

  if(tempLowest > temp)
    tempLowest = temp;

  if(tempHighest < temp)
    tempHighest = temp;

  myDisplay.fill(BLACK);
  myDisplay.stroke(BLACK);
  myDisplay.rect(45,40,75,10);
  myDisplay.setCursor(45,40);
  myDisplay.stroke(CYAN);
  myDisplay.println(String(temp) + (char)248 +"C");
  //delay(100);
  myDisplay.fill(BLACK);
  myDisplay.stroke(BLACK);
  myDisplay.rect(45,50,75,10);
  myDisplay.setCursor(45,50);
  myDisplay.stroke(CYAN);
  myDisplay.println(String(tempLowest) + (char)248 +"C");
  //delay(100);
  myDisplay.fill(BLACK);
  myDisplay.stroke(BLACK);
  myDisplay.rect(45,60,75,10);
  myDisplay.setCursor(45,60);
  myDisplay.stroke(CYAN);
  myDisplay.println(String(tempHighest) + (char)248 +"C");

  delay(500);

  humTemp = dht.readHumidity();
  if(humHighest < humTemp)
    humHighest = humTemp;
  if(humMin > humTemp)
    humMin = humTemp;  
  sTemp = String(humTemp) + "%  " + dht.readTemperature();
  myDisplay.fill(BLACK);
  myDisplay.stroke(BLACK);
  myDisplay.rect(45,75,80,10);
  myDisplay.setCursor(45,75);
  myDisplay.stroke(YELLOW);
  myDisplay.println(sTemp);
  myDisplay.fill(BLACK);
  myDisplay.stroke(BLACK);
  myDisplay.rect(45,85,80,10);
  myDisplay.stroke(YELLOW);
  myDisplay.setCursor(45,85);
  myDisplay.println(humMin);
  myDisplay.fill(BLACK);
  myDisplay.stroke(BLACK);
  myDisplay.rect(45,95,80,10);
  myDisplay.stroke(YELLOW);
  myDisplay.setCursor(45,95);
  myDisplay.println(humHighest);

  delay(500);

  myDisplay.fill(BLACK);
  myDisplay.stroke(BLACK);
  myDisplay.rect(45,110,75,10);
  myDisplay.stroke(WHITE);
  myDisplay.setCursor(45,110);
  myDisplay.println(String(paH));
  //delay(500);
  myDisplay.fill(BLACK);
  myDisplay.stroke(BLACK);
  myDisplay.rect(45,120,75,10);
  myDisplay.stroke(WHITE);
  myDisplay.setCursor(45,120);
  myDisplay.println(String(paM));

  
  lmTemp=analogRead(A0); // reads the sensor output
  lmTemp=lmTemp*0.10546875;
  // converts the sensor reading to temperature
  if(lmHighest < lmTemp)
    lmHighest = lmTemp;
  if(lmMin > lmTemp)
    lmMin = lmTemp;  
  myDisplay.fill(BLACK);
  myDisplay.stroke(BLACK);
  myDisplay.rect(45,135,75,10);
  myDisplay.stroke(GREEN);
  myDisplay.setCursor(45,135);
  myDisplay.println(String(lmTemp));
  //delay(500);
  myDisplay.fill(BLACK);
  myDisplay.stroke(BLACK);
  myDisplay.rect(45,145,75,10);
  myDisplay.stroke(GREEN);
  myDisplay.setCursor(45,145);
  myDisplay.println(String(lmMin));
     
 
  if(millis() - lastCapture >  300000)
  {
    lastCapture = millis();
    
    esp8266.println("AT+CWJAP="xxxxxxxxxxxxxxxx","xxxxxxxxxxxxxxxxxx""); esp8266.flush();  delay(5000);
    
    data1 = "GET /interface_1.php?action=1&temp="+String(temp)+"&paM="+String(paM)+"&paH="+String(paH)+" HTTP/1.1";
    data2 = "Host: 128.199.183.127";
    data3 = "User-Agent: IOT";
    data5 = "Connection: close";
    
    Serial.println(data1);
    //Serial.println(data1.length()+data2.length()+data3.length()+data4.length()+data5.length());
       
    esp8266.println("AT+CIPSTART=4,"TCP","xxx.xxx.xxx.xxx",nn");  delay(1000); 
    while(esp8266.available())
    {
        //Serial.write(esp8266.read());
        esp8266.read();
        delay(10);
    }
  
    slength = String(data1.length()+data2.length()+data3.length()+data5.length()+12);
    esp8266.println("AT+CIPSEND=4,"+slength);
    delay(1000);
    while(esp8266.available())
    {
        //Serial.write(esp8266.read());
        esp8266.read();
        delay(10);
    }
    
    // put your main code here, to run repeatedly:
    esp8266.println(data1); delay(1);
    esp8266.println(data2); delay(1);
    esp8266.println(data3); delay(1);
    esp8266.println(data5); delay(1);
    esp8266.println();  delay(1); esp8266.flush();
  
    while(1)
    {
      if(esp8266.available())
        inputBuffer += (char)esp8266.read();
        
      if(inputBuffer.indexOf("CLOSED")> 0 || millis() - startTimeDataCapture > 10000) //don't wait more than 20 seconds
      {
        stringComplete = true;
        Serial.println(inputBuffer);
        delay(1);
        break;
      }
    }
    esp8266.println("AT+CIPCLOSE=4");
    delay(10);
    esp8266.println("AT+CWQAP");
  }
  
  delay(1000);
  
  
}

An Arduino Pro Mini running at 3.3v will be suitable for this. There will be no need of the logic level converters.

Arduino Voltmeter – 2 (more precise)

On some Arduino boards there is a Pin labelled as AREF or Analog Reference. This pin is very useful in cases where a stable and precise voltage reference is needed for the ADC. Practically the supplied voltage to the board can vary a bit, specially it can fall below the rated voltage depending on the load to the board.

By default Arduino uses the voltage of the board, that is 5v or 3.3v (depending on the board). Using the function analogReference() this can be changed. The function accepts one parameter called type. If the type mentioned is DEFAULT then it will use the voltage of the board. INTERNAL type will use a built-in reference equal to 1.1 volts on the ATmega168 or ATmega328 and 2.56 volts on the ATmega8. And EXTERNAL will use the voltage supplied to the AREF pin. 

(More about analogReference can be read at https://www.arduino.cc/en/Reference/AnalogReference)

Please note the voltage at AREF can 0-5 volts only and the input voltage at the I/O pin (here A0) cannot exceed that of the AREF pin.

The simple voltmeter described in a previous article has been modified here. It is now supplied with a precise reference voltage at the AREF pin.

Volt Meter Precise

The 5K resistance is not a necessity, it has been added for safety (switching to the INTERNAL while external power is given to AREF can damage the board with that resistance). If the resistance is used then the voltage at AREF will not be exact as supplied. That is because internally there is a 32k resistor connected to the AREF pin.

So in above case the voltage that the AREF actually getting is 3.3*32/(32+5) = 2.8540 (the actual will vary due to tolerance of components, so for cases where high precision is needed, the values of the resistors will have to be measured and also the voltage of the zener, and the voltage in the code nees to be changed accordingly).

#define READINGS 5

int sensorPin = A0;
short int readingsTaken = 0;
float voltage = 0.0, readingTotal = 0.0;

void setup() {
  // put your setup code here, to run once:
  pinMode(sensorPin, INPUT);
  analogReference(EXTERNAL);
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  readingTotal = 0.0;
  readingsTaken = 0;
  
  // we will take 5 readings at 1 sec interval and then do an average of that
  while(readingsTaken < READINGS) 
  {
    readingTotal += analogRead(sensorPin);
    readingsTaken++;
    delay(1000); //at every 1 second interval
  }

  voltage = (readingTotal/READINGS) * (2.8540/1024); // 2.8540 is the ref voltage being used. //the value in voltage at this point is what Arduino read based on input from voltage divider network. Need to calculate the original -- see below

  voltage = (20/2.609) * voltage; //unitary method to calculate the actual voltage that is read. When voltage read is 2.609, the input is 20v. With the above voltage divider used at input (100K ohm and 15k ohm) the input voltage at the I/O (pin A0) will be 2.609 when 20v is applied. 
   
  Serial.println(voltage); 
}