Appendix A - Open-Source Code
//////SPI uSD STUFF /////////////////
//MOSI 23
//MISO 19
//SCLK 18
//SS 5 #include “FS.h”
#include “SD.h” #include “SPI.h” byte RECORD = 0; char
/////////I2C STUFF////////////
//I2C
//SDA 21
//SCL 22
#include
<Wire.h>
//////////OLED STUFF//////////
#include <Adafruit_GFX.h> #define
SSD1306_128_32
#include <Adafruit_SSD1306.h> Adafruit_SSD1306 display = Adafruit_SSD1306();
unsigned long previousMillis = 0; const long interval =
2500;
/////////ENS160 STUFF/////////
<DFRobot_ENS160.h>
DFRobot_ENS160_I2C ENS160(&Wire, /*I2CAddr*/ 0x52); // for 0x52 disconect SDO and GND
uint8_t Status; uint8_t AQI; uint16_t TVOC; uint16_t
ECO2;
////////BME STUFF///////////
“DFRobot_BME280.h”
typedef DFRobot_BME280_IIC BME; // ******** use abbreviations instead of full names ********
/**IIC address is 0x77 when pin SDO is high
*/
/**IIC address is 0x76 when pin SDO is low */ BME bme(&Wire, 0x76); // select
TwoWire peripheral and set sensor address #define SEA_LEVEL_PRESSURE 1015.0f
float temp
= bme.getTemperature();
uint32_t pres = bme.getPressure(); float alti =
bme.calAltitude(SEA_LEVEL_PRESSURE, pres); float humi = bme.getHumidity();
//////////JOY STUFF/////////// #define btnUP 26
#define btnDWN 27
#define btnLFT 14 #define btnRGT
12
#define btnCTR 15
#define btnAUX 13 byte UP = 1;
byte DWN = 1;
byte LFT = 1; byte RGT
= 1;
byte CTR = 1; byte AUX = 1; byte LATCH = 0;
////////ACELL/////////////// #include
<Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>
Adafruit_ADXL345_Unified
accel = Adafruit_ADXL345_Unified(12345); float acellX = 0;
float acellY = 0; float acellZ =
0;
////////RTC///////////////// #include <RTClib.h> RTC_DS3231 rtc;
char daysOfWeek[7][12] = {
“Sunday”,
“Monday”, “Tuesday”,
“Wednesday”, “Thursday”, “Friday”,
“Saturday”
};
uint16_t Year = 0; uint16_t Month = 0; uint16_t Day = 0; uint16_t
Hour = 0; uint16_t Min = 0; uint16_t Sec = 0;
/////MAX6675 STUFF////////// #include
“max6675.h”
#define thermoDO 35
#define thermoCS 32
#define thermoCLK 33 MAX6675
thermocouple(thermoCLK, thermoCS, thermoDO); float TEMP = 0;
///////////MIC STUFF/////////////////////////
// ADC D34
uint16_t ADC = 0;
////////////INT TO STRING///////////////////////
void intToChar(int num, char* buffer, size_t bufferSize) {
itoa(num, buffer, 10); // 10 is the base (decimal)
}
/////////////UPTIME STUFF//////////////////
// long Day=0; int uMillis = 0; int uHour = 0; int uMinute =
0;
//int Second=0;
int HighMillis = 0; int Rollover = 0; int timex = 0;
long secsUp; byte
setUPTIME = 0;
//////////////////////////////////////
////////////// SEUP
//////////////////
////////////////////////////////////// void setup() {
////I2C///
Wire.begin(21, 22); // Initialize I2C communication
////OLED///
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //INICIALIZA O DISPLAY COM ENDEREÇO I2C 0x3C
display.setTextColor(WHITE); //DEFINE A COR DO TEXTO WHITE/BLACK/ INVERSE display.setTextSize(1); //DEFINE O TAMANHO DA FONTE DO TEXTO
display.clearDisplay(); //LIMPA AS INFORMAÇÕES DO DISPLAY
///////BME////////////// bme.begin();
///////ENS160/////////////// ENS160.begin(); ENS160.setPWRMode(ENS160_STANDARD_MODE);
ENS160.setTempAndHum(/*temperature=*/25.0, /*humidity=*/50.0);
/////////ACELL//////////// accel.begin(0x53); accel.setRange(ADXL345_RANGE_16_G);
///////////SERIAL//////////// Serial.begin(115200);
///RTC///
// SETUP RTC MODULE
if (! rtc.begin()) {
Serial.println(“RTC module is NOT found”);
Serial.flush(); while (1);
}
// automatically sets the RTC to the date & time on PC this sketch was compiled
rtc.adjust(DateTime(F( DATE ), F( TIME )));
//Manual
//rtc.adjust(DateTime(2024, 2, 12, 13, 20, 0)); delay(2000);
///////uSD//////////// while (!SD.begin(5)) {
display.clearDisplay(); display.setCursor(30, 12);
display.print(“CARTAO FALHOU”); display.display();
//return;
}
uint8_t cardType = SD.cardType(); while (cardType == CARD_NONE) {
display.clearDisplay(); display.setCursor(20, 12); display.print(“CARTAO NAO
ENCONTRADO”);
display.display();
//return;
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf(“SD Card Size: %lluMB\n”, cardSize);
//init File.SD
writeFile(SD, “/dl1.txt”, “\n”);
///JOY///
pinMode(btnUP, INPUT_PULLUP); pinMode(btnDWN, INPUT_PULLUP); pinMode(btnLFT,
INPUT_PULLUP);
pinMode(btnRGT, INPUT_PULLUP); pinMode(btnCTR, INPUT_PULLUP);
pinMode(btnAUX, INPUT_PULLUP);
}
//////////////////////////////////////
////////////// LOOP
//////////////////
////////////////////////////////////// void loop() {
AUX =
digitalRead(btnAUX);
if ((AUX != 1) && (LATCH == 0)) {
Record(); uMillis =
millis();
delay(2000);
LATCH = 1;
RECORD = 1;
}
AUX =
digitalRead(btnAUX);
if ((AUX != 1) && (LATCH == 1)) {
Closing();
delay(2000);
LATCH = 0;
RECORD = 0;
}
///ACELL/// sensors_event_t event;
accel.getEvent(&event);
acellX = event.acceleration.x; acellY =
event.acceleration.y;
acellZ = event.acceleration.z;
///ADC/// ADC =
analogRead(34);
//intToChar(ADC, ADCstr, sizeof(ADCstr));
///MAX6675/// TEMP =
thermocouple.readCelsius();
///JOY/// JOY();
///uSD RUN/// uSD();
///UPTIME/// UPtime();
///ENS///
ens();
///BME/// bmee();
///OLED +
RTC///
unsigned long currentMillis = millis(); if (currentMillis - previousMillis >=
interval) {
RTC();
oled();
previousMillis = currentMillis;
}
///Serial TAB///
serial();
}
//////////////////////////////////////
//////////////////////////////////////
//COMPONENTES
//////////////////////////////////////
//////////////////////////////////////
/////////////////////////////////////
// BME
void bmee() { temp =
bme.getTemperature();
pres = bme.getPressure(); alti =
bme.calAltitude(SEA_LEVEL_PRESSURE, pres); humi = bme.getHumidity();
}
void
printLastOperateStatus(BME::eStatus_t eStatus)
{
switch (eStatus) { case
BME::eStatusOK: Serial.println(“everything ok”); break; case BME::eStatusErr:
Serial.println(“unknow error”); break; case BME::eStatusErrDeviceNotDetected:
Serial.println(“device not detected”); break; case BME::eStatusErrParameter:
Serial.println(“parameter error”); break; default: Serial.println(“unknow
status”); break;
}
}
/////////////////////////////////////
//ENS
void ens()
{
Status = ENS160.getENS160Status(); Serial.print(“Sensor operating status :
“);
Serial.println(Status);
/**
Get the air quality index Return
value: 1-Excellent, 2-Good, 3-Moderate, 4-Poor, 5-Unhealthy
*/
AQI = ENS160.getAQI();
Serial.print(“Air quality index : “); Serial.println(AQI);
/**
Get
TVOC concentration
Return value range: 0–65000, unit: ppb
*/ TVOC =
ENS160.getTVOC();
Serial.print(“Concentration of total volatile organic compounds :
“);
Serial.print(TVOC); Serial.println(“ ppb”);
/**
Get CO2
equivalent concentration calculated according to the detected data of VOCs and hydrogen (eCO2
– Equivalent CO2)
Return value range: 400–65000, unit: ppm Five levels:
Excellent(400 - 600), Good(600 - 800), Moderate(800 - 1000),
Poor(1000 - 1500), Unhealthy(> 1500)
*/
ECO2 = ENS160.getECO2();
Serial.print(“Carbon
dioxide equivalent concentration : “); Serial.print(ECO2); Serial.println(“
ppm”);
}
/////////////////////////////////////
//JOY
void JOY() {
// UP = digitalRead(btnUP);
// DWN = digitalRead(btnDWN);
// LFT = digitalRead(btnLFT);
//
RGT = digitalRead(btnRGT);
// CTR = digitalRead(btnCTR);
//AUX = digitalRead(btnAUX);
// if (UP !=1){
// Serial.println(“UP”);
// }
// if (DWN !=1){
// Serial.println(“DOWN”);
// }
// if (LFT !=1){
// Serial.println(“LEFT”);
// }
// if (RGT !=1){
// Serial.println(“RIGHT”);
// }
// if (CTR !=1){
// Serial.println(“CENTER”);
//
}
}
/////////////////////////////////
//OLED
//128x64 pixel
// Each pixel has 8x8 pixels
void oled() { display.clearDisplay();
///////////////LINHA 1//////////
display.setCursor(0, 0); display.print(Year, DEC); display.setCursor(26, 0);
display.print(‘/’); display.setCursor(36, 0); display.print(Month, DEC);
display.setCursor(44, 0); display.print(‘/’); display.setCursor(52, 0);
display.print(Day, DEC); if (RECORD == 0) {
display.setCursor(72, 0);
display.print(“Press OK”);
}
if (RECORD == 1) {
display.setCursor(72,
0);
0);
display.print(“@”); if (uHour <= 9) {
display.setCursor(88,
display.print(“0”); display.setCursor(96, 0);
display.print(uHour);
if (uMinute <= 9) { display.setCursor(104, 0);
display.print(“:0”); display.setCursor(120, 0);
display.print(uMinute);
}
else {
display.setCursor(104, 0);
display.print(“:”);
display.setCursor(112, 0);
display.print(uMinute);
}
0);
}
if (uHour >= 10) { display.setCursor(88,
display.print(uHour); if (uMinute <= 9) {
display.setCursor(104, 0);
display.print(“:0”);
display.setCursor(120, 0);
display.print(uMinute);
}
else {
display.setCursor(104, 0);
display.print(“:”);
display.setCursor(112, 0);
display.print(uMinute);
}
}
}
///////////////LINHA 2////////// display.setCursor(0, 8);
display.print(“MIC:”);
display.setCursor(28, 8); display.print(ADC);
display.setCursor(66, 8); display.print(“CO2:”); display.setCursor(92, 8);
display.print(ECO2);
///////////////LINHA 3////////// display.setCursor(0, 16);
display.print(“TMP1”); display.setCursor(30, 16); display.print(temp);
display.setCursor(66, 16); display.print(“TMP2”); display.setCursor(96, 16);
display.print(TEMP);
///////////////LINHA 4////////// display.setCursor(0, 24);
display.print(“X:”); display.setCursor(15, 24); display.print(acellX);
display.setCursor(40, 24); display.print(“Y:”); display.setCursor(52, 24);
display.print(acellY); display.setCursor(85, 24); display.print(“Z:”);
display.setCursor(97, 24); display.print(acellZ); display.display();
}
void Record()
{
display.clearDisplay(); display.setCursor(50, 12);
display.print(“WAIT”); display.display();
}
void Closing() {
display.clearDisplay(); display.setCursor(30, 12); display.print(“FINISHING
UP”);
display.display();
}
/////////////////////////////////
//RTC
void RTC()
{
DateTime now = rtc.now(); Year = now.year();
// Week = daysOfWeek[now.dayOfTheWeek()],
Month = now.month();
Day = now.day();
Hour =
now.hour();
Min = now.minute();
Sec =
now.second();
}
//////////////////////////////
//SERIAL
void serial() {
Serial.print(“Mic Level: “); Serial.println(ADC); Serial.print(“Probe Temp:
“); Serial.println(TEMP);
Serial.print(“RTC:”);
Serial.print(Year,
DEC);
Serial.print(‘/’); Serial.print(Month, DEC); Serial.print(‘/’);
Serial.print(Day, DEC);
Serial.print(“ (“);
//Serial.print(daysOfWeek[now.dayOfTheWeek()]);
//Serial.print(“) “);
Serial.print(Hour, DEC); Serial.print(‘:’); Serial.print(Min, DEC);
Serial.print(‘:’); Serial.print(Sec, DEC); Serial.println(“) “);
Serial.print(“AXCEL:”);
Serial.print(“X: “); Serial.print(acellX); Serial.print(“ “);
Serial.print(“Y: “); Serial.print(acellY); Serial.print(“ “);
Serial.print(“Z: “); Serial.print(acellZ); Serial.println(“ m/s^2 “);
Serial.print(“temperature (unit Celsius): “); Serial.println(temp);
Serial.print(“pressure (unit pa): “); Serial.println(pres);
Serial.print(“altitude (unit meter): “); Serial.println(alti);
Serial.print(“humidity (unit percent): “); Serial.println(humi);
Serial.print(“Sensor operating status : “);
Serial.println(Status); Serial.print(“Air quality index : “);
Serial.println(AQI);
Serial.print(“Concentration of total volatile organic compounds : “);
Serial.print(TVOC); Serial.println(“ ppb”);
Serial.print(“Carbon dioxide equivalent concentration : “); Serial.print(ECO2);
Serial.println(“ ppm”);
Serial.println();
Serial.println();
Serial.println();
Serial.flush();
}
////////////////////////////
//UPTIME
void UPtime() {
//** Making Note of an expected rollover *****// if (millis() >=
3000000000) {
HighMillis = 1;
}
//** Making note of actual rollover **// if
(millis() <= 100000 && HighMillis == 1) { Rollover++;
HighMillis = 0;
}
secsUp = (millis() - uMillis) / 1000; uMinute = (secsUp / 60) % 60;
uHour = (secsUp
/ (60 * 60)) % 24;
}
////////////////////////////////
//uSD
//Functions:
// listDir(SD, “/”, 0);
// createDir(SD, “/mydir”);
// listDir(SD, “/”, 0);
// removeDir(SD, “/mydir”);
// listDir(SD, “/”, 2);
//
writeFile(SD, “/hello.txt”, “Hello “);
// appendFile(SD, “/hello.txt”, “World!\n”);
// readFile(SD, “/hello.txt”);
//
deleteFile(SD, “/foo.txt”);
// renameFile(SD, “/hello.txt”, “/foo.txt”);
// readFile(SD, “/foo.txt”);
// testFileIO(SD, “/test.txt”);
// Serial.printf(“Total space: %lluMB\n”, SD.totalBytes() / (1024 * 1024));
// Serial.printf(“Used space: %lluMB\n”, SD.usedBytes() / (1024 * 1024));
void uSD() {
//Sequencia:
// DATA;TEMP ONBOARD;TEMP PROBE;MIC;CO2;BAR;ORG;UMID;X;Y;Z
if (RECORD == 1) {
////Grava Data////
intToChar(Year, uSDstr, sizeof(uSDstr)); appendFile(SD, “/dl1.txt”, uSDstr);
appendFile(SD, “/dl1.txt”, “/”); intToChar(Month, uSDstr,
sizeof(uSDstr));
appendFile(SD, “/dl1.txt”, uSDstr); appendFile(SD,
“/dl1.txt”, “/”);
intToChar(Day, uSDstr, sizeof(uSDstr));
appendFile(SD, “/dl1.txt”, uSDstr); appendFile(SD, “/dl1.txt”,
“;”);
///Grava temperatura 1 e 2 intToChar(temp, uSDstr, sizeof(uSDstr));
appendFile(SD, “/dl1.txt”, uSDstr); intToChar(TEMP, uSDstr,
sizeof(uSDstr));
appendFile(SD, “/dl1.txt”, “;”);
///Grava Micrifone e Nivel CO2
intToChar(ADC, uSDstr, sizeof(uSDstr)); appendFile(SD,
“/dl1.txt”, uSDstr);
appendFile(SD, “/dl1.txt”, “;”);
intToChar(ECO2, uSDstr, sizeof(uSDstr)); appendFile(SD, “/dl1.txt”, uSDstr);
appendFile(SD, “/dl1.txt”, “;”);
///Grava ATM, Gases organicos, umidade
intToChar(pres, uSDstr, sizeof(uSDstr)); appendFile(SD, “/dl1.txt”,
uSDstr);
appendFile(SD, “/dl1.txt”, “;”); intToChar(TVOC, uSDstr,
sizeof(uSDstr));
appendFile(SD, “/dl1.txt”, uSDstr); appendFile(SD,
“/dl1.txt”, “;”);
intToChar(humi, uSDstr, sizeof(uSDstr));
appendFile(SD, “/dl1.txt”, uSDstr); appendFile(SD, “/dl1.txt”,
“;”);
///Grava X Y Z
intToChar(acellX, uSDstr, sizeof(uSDstr));
appendFile(SD, “/dl1.txt”, uSDstr); appendFile(SD, “/dl1.txt”,
“;”);
intToChar(acellY, uSDstr, sizeof(uSDstr)); appendFile(SD,
“/dl1.txt”, uSDstr);
appendFile(SD, “/dl1.txt”, “;”);
intToChar(acellZ, uSDstr, sizeof(uSDstr)); appendFile(SD, “/dl1.txt”, uSDstr);
appendFile(SD, “/dl1.txt”, “;”); appendFile(SD,
“/dl1.txt”, “\n”);
}
}
void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
Serial.printf(“Listing directory: %s\n”, dirname);
File root = fs.open(dirname); if (!root) {
Serial.println(“Failed to open directory”);
return;
}
if (!root.isDirectory()) {
Serial.println(“Not a directory”);
return;
}
File file = root.openNextFile(); while (file) {
if (file.isDirectory()) { Serial.print(“ DIR : “);
Serial.println(file.name()); if (levels) {
listDir(fs, file.name(), levels -
1);
}
} else {
Serial.print(“ FILE: “);
Serial.print(file.name()); Serial.print(“ SIZE: “);
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void
createDir(fs::FS &fs, const char * path) { Serial.printf(“Creating Dir: %s\n”,
path);
if (fs.mkdir(path)) { Serial.println(“Dir created”);
} else {
Serial.println(“mkdir failed”);
}
}
void removeDir(fs::FS &fs, const char
* path) {
Serial.printf(“Removing Dir: %s\n”, path); if (fs.rmdir(path)) {
Serial.println(“Dir removed”);
} else {
Serial.println(“rmdir failed”);
}
}
void readFile(fs::FS &fs, const char * path) { Serial.printf(“Reading file: %s\n”, path);
File file = fs.open(path); if
(!file) {
Serial.println(“Failed to open file for reading”); return;
}
Serial.print(“Read from file: “); while (file.available()) {
Serial.write(file.read());
}
file.close();
}
void writeFile(fs::FS &fs, const char * path, const char * message) {
Serial.printf(“Writing file: %s\n”, path);
File file = fs.open(path, FILE_WRITE); if (!file) {
Serial.println(“Failed to open file for writing”); return;
}
if (file.print(message)) {
Serial.println(“File written”);
} else {
Serial.println(“Write failed”);
}
file.close();
}
void appendFile(fs::FS
&fs, const char * path, const char * message) { Serial.printf(“Appending to file:
%s\n”, path);
File file = fs.open(path, FILE_APPEND); if (!file) {
Serial.println(“Failed to open file for appending”); return;
}
if (file.print(message)) {
Serial.println(“Message appended”);
} else {
Serial.println(“Append failed”);
}
file.close();
}
void renameFile(fs::FS
&fs, const char * path1, const char * path2) { Serial.printf(“Renaming file %s to
%s\n”, path1, path2);
if (fs.rename(path1, path2)) {
Serial.println(“File renamed”);
} else {
Serial.println(“Rename failed”);
}
}
void
deleteFile(fs::FS &fs, const char * path) { Serial.printf(“Deleting file:
%s\n”, path);
if (fs.remove(path)) { Serial.println(“File deleted”);
} else {
Serial.println(“Delete failed”);
}
}
void testFileIO(fs::FS &fs, const char * path) {
File file = fs.open(path); static uint8_t buf[512];
size_t len = 0;
uint32_t start = millis(); uint32_t end = start;
if (file) { len
= file.size();
size_t flen = len; start = millis(); while (len) {
size_t toRead = len;
if (toRead > 512) { toRead = 512;
}
file.read(buf, toRead); len -= toRead;
}
end = millis() - start;
Serial.printf(“%u bytes read for %u ms\n”, flen, end); file.close();
} else
{
Serial.println(“Failed to open file for reading”);
}
file =
fs.open(path, FILE_WRITE); if (!file) {
Serial.println(“Failed to open file for writing”);
return;
}
size_t i;
start = millis();
for (i = 0; i < 2048; i++) {
file.write(buf, 512);
}
end = millis() - start;
Serial.printf(“%u
bytes written for %u ms\n”, 2048 * 512, end); file.close();
}