Pseudo-Medical Monitor: Difference between revisions
Jump to navigation
Jump to search
| Line 596: | Line 596: | ||
==== Fingerprint Scanner ==== | ==== Fingerprint Scanner ==== | ||
<nowiki> | |||
#define FPSerial Serial1 | |||
#define FP_INIT 3 | |||
DFRobot_ID809 fingerprint; | |||
String desc; | |||
File myFile; | |||
//#define QUARTER | |||
#ifdef QUARTER | |||
uint8_t data[6400]; //Quarter image | |||
#else | |||
uint8_t data[25600]; //Full image | |||
#endif | |||
void setup_FP() | |||
{ | |||
pinMode(FP_INIT,INPUT); | |||
/*Init FPSerial*/ | |||
FPSerial.begin(115200); | |||
/*Take FPSerial as communication port of fingerprint module */ | |||
fingerprint.begin(FPSerial); | |||
/*Wait for Serial to open*/ | |||
/*Test whether device can communicate properly with mainboard | |||
Return true or false | |||
*/ | |||
while(fingerprint.isConnected() == false) | |||
{ | |||
Serial.println("Communication with device failed, please check connection"); | |||
/*Get error code information */ | |||
desc = fingerprint.getErrorDescription(); | |||
Serial.println(desc); | |||
delay(1000); | |||
} | |||
} | |||
int FP_x_offset = 46; | |||
int FP_y_offset = 78; | |||
int FP_x_width = 82; | |||
int FP_y_height = 82; | |||
bool fingerprint_captured = false; | |||
bool FP_first_pass = true; | |||
void FP_Frame() | |||
{ | |||
int box_top = FP_y_offset; | |||
int box_bottom = box_top + FP_y_height; | |||
int box_left = FP_x_offset; | |||
int box_right = box_left + FP_x_width; | |||
int box_width = FP_x_width; | |||
int box_height = FP_y_height; | |||
int p_x, p_y, p_i, p_data; | |||
if (FP_first_pass) | |||
{ | |||
tft.drawRect(box_left, box_top, box_width, box_height, ST7735_MAGENTA); | |||
tft.fillRect(box_left + 1, box_top + 1, box_width - 2, box_height - 2, ST7735_BLACK); | |||
fingerprint.ctrlLED(/*LEDMode = */fingerprint.eBreathing, /*LEDColor = */fingerprint.eLEDRed, /*blinkCount = */0); | |||
tft.setCursor(box_left + 4, box_top + 4); | |||
tft.println("Place Finger"); | |||
tft.setCursor(box_left + 4, box_top + 16); | |||
tft.println("on scanner."); | |||
FP_first_pass = false; | |||
} | |||
if ((fingerprint.detectFinger()) && (!fingerprint_captured)) | |||
{ | |||
tft.setCursor(box_left + 4, box_top + 4); | |||
tft.println("Keep Finger "); | |||
tft.setCursor(box_left + 4, box_top + 16); | |||
tft.println("on scanner."); | |||
fingerprint.getFingerImage(data); | |||
fingerprint.ctrlLED(/*LEDMode = */fingerprint.eKeepsOn, /*LEDColor = */fingerprint.eLEDGreen, /*blinkCount = */0); | |||
for (p_x=0; p_x < 80; ++p_x) | |||
for (p_y=0; p_y < 80; ++p_y) | |||
{ | |||
xxxxxxxxxxxxxx | |||
p_data = p_data/4; | |||
tft.drawPixel(box_left+1+p_x,box_top+1+p_y,p_data<<5); | |||
} | |||
} | |||
} | |||
</nowiki> | |||
==== MLX90614 Sensor Code ==== | ==== MLX90614 Sensor Code ==== | ||
Revision as of 23:03, 16 October 2021
Pseudo-Medical Monitor for Christmas Cheap Gift
In preparation for the expected Christmas Gift availability crisis, I present the Pseudo-Gift of the season. The time honored tradition of knockoff products hitting the market before Christmas is alive and well. What better than a multi-property knockoff device? Star Trek / Arduino / Medical knockoff device gift for everyone. This Pseudo-Medical Tricorder ripoff is the stocking stuffer for 2021.
Operations
- Thermal Image from AMG8833 Sensor.
- Ambient and Object Temperature from MLX90614 Sensor.
- Distance of device from user via VL53L0X Laser TOF Sensor.
- Pulse Rate from MAX30102 Sensor
- Fingerprint Scan image capture from Capacitive Sensor with ID809 processing capabilities.
Parts List
- Arduino Due Generic Clone (alternative: ITEADUINO DUE)
- Arduino Mega Prototype Shield Generic Clone (alternative: KEYESTUDIO)
- MLX90614 Contactless Temperature Sensor Generic Clone (alternative: )
- AMG8833 Thermal Imager Sensor Generic Clone (alternative: TinyCircuits)
- VL53L0X TOF Laser Distance Sensor Generic Clone (alternative: Onyehn)
- MAX30102 Pulse and O2 Saturation Sensor Generic Clone (alternative: MH-ET Live)
- Capacitive Touch Fingerprint Scanner Generic Clone (alternative: DFROBOT)
- 160x128 LCD TFT SPI 1.8" Module with SD Socket Generic Clone (alternative: Heyaodz111208)
Wiring
| Pin Mapping | ||||||||
|---|---|---|---|---|---|---|---|---|
| Due Pin | Function | MLX90614 | AMG8833 | VL53L0X | MAX30102 | FP Scan | TFT | SD Socket |
| 3 | Interrupt | IRQ | ||||||
| 4 | Interrupt | INT | ||||||
| 5 | Interrupt | INT | ||||||
| 6 | Digital I/O | GPIO1 | ||||||
| 7 | Digital I/O | XSHUT | ||||||
| 8 | Digital I/O | SD_CS | ||||||
| 9 | Digital I/O | RST | ||||||
| 10 | Digital I/O | CS | ||||||
| 11 | Digital I/O | AO | ||||||
| 18 | TX_1 | RX | ||||||
| 19 | RX_1 | TX | ||||||
| 20 | SDA | SDA | SDA | SDA | SDA | |||
| 21 | SCL | SCL | SCL | SCL | SCL | |||
| SPI | MISO | SD_MISO | ||||||
| SPI | MOSI | SDA | SD_MOSI | |||||
| SPI | SCK | SCK | SD_SCK | |||||
Code
Special Libraries
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <Adafruit_VL53L0X.h>
#include <Adafruit_AMG88xx.h>
#include <MAX30105.h>
#include <SparkFunMLX90614.h>
#include <DFRobot_ID809.h>
Library Modification
// In this Library : #include <SparkFunMLX90614.h>
//Change the following line in the bool IRTherm::I2CReadWord(byte reg, int16_t * dest) routine.
//
// I2C processing change needed for Arduino Due implementation
//
// Comment Out Line Below
// _i2cPort->requestFrom(_deviceAddress, (uint8_t) 3, (uint8_t) true);
// Add Line Below
_i2cPort->requestFrom(_deviceAddress, (uint8_t) 3, (uint32_t)reg, (uint8_t)1, (uint8_t)true);
Defines - Variables - Routines
Includes
#include <Wire.h> #include <SPI.h> #include <Adafruit_GFX.h> #include <Adafruit_ST7735.h> #include "Adafruit_VL53L0X.h" #include <Adafruit_AMG88xx.h> #include <MAX30105.h> #include <SparkFunMLX90614.h> #include <DFRobot_ID809.h> #include "bmpHeader.h" #include <SD.h> #include "TFT_Stuff.h" #include "HB_Stuff.h" #include "AMG_Stuff.h" #include "VL_Stuff.h" #include "CT_Stuff.h" #include "FP_Stuff.h"
VL53L0X Sensor
#define START_DISTANCE 200
Adafruit_VL53L0X lox = Adafruit_VL53L0X();
void setup_VL()
{
lox.begin();
}
int last_range_measurement = -1;
int VL_x_offset = 118;
int VL_y_offset = 0;
int VL_x_width = 10;
int VL_y_height = 74;
void range_display(int range_measurement)
{
int box_top = VL_y_offset;
int box_bottom = box_top + VL_y_height;
int box_left = VL_x_offset;
int box_right = box_left + VL_x_width;
int box_width = VL_x_width;
int box_height = VL_y_height;
int bar_top = box_top + 1;
int bar_bottom = box_bottom - 1;
int bar_left = box_left + 1;
int bar_right = box_right -1;
int bar_width = VL_x_width - 2;
int bar_height = VL_y_height - 2;
int bar_measure;
if (last_range_measurement == -1)
{
// Draw Box
tft.fillRect(box_left, box_top, box_width, box_height, ST7735_BLACK);
tft.drawRect(box_left, box_top, box_width, box_height, ST7735_YELLOW);
}
if (last_range_measurement != range_measurement)
{
tft.fillRect(bar_left, bar_top, bar_width, bar_height, ST7735_BLACK);
if (range_measurement > START_DISTANCE)
tft.fillRect(bar_left, bar_top, bar_width, bar_height, ST7735_RED);
else
{
bar_measure = ((float)range_measurement / (float)START_DISTANCE) * bar_height;
tft.fillRect(bar_left, bar_bottom - bar_measure, bar_width, bar_measure, ST7735_GREEN);
}
}
last_range_measurement = range_measurement;
}
void VL_Frame()
{
int range_measure;
VL53L0X_RangingMeasurementData_t measure;
lox.rangingTest(&measure, false); // pass in 'true' to get debug data printout!
if (measure.RangeStatus != 4)
{ // phase failures have incorrect data
range_measure = measure.RangeMilliMeter;
}
else
{
range_measure = 9999;
}
range_display(range_measure);
// delay(100);
}
Heart Beat Sensor
#include "heartRate.h"
static const unsigned char PROGMEM still_heart_logo_bmp[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x0F, 0x00, 0x00, 0x67, 0x18, 0xC0, 0x00, 0xC1, 0xB0, 0x60,
0x01, 0x80, 0xE0, 0x20, 0x01, 0x00, 0xC0, 0x30, 0x01, 0x00, 0x40, 0x10, 0x01, 0x00, 0x40, 0x10,
0x01, 0x04, 0x00, 0x10, 0x01, 0x04, 0x00, 0x10, 0x01, 0x0C, 0x00, 0x30, 0x00, 0x88, 0x80, 0x20,
0x00, 0x8B, 0x80, 0x40, 0x0F, 0xF3, 0x70, 0x80, 0x00, 0x13, 0x01, 0x80, 0x00, 0x19, 0x03, 0x00,
0x00, 0x0C, 0x06, 0x00, 0x00, 0x06, 0x0C, 0x00, 0x00, 0x03, 0x18, 0x00, 0x00, 0x01, 0xB0, 0x00,
0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const unsigned char PROGMEM beat_heart_logo_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
};
MAX30105 particleSensor;
#define HB_INT 4
void setup_HB()
{
// Initialize sensor
if (!particleSensor.begin()) //Use default I2C port, 400kHz speed
{
Serial.println("MAX30105 was not found. Please check wiring/power. ");
while (1);
}
// Serial.println("Place your index finger on the sensor with steady pressure.");
particleSensor.setup(); //Configure sensor with default settings
particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
particleSensor.setPulseAmplitudeGreen(0); //Turn off Green LED
}
int HB_x_offset = 0;
int HB_y_offset = 78;
int HB_x_width = 46;
int HB_y_height = 82;
int HB_initialize_screen = -1;
void HB_Frame()
{
int box_top = HB_y_offset;
int box_bottom = box_top + HB_y_height;
int box_left = HB_x_offset;
int box_right = box_left + HB_x_width;
int box_width = HB_x_width;
int box_height = HB_y_height;
const byte RATE_SIZE = 6; //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 = -1, lastAvg = 0;
bool beatDetect = false;
int latentBeatMax = 2;
int latentBeat = 0;
long irValue = 0;
long maxValue = 0;
long lastValue = 0;
long turnValue = 0;
long lastMax = 0;
int tft_HB_Screen = 0;
int last_HB_Screen = -1;
unsigned long start_time;
unsigned long delta = 0;
int HB_detect_threshold = 7000;
// Clear rate calculating array
for(byte x = 0; x < RATE_SIZE ; ++x)
rates[x] = 0;
if (HB_initialize_screen == -1)
{
tft.fillRect(box_left, box_top, box_width, box_height, ST7735_BLACK);
tft.drawRect(box_left, box_top, box_width, box_height, ST7735_BLUE);
tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
tft.setCursor(box_left + 3,box_top + 4);
tft.println("Place ");
tft.setCursor(box_left + 3,box_top + 16);
tft.println("your ");
tft.setCursor(box_left + 3,box_top + 28);
tft.println("finger ");
tft.setCursor(box_left + 3,box_top + 40);
tft.println("on ");
tft.setCursor(box_left + 3,box_top + 52);
tft.println("sensor ");
HB_initialize_screen = 0;
for (byte x = 0 ; x < RATE_SIZE ; x++)
rates[x] = 0;
}
irValue = particleSensor.getIR();
while(irValue > HB_detect_threshold)
{
irValue = particleSensor.getIR(); //Reading the IR value it will permit us to know if there's a finger on the sensor or not
Serial.print(irValue);
Serial.print(",");
Serial.print(maxValue);
Serial.print(",");
Serial.print(turnValue);
Serial.print(",");
Serial.print(lastMax);
Serial.println();
if (irValue > 7000)
{
//finger is detected
tft_HB_Screen = 1;
if (irValue > maxValue)
maxValue = irValue;
// if ((irValue < maxValue - 200) && (irValue > lastValue + 20)) // alternate detect beat method
if (irValue < maxValue - 200)
{
beatDetect = true;
lastMax = maxValue;
maxValue = irValue;
turnValue = lastValue;
latentBeat = latentBeatMax;
}
lastValue = irValue;
if (beatDetect == true)
{
beatDetect = false;
//We sensed a beat!
delta = millis() - lastBeat; //Measure duration between two beats
lastBeat = millis();
beatsPerMinute = 60 / (delta / 1000.0); //Calculating the BPM
lastAvg = beatAvg;
if ((beatsPerMinute < 255.0) && (beatsPerMinute > 20.0)) //To calculate the average we strore some values (4) then do some math to calculate the average
{
rates[rateSpot++] = (byte)beatsPerMinute; //Store this reading in the array
rateSpot %= RATE_SIZE; //Wrap variable
//Take average of readings
beatAvg = 0;
for (byte x = 0 ; x < RATE_SIZE ; x++)
beatAvg += rates[x];
beatAvg /= RATE_SIZE;
}
}
}
if (irValue < 7000)
{ //If no finger is detected it inform the user and put the average BPM to 0 or it will be stored for the next measure
tft_HB_Screen = 0;
beatAvg=0;
lastAvg = 0;
for(byte x = 0; x < RATE_SIZE ; ++x)
rates[x] = 0;
}
switch(tft_HB_Screen)
{
case 0:
if (last_HB_Screen != 0)
tft.fillRect(box_left + 1, box_top + 1, box_width - 2, box_height - 2, ST7735_BLACK);
tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
tft.setCursor(box_left + 3,box_top + 4);
tft.println("Place ");
tft.setCursor(box_left + 3,box_top + 16);
tft.println("your ");
tft.setCursor(box_left + 3,box_top + 28);
tft.println("finger ");
tft.setCursor(box_left + 3,box_top + 40);
tft.println("on ");
tft.setCursor(box_left + 3,box_top + 52);
tft.println("sensor ");
break;
case 1:
if (last_HB_Screen != 1)
tft.fillRect(box_left + 1,box_top + 1,32,33,ST7735_BLACK);
tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
if (latentBeat == latentBeatMax)
{
tft.fillRect(box_left + 1,box_top + 1, box_width - 2, 33, ST7735_BLACK);
tft.drawBitmap(box_left + 2,box_top + 2, beat_heart_logo_bmp, 32, 32, ST7735_RED); //Draw the second picture (bigger heart)
}
if (latentBeat == 0)
{
tft.fillRect(box_left + 1,box_top + 1, box_width - 2, 33, ST7735_BLACK);
tft.drawBitmap(box_left + 2, box_top + 2, still_heart_logo_bmp, 32, 32, ST7735_WHITE); //Draw the first bmp picture (little heart)
latentBeat = -1;
}
if (latentBeat > 0)
-- latentBeat;
if (lastAvg != beatAvg)
{
tft.fillRect(box_left + 1,box_top + 34 ,box_width - 2,box_height - 35, ST7735_BLACK);
tft.setCursor(box_left + 4,box_top + 34);
tft.println("BPM");
tft.setCursor(box_left + 4,box_top + 44);
tft.println(beatAvg);
lastAvg = beatAvg;
}
break;
case 2:
tft.fillRect(box_left + 1,box_top + 2, 32, 32, ST7735_BLACK);
tft.drawBitmap(box_left + 2,box_top + 2, beat_heart_logo_bmp, 32, 32, ST7735_RED); //Draw the second picture (bigger heart)
tft.fillRect(box_left + 1,box_top + 34 ,box_width - 2,box_height - 35, ST7735_BLACK);
tft.setCursor(box_left + 4,box_top + 34);
tft.println("BPM");
tft.setCursor(box_left + 4,box_top + 44);
tft.println(beatAvg);
break;
case 3:
break;
}
last_HB_Screen = tft_HB_Screen;
delay(100);
}
}
Fingerprint Scanner
#define FPSerial Serial1
#define FP_INIT 3
DFRobot_ID809 fingerprint;
String desc;
File myFile;
//#define QUARTER
#ifdef QUARTER
uint8_t data[6400]; //Quarter image
#else
uint8_t data[25600]; //Full image
#endif
void setup_FP()
{
pinMode(FP_INIT,INPUT);
/*Init FPSerial*/
FPSerial.begin(115200);
/*Take FPSerial as communication port of fingerprint module */
fingerprint.begin(FPSerial);
/*Wait for Serial to open*/
/*Test whether device can communicate properly with mainboard
Return true or false
*/
while(fingerprint.isConnected() == false)
{
Serial.println("Communication with device failed, please check connection");
/*Get error code information */
desc = fingerprint.getErrorDescription();
Serial.println(desc);
delay(1000);
}
}
int FP_x_offset = 46;
int FP_y_offset = 78;
int FP_x_width = 82;
int FP_y_height = 82;
bool fingerprint_captured = false;
bool FP_first_pass = true;
void FP_Frame()
{
int box_top = FP_y_offset;
int box_bottom = box_top + FP_y_height;
int box_left = FP_x_offset;
int box_right = box_left + FP_x_width;
int box_width = FP_x_width;
int box_height = FP_y_height;
int p_x, p_y, p_i, p_data;
if (FP_first_pass)
{
tft.drawRect(box_left, box_top, box_width, box_height, ST7735_MAGENTA);
tft.fillRect(box_left + 1, box_top + 1, box_width - 2, box_height - 2, ST7735_BLACK);
fingerprint.ctrlLED(/*LEDMode = */fingerprint.eBreathing, /*LEDColor = */fingerprint.eLEDRed, /*blinkCount = */0);
tft.setCursor(box_left + 4, box_top + 4);
tft.println("Place Finger");
tft.setCursor(box_left + 4, box_top + 16);
tft.println("on scanner.");
FP_first_pass = false;
}
if ((fingerprint.detectFinger()) && (!fingerprint_captured))
{
tft.setCursor(box_left + 4, box_top + 4);
tft.println("Keep Finger ");
tft.setCursor(box_left + 4, box_top + 16);
tft.println("on scanner.");
fingerprint.getFingerImage(data);
fingerprint.ctrlLED(/*LEDMode = */fingerprint.eKeepsOn, /*LEDColor = */fingerprint.eLEDGreen, /*blinkCount = */0);
for (p_x=0; p_x < 80; ++p_x)
for (p_y=0; p_y < 80; ++p_y)
{
xxxxxxxxxxxxxx
p_data = p_data/4;
tft.drawPixel(box_left+1+p_x,box_top+1+p_y,p_data<<5);
}
}
}
MLX90614 Sensor Code
IRTherm therm; // Create an IRTherm object to interact with throughout
void setup_CT()
{
if (therm.begin() == false) { // Initialize thermal IR sensor
Serial.println("Qwiic IR thermometer did not acknowledge! Freezing!");
while (1);
}
// Serial.println("Qwiic IR Thermometer did acknowledge.");
therm.setUnit(TEMP_F); // Set the library's units to Farenheit
// Alternatively, TEMP_F can be replaced with TEMP_C for Celsius or
// TEMP_K for Kelvin.
}
int last_object_measurement = -1;
int last_ambient_measurement = -1;
int CT_x_offset = 0;
int CT_y_offset = 0;
int CT_x_width = 44;
int CT_y_height = 74;
void CT_Frame()
{
int box_top = CT_y_offset;
int box_bottom = box_top + CT_y_height;
int box_left = CT_x_offset;
int box_right = box_left + CT_x_width;
int box_width = CT_x_width;
int box_height = CT_y_height;
int ambient_x_offset = box_left + 1;
int ambient_y_offset = box_top + 8;
int object_x_offset = box_left + 1;
int object_y_offset = ambient_y_offset + 20;
int ambient_measurement;
int object_measurement;
if ((last_ambient_measurement == -1) && (last_object_measurement == -1))
{
tft.drawRect(box_left, box_top, box_width, box_height, ST7735_RED);
tft.setCursor(ambient_x_offset, ambient_y_offset);
tft.println("MLX90XX");
tft.setCursor(object_x_offset, object_y_offset);
tft.println("Object");
}
therm.read();
ambient_measurement = therm.ambient();
object_measurement = therm.object();
if ( last_ambient_measurement != ambient_measurement)
{
tft.setCursor(ambient_x_offset, ambient_y_offset + 8);
tft.println(String(therm.ambient(), 2));
}
if ( last_object_measurement != object_measurement)
{
tft.setCursor(object_x_offset, object_y_offset + 8);
tft.println(String(therm.object(), 2));
}
last_ambient_measurement = ambient_measurement;
last_object_measurement = object_measurement;
}
AMG8833 Sensor
//low range of the sensor (this will be blue on the screen)
#define MINTEMP 20
//high range of the sensor (this will be red on the screen)
#define MAXTEMP 28
//the colors we will be using
const uint16_t camColors[] = {0x480F,
0x400F, 0x400F, 0x400F, 0x4010, 0x3810, 0x3810, 0x3810, 0x3810, 0x3010, 0x3010,
0x3010, 0x2810, 0x2810, 0x2810, 0x2810, 0x2010, 0x2010, 0x2010, 0x1810, 0x1810,
0x1811, 0x1811, 0x1011, 0x1011, 0x1011, 0x0811, 0x0811, 0x0811, 0x0011, 0x0011,
0x0011, 0x0011, 0x0011, 0x0031, 0x0031, 0x0051, 0x0072, 0x0072, 0x0092, 0x00B2,
0x00B2, 0x00D2, 0x00F2, 0x00F2, 0x0112, 0x0132, 0x0152, 0x0152, 0x0172, 0x0192,
0x0192, 0x01B2, 0x01D2, 0x01F3, 0x01F3, 0x0213, 0x0233, 0x0253, 0x0253, 0x0273,
0x0293, 0x02B3, 0x02D3, 0x02D3, 0x02F3, 0x0313, 0x0333, 0x0333, 0x0353, 0x0373,
0x0394, 0x03B4, 0x03D4, 0x03D4, 0x03F4, 0x0414, 0x0434, 0x0454, 0x0474, 0x0474,
0x0494, 0x04B4, 0x04D4, 0x04F4, 0x0514, 0x0534, 0x0534, 0x0554, 0x0554, 0x0574,
0x0574, 0x0573, 0x0573, 0x0573, 0x0572, 0x0572, 0x0572, 0x0571, 0x0591, 0x0591,
0x0590, 0x0590, 0x058F, 0x058F, 0x058F, 0x058E, 0x05AE, 0x05AE, 0x05AD, 0x05AD,
0x05AD, 0x05AC, 0x05AC, 0x05AB, 0x05CB, 0x05CB, 0x05CA, 0x05CA, 0x05CA, 0x05C9,
0x05C9, 0x05C8, 0x05E8, 0x05E8, 0x05E7, 0x05E7, 0x05E6, 0x05E6, 0x05E6, 0x05E5,
0x05E5, 0x0604, 0x0604, 0x0604, 0x0603, 0x0603, 0x0602, 0x0602, 0x0601, 0x0621,
0x0621, 0x0620, 0x0620, 0x0620, 0x0620, 0x0E20, 0x0E20, 0x0E40, 0x1640, 0x1640,
0x1E40, 0x1E40, 0x2640, 0x2640, 0x2E40, 0x2E60, 0x3660, 0x3660, 0x3E60, 0x3E60,
0x3E60, 0x4660, 0x4660, 0x4E60, 0x4E80, 0x5680, 0x5680, 0x5E80, 0x5E80, 0x6680,
0x6680, 0x6E80, 0x6EA0, 0x76A0, 0x76A0, 0x7EA0, 0x7EA0, 0x86A0, 0x86A0, 0x8EA0,
0x8EC0, 0x96C0, 0x96C0, 0x9EC0, 0x9EC0, 0xA6C0, 0xAEC0, 0xAEC0, 0xB6E0, 0xB6E0,
0xBEE0, 0xBEE0, 0xC6E0, 0xC6E0, 0xCEE0, 0xCEE0, 0xD6E0, 0xD700, 0xDF00, 0xDEE0,
0xDEC0, 0xDEA0, 0xDE80, 0xDE80, 0xE660, 0xE640, 0xE620, 0xE600, 0xE5E0, 0xE5C0,
0xE5A0, 0xE580, 0xE560, 0xE540, 0xE520, 0xE500, 0xE4E0, 0xE4C0, 0xE4A0, 0xE480,
0xE460, 0xEC40, 0xEC20, 0xEC00, 0xEBE0, 0xEBC0, 0xEBA0, 0xEB80, 0xEB60, 0xEB40,
0xEB20, 0xEB00, 0xEAE0, 0xEAC0, 0xEAA0, 0xEA80, 0xEA60, 0xEA40, 0xF220, 0xF200,
0xF1E0, 0xF1C0, 0xF1A0, 0xF180, 0xF160, 0xF140, 0xF100, 0xF0E0, 0xF0C0, 0xF0A0,
0xF080, 0xF060, 0xF040, 0xF020, 0xF800,
};
Adafruit_AMG88xx amg;
unsigned long delayTime;
#define AMG_COLS 8
#define AMG_ROWS 8
float pixels[AMG_COLS * AMG_ROWS];
#define INTERPOLATED_COLS 24
#define INTERPOLATED_ROWS 24
float get_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
void set_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y, float f);
void get_adjacents_1d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
void get_adjacents_2d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
float cubicInterpolate(float p[], float x);
float bicubicInterpolate(float p[], float x, float y);
void interpolate_image(float *src, uint8_t src_rows, uint8_t src_cols,
float *dest, uint8_t dest_rows, uint8_t dest_cols);
void setup_AMG()
{
if (!amg.begin())
{
Serial.println("Could not find a valid AMG88xx sensor, check wiring!");
while (1) { delay(1); }
}
// Serial.println("-- Thermal Camera Test --");
}
void drawpixels(int x_offset, int y_offset, float *p, uint8_t rows, uint8_t cols, uint8_t boxWidth, uint8_t boxHeight)
{
int colorTemp;
// int x_offset = 4, y_offset = 0;
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < cols; x++)
{
float val = get_point(p, rows, cols, x, y);
if (val >= MAXTEMP) colorTemp = MAXTEMP;
else if (val <= MINTEMP) colorTemp = MINTEMP;
else colorTemp = val;
uint8_t colorIndex = map(colorTemp, MINTEMP, MAXTEMP, 0, 255);
colorIndex = constrain(colorIndex, 0, 255);
//draw the pixels!
uint16_t color;
color = val * 2;
tft.fillRect(x_offset + (boxWidth * x), y_offset + (((rows-1) - y) * boxHeight), boxWidth, boxHeight, camColors[colorIndex]);
}
}
}
int AMG_x_offset = 44;
int AMG_y_offset = 0;
int AMG_x_width = 74;
int AMG_y_height = 74;
void AMG_Frame()
{
int AMG_box_top = AMG_y_offset;
int AMG_box_left = AMG_x_offset;
int AMG_box_bottom = AMG_box_top + AMG_y_height;
int AMG_box_right = AMG_box_left + AMG_x_width;
int AMG_box_width = AMG_x_width;
int AMG_box_height = AMG_y_height;
int AMG_frame_left = AMG_box_left + 1;
int AMG_frame_top = AMG_box_top + 1;
int box_size = 3;
//read all the pixels
amg.readPixels(pixels);
float dest_2d[INTERPOLATED_ROWS * INTERPOLATED_COLS];
int32_t t = millis();
interpolate_image(pixels, AMG_ROWS, AMG_COLS, dest_2d, INTERPOLATED_ROWS, INTERPOLATED_COLS);
// Serial.print("Interpolation took "); Serial.print(millis() - t); Serial.println(" ms");
// uint16_t boxsize = min(tft.width() / INTERPOLATED_COLS, tft.height() / INTERPOLATED_COLS);
tft.drawRect(AMG_box_left, AMG_box_top, AMG_box_width, AMG_box_height, ST7735_ORANGE);
drawpixels(AMG_frame_left,AMG_frame_top,dest_2d, INTERPOLATED_ROWS, INTERPOLATED_COLS, box_size, box_size);
}
Core
void setup()
{
Wire.begin();
Serial.begin(115200);
Serial.println("SETUP - Begin");
Serial.println("TFT");
setup_TFT();
Serial.println("CT");
setup_CT();
Serial.println("AMG");
setup_AMG();
Serial.println("VL");
setup_VL();
Serial.println("HB");
setup_HB();
Serial.println("FP");
setup_FP();
Serial.println("SETUP - End");
}
void loop()
{
VL_Frame();
AMG_Frame();
CT_Frame();
FP_Frame();
HB_Frame();
}







