Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
Hand tools and fabrication machines | ||||||
|
Resistive or Capacitive Touch? Well you might ask what kinds of applications can these be used in? Although there might be a preference towards a capacitive screen over the former, there are some applications where a resistive touch screen will give the end-user easier operation/maintenance. Like for example, in medical apps a user might not be able to remove gloves in order to use the device or where a touch-stylus and resistive screen is much quicker.
These are popular and cheap displays but there are a lot of confusing information about these devices. I got mine from amazon.ca - https://www.amazon.ca/gp/product/B087C3PP9G/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1
I am using an esp32 WROOM 32 dev kit, but you can use any esp32 as long as you configure the pins correctly. If you notice that I am using two separate SPI buses, one for the display and one for the touch interface. At first I tried to run both controllers off the same spi (as most of the instructions out there seem to implement) but was not successful. Once they were independent of each other, the system stabilized.
XPT2046 Touch Controller see - https://github.com/PaulStoffregen/XPT2046_Touchscreen
Menu system...
My first attempt at a keyboard!
UPDATE Feb. 14, 2021
1. Moved the project from the breadboard and gave it a home!
2. Adding new code to address scanning for keys
3. Moved around files, created a Helper.h library
4. Implemented Interrupt-Driven system to manage keys - experimental.
The next step is to add I/O. First onboard the display PCB, a BME280
I had an MPU6050 so I added it to the project. Next I will add an oximeter, a MLX90640(software added 2/24/21) and SD card to the SPI bus(later). also on the horizon - a blue-tooth interface to an android device... stay tuned.
/*
Created: 11:06 PM 9/15/2020
Last Updated: 4:45 PM 2/21/2021
MIT License
Copyright (c) 2021 Zulfikar Naushad 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 NodeMCU Devkit esp32 wroom 32 module (38pin)
In this application the need for exact pixel-to-touch positioning is not required.
Hence the lack of calibration software. I use the technique "ball-park" method to
derive co-ord info. It's a little rough mind you.
I2C Device Listing
0x33 - MLX90640 Flir
0x3C - OLED - not used
0x3D - OLED - not used
0x40 - HDC1080 Humidity
0x57 - AT24C32 address
0x5A - CCS811 AQ
0x5B - MLX90614 (note: needs to have its address changed)done! OK 9-15-20 ZNA
0x60 - Si1145 LQ
0x68 - RTC - DS3231
0x76 - BME280
SPI Listing
ILI9341 Display Controller
display - Click here - https://www.amazon.ca/gp/product/B087C3PP9G/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1
ThingPulse_XPT2046 Touch Controller
see - https://github.com/PaulStoffregen/XPT2046_Touchscreen
Latest Modifications: 2/15/21
Create Helper.h file
Add Button command engine (basic)
function that takes x,y and returns 0 if out of range, 1 - n, n=number of buttons available
*/
#include <WiFi.h> // Wifi
#include <WiFiUdp.h> // UDP
#include <NTPClient.h> // time server
#include <SD.h> // SD Card
//#include <TinyGsmClient.h> // cell stuff.
#include <SPI.h> // spi
#include <Adafruit_GFX.h> // graphics
#include <Adafruit_ILI9341.h> // display
#include <Adafruit_MLX90614.h> // Melexis IR temp
#include <Adafruit_MLX90640.h> // Flir
#include <MAX30105.h> // MAX30102 oxi/pulse (on hold just yet)new compile to ESP32 WROOM 32 today (9-15-2020)
#include <heartRate.h> // Heart rate calculating algorithm
#include <XPT2046_Touchscreen.h> // touch
#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_SI1145.h> // GY-1145 light quality sensor
#include <RTClib.h> // RTC library
#include <time.h> // standard time stuff
#include <Adafruit_MPU6050.h> // Gyro
#include <Adafruit_TCS34725.h> // RGB Sensor
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
//***********************************************************************
#include "Helper.h" // my helper header
// SETUP ***************************************************************
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);// for debug purposes.
// Keep power when running from battery
//bool isOk = setPowerBoostKeepOn(1);
InitDisplay();
showBiosInfo();
scanI2CBus();
initializeSensorGroup();
delay(2000);
ClearScreen();
infoBlocks();
MENU_MODE = 0;
showMenuSystem(MENU_MODE);
delay(200);
initMyTouch();
delay(200);
clearStatus();
//BUILTIN LED
pinMode (2, OUTPUT);
digitalWrite(2, LOW);
//touch irq pin
pinMode (35, INPUT);
AttachTouch();
}
// LOOP *******************************************************************
void loop() {
//set the BUILTIN_LED off.
digitalWrite(BUILTIN_LED, LOW);
// if TouchType is 0 then here is where the actual parsing of the button occurs - action();
// first we check for keypress by looking at PAD_DOWN event
//action(); will invoke the loop
if (PAD_DOWN && GLOBAL_TOUCH_TYPE == MENU) {
// at this point to remember is that the interrupt routine
//just returns the vales to TouchX & TouchY and sets PAD_DOWN = true
// here we can take the time to analyze x,y and come up with BUTTON_NUMBER
BUTTON_NUMBER = parseMenuTouch(TouchX , TouchY );
action(BUTTON_NUMBER);
PAD_DOWN = false;
}
if (PAD_DOWN && GLOBAL_TOUCH_TYPE == NUMERIC) {
// has a valid entry(number,.,<OK>) been entered?
GLOBAL_NUMBER = parseForNumber(TouchX, TouchY);
PAD_DOWN = false;
}
// next skip through the loop...anything else you need to loop
//delay(250);//debounce for now...
// all of the items you need to run can be done like this...
// just activate your items one at a time set SystemMode to 1-4.
if (SystemMode == 0) {
//display what you need to in your idle loop
}
if (SystemMode == TIME) {
showDateTime();
}
if (SystemMode == GYRO) {
showGyroData();
}
if (SystemMode == OXIMETER) {
//display what you need to in your oxi loop
}
if (SystemMode == FLIR) {
//display what you need to in your FLIR loop
updateFlirImage();
}
if (SystemMode == ENVIRONMENT) {
//display what you need to in your BME280 loop
showWeather();
}
if (SystemMode == RGB_SCAN) {
//display what you need to in your BME280 loop
showRGBReader();
}
// and so on...
}// end of loop
/*
Pads
*/
void showAlphaPad(int x, int y) {
GLOBAL_PAD_XPOS = x;
GLOBAL_PAD_YPOS = y;
GLOBAL_TOUCH_TYPE = ALPHA;
//ClearScreen();
tft.fillRect(0, 0, 319, 239, ILI9341_BLACK);
tft.drawRoundRect(x - 5, y - 5, 255, 105, 10, ILI9341_YELLOW);
// first row
int keyx = x;
int keyy = y;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("Q");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("W");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("E");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("R");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("T");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("Y");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("U");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("I");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("O");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("P");
// second row of keys
keyx = x;
keyy = y + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("A");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("S");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("D");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("F");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("G");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("H");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("J");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("K");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("L");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 4, keyy + 6);
tft.print("cr");
// third row of keys
keyx = x;
keyy = y + 50;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("Z");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("X");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("C");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("V");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("B");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("N");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 7, keyy + 6);
tft.print("M");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 1, keyy + 6);
tft.print("ctrl");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 2, keyy + 6);
tft.print("ALT");
keyx = keyx + 25;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 2, keyy + 6);
tft.print("esc");
// fourth row of keys - will be adding more toggle buttons
keyx = x + 75;
keyy = y + 75;
tft.fillRoundRect(keyx, keyy, 70, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 22, keyy + 6);
tft.print("SPACE");
keyx = keyx + 85;
tft.fillRoundRect(keyx, keyy, 20, 20, 5, ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
tft.setCursor(keyx + 2, keyy + 6);
tft.print("bsp");
}
void showNumPad(int x, int y) {
GLOBAL_PAD_XPOS = x;
GLOBAL_PAD_YPOS = y;
GLOBAL_TOUCH_TYPE = NUMERIC;
tft.drawRoundRect(x - 5, y - 5, 90, 105, 10, border_colour);
tft.fillRoundRect(x, y, 20, 20, 5, num_button_colour);
tft.fillRoundRect(x + 30, y, 20, 20, 5, num_button_colour);
tft.fillRoundRect(x + 60, y, 20, 20, 5, num_button_colour);
tft.fillRoundRect(x, y + 25, 20, 20, 5, num_button_colour);
tft.fillRoundRect(x + 30, y + 25, 20, 20, 5, num_button_colour);
tft.fillRoundRect(x + 60, y + 25, 20, 20, 5, num_button_colour);
tft.fillRoundRect(x, y + 50, 20, 20, 5, num_button_colour);
tft.fillRoundRect(x + 30, y + 50, 20, 20, 5, num_button_colour);
tft.fillRoundRect(x + 60, y + 50, 20, 20, 5, num_button_colour);
tft.fillRoundRect(x, y + 75, 20, 20, 5, num_button_colour);
tft.fillRoundRect(x + 30, y + 75, 20, 20, 5, num_button_colour);
tft.fillRoundRect(x + 60, y + 75, 20, 20, 5, num_button_colour);
tft.setTextColor(num_text_colour, num_button_colour);
tft.setCursor(x + 7, y + 6);
tft.print("1");
tft.setCursor(x + 37, y + 6);
tft.print("2");
tft.setCursor(x + 67, y + 6);
tft.print("3");
tft.setCursor(x + 7, y + 31);
tft.print("4");
tft.setCursor(x + 37, y + 31);
tft.print("5");
tft.setCursor(x + 67, y + 31);
tft.print("6");
tft.setCursor(x + 7, y + 56);
tft.print("7");
tft.setCursor(x + 37, y + 56);
tft.print("8");
tft.setCursor(x + 67, y + 56);
tft.print("9");
tft.setCursor(x + 7, y + 81);
tft.print(".");
tft.setCursor(x + 37, y + 81);
tft.print("0");
tft.setCursor(x + 65, y + 81);
tft.print("OK");
}
void showYesNo(int x, int y) {
GLOBAL_PAD_XPOS = x;
GLOBAL_PAD_YPOS = y;
GLOBAL_TOUCH_TYPE = YESNO;
tft.drawRoundRect( x, y, 80, 30, 10, border_colour);
tft.fillRoundRect(x + 5, y + 5, 30, 20, 5, yes_no_button_colour);
tft.fillRoundRect(x + 45, y + 5, 30, 20, 5, yes_no_button_colour);
tft.setTextColor(ILI9341_BLACK, yes_no_button_colour);
tft.setCursor(x + 10, y + 12);
tft.print("YES");
tft.setCursor(x + 55, y + 12);
tft.print("NO");
}
/*
this can be added after ShowYesNo(x,y) is used
*/
bool checkYesNo(int x, int y) {
GLOBAL_TOUCH_TYPE = YESNO;
showYesNo(100, 100);
bool YES = false;
// simply split the x axis
// TODO: return with response
// just check for true else...
if (YES)return true;
return false;
}
int getKeyboardNumeric() {
int val = 0;
int x = 75;
int y = 75;
showNumPad( x, y);
bool ENTRY_COMPLETE = false;
return val;
}
String getKeyboardString() {
GLOBAL_TOUCH_TYPE = ALPHA;
String str;
//show the keyboard
showAlphaPad(5, 110);
//scan for keys pressed and append to @str
// this will override the button test and scan the whole display for keys
// if key is the return key then finish up
// return control to TouchType.Menu
GLOBAL_TOUCH_TYPE = MENU;
return str;
}
/*
This helper file contains all the function calls required by the "OS"
*/
#ifndef _HELPER_H
#define _HELPER_H
// DEFINES **************************************************
#define CYCLE_DURATION 5000
#define HDC1080_ADDR 0x40
#define MAX30102_ADDR 0x57
#define CCS811_ADDR 0x5A //Alternate I2C Address
#define MLX90614_ADDR 0x5B
#define SI1145_ADDR 0x60
#define MPU6050_ADDR 0x68
#define BME280_ADDR 0x76
#define MLX90640_ADDR 0x33
#define TCS34725_ADDR 0x29
// For the ESP32 WROOM 32, these are the default GPIOs.
// Display - updated Feb.,26,2021 - to adjust for SD Card on SPI bus GPIO5 is now SD_CS as per library.
#define TFT_DC 27 //GPIO27
#define TFT_CS 15 //GPIO15
#define TFT_MOSI 23 //GPIO23 - VSPI-MOSI
#define TFT_CLK 18 //GPIO18 - VSPI CLK
#define TFT_RST 4 //GPIO4
#define TFT_MISO 19 //GPIO19 - VSPI-MISO
#define TFT_BLANK 8 //GPIO8
// new for blanking tft via MOSFET - GPIO6
//**********************************************************
//Bluetooth Low Energy
#define SERVICE_UUID "4a41d6bc-24ed-4a80-b3b4-dc1334f5c59f"
#define CHARACTERISTIC_UUID "0b48fbda-ec20-45f7-9f6b-908c7a4d17da"
//**********************************************************
#define BUILTIN_LED 2
// Touch SPI
#define _sclk 25 //GPIO25
#define _mosi 32 //GPIO32
#define _miso 39 //GPIO39
#define TOUCH_CS 33 //GPIO33
#define SEALEVELPRESSURE_HPA (1013.25)
#define TFT_LANDSCAPE 1
#define TFT_PORTRAIT_NORMAL 2
#define TFT_LANDSCAPE_INVERT 3
#define TFT_PORTRAIT_INVERT 4
#define border_colour ILI9341_YELLOW
#define num_button_colour ILI9341_RED
#define key_button_colour ILI9341_WHITE
#define yes_no_button_colour ILI9341_GREEN
#define num_text_colour ILI9341_BLACK
#define MENU 0
#define ALPHA 1
#define NUMERIC 2
#define YESNO 3
int GLOBAL_NUMBER = 0; // this is the holder for numeric input.
String GLOBAL_STRING = ""; // this is for the global string.
int GLOBAL_PAD_XPOS = 0; // holder for the X-POS position of the pad.
int GLOBAL_PAD_YPOS = 0; // Y-POS, used to calc the touch offset position.
int GLOBAL_TOUCH_TYPE = 0; // this tells the system what to look for menu,alpha,numeric,boolean(y/n).
// VARS ********************************************************
bool DEBUG = false;
char *ssid = "****"; // add your own credentials.
char *password = "********"; // here.
const char* ntpServer = "pool.ntp.org";
const int LOCAL_TIME_OFFSET = -4;
const long utcOffsetInSeconds = 3600 * LOCAL_TIME_OFFSET;
bool Century = false, h12, pm;
char daysOfTheWeek[7][20] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
char months[12][4] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
int dow;
int counter = 1;
int groupMode = 0;
//BLE
bool deviceConnected = false;
bool oldDeviceConnected = false;
// our RGB -> eye-recognized gamma color - TCS 34725
byte gammatable[256];
// Your GPRS credentials (leave empty, if not needed)
const char apn[] = ""; // APN (example: internet.vodafone.pt) use https://wiki.apnchanger.org
const char gprsUser[] = ""; // GPRS User
const char gprsPass[] = ""; // GPRS Password
// SIM card PIN (leave empty, if not defined)
const char simPIN[] = "";
double ATC, OTC, ATF, OTF;
const uint8_t TFT_ORIENTATION = TFT_LANDSCAPE_INVERT;
int GFIPZ = 3; // values from 1 to 4. 1 - 1:1, 2 - 2:1, 3 - 3:1, 4 - 4:1.
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;
// Touch/Menu stuff ******************
//add to your menus here
/*
1 main 1
2 main 2
3 main 3
4 flir 1
5 flir 2 - other
6 flir 3 - zoom
7 flir 4 - colour select
7 time 1
8 network 1
9 news 1
10 medical 1
11 services 1
*/
const int M_M1 = 0;
const int M_M2 = 1;
const int M_M3 = 2;
const int M_FLIR = 3;
const int M_FLIR2 = 4;
const int M_FLIR_ZOOM = 5;
const int M_FLIR_COLOUR = 6;
const int M_TIME = 7;
const int M_NETWORK = 8;
const int M_NEWS = 9;
const int M_MEDICAL = 10;
const int M_SERVICES = 11;
const int NOB = 5;//number of buttons.
const int NOM = 12;// number of menus
String main[NOM][NOB] = {{"WEATHER", "TIME", "FLIR", "NEWS", "MORE..."}, {"NETWORK", "E-MAIL", "MEDICAL", "ADMIN", "MORE..."},
{"BLUETOOTH", "GYRO", "RGB", "SERVICES", "BACK..."}, {"MODE", "RESOLUTION", "STATUS", "ON/OFF", "MORE..."},
{"ZOOM", "COLOUR", "***", "***", "BACK..."}, {"1:1", "2:1", "3:1", "4:1", "BACK..."},
{"COLOUR 1", "COLOUR 2", "COLOUR 3", "COLOUR 4", "COLOUR 5"}, {"SET TIME", "SET ALARM", "CLEAR", "INFO", "BACK..."},
{"RECONNECT", "DISCONNECT", "SELECT", "SCAN", "BACK..."}, {"SPORTS", "LIFESTYLES", "TECH", "WORLD", "BACK..."},
{"OXIMETER", "BODY TEMP", "SPIROMETER", "***", "BACK..."}, {"HARDWARE", "KILL I/O", "RESTORE", "***", "BACK..."}
};
int MENU_MODE;
bool PAD_DOWN = false;//the interrupt returns these values.
int TouchX = 0;
int TouchY = 0;
const int TOUCH_IRQ = 35;// to identify the pin to watch.
int BUTTON_NUMBER = 0; // this is for the selected menu buttons. 0- 4.
#define IDLE 0
#define ENVIRONMENT 1 // all of the components attached to the ESP32.
#define OXIMETER 2 // used to run the automation.
#define FLIR 3
#define RGB_SCAN 4
#define GYRO 5
#define TIME 6
#define NETWORK 7
int SystemMode = IDLE; // manages which unit is running. 0 means idle.
// Status and Data from sensors initial values
// CJMCU 8128 module
bool BME280_READY = false;
bool BME280_ACTIVE = false;
bool CCS811_READY = false;
bool HDC1080_READY = false;
// GY1145 Light Quality
bool LIGHTQ_READY = false;
bool LIGHTQ_ACTIVE = false;
// MLX90614 ir
bool IR_READY = false;
bool IR_ACTIVE = false;
// MAX30102 oxi
bool OXI_READY = false;
bool OXI_ACTIVE = false;
// RTC
bool RTC_READY = false;
bool RTC_ACTIVE = false;
// Flir
bool FLIR_READY = false;
bool FLIR_ACTIVE = false;
// GY-521 - gyro/accel
bool MPU6050_READY = false;
bool MPU6050_ACTIVE = false;
// TCS34725 rgb sensor
bool TCS34725_READY = false;
bool TCS34725_ACTIVE = false;
// INITIALIZATION ******************************************************
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
Adafruit_SI1145 light_data = Adafruit_SI1145();
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
Adafruit_MLX90640 flirCam;
Adafruit_MPU6050 myGyro;
float flirFrame[32 * 24]; // buffer for full frame of temperatures
XPT2046_Touchscreen touch(TOUCH_CS);
TS_Point rawLocation;
CCS811 myCCS811(CCS811_ADDR);
ClosedCube_HDC1080 myHDC1080;
BME280 myBME280;
MAX30105 particleSensor;
Adafruit_TCS34725 rgbSensor = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
WiFiClient client;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
//Logo2 and Logo3 are two bmp pictures that display on the TFT if called
// these can be moved to a file(later)
static const unsigned char PROGMEM logo2_bmp[] =
{ 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 logo3_bmp[] =
{ 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
};
/*
remember that when adding code to this header is to keep your functions and variables
"visible" to one another.
ie don't go C=A+B
A=1
B=2
do it like so...
A=1
B=2
C=A+B
this is because the compiler only looks in one direction (no forward referencing)
typical complier error "scope" issues are related to this.
FYI list of functions *************************************************************************
IRAM_ATTR ScreenPressed();
AttachTouch();
InitDisplay();
infoBlocks();
clearAll();
clearBody();
clearStatus();
showStatus();
ClearScreen();
showBiosInfo();
syncronizeRTC();
showDateTime();
showMail();
initMyTouch();
scanI2CBus();
initializeSensorGroup();
showMenuSystem(int m);
showAlphaPad(int x, int y);
showNumPad(int x, int y);
showYesNo(int x, int y);
bool checkYesNo(int x, int y);
ShowIRResults();
oxiTest();
showWeather();
showLightData();
showWifi();
connectToNetwork();
disconnectFromNetwork();
showPhone();
showNews();
showAdmin();
showStars();
int menuButtonCheck(int a, int b);
parseTouchData(int x, int y);
action(int bp);
*/
#include "Pads.h"
// FUNCTIONS & ROUTINES ***********************************************
// The almighty RAM LOAD INTERRUPT(someone touched me and I know where!) TouchX,TouchY,PAD_DOWN gets updated
void IRAM_ATTR ScreenPressed() {
// halt further interrupts
detachInterrupt(TOUCH_IRQ);
if ( touch.touched() )
{
rawLocation = touch.getPoint();
TouchX = rawLocation.x;
TouchY = rawLocation.y;
PAD_DOWN = true;
}
digitalWrite(BUILTIN_LED, HIGH);
// OK good to go...
attachInterrupt(digitalPinToInterrupt(TOUCH_IRQ), ScreenPressed, FALLING);
}
//This is to re-enabe the touch interrupt
void AttachTouch() {
PAD_DOWN = false;
attachInterrupt(digitalPinToInterrupt(TOUCH_IRQ), ScreenPressed, FALLING);
}
void InitDisplay() {
tft.begin(60000000);
delay(10);
tft.setRotation(TFT_ORIENTATION);
tft.fillScreen(ILI9341_BLACK);
}
void infoBlocks() {
tft.fillRoundRect(5, 5, 230, 25, 10, ILI9341_WHITE);
tft.fillRoundRect(7, 7, 226, 21, 8, ILI9341_BLACK);
tft.fillRoundRect(5, 35, 230, 200, 10, ILI9341_WHITE);
tft.fillRoundRect(7, 37, 226, 196, 8, ILI9341_BLACK);
}
void clearAll() {
tft.fillRoundRect(7, 7, 226, 21, 8, ILI9341_BLACK);
tft.fillRoundRect(7, 37, 226, 196, 8, ILI9341_BLACK);
}
void clearBody() {
tft.fillRoundRect(7, 37, 226, 196, 8, ILI9341_BLACK);
}
void clearStatus() {
tft.fillRoundRect(7, 7, 226, 21, 8, ILI9341_BLACK);
}
/*
show status will have two colours to display red and yellow
*/
void showStatus(String z) {
tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
tft.fillRoundRect(7, 7, 226, 21, 8, ILI9341_BLACK);
tft.setCursor(15, 15);
tft.print(z);
}
// Clear Screen! just so i don't have to type blah blah blah! (macro)
void ClearScreen() {
tft.fillScreen(ILI9341_BLACK);
}
void initSDCard() {
if (!SD.begin()) {
showStatus("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
showStatus("No SD card attached");
return;
}
showStatus("SD Card Type: ");
if (cardType == CARD_MMC) {
showStatus("MMC");
} else if (cardType == CARD_SD) {
showStatus("SDSC");
} else if (cardType == CARD_SDHC) {
showStatus("SDHC");
} else {
showStatus("UNKNOWN");
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
showStatus("SD Card Size: %lluMB\n" + cardSize);
}
void InitBLE() {
}
void showBiosInfo() {
ClearScreen();
tft.setCursor(0, 0);
tft.drawRoundRect(0, 0, 320, 240, 10, border_colour);
tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
tft.setCursor(65, 10);
tft.print("ETMS - CAPRICORN SOFTWARE - 2021");
tft.setCursor(90, 20);
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
tft.print("BIOS V1.02.6 - 2/15/2021");
tft.setCursor(135, 30);
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft.println("-System-");
tft.setCursor(100, 40);
tft.setTextColor(ILI9341_MAGENTA, ILI9341_BLACK);
tft.print("ESP WROOM 32 240MHz");
tft.setTextColor(ILI9341_CYAN, ILI9341_BLACK);
tft.setCursor(30, 50);
tft.print("CPU Dual Core..Pass");
tft.setCursor(30, 60);
tft.print("Memory.........Pass");
tft.setCursor(180, 50);
tft.print("ILI9341........Pass");
tft.setCursor(180, 60);
tft.print("XPT2046........Pass");
}
void deactivateAll() {
bool BME280_READY = false;
bool MPU6050_READY = false;
bool TCS34725_READY = false;
bool LIGHTQ_READY = false;
bool OXI_READY = false;
bool IR_READY = false;
bool FLIR_READY = false;
bool RTC_READY = false;
}
//not working - FIXME:
void syncronizeRTC() {
if ( WiFi.status() == WL_CONNECTED) {
showStatus("Fetching time from server..");
configTime(3600, 3600, ntpServer);
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
showStatus("Failed to obtain time");
return;
}
tft.setCursor(50, 50);
tft.print(&timeinfo, "%A, %B %d %Y %H:%M:%S");
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
} else {
showStatus("No network connection");
}
}
void showDateTime() {
}
/*
this is for the touch controller XPT2046
divide the clock by 1 - bus speed 60Mhz ??
*/
void initMyTouch() {
SPI.begin(_sclk, _miso, _mosi);
SPI.setClockDivider(1);
SPI.beginTransaction(SPISettings(60000000, MSBFIRST, SPI_MODE0));
SPI.endTransaction();
touch.begin();
showStatus("Touch Screen is ready!");
}
/*
ScanI2CBus is implemented - 9/21/2020
this has to be done before init sensor group
sets the sensor availability so the system can ignore offline sensors
to manage performance and no bad data woes.
*/
void scanI2CBus() {
int lastRow = 220;
byte error, address;
int nDevices;
Wire.begin();
tft.setCursor(15, lastRow);
tft.print("I2C Bus Scan:");
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.setCursor(15, lastRow - 20);
tft.setTextColor(ILI9341_BLUE, ILI9341_BLACK);
tft.print("I2C device at address 0x");
if (address < 0x10) {
tft.print("0");
}
tft.print(address, HEX);
tft.print(" hex !");
//tft.setCursor(60, lastRow);
//tft.print(address);
tft.setCursor(100, lastRow);
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
if (address == 0x29) {
tft.print("TCS34725 RGB Sensor ");
TCS34725_READY = true;
}
if (address == 0x33) {
tft.print("MLX90640 Flir ");
FLIR_READY = true;
}
if (address == 0x40) {
tft.print("HDC1080 Humidity ");
HDC1080_READY = true;
}
if (address == 0x57) {
tft.print("MAX30102 Oxiometer ");
OXI_READY = true;
}
if (address == 0x5A) {
tft.print("CCS811 Air Quality ");
CCS811_READY = true;
}
if (address == 0x60) {
tft.print("Si1145 Light Quality ");
LIGHTQ_READY = true;
}
if (address == 0x68) {
tft.print("MPU6050 Gyro/Accel ");
MPU6050_READY = true;
}
if (address == 0x76) {
tft.print("BME280 Pressure/Temp ");
BME280_READY = true;
}
nDevices++;
delay(500);
}
else if (error == 4)
{
tft.setCursor(20, lastRow);
tft.print("Error at address 0x");
if (address < 16)
tft.print("0");
tft.println(address, HEX);
}
}
if (nDevices == 0)
{
tft.setCursor(180, lastRow);
tft.print("No I2C devices found");
}
else
{
tft.setCursor(15, lastRow);
tft.print("I2C Bus Scan:");
tft.setCursor(100, lastRow);
tft.print("Done.... ");
}
delay(500);
}
/*
This initialize handles most of the devices that is available
If it finds a sensor it attempts to initialize or if the
sensor is not attached it will flag the unit so the system
will ignore it.
*/
void initializeSensorGroup() {
int lineCount = 80;
int itemStart = 40;
int resutPos = 170;
IR_READY = false;
tft.setCursor(95, lineCount - 10);
tft.print("-Sensors-");
//start BME280
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();
delay(50);
if (!myBME280.begin()) {
BME280_READY = false;
}
// RGB Sensor - TCS34725
if (rgbSensor.begin()) {
TCS34725_READY = true;
} else {
TCS34725_READY = false;
}
//Light sensor start
if (!light_data.begin()) {
LIGHTQ_READY = false;
} else {
LIGHTQ_READY = true;
}
//gyro sensor start
if (MPU6050_READY) {
// init gyro myGyro
myGyro.begin(0x68);
myGyro.setAccelerometerRange(MPU6050_RANGE_8_G);
myGyro.setGyroRange(MPU6050_RANGE_500_DEG);
myGyro.setFilterBandwidth(MPU6050_BAND_21_HZ);
}
//light start
light_data.begin(SI1145_ADDR);
//humidity start
myHDC1080.begin(0x40);
delay(100);
myCCS811.begin();
delay(150);
if (!myCCS811.begin()) {
CCS811_READY = false;
}
//BME280 sensor results.
lineCount += 10;
tft.setCursor(itemStart, lineCount);
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft.print("TEMP/PRESSURE");
if (BME280_READY) {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
tft.print("Pass");
} else {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
tft.print("Fail");
}
//flir test results.
lineCount += 10;
tft.setCursor(itemStart, lineCount);
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft.print("FLIR");
if (FLIR_READY) {
flirCam.begin(MLX90640_I2CADDR_DEFAULT, &Wire);
flirCam.setMode(MLX90640_CHESS);
flirCam.setResolution(MLX90640_ADC_18BIT);
flirCam.setRefreshRate(MLX90640_2_HZ);
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
tft.print("Pass");
} else {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
tft.print("Fail");
}
//rgb sensor test results.
lineCount += 10;
delay(100);
tft.setCursor(itemStart, lineCount);
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft.print("RGB");
if (TCS34725_READY) {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
tft.print("Pass");
} else {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
tft.print("Fail");
}
//gyro sensor test results.
lineCount += 10;
delay(100);
tft.setCursor(itemStart, lineCount);
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft.print("GYRO");
if (MPU6050_READY) {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
tft.print("Pass");
} else {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
tft.print("Fail");
}
//gas sensor test resuts.
lineCount += 10;
delay(100);
tft.setCursor(itemStart, lineCount);
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft.print("GAS");
if (CCS811_READY) {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
tft.print("Pass");
} else {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
tft.print("Fail");
}
//humidity sensor test results.
lineCount += 10;
tft.setCursor(itemStart, lineCount);
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft.print("HUMIDITY");
if (HDC1080_READY) {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
tft.print("Pass");
} else {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
tft.print("Fail");
}
// light sensor test results.
lineCount += 10;
tft.setCursor(itemStart, lineCount);
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft.print("UV");
if (LIGHTQ_READY) {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
tft.print("Pass");
} else {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
tft.print("Fail");
}
// MLX90614 test results.
lineCount += 10;
tft.setCursor(itemStart, lineCount);
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft.print("IR");
if (IR_READY) {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
tft.print("Pass");
} else {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
tft.print("Fail");
}
// oxi test results.
lineCount += 10;
tft.setCursor(itemStart, lineCount);
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft.print("OXIMETER");
if (OXI_READY) {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
tft.print("Pass");
} else {
tft.setCursor(resutPos, lineCount);
tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
tft.print("Fail");
}
delay(5000);
Wire.setClock(400000);
}
void showSystemStatus() {
// in here we just get a look at all hardware connected to the unit.
clearAll();
showStatus("not ready!");
}
/*
Main menu system - sets the active menu and displays the corresponding list.
*/
void showMenuSystem(int m) {
// m selects the buttons to be displayed (0-4)
int menu_x = 240;
int menu_y = 27;
int text_offset = 10;
tft.setTextSize(1);
tft.setTextColor(ILI9341_BLACK);
tft.fillRoundRect(menu_x, 10, 80, 40, 10, ILI9341_BLUE);
tft.fillRoundRect(menu_x, 55, 80, 40, 10, ILI9341_YELLOW);
tft.fillRoundRect(menu_x, 100, 80, 40, 10, ILI9341_GREEN);
tft.fillRoundRect(menu_x, 145, 80, 40, 10, ILI9341_CYAN);
tft.fillRoundRect(menu_x, 190, 80, 40, 10, ILI9341_RED);
tft.setCursor(menu_x + text_offset, menu_y);
tft.print(main[m][0]); // button1
tft.setCursor(menu_x + text_offset, menu_y + 45);
tft.print(main[m][1]); // button2
tft.setCursor(menu_x + text_offset, menu_y + 90);
tft.print(main[m][2]); // button3
tft.setCursor(menu_x + text_offset, menu_y + 135);
tft.print(main[m][3]); // button4
tft.setCursor(menu_x + text_offset, menu_y + 180);
tft.print(main[m][4]); // button5
}
// the idea here is to return with a number 0-9 or a '.' or <OK> to complete the transaction (ENTRY_COMPLETE=true;)
int parseForNumber(int x, int y) {
int mx = x / 50;
int my = y / 50;
tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
tft.setCursor(40, 50);
tft.print("X : " + String(mx));
tft.print(" Y : " + String(my));
//TODO -more parsing...
int number = 0;
return number;
}
/*
Gyro stuff
*/
void showGyroData() {
sensors_event_t a, g, temp;
myGyro.getEvent(&a, &g, &temp);
/* Print out the values */
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft.setCursor(20, 80);
tft.print("Acceleration:");
tft.setCursor(20, 100);
tft.print("X:");
tft.print(a.acceleration.x);
tft.print(", Y:");
tft.print(a.acceleration.y);
tft.print(", Z:");
tft.print(a.acceleration.z);
tft.print("m/s^2 ");
tft.setCursor( 20, 120);
tft.print("Rotation:");
tft.setCursor(20, 140);
tft.print("X:");
tft.print(g.gyro.x);
tft.print(", Y:");
tft.print(g.gyro.y);
tft.print(", Z:");
tft.print(g.gyro.z);
tft.print(" rad/s ");
tft.setCursor( 20, 160);
tft.print("IMU IC Temp: ");
tft.print(temp.temperature);
tft.print(" deg C ");
}
/*
here we interrogate the TCS34725 for rgb values 0-255 per colour
*/
void getColourSample() {
if (TCS34725_READY) {
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft.setCursor(20, 80);
float red, green, blue;
rgbSensor.setInterrupt(false); // turn on LED
delay(60); // takes 50ms to read
rgbSensor.getRGB(&red, &green, &blue);
rgbSensor.setInterrupt(true); // turn off LED
tft.print("R:\t"); tft.print(int(red));
tft.print("\tG:\t"); tft.print(int(green));
tft.print("\tB:\t"); tft.print(int(blue));
tft.setCursor(20, 100);
tft.print((int)red, HEX); tft.print((int)green, HEX); tft.print((int)blue, HEX);
} else {
showStatus("RGB sensor not connected!");
}
}
/*
*/
void demoBluetooth() {
showStatus("BLUETOOTH DEMO");
}
/*
Show MLX 640 stuff ********************************************
*/
void getFlirStatus() {
if (FLIR_READY) {
showStatus("FLIR STATUS");
tft.setCursor(20, 60);
tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft.print("Current mode : ");
if (flirCam.getMode() == MLX90640_CHESS) {
//tft.setCursor(140, 60);
tft.print("Chess");
} else {
tft.print("Interleave");
}
tft.setCursor(20, 80);
tft.print("Current Resolution : ");
//tft.setCursor(160, 80);
mlx90640_resolution_t res = flirCam.getResolution();
switch (res) {
case MLX90640_ADC_16BIT: tft.print("16 bit"); break;
case MLX90640_ADC_17BIT: tft.print("17 bit"); break;
case MLX90640_ADC_18BIT: tft.print("18 bit"); break;
case MLX90640_ADC_19BIT: tft.print("19 bit"); break;
}
flirCam.setRefreshRate(MLX90640_16_HZ);
tft.setCursor(20, 100);
tft.print("Current frame rate: ");
//tft.setCursor(140, 100);
mlx90640_refreshrate_t rate = flirCam.getRefreshRate();
switch (rate) {
case MLX90640_0_5_HZ: tft.print("0.5 Hz"); break;
case MLX90640_1_HZ: tft.print("1 Hz"); break;
case MLX90640_2_HZ: tft.print("2 Hz"); break;
case MLX90640_4_HZ: tft.print("4 Hz"); break;
case MLX90640_8_HZ: tft.print("8 Hz"); break;
case MLX90640_16_HZ: tft.print("16 Hz"); break;
case MLX90640_32_HZ: tft.print("32 Hz"); break;
case MLX90640_64_HZ: tft.print("64 Hz"); break;
}
} else {
showStatus("Flir - offline!");
}
}
//
void toggleFlirMode() {
if (FLIR_READY) {
if (flirCam.getMode() == MLX90640_CHESS) {
flirCam.setMode(MLX90640_INTERLEAVED);
}
if (flirCam.getMode() == MLX90640_INTERLEAVED) {
flirCam.setMode(MLX90640_CHESS);
}
} else {
showStatus("Flir - offline!");
}
}
//
void setFlirResolution() {
if (FLIR_READY) {
showStatus("SET RESOLUTION");
flirCam.setResolution(MLX90640_ADC_18BIT);
} else {
showStatus("Flir - offline!");
}
}
void toggleFlirOnOff() {
if (SystemMode == FLIR) {
showStatus("Flir OFF");
SystemMode = IDLE;//idle
} else {
showStatus("Flir ON");
SystemMode = FLIR;//idle
}
}
/*
Because the adafruit library only returns numbers, we will take the values and
plot them to the screen at a default scale and pallete. This is adjustable with
functions setZoom() and setFlirColours will set the optional parameters.
*/
uint16_t numberToColour(float t) {
// t is your temp range (20-39)
// here is where we map the temperature to a selected pixel from a group of custom palettes.
if (t < 20) return ILI9341_BLACK;
else if (t < 23) return ILI9341_BLUE;
else if (t < 25) return ILI9341_MAGENTA;
else if (t < 27) return ILI9341_CYAN;
else if (t < 29) return ILI9341_GREEN;
else if (t < 31) return ILI9341_YELLOW;
else if (t < 33) return ILI9341_ORANGE;
else if (t < 35) return ILI9341_PINK;
else if (t < 37) return ILI9341_RED;
else if (t < 39) return ILI9341_BLACK;
}
void bufferToScreen() {
uint8_t x = 200 / GFIPZ;
uint8_t y = 180 / GFIPZ;
for (uint8_t h = 0; h < 24; h++)
{
for (uint8_t w = 0; w < 32; w++)
{
float t = flirFrame[h * 32 + w];
//centering position offset depending on zoom factor 1 - 4
int xpixel = x + (w * GFIPZ);
int ypixel = y + (h * GFIPZ);
//tft.fillRect(xpixel, ypixel, (xpixel + GFIPZ), (ypixel + GFIPZ), numberToColour(t));
//
tft.drawPixel(xpixel, ypixel, numberToColour(t));
tft.drawPixel(xpixel + 1, ypixel, numberToColour(t));
tft.drawPixel(xpixel, ypixel + 1, numberToColour(t));
tft.drawPixel(xpixel + 1, ypixel + 1, numberToColour(t));
}
}
}
void updateFlirImage() {
if (FLIR_READY) {
//clearAll();
//showStatus("THERMAL CAMERA");
//TODO: cycle through the frame buffer and create an image on the tft
if (flirCam.getFrame(flirFrame) != 0) {
showStatus("Frame retrieve fail");
return;
}
showStatus("Frames OK.");
bufferToScreen();
} else {
showStatus("Flir - gone offline!");
}
}
void setZoom(int zv) {
//TODO: to be implemented later
if (zv = 0) {
GFIPZ = 1;
showStatus("Zoom set to 1:1");
}
if (zv = 1) {
GFIPZ = 2;
showStatus("Zoom set to 2:1");
}
if (zv = 2) {
GFIPZ = 3;
showStatus("Zoom set to 3:1");
}
...
This file has been truncated, please download it to see its full contents.
Comments