BAROGRAPH with TFT 2,2 " working project

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
Aristodaniel
 
Posts: 17
Joined: Thu Nov 06, 2014 7:08 am

BAROGRAPH with TFT 2,2 " working project

Post by Aristodaniel »

Hi,
I created a BAROGRAPH with the 2,2" TFT Adafruit display and Pressure sensor BMP180.
After spending quite some time the project is now finished and I would like to share it with people possibly
interested since I have not found many identical projects on the web.
At the beginning of the sketch you find the details of what the project does.
I also join a picture of the finished product.
Good luck to everybody wanting to make his own barograph.

Code: Select all

/*
 ELECTRONIC BAROGRAPH
   This sketch measures Temperature and Atmospheric Pressure,
   saves the data on SD card and brings the following data to the TFT screen:
         atmospheric pressure
         temperature
         pressure trend over one hour
         graph of atmospheric pressure over the past 48 hours
         If pressure drops more than 140 Pa/H an alarm sounds and LED flashes.(valuable for sailors)
   Pressure is calibrated and compensated with the sensor's constants to sea level
   using the sketch from Lindblom
   Components used: Arduino pro mini 5V 328
                    Adafruit TFT 2,2" with SD card  ILI9340
                    Adafruit Barometric Pressure sensor BMP180 5V
                    A regulated 5V power source with LM2574 for
                    installation on a yacht accepting 12V or 24V               
   Sketch based on ideas and work from Paul Torruella and Lindblom.               
*/



#include <Adafruit_GFX.h>
#include <Adafruit_ILI9340.h> 
#include <SPI.h>
#include <Wire.h>
#include <SD.h>
#define BMP085_ADDRESS 0x77  // I2C address of BMP085
#define _sclk 13
#define _miso 12
#define _mosi 11
#define _cs 10
#define _dc 9
#define _rst 8
#define sd_cs 4
#define FREQBUZ 2500
#define BUZ 7
int led =6;
Adafruit_ILI9340 tft = Adafruit_ILI9340( _cs, _dc, _rst); 
const unsigned char OSS = 0;  // Oversampling Setting
unsigned long lastMeasurementTime =0;  
unsigned long lastRefreshDisplay =0;
byte heightsToDisplay[320];

// Calibration values
int ac1;
int ac2;
int ac3;
unsigned int ac4;
unsigned int ac5;
unsigned int ac6;
int b1;
int b2;
int mb;
int mc;
int md;

// b5 is calculated in bmp085GetTemperature(...), this variable is also used in bmp085GetPressure(...)
// so ...Temperature(...) must be called before ...Pressure(...).
long b5; 
File historicFile;
void setup(){
  pinMode (6,OUTPUT);
  pinMode (7,OUTPUT);
  pinMode(10, OUTPUT);
  tft.begin();
  tft.fillScreen(ILI9340_BLUE);
  tft.setRotation(1);
  
  //Drawing frames
  tft.fillScreen(ILI9340_BLUE);
  tft.drawRect(1,1,318,238,ILI9340_WHITE);    // white rectangle at display border
  tft.drawFastVLine(317, 1, 238,ILI9340_WHITE); 
  tft.drawFastVLine(316, 1, 238,ILI9340_WHITE); 
  tft.drawRect(10,50, tft.width()-70, 150, ILI9340_WHITE);   // frame for the graph
  tft.drawFastHLine(10,125,tft.width()-70, ILI9340_WHITE);   //HL in the middle of the graph at 1007
 
  // hPa scale indication
  tft.setCursor(tft.width()-55, tft.height()-45);
  tft.setTextColor(ILI9340_WHITE);  tft.setTextSize(2);
  tft.println("980");
  tft.setCursor(tft.width()-55, tft.height()-120);
  tft.println("1007");
  tft.setCursor(tft.width()-55, 50);
  tft.println("1035");
  
  // Value units indication
  
  tft.setTextColor(ILI9340_WHITE);  tft.setTextSize(2);
  tft.setCursor(88, tft.height()-214);
  tft.println("hPa");
  tft.setCursor(197, tft.height()-214);
  tft.println("Pa/H");
  tft.setCursor(10, tft.height()-25);
  tft.println("48H");
  tft.setCursor(120, tft.height()-25);
  tft.println("24H");
  tft.setCursor(tft.width()-85, tft.height()-25);
  tft.println("0H");
  
  // puts °C on the screen
  tft.fillRect(140,4,50,43,ILI9340_BLUE);
  tft.setTextColor(ILI9340_WHITE);  tft.setTextSize(2);
  tft.setCursor(tft.width()-25, 10);
  tft.println("C");
  tft.drawCircle(tft.width()-35,12,3,ILI9340_WHITE);  
 
  Serial.begin(9600);
  Wire.begin();
  bmp085Calibration();
   if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  }
 void loop()
 {
  unsigned long gap = millis() - lastMeasurementTime;
  if (gap>=5000){
     lastMeasurementTime +=gap;
  
  float temperature = bmp085GetTemperature(bmp085ReadUT()); //MUST be called first
  long pressure1 = bmp085GetPressure(bmp085ReadUP());
  long pressure = pressure1 + 3000;//correction I had to apply

 
  tft.fillRect(10,4,75,43, ILI9340_BLUE);//clear rectangle pressure value
  tft.setCursor(10,tft.height()-220);
  tft.setTextColor(ILI9340_WHITE); tft.setTextSize(3);
  tft.print(pressure/100);// clear rectangle trend value
  tft.fillRect(tft.width()-54,25,50,20,ILI9340_BLUE);//clear rectangle temperature value
  tft.setCursor(tft.width()-54, tft.height()-210);
  tft.setTextColor(ILI9340_WHITE);  tft.setTextSize(2);
  tft.println(temperature,1); 
  
  
      computePressureTrend();
      appendPressureInHistoric();
      gap = millis() - lastRefreshDisplay;//refresh graph every minute
         if (gap>60000){
         lastRefreshDisplay += gap;
         updateDataToDisplay();
      }
   }
 }
  // read calibration values from sensor
  void bmp085Calibration()
 {
  ac1 = bmp085ReadInt(0xAA);
  ac2 = bmp085ReadInt(0xAC);
  ac3 = bmp085ReadInt(0xAE);
  ac4 = bmp085ReadInt(0xB0);
  ac5 = bmp085ReadInt(0xB2);
  ac6 = bmp085ReadInt(0xB4);
  b1 = bmp085ReadInt(0xB6);
  b2 = bmp085ReadInt(0xB8);
  mb = bmp085ReadInt(0xBA);
  mc = bmp085ReadInt(0xBC);
  md = bmp085ReadInt(0xBE);
 }

// Calculate temperature in deg C
  float bmp085GetTemperature(unsigned int ut){
  long x1, x2;

  x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15;
  x2 = ((long)mc << 11)/(x1 + md);
  b5 = x1 + x2;

  float temp = ((b5 + 8)>>4);
  temp = temp /10;

  return temp;
}

// Calculate pressure given up
// calibration values must be known
// b5 is also required so bmp085GetTemperature(...) must be called first.
// Value returned will be pressure in units of Pa.
  long bmp085GetPressure(unsigned long up){
  long x1, x2, x3, b3, b6, p;
  unsigned long b4, b7;

  b6 = b5 - 4000;
  // Calculate B3
  x1 = (b2 * (b6 * b6)>>12)>>11;
  x2 = (ac2 * b6)>>11;
  x3 = x1 + x2;
  b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2;

  // Calculate B4
  x1 = (ac3 * b6)>>13;
  x2 = (b1 * ((b6 * b6)>>12))>>16;
  x3 = ((x1 + x2) + 2)>>2;
  b4 = (ac4 * (unsigned long)(x3 + 32768))>>15;

  b7 = ((unsigned long)(up - b3) * (50000>>OSS));
  if (b7 < 0x80000000)
    p = (b7<<1)/b4;
  else
    p = (b7/b4)<<1;

  x1 = (p>>8) * (p>>8);
  x1 = (x1 * 3038)>>16;
  x2 = (-7357 * p)>>16;
  p += (x1 + x2 + 3791)>>4;

  long temp = p;
  return temp;
 }

// Read 1 byte from the BMP085 at 'address'
  char bmp085Read(unsigned char address)
 {
  unsigned char data;

  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(address);
  Wire.endTransmission();

  Wire.requestFrom(BMP085_ADDRESS, 1);
  while(!Wire.available())
    ;

  return Wire.read();
 }

// Read 2 bytes from the BMP085
// First byte will be from 'address'
// Second byte will be from 'address'+1
 int bmp085ReadInt(unsigned char address)
 {
  unsigned char msb, lsb;

  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(address);
  Wire.endTransmission();

  Wire.requestFrom(BMP085_ADDRESS, 2);
  while(Wire.available()<2);
  msb = Wire.read();
  lsb = Wire.read();

  return (int) msb<<8 | lsb;
 }

// Read the uncompensated temperature value
  unsigned int bmp085ReadUT(){
  unsigned int ut;

  // Write 0x2E into Register 0xF4
  // This requests a temperature reading
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(0xF4);
  Wire.write(0x2E);
  Wire.endTransmission();

  // Wait at least 4.5ms
  delay(5);

  // Read two bytes from registers 0xF6 and 0xF7
  ut = bmp085ReadInt(0xF6);
  return ut;
 }

// Read the uncompensated pressure value
  unsigned long bmp085ReadUP(){

  unsigned char msb, lsb, xlsb;
  unsigned long up = 0;

  // Write 0x34+(OSS<<6) into register 0xF4
  // Request a pressure reading w/ oversampling setting
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(0xF4);
  Wire.write(0x34 + (OSS<<6));
  Wire.endTransmission();

  // Wait for conversion, delay time dependent on OSS
  delay(2 + (3<<OSS));

  // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
  msb = bmp085Read(0xF6);
  lsb = bmp085Read(0xF7);
  xlsb = bmp085Read(0xF8);

  up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS);

  return up;
 }

  void writeRegister(int deviceAddress, byte address, byte val) {
  Wire.beginTransmission(deviceAddress); // start transmission to device 
  Wire.write(address);     // send register address
  Wire.write(val);         // send value to write
  Wire.endTransmission();  // end transmission
 }

  int readRegister(int deviceAddress, byte address){

  int v;
  Wire.beginTransmission(deviceAddress);
  Wire.write(address); // register to read
  Wire.endTransmission();

  Wire.requestFrom(deviceAddress, 1); // read a byte

  while(!Wire.available()) {
    // waiting
  }

  v = Wire.read();
  return v;
    
  }
 
    void updateDataToDisplay(){
    tft.fillRect(11,51, 248, 74, ILI9340_BLUE);//clear screen  graph rectangles
    tft.fillRect(11, 126, 248, 73, ILI9340_BLUE);  

    int i=0;
    File historicFile = SD.open("test15.txt");//data saved in file test15
    if(!historicFile){
    return;
    }
    long fileSize = historicFile.size();
   
    long pos = ( fileSize - 276480);// 12 records /min* 60 min/h*48h * 8 bits /record
    
    char pressureArray[7];                       
    while(i<248 && pos <  4000000000 ){                                   
    historicFile.seek(pos);
     for(int j = 0; j < 6; j++){         // reads the record bytes one by one
     pressureArray[j] = historicFile.read();
     if(pressureArray[j]==' '){
          pressureArray[j] =0;
         }
      }
     pressureArray[6]=0;
     long pressureValue1 = atol(pressureArray); 
     long pressureValue = pressureValue1 + 3000;
     
     // Graph boarder limits
     
     if(pressureValue<98000){   
       pressureValue = 98000;
     }
     if(pressureValue>103500){
       pressureValue=103500;
     }
    
     heightsToDisplay[i] = map(pressureValue, 98000, 103500,tft.height()-42,tft.height()-189 );
     tft.drawPixel(tft.width()-310 +i, heightsToDisplay[i], ILI9340_WHITE);
     tft.drawPixel(tft.width()-310 +i, heightsToDisplay[i]-1, ILI9340_WHITE);// to increase thikness of the graph
    
     i++; 
     pos = pos+1112; // 276480 bits spread over 248 observations
    }
     historicFile.close();
  }
  
    void appendPressureInHistoric(){
      
    long pressure = bmp085GetPressure(bmp085ReadUP()); 
    char pressureArray[7];
    String pressureStr = String (pressure);
    pressureStr.toCharArray(pressureArray,7);
    if (pressure<100000){
      pressureArray[5] =' ';
     }
    pressureArray[6]=0;
    historicFile = SD.open("test15.txt", FILE_WRITE);
    if(!historicFile){   
    return;
    
    }
    historicFile.println(pressureArray);
    historicFile.close();
 
 }
   //compute the 1 h pressure change
   
   void computePressureTrend(){  
    
    long pressure = bmp085GetPressure(bmp085ReadUP());
    File historicFile = SD.open("test15.txt"); 
    if(!historicFile){
     
    return;
    }
    
    long fileSize = historicFile.size();
    long pos = ( fileSize - 8*12*60);  //record(8)*records per min(12)*min/h(60)
    char pressureArray[7];                       
    historicFile.seek(pos);
   
    
    for(int j = 0; j < 6; j++){    
    pressureArray[j] = historicFile.read();
    if(pressureArray[j]==' '){
           pressureArray[j] =0;
          }
     }
    pressureArray[6]=0;
    long pressure1HValue = atol(pressureArray);    
    int OneHourTrend = int( pressure - pressure1HValue);
    
    if(OneHourTrend < -140){ // sound buzzer if pressure drop < -140 Pa/h
     tone ( 6, 4000,500);
     delay(500);
     tone (6, 4500, 500);
     delay(500);
     digitalWrite(7,HIGH);//flash LED
     delay(500);
     digitalWrite(7,LOW);
    }
    
    noTone(6);
    digitalWrite(led,LOW);
    
    
    tft.fillRect(140,4,47,43,ILI9340_BLUE);        
    tft.setCursor(140 ,tft.height()-214);           
    tft.setTextColor(ILI9340_WHITE);  tft.setTextSize(2);
    tft.println(OneHourTrend);
    historicFile.close();
 }
 
BAROGRAPH1.jpg
BAROGRAPH1.jpg (7.9 KiB) Viewed 1723 times
BAROGRAPH2.jpg
BAROGRAPH2.jpg (4.66 KiB) Viewed 1723 times

User avatar
adafruit_support_bill
 
Posts: 88037
Joined: Sat Feb 07, 2009 10:11 am

Re: BAROGRAPH with TFT 2,2 " working project

Post by adafruit_support_bill »

Nice work! Thanks for posting your results.

User avatar
redwing57
 
Posts: 2
Joined: Tue Feb 07, 2012 10:38 pm

Re: BAROGRAPH with TFT 2,2 " working project

Post by redwing57 »

I thought you might like to know that a friend spotted your post and we are planning to base a project on this. Nice work!

User avatar
djae
 
Posts: 1
Joined: Mon Jun 15, 2015 3:51 pm

Re: BAROGRAPH with TFT 2,2 " working project

Post by djae »

Hi
Can't see a schematic for the project. Is there one available?

David

ka1axy
 
Posts: 9
Joined: Tue Jan 22, 2008 10:41 am

Re: BAROGRAPH with TFT 2,2 " working project

Post by ka1axy »

I'm currently working on a barograph project, based on Werner Kurzbauer's expanded version of Daniel's project. I'm using an Arduino Mega 2650 and the 2.8" TFT shield with SD card. Sensor is the new BMP280.

The big change is that the code is MUCH simpler than the original code. Much that had to be done by hand is now part of the Adafruit libraries. The BMP280 is factory calibrated and requires no user calibration.

BTW, the schematic is *real* simple: the shield just plugs on, and the BMP280 connects to the I2C interface (5V, GND and pins 20 and 21 of the Mega). There is also a switch [eliminated, see below] and an LED which just connect to some IO pins (don't have the code in front of me right now)

Thanks for the leg-up, Daniel and Werner!

[edit] I've got it working. I replaced the original switches with touch commands, and changed the display from metric to US units (it's easy to change back) and longterm, I intend to use the touch screen to select units, enter height above sea level, and such. The BMP280 is working fine, right on the money accurate (my work location is within sight of an airport, so comparison with known data is quite easy). I've attached my code in case anyone feels like playing.

[edit] Updated the file, added some new features. Stable and working.

Adafruit products used:
Arduino Mega 2650 r3 - https://www.adafruit.com/product/191
BMP280 - https://www.adafruit.com/product/2651
2.8" TFT w/Touch Shield - https://www.adafruit.com/product/1651
Attachments
PZS_barograph.txt
(20.8 KiB) Downloaded 446 times

ka1axy
 
Posts: 9
Joined: Tue Jan 22, 2008 10:41 am

Re: BAROGRAPH with TFT 2,2 " working project

Post by ka1axy »

Now, updated to use the Adafruit 5.0" TFT (1596) and 8875 driver PCB (1590), Micro SD card (254) and BMP280 (2651). Uses Arduino Mega 2560 because of display memory requirements.

Supports touch for both vertical and horizontal zoom.

I built a carrier board to make things easier. Schematic below and the .pcb layout file is in the attached ZIP file
Attachments
Arduino mega 8875 Display SD Shield.zip
ExpressPCB layout file for carrier PCB
(11.9 KiB) Downloaded 64 times
8875 Barograph Carrier.pdf
Schematic of carrier PCB
(26.14 KiB) Downloaded 107 times

[The extension ino has been deactivated and can no longer be displayed.]


Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino”