Nash Ali
Published © MIT

Arduino Due with 480x320 TFT with Touch

This project uses a 480x320 TFT display driven by a ST7796S controller, the touch screen is driven by a XPT2046 controller.

IntermediateWork in progress8 hours8,642
Arduino Due with 480x320 TFT with Touch

Things used in this project

Hardware components

Arduino Due
Arduino Due
×1
3.95" TFT display
×1
Keystudio Mega2560 protoboard
×1
Inertial Measurement Unit (IMU) (6 deg of freedom)
Inertial Measurement Unit (IMU) (6 deg of freedom)
×1
GY-273
×1
GY-1145
×1
CJMCU-8128
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free
Wire Stripper, 30-22 AWG / 0.05-0.34mm² Capacity Solid Wires
Wire Stripper, 30-22 AWG / 0.05-0.34mm² Capacity Solid Wires
30 awg wire for point to point connections
Solder Flux, Soldering
Solder Flux, Soldering

Story

Read more

Code

DueAll

C/C++
Main Code
/*
  Created:      3:06 PM 10/2/2020
  Last Updated: 7:26 PM 10/16/2020
  MIT License

  Copyright (c) 2020 Zulfikar Naushad(Nash) Ali

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.

  Uses the Arduino DUE
  NOTES:
  This program requires a modified version of the UTFT Library to include the ST7796S controller.
  
  I2C Listing
  0x40 - HDC1080
  0x5A - CCS811
  0x5B - MLX90614 (note: needs to have its address changed)done! OK 9-15-20 ZNA
  0x60 - Si1145
  0x68 - RTC - DS3231
  0x76 - BME280
  0x1E - GYRO     builtin
  0x3D - COMPASS  builtin - part of the display adapter

*/
//  includes  **********************************************************************

#include <Wire.h>
#include <SD.h>                   // include the SD library:

#include <SPI.h>                  //  spi library
#include <SparkFunBME280.h>       //  Click here to get the library: http://librarymanager/All#SparkFun_BME280
#include <SparkFunCCS811.h>       //  Air Quality Index
#include <ClosedCube_HDC1080.h>   //  temp & humidity
#include <Adafruit_Sensor.h>      //  Base sensor 
#include <Adafruit_SI1145.h>      //  GY-1145 light quality sensor
#include <Adafruit_MLX90614.h>    //  Melexis IR temp
#include <Adafruit_MPU6050.h>     //  Gyro
#include <Adafruit_HMC5883_U.h>   //  Compass
#include <RTClib.h>               //  RTC
#include <UTFT.h>                 //  Modified Display controller hardware-specific library - added support ST7796S
#include <MAX30105.h>             //  MAX3010x Library
#include <XPT2046_Touchscreen.h>  //  Touch Library
#include <JPEGDecoder.h>          // JPEG decoder library
#include "DueAll.h"

//  Initialization  ****************************************************************
// set up variables using the SD utility library functions:

//Standard SD lib
Sd2Card sdcard;
SdVolume volume;
File root;
RTC_DS3231 Clock;
//  Sensors
Adafruit_HMC5883_Unified mag  = Adafruit_HMC5883_Unified(69);
CCS811 myCCS811(CCS811_ADDR);
ClosedCube_HDC1080 myHDC1080;
BME280 myBME280;
MAX30105 particleSensor;
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
Adafruit_SI1145 light_data = Adafruit_SI1145();
Adafruit_MPU6050 myGyro;
//  display
UTFT tft(ST7796S, 38, 39, 40, 41); //model,CS,DC,WR,RD,RESET
//  touch
XPT2046_Touchscreen myTouch(TOUCH_SS, TOUCH_IRQ);
TS_Point rawLocation;


// -- LOCAL VARIABLES --
// Declare which fonts we will be using
extern uint8_t SmallFont[];
#include "Helper.h"
/*
   SETUP  ****************************************************************************
*/
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  char somedata[] = "nashali"; // data to write to eeprom
  Wire.begin(); // initialise the connection

  // write to EEPROM test
  //  i2c_eeprom_write_page(0x57, 0, (byte *)somedata, sizeof(somedata));

  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect...
  }

  // put your setup code here, to run once:
  InitDisplay();
  ScanI2CBus();
  delay(2000);
  InitI2CDevices();
  InitMyTouch();
  InitMySDCard();
  CheckSDCard();
  //StopSDCard();
  // show all sensor values...
  ShowAll();
  delay(8000);
  ShowGraph(0);
  DemoPlot();
  delay(5000);
  ShowAllJpg();
  BiosMenu(1);

} //  end of setup

/*
   LOOP STARTS HERE ***************************************************************
*/
void loop() {
  // put your main code here, to run repeatedly:
  if (myTouch.tirqTouched()) {
    if (myTouch.touched()) {
      rawLocation = myTouch.getPoint();
      delay(30);
      ParseTouchData(rawLocation.x, rawLocation.y);
    }
    delay(30);  //  debounce
  }
}  //  end loop

Helper.h

C/C++
Contains all macros, routines and functions
#ifndef _HELPER_H
#define _HELPER_H




// Return the minimum of two values a and b
#define minimum(a,b)     (((a) < (b)) ? (a) : (b))

void SetFgBg(int fg, int bg) {
  tft.setBackColor(bg);
  tft.setColor(fg);
}
void ClearScreen() {
  tft.clrScr();
}

//  *************************** BASIC I/O SYSTEM  *****************************************
void BiosMenu(uint8_t v) {
  tft.clrScr();
  SetFgBg(DKBLUE, BLACK);
  tft.setColor(DKBLUE);
  tft.drawRect(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
  tft.fillRect(0, 0, SCREEN_WIDTH - 1, 15);
  SetFgBg(WHITE, DKBLUE);
  tft.setFont(SmallFont);
  tft.print("ETMS - CapSoft Ltd. MiUAIG BIOS (c) 2020 - 2021", CENTER, 2);
  switch (v) {
    case 0:
      tft.setColor(RED);
      tft.fillRect(0, 302, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
      SetFgBg(WHITE, RED);
      tft.print("Main Information", CENTER, 305);
      break;
    case 1:
      tft.setColor(PINK);
      tft.fillRect(0, 302, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
      SetFgBg(WHITE, PINK);
      tft.print("Touchscreen Calibration", CENTER, 305);
      break;
    case 2:
      tft.setColor(DKBLUE);
      tft.fillRect(0, 302, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
      SetFgBg(WHITE, DKBLUE);
      tft.print("Sensor Information", CENTER, 305);
      break;
    case 3:
      tft.setColor(RED);
      tft.fillRect(0, 302, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
      SetFgBg(WHITE, RED);
      tft.print("Drive Information", CENTER, 305);
      break;
    case 4:
      tft.setColor(RED);
      tft.fillRect(0, 302, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
      SetFgBg(WHITE, RED);
      tft.print("Data Logs", CENTER, 305);
      break;
    case 5:
      tft.setColor(DKBLUE);
      tft.fillRect(0, 302, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
      SetFgBg(WHITE, DKBLUE);
      tft.print("Graph Data", CENTER, 305);
      break;
    case 6:
      tft.setColor(BLUE);
      tft.fillRect(0, 302, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
      SetFgBg(WHITE, BLUE);
      tft.print("2 CH SCOPE", CENTER, 305);
      break;
    default:
      break;
  }
}
//====================================================================================
/*
   ******************** Menu System V1.1  ***********************************
*/
void MenuSystem(uint16_t msc , uint16_t msr, uint8_t level) {

  uint8_t vo = 5;
  uint8_t bw = 80;
  uint8_t bh = 20;
  tft.setColor(BLACK);
  switch (level)
  {
    case 0:
      for (int i = 0; i < 9; i++) {
        tft.setColor(BLUE);
        tft.fillRoundRect(msc, msr, msc + bw, msr + bh);
        SetFgBg(YELLOW, BLUE);
        tft.print(MainMenuText[i], msc + 10, msr + vo);
        msr = msr + bh + 10;
      }
      break;
    case 1:
      for (int i = 0; i < 9; i++) {
        tft.setColor(BLUE);
        tft.fillRoundRect(msc, msr, msc + bw, msr + bh);
        tft.setBackColor(BLUE);
        tft.setColor(YELLOW);
        tft.print(AuxMenuText[i], msc + 10, msr + vo);
        msr = msr + bh + 10;
      }
      break;
    default:
      break;
  }
}
/*
 * *********************************  Show all data on one page.....
*/
void ShowAll() {
  BiosMenu(2);
  SetFgBg(BLUE, BLACK);
  tft.drawRect(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
  /* Get a new sensor event */
  sensors_event_t event;
  mag.getEvent(&event);
  float heading = atan2(event.magnetic.y, event.magnetic.x);
  float declinationAngle = 0.22;
  heading += declinationAngle;
  if (heading < 0)
    heading += 2 * PI;
  if (heading > 2 * PI)
    heading -= 2 * PI;
  headingDegrees = heading * 180 / M_PI;  // Convert radians to degrees for readability.
  tft.print("Current Heading: ", 100, 20);
  tft.printNumF(headingDegrees, 0 , 240, 20);
  tft.print("degrees", 290, 20);
  if (CCS811_READY) {
    //compensating the CCS811 with humidity and temperature readings from the HDC1080
    myCCS811.setEnvironmentalData(myHDC1080.readHumidity(), myHDC1080.readTemperature());
    myCCS811.readAlgorithmResults();

    tft.print("Temp=", 20, 40);
    tft.printNumF(myHDC1080.readTemperature(), 2, 65, 40);
    tft.print("C", 130, 40);
    tft.print("Humidity=", 180, 40);
    tft.printNumI(myHDC1080.readHumidity(), 255, 40);
    tft.print("%", 275, 40);
    tft.print("Baro=", 320, 40);
    tft.printNumF(myBME280.readFloatPressure() * 0.00750062, 2, 365, 40);
    tft.print(" hPa", 420, 40);

    tft.print("Alt.=", 20, 60);
    tft.printNumF(myBME280.readFloatAltitudeMeters(), 2, 65, 60);
    tft.print("m", 140, 60);
    tft.print("CO2=", 180, 60);
    tft.printNumF(myCCS811.getCO2(), 2, 220, 60);
    tft.print("ppm", 280, 60);
    tft.print("TVOC=", 320, 60);
    tft.printNumF(myCCS811.getTVOC(), 3, 365, 60);
    tft.print("ppb", 420, 60);
  }
  if (SI1145_READY) {
    tft.print("Vis:", 20, 80);
    tft.printNumI(light_data.readVisible(), 60, 80);
    tft.print("UV Index:", 180, 80);
    tft.printNumF(light_data.readUV() / 100, 3, 255, 80);
    tft.print("Ir:", 320, 80);
    tft.printNumI(light_data.readIR(), 350, 80);
  }
  sensors_event_t a, g, temp;
  myGyro.getEvent(&a, &g, &temp);
  /* Print out the values */
  tft.print("Acceleration X:", 20, 100);
  tft.printNumF(a.acceleration.x, 3, 150, 100);
  tft.print(", Y:", 190, 100);
  tft.printNumF(a.acceleration.y, 3, 240, 100);
  tft.print(", Z:", 300, 100);
  tft.printNumF(a.acceleration.z, 3, 340, 100);
  tft.print("m/s^2", 400, 100);

  tft.print("Rotation X:", 20, 120);
  tft.printNumF(g.gyro.x, 3, 150, 120);
  tft.print(", Y:", 190, 120);
  tft.printNumF(g.gyro.y, 3, 240, 120);
  tft.print(", Z:", 300, 120);
  tft.printNumF(g.gyro.z, 3, 340, 120);
  tft.print(" rad/s", 400, 120);

  tft.print("IMU IC Temp: ", 20, 140);
  tft.printNumF(temp.temperature, 2, 130, 140);
  tft.print("deg C", 175, 140);

  tft.print("Analog CH0:",  20, 160); tft.printNumI(analogRead(0), 110, 160); tft.print("mV", 150, 160);
  tft.print("Analog CH1:", 180, 160); tft.printNumI(analogRead(1), 270, 160); tft.print("mV", 310, 160);
  tft.print("Analog CH2:", 340, 160); tft.printNumI(analogRead(2), 430, 160); tft.print("mV", 460, 160);
  tft.print("Analog CH3:",  20, 180); tft.printNumI(analogRead(3), 110, 180); tft.print("mV", 150, 160);
  tft.print("Analog CH4:", 180, 180); tft.printNumI(analogRead(4), 270, 180); tft.print("mV", 310, 160);
  tft.print("Analog CH5:", 340, 180); tft.printNumI(analogRead(5), 430, 180); tft.print("mV", 460, 160);
  delay(4000);
}


/*
 * ************************** DISPLAY *******************************************************
*/
void InitDisplay() {
  tft.InitLCD(0);
  delay(30);
  BiosMenu(0);
  SetFgBg(RED, BLACK);
  tft.print("ST7796S TFT controller initialized OK", CENTER, 40);
  tft.print("XPT2046 Touch sort of OK?", CENTER, 60);
}

/*
 * ***************  TOUCH *********************************************************************
*/
void InitMyTouch() {
  myTouch.begin();
  //myTouch.calibrate(cal);
}
/*
   xpos & ypos are screen coordinates!
*/
void DrawCalTarget(int xpos, int ypos) {
  SetFgBg(RED, BLACK);
  tft.drawCircle   (xpos, ypos, 6);
  tft.drawLine(xpos - 5, ypos, xpos + 5, ypos);
  tft.drawLine(xpos, ypos - 5, xpos, ypos + 5);
}


void ParseTouchData(int x, int y) {
  SetFgBg(GREEN, BLACK);
  float xpos, ypos;
  tft.print( "Touch Raw Data:", 130, 20);
  tft.print( "X=        ", 255, 20);
  xpos = (((float)x / 4096) * SCREEN_WIDTH);
  ypos = (((float)y / 4096 ) * SCREEN_HEIGHT);
  tft.printNumI(xpos , 275, 20);
  tft.print( "Y=        ", 315, 20 );
  tft.printNumI(ypos , 335, 20);
  DrawCalTarget(xpos, ypos);
  delay(100);
}

/*
   *******************  ScanI2CBus is implemented - 10/02/2020  *****************************************
*/
void ScanI2CBus() {
  byte error, address;
  int nDevices;
  Wire.begin();
  Wire.setClock(50000);
  tft.setFont(SmallFont);
  tft.print("I2C Bus Scan:", 20, 260);
  tft.print("Scanning...", 180, 260);
  int row = 100;
  for (address = 1; address < 127; address++ )

  {
    /*
      The i2c_scanner uses the return value of
      the Write.endTransmisstion to see if
      a device did acknowledge to the address.
    */

    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      tft.print("I2C device at address > ", 30, row);
      String str = String(address, HEX);
      tft.print("0x" + str, 235, row);
      //tft.printNumI(address, 240, row);

      if (address == 61) {
        tft.print("OLED Display2", 280, row);
      }
      if (address == 0x40) {
        tft.print("HDC1080 Humidity", 280, row);
        HDC1080_AVAIL = true;
      }
      if (address == 0x51) {
        tft.print("24C32 EEPROM", 280, row);
        EEPROM_AVAIL = true;
      }
      if (address == 0x57) {
        tft.print("MAX30102 Oxiometer", 280, row);
        MAX30102_AVAIL = true;
      }
      if (address == 0x5A) {
        tft.print("CCS811 Air Quality", 280, row);
        CCS811_AVAIL = true;
      }
      if (address == 0x60) {
        tft.print("Si1145 Light Quality", 280, row);
        SI1145_AVAIL = true;
      }
      if (address == 0x76) {
        tft.print("BME280 Atmospherics", 280, row);
        BME280_AVAIL = true;
      }
      if (address == 0x68) {
        tft.print("DS3231 RTC", 280, row);
        DS3231_AVAIL = true;

      }
      if (address == 0x69) {
        tft.print("MPU6050 Gyro/Accel", 280, row);
        MPU6050_AVAIL = true;
      }
      if (address == 0x1E) {
        tft.print("HMC5883 Compass", 280, row);
        HMC5883_AVAIL = true;
      }
      row = row + 12;
      nDevices++;
      delay(500);
    }
    else if (error == 4)
    {
      tft.print("Unknown error at address >", 20, 260);
      tft.printNumI(address, 220, 260);
    }
  }
  if (nDevices == 0)
  {
    tft.print("No I2C devices found    ", 260, 260);
  }
  else
  {
    tft.print("Done....    ", 180, 260);
  }
  delay(2000);
}

/*
   Initialize any i2c device that was found by scan - hence RUN Scan First!
*/
void InitI2CDevices() {
  //  for all the found devices an attempt to start devices and if started _READY will be true
  if (DS3231_AVAIL) {
    DS3231_READY = true;
  }
  if (BME280_AVAIL) {

    myBME280.settings.commInterface = I2C_MODE;
    myBME280.settings.I2CAddress = 0x76;
    myBME280.settings.runMode = 3; //Normal mode
    myBME280.settings.tStandby = 0;
    myBME280.settings.filter = 4;
    myBME280.settings.tempOverSample = 5;
    myBME280.settings.pressOverSample = 5;
    myBME280.settings.humidOverSample = 5;
    myBME280.begin();
  }
  if (SI1145_AVAIL) {
    light_data.begin(SI1145_ADDR);
    SI1145_READY = true;
  }
  if (CCS811_AVAIL) {
    myCCS811.begin();
    CCS811_READY = true;
  }
  if (HDC1080_AVAIL) {
    myHDC1080.begin(HDC1080_ADDR);
    HDC1080_READY = true;
  }
  if (MLX90614_AVAIL) {
    mlx.begin();
    MLX90614_READY = true;
  }
  if (MPU6050_AVAIL) {
    // init gyro myGyro
    myGyro.begin(0x69);
    myGyro.setAccelerometerRange(MPU6050_RANGE_8_G);
    myGyro.setGyroRange(MPU6050_RANGE_500_DEG);
    myGyro.setFilterBandwidth(MPU6050_BAND_21_HZ);
    MPU6050_READY = true;
  }
  if (HMC5883_AVAIL) {
    // init compass mag
    mag.begin();
  }
  if (MAX30102_AVAIL) {
    //  init oximeter
    particleSensor.begin(Wire, I2C_SPEED_FAST); //Use default I2C port, 400kHz speed
    particleSensor.setup(); //Configure sensor with default settings
    particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
  }
}

/*
   ***********************  COMPASS  *************************************************
*/
void ShowCompassDetails(void) {
  ClearScreen();
  sensor_t sensor;
  mag.getSensor(&sensor);
  tft.setFont(SmallFont);
  tft.setColor(BLUE);
  tft.print("Sensor:", 100, 120); tft.print((sensor.name), 200, 120);
  tft.print("Driver Ver:", 100, 140); tft.printNumI((sensor.version), 200, 140);
  tft.print("Unique ID:", 100, 160); tft.printNumI((sensor.sensor_id), 200, 160);
}

/*
   this plot function checks for the boundaries of the field of view, ie., the tft dimensional limits.
   if the values of x and y are outside of the limits the plot is ignored.
*/
void PlotXY(int x, int y) {
  if ((480 < x >= 0 ) & (320 < y >= 0)) {
    tft.drawPixel(x, y);
  }
}
/*
  Plot a sine wave
*/


void DemoPlot() {
  SetFgBg(YELLOW, BLACK);
  int yoffset = 160;
  float dtr = 3.141592 / 180;
  float yval = 0;
  int xval = 0;
  for (int xpos = 45; xpos < 460; xpos += 1) {
    yval = sin(dtr * xval);
    yval = (yval * 100)+yoffset;
    PlotXY(xpos, yval);
    Serial.println(yval);
    xval += 1;
  }
}


/*
   Main Graph plot...
*/
void ShowGraph(int Gtype) {
  tft.clrScr();
  //draw grid as defined by Gtype
  BiosMenu(5);
  int ScaleXMax = 60;
  tft.setColor(GREEN);
  tft.drawLine(40, 20, 40, 280);
  tft.drawLine(40, 280, 460, 280);
  for (int ypos = 20; ypos < 280; ypos += 20) {
    tft.drawLine(35, ypos, 55, ypos);
    for (int xi = 45; xi < 460; xi += 20) {
      tft.drawPixel(xi, ypos);
    }
    SetFgBg(WHITE, BLACK);
    tft.printNumI(ScaleXMax, 1, ypos - 5);
    tft.setColor(GREEN);
    ScaleXMax -= 10;
  }
  for (int xpos = 45; xpos < 460; xpos += 20) {
    tft.drawLine(xpos, 275, xpos, 285);
  }


}


/*
   RTC
*/
void ShowClock() {
  if (DS3231_READY) {
    tft.clrScr();
    int xpos = 10;
    int ypos = 40;
    DateTime now = Clock.now();

    tft.print("Current Date:", xpos, ypos);
    xpos += 110;
    tft.printNumI(now.year(), xpos, ypos);
    xpos += 50;
    tft.print("/", xpos, ypos);
    xpos += 8;
    tft.printNumI(now.month(), xpos, ypos);
    xpos += 14;
    tft.print("/", xpos, ypos);
    xpos += 8;
    tft.printNumI(now.day(), xpos, ypos);
    xpos += 14;
    tft.print("(", xpos, ypos);
    xpos += 24;
    tft.print(daysOfTheWeek[now.dayOfTheWeek()], xpos, ypos);
    xpos += 100;
    tft.print(")", xpos, ypos);
    xpos = 10;
    ypos += 20;
    tft.print("Current Time:", xpos, ypos);
    xpos += 110;
    tft.printNumI(now.hour(), xpos, ypos);
    xpos += 14;
    tft.print(":", xpos, ypos); xpos += 8;
    tft.printNumI(now.minute(), xpos, ypos); xpos += 14;
    tft.print(":", xpos, ypos); xpos += 8;
    tft.printNumI(now.second(), xpos, ypos);

  }
}
void SetClock(int MM, int DD, int YY, int hh, int mm, int ss) {
  Clock.adjust(DateTime(YY, MM, DD, hh, mm, ss));
  DateTime now = Clock.now();
}

/*
 * *******************  IR sensor  ******************************
*/
void ReadIRTemp() {
  Wire.setClock(100000);
  OTC = mlx.readObjectTempC();
  OTF = mlx.readObjectTempF();
  ATC = mlx.readAmbientTempC();
  ATF = mlx.readAmbientTempF();
  Wire.setClock(400000);
}

/*
   ****************** Oxi ***************************************
*/
void ScanOximeter() {
  long irValue = particleSensor.getIR();    //Read IR value to know if there's a finger on the sensor or not
  if (irValue > 7000) {
    // tft.drawBitmap(5, 5,24 ,21,SmallHeart,1);       //Draw the first bmp picture (little heart)
  }
}

// Return the minimum of two values a and b
#define minimum(a,b)     (((a) < (b)) ? (a) : (b))
//====================================================================================
//   Decode and render onto the TFT screen
//====================================================================================

void renderJPEG(int xpos, int ypos) {

  // retrieve infomration about the image
  uint16_t *pImg;
  uint16_t mcu_w = JpegDec.MCUWidth;
  uint16_t mcu_h = JpegDec.MCUHeight;
  uint16_t max_x = JpegDec.width;
  uint16_t max_y = JpegDec.height;

  // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs)
  // Typically these MCUs are 16x16 pixel blocks
  // Determine the width and height of the right and bottom edge image blocks
  uint16_t min_w = minimum(mcu_w, max_x % mcu_w);
  uint16_t min_h = minimum(mcu_h, max_y % mcu_h);

  // save the current image block size
  uint16_t win_w = mcu_w;
  uint16_t win_h = mcu_h;

  // record the current time so we can measure how long it takes to draw an image
  //uint32_t drawTime = millis();

  // save the coordinate of the right and bottom edges to assist image cropping
  // to the screen size
  max_x += xpos;
  max_y += ypos;

  // read each MCU block until there are no more
  while ( JpegDec.read()) {

    // save a pointer to the image block
    pImg = JpegDec.pImage;

    // calculate where the image block should be drawn on the screen
    int mcu_x = JpegDec.MCUx * mcu_w + xpos;
    int mcu_y = JpegDec.MCUy * mcu_h + ypos;

    // check if the image block size needs to be changed for the right and bottom edges
    if (mcu_x + mcu_w <= max_x) win_w = mcu_w;
    else win_w = min_w;
    if (mcu_y + mcu_h <= max_y) win_h = mcu_h;
    else win_h = min_h;

    // calculate how many pixels must be drawn
    uint16_t mcu_pixels = win_w * win_h;

    // draw image MCU block only if it will fit on the screen
    if (( mcu_x + win_w ) <= tft.getDisplayXSize() && ( mcu_y + win_h ) <= tft.getDisplayYSize())
    {
      // Now set a MCU bounding window on the TFT to push pixels into (x, y, x + width - 1, y + height - 1)
      digitalWrite(TFT_CS, LOW); // Set chip select low so we can take control of display
      tft.setXY(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1);

      // Write all MCU pixels to the TFT window
      while (mcu_pixels--) {
        // Push each pixel to the TFT MCU area
        uint8_t col_h = (*pImg) >> 8;    // High byte
        uint8_t col_l = (*pImg) & 0xFF;  // Low byte
        pImg++;                          // Increment pointer
        tft.LCD_Write_DATA(col_h, col_l); // Send a pixel colour to window
      }
      digitalWrite(TFT_CS, HIGH);  // Set chip select high to release contol
    }
    // Stop drawing blocks if the bottom of the screen has been reached,
    // the abort function will close the file
    else if ( (mcu_y + win_h) >= tft.getDisplayYSize()) JpegDec.abort();
  }
}
//====================================================================================
//  Open a Jpeg image file and displays it at the given coordinates.
//====================================================================================

void jpegDraw(const char* filename, int x, int y) {

  File   jpegFile;

  // Try to open requested file on SD card
  if (!SD.open(filename, O_READ)) {
    //tft.print("Jpeg file not found on SD card.");
    return;
  }

  tft.print("Decoding image : ", 10, 10);
  tft.print(filename, 160, 10);
  //tft.println('\'');
  delay(1000);
  // initialise the decoder, check compatibility and gain access to image information
  boolean decoded = JpegDec.decodeSdFile(filename);

  if (decoded) {
    // render the image onto the screen at given coordinates
    renderJPEG(x, y);
  }
  else {
    tft.print("Jpeg file format not supported.", 10, 10);
  }
}


//====================================================================================
void SaveCalToSD(String CalDataString, int len) {
  if (SDCARD_READY) {
    //  if the sd card is ready then save calibration values to touch.cal

    File dataFile = SD.open("touch.cal", FILE_WRITE);
    // if the file is available, write to it:
    if (dataFile) {
      tft.print("saving calibration", 10, 312);
      //      dataFile.write(CalDataString,len);
      dataFile.close();
    }
    // if the file isn't open, pop up an error:
    else {
      tft.print("error opening touch.cal", 10, 312);
    }
  }
}
void GetCalFromSD() {
  if (SDCARD_READY) {
    tft.print("getting calibration", 10, 312);
    // open the file. note that only one file can be open at a time,
    // so you have to close this one before opening another.
    File dataFile = SD.open("touch.cal");
    // if the file is available, read from it:
    if (dataFile) {
      while (dataFile.available()) {
        //        String CalDataString = (dataFile.read());
      }
      dataFile.close();
    }
    // if the file isn't open, pop up an error:
    else {
      tft.print("error opening touch.cal", 10, 312);
    }
  }
}
/*
  Show all jpeg images on sd card
*/
void ShowAllJpg() {
  File dir = SD.open("/");
  while (true) {
    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    tft.clrScr();
    jpegDraw( entry.name(), 0, 0 );
    entry.close();
    delay(5000);
  }
}
/*
   *****************  SD CARD FILE OPERATIONS  *************************************************
*/
void InitMySDCard() {
  pinMode(48, OUTPUT);
  digitalWrite(48, HIGH);
  pinMode(44, INPUT);
  pinMode(53, OUTPUT);
  digitalWrite(53, HIGH);
  SD.begin(48);
}
void StopSDCard() {
  SD.end();
}
void printDirectory(File dir, int numTabs) {
  // Begin at the start of the directory
  dir.rewindDirectory();
  uint8_t ypos = 80;
  while (true) {
    File entry =  dir.openNextFile();
    ypos = ypos + 12;
    if (! entry) {
      // no more files
      break;
    }
    // print the 8.3 name to LCD
    tft.setColor(YELLOW);
    tft.print(entry.name(), 40, ypos);
    // Recurse for directories, otherwise print the file size
    if (entry.isDirectory()) {
      String ename = entry.name();
      tft.print("/", ename.length() + 65, ypos);
      ypos = ypos + 12;
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      tft.setColor(RED);
      tft.printNumI(entry.size(), 180, ypos);
    }
    entry.close();
  }
  delay(2000);
}
/*
   Mount drive if exists
*/
void CheckSDCard() {
  BiosMenu(3);
  SetFgBg(WHITE, BLACK);
  tft.print("Looking for SD card...", 10, 15);
  // we'll use the initialization code from the utility libraries
  // since we're just testing if the card is working!
  if (!sdcard.init(SPI_HALF_SPEED, chipSelect)) {
    tft.print("No SD card found!", 260, 15);
    SDCARD_READY = false;
    delay(2000);
    return;
  } else {
    SDCARD_READY = true;
    tft.print("A card is present.       ", 10, 17);
  }
  // print the type of card
  tft.print("Card type: ", 10, 30);
  switch (sdcard.type()) {
    case SD_CARD_TYPE_SD1:
      tft.print("SD1", 95, 30);
      break;
    case SD_CARD_TYPE_SD2:
      tft.print("SD2", 95, 30);
      break;
    case SD_CARD_TYPE_SDHC:
      tft.print("SDHC", 95, 30);
      break;
    default:
      tft.print("Unknown", 95, 30);
  }
  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
  if (!volume.init(sdcard)) {
    tft.print("Could not find a FAT16/FAT32 partition.", 20, 80);
    tft.print("Make sure you've formatted the card", 20, 92);
    tft.print("Power down, and check your SD Card!", 20, 104);
    tft.print("Continuing without the SD card will result", 20, 116);
    tft.print("in lost logs, no saved data. Any screen calibration", 20, 128);
    tft.print("data will not be available. Are you sure?", 20, 140);
    delay(5000);
    return;
  }
  // display the type and size of the first FAT-type volume
  uint32_t volumesize;
  tft.print("Volume type is FAT", 145, 30);
  tft.printNumI(volume.fatType(), 300, 30);
  volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
  volumesize *= volume.clusterCount();       // we'll have a lot of clusters
  //volumesize *= 512;                            // SD card blocks are always 512 bytes
  volumesize /= 2048;
  //volumesize /= 1024;
  tft.print("Volume size (Mbytes): ", 10, 50);
  tft.printNumI(volumesize, 180, 50);
  tft.print("Files were found on the card (name and size in bytes): ", 10, 72);
  root = SD.open("/");
  printDirectory(root, 0);
}



void PutEEPROM(String dataString) {

}
void GetEEPROM() {

}
void LogToSD(String dataString) {
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
  }
  // if the file isn't open, pop up an error:
  else {
    tft.print("error opening datalog.txt", 10, 312);
  }
}
void DumpLog() {
  if (SDCARD_READY) {
    tft.print("card ready!", 10, 312);
    // open the file. note that only one file can be open at a time,
    // so you have to close this one before opening another.
    File dataFile = SD.open("datalog.txt");
    // if the file is available, write to it:
    if (dataFile) {
      while (dataFile.available()) {
        Serial.write(dataFile.read());
      }
      dataFile.close();
    }
    // if the file isn't open, pop up an error:
    else {
      tft.print("error opening datalog.txt", 10, 312);
    }
  }
}








#endif

DueAll.h

C/C++
Header file
#ifndef _DUEALL_H
#define _DUEALL_H



#define SD_CHIP_SELECT_PIN 48
#define TOUCHPEN  20
#define FINGER    40
#define TFT_CS  40
#define TOUCH_SS  53
#define TOUCH_IRQ 44
#define SCREEN_WIDTH 480
#define SCREEN_HEIGHT 320
//  *************************I2C Address devices...
#define HDC1080_ADDR 0x40
#define MAX30102_ADDR 0x57
#define CCS811_ADDR 0x5A    //Alternate I2C Address
#define MLX90614_ADDR 0x5B
#define SI1145_ADDR 0x60
#define DS3231_ADDR 0x68
#define AT24C32_ADDR  0x51    //  EEPROM
#define BME280_ADDR 0x76
#define MPU6050_ADDR 0x69
#define HMC5883_ADDR 0x3C

//
#define ACCEL 0
#define HEART 1

//  standard colour defines ****************************************************
//  565 colour defines
#define LTBLUE    0xB6DF
#define LTTEAL    0xBF5F
#define LTGREEN   0xBFF7
#define LTCYAN    0xC7FF
#define LTRED     0xFD34
#define LTMAGENTA 0xFD5F
#define LTYELLOW  0xFFF8
#define LTORANGE  0xFE73
#define LTPINK    0xFDDF
#define LTPURPLE  0xCCFF
#define LTGREY    0xE71C

#define BLUE      0x001F
#define TEAL      0x0438
#define GREEN     0x07E0
#define CYAN      0x07FF
#define RED       0xF800
#define MAGENTA   0xF81F
#define YELLOW    0xFFE0
#define ORANGE    0xFC00
#define PINK      0xF81F
#define PURPLE    0x8010
#define GREY      0xC618
#define WHITE     0xFFFF
#define BLACK     0x0000

#define DKBLUE    0x000D
#define DKTEAL    0x020C
#define DKGREEN   0x03E0
#define DKCYAN    0x03EF
#define DKRED     0x6000
#define DKMAGENTA 0x8008
#define DKYELLOW  0x8400
#define DKORANGE  0x8200
#define DKPINK    0x9009
#define DKPURPLE  0x4010
#define DKGREY    0x4A49


//  Status and Data flags for sensors and other attached equipment
bool BME280_AVAIL = false;      //  device found list
bool CCS811_AVAIL = false;
bool HDC1080_AVAIL = false;
bool SI1145_AVAIL = false;
bool MLX90614_AVAIL = false;
bool MAX30102_AVAIL = false;
bool DS3231_AVAIL = false;
bool MPU6050_AVAIL = false;
bool HMC5883_AVAIL = false;
bool EEPROM_AVAIL = false;
//  If AVAIL and is ready flags
bool EEPROM_READY = false;      //  AT24C32 EEPROM...(avail when DS3231 is plugged in)
bool BME280_READY = false;      //  Temp, Air Pressure...
bool CCS811_READY = false;      //  AQI sensor
bool HDC1080_READY = false;     //  humidity sensor
bool SI1145_READY = false;      //  light quality -  GY1145 PCB
bool MLX90614_READY = false;    //  MLX90614 IR Temp device
bool MAX30102_READY = false;    //  MAX30102 Oximeter
bool DS3231_READY = false;      //  RTC
bool HMC5883_READY = false;     //  GY-271 - compass
bool MPU6050_READY = false;     //  GY-521  - gyro/accel
//  sdcard
bool SDCARD_READY = false;      //  if a card is inserted
//  DS3231 Clock vars
bool Century = false;
bool h12;
bool PM;
byte ADay, AHour, AMinute, ASecond, ABits;
bool ADy, A12h, Apm;
//  MLX90614 vars
double ATC, OTC, ATF, OTF;
//  Compass
float headingDegrees;
//  Light
float UVindex;
//  Touch
bool CALIBRATED = false;
//  Env

//  Heart rate stuff
const byte RATE_SIZE = 4; //Increase this for more averaging. 4 is good.
byte rates[RATE_SIZE]; //Array of heart rates
byte rateSpot = 0;
long lastBeat = 0; //Time at which the last beat occurred
float beatsPerMinute;
int beatAvg;

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
char  *MainMenuText[] = {"ADMIN", "PHONE", "SCOPE", "ENV/AQI", "FILES", "NETWORK", "MEDICAL", "GPS", "MORE.."};
char  *AuxMenuText[] = {"NOTES", "CALC", "DRAW", "avail", "avail", "avail", "TEST", "EVALUATE", "MORE.."};

uint8_t SCREEN_ORIENTATION = 0;
uint8_t TOUCH_ORIENTATION = 0;

// this is the SD card SPI SS pin
const int chipSelect = 48;  // has to be pin 48 on a mega 2560 for the SD card.

enum class PointID { NONE = -1, A, B, C, COUNT };

//  VARS  *********************************************************
//SmallHeart and BigHeart are two bmp pictures for the heartrate sensor
static const unsigned char PROGMEM SmallHeart[] =
{ 0x03, 0xC0, 0xF0, 0x06, 0x71, 0x8C, 0x0C, 0x1B, 0x06, 0x18, 0x0E, 0x02, 0x10, 0x0C, 0x03, 0x10,
  0x04, 0x01, 0x10, 0x04, 0x01, 0x10, 0x40, 0x01, 0x10, 0x40, 0x01, 0x10, 0xC0, 0x03, 0x08, 0x88,
  0x02, 0x08, 0xB8, 0x04, 0xFF, 0x37, 0x08, 0x01, 0x30, 0x18, 0x01, 0x90, 0x30, 0x00, 0xC0, 0x60,
  0x00, 0x60, 0xC0, 0x00, 0x31, 0x80, 0x00, 0x1B, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x04, 0x00,
};

static const unsigned char PROGMEM BigHeart[] =
{ 0x01, 0xF0, 0x0F, 0x80, 0x06, 0x1C, 0x38, 0x60, 0x18, 0x06, 0x60, 0x18, 0x10, 0x01, 0x80, 0x08,
  0x20, 0x01, 0x80, 0x04, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0xC0, 0x00, 0x08, 0x03,
  0x80, 0x00, 0x08, 0x01, 0x80, 0x00, 0x18, 0x01, 0x80, 0x00, 0x1C, 0x01, 0x80, 0x00, 0x14, 0x00,
  0x80, 0x00, 0x14, 0x00, 0x80, 0x00, 0x14, 0x00, 0x40, 0x10, 0x12, 0x00, 0x40, 0x10, 0x12, 0x00,
  0x7E, 0x1F, 0x23, 0xFE, 0x03, 0x31, 0xA0, 0x04, 0x01, 0xA0, 0xA0, 0x0C, 0x00, 0xA0, 0xA0, 0x08,
  0x00, 0x60, 0xE0, 0x10, 0x00, 0x20, 0x60, 0x20, 0x06, 0x00, 0x40, 0x60, 0x03, 0x00, 0x40, 0xC0,
  0x01, 0x80, 0x01, 0x80, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x30, 0x0C, 0x00,
  0x00, 0x08, 0x10, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x01, 0x80, 0x00
};


#endif

Credits

Nash Ali

Nash Ali

13 projects • 13 followers
Put together a transistor radio by "Heathkit" when I was around 10, fell in love with electronics and has been a hobby ever since.

Comments