#include <Seeed_FS.h>
#include "TFT_eSPI.h"
#include <SPI.h>
#include <SD/Seeed_SD.h>
#include <Wire.h>
#include "SparkFun_SCD30_Arduino_Library.h"
#include <RawImage.h>
#include <SoftwareSerial.h>
#include <TinyGPS++.h>
//We define the class types for the different sensors we will be employing throughout the programme (gps, and light and gas sensors)
SCD30 airSensor;
TinyGPSPlus gps;
//We also define the class types for the display of objects in the screen
TFT_eSPI tft;
//We indicate the pins for the GPS device
SoftwareSerial mySerial(2, 3);
//Here we define the variables employed in the code
double dist_LAT = 34.9722899, dist_LONG = 138.3868869;
String p_hour, p_lat, p_lng, p_alt, p_sat, p_date;
String p_my_speed, p_my_course, p_dist_dTo, p_dist_cTo;
String pdist_LAT, pdist_LONG;
String sdist_LAT = String(dist_LAT);
String sdist_LONG = String(dist_LONG);
String Date[10], Dat;
int menu = 1;
byte RX1;
uint8_t Cut = 78;
char buffer[64], Data [64], Message; // buffer array for data receive over serial port
int count=0; // counter for buffer array
double Val1, Val2;
int count3 = 0;
int y, Latc, Lonc, i, j, Lat[10], val1, val2, val3, s, p, z, tUV, tlux;
float tTemp, tHum, tCO2, Buff;
uint8_t val[2];
double LatLim1, LatLim2, LonLim1, LonLim2;
String N_Stemp, p_Temp, p_Stemp, N_mois, N_EC, N_CO2, N_Hum, N_Temp, p_STemp, p_mois, p_EC, p_CO2, p_Hum;
int Log_f = 0;
String N_date, hour0;
unsigned long p_time;
int N_y, N_m, N_d;
String hr1, min1, sec1;
String F_name, N_Mois, p_Mois, nhour0[5];
bool sd;
float tEC, tMois, tStemp;
int l, Lng[10];
String N_lux, N_UV, p_lux, p_UV;
int Num = 0;
int k = 1;
float lux[10], Temp[10], Hum[10], CO2[10], Stemp[10], EC[10], Mois[10], UV[10];
String Longitude[10], Latitude[10], Alt[10], Sat[10];
static const int MAX_SATELLITES = 40;
float uUV, ulux, uCO2, uSTemp, uHum, uTemp, uEC, uMois;
//We will initialise the custom types from the TinyGPS++ library, to determinethe position, elevation, and number of satellites
TinyGPSCustom ExtLat(gps, "GPGGA", 3);
TinyGPSCustom ExtLng(gps, "GPGGA", 5);
TinyGPSCustom totalGPGSVMessages(gps, "GPGSV", 1);
TinyGPSCustom messageNumber(gps, "GPGSV", 2);
TinyGPSCustom satsInView(gps, "GPGSV", 3);
TinyGPSCustom satNumber[4]; // to be initialized later
TinyGPSCustom elevation[4];
TinyGPSCustom azimuth[4];
TinyGPSCustom snr[4];
//Define the addresses of the soil probe device for the determination of Temperature, conductivity and moisture
const byte Addr[] = {0x01, 0x04, 0x00, 0x00, 0x00, 0x03, 0xB0, 0x0B};
struct
{
bool active;
int elevation;
int azimuth;
int snr;
int dsp;
} sats[MAX_SATELLITES];
volatile uint32_t newlines = 0UL;
static void handleRxChar( uint8_t c )
{
if (c == '\n')
newlines++;
}
void setup() {
mySerial.begin(9600);
tft.begin();
tft.setRotation(3);
//This command initialises the SD device included in the Wio terminal
if (!SD.begin(SDCARD_SS_PIN, SDCARD_SPI)) {
sd = false;
}
else {
SerialUSB.println("initialization done.");
//First, we need to initialise the devices that will be used on this project, and the Serial communications
Wire.begin();
airSensor.begin();
Serial.begin(9600);
sd = true;
}
for (int i=0; i<4; ++i)
{
satNumber[i].begin(gps, "GPGSV", 4 + 4 * i); // offsets 4, 8, 12, 16
elevation[i].begin(gps, "GPGSV", 5 + 4 * i); // offsets 5, 9, 13, 17
azimuth[i].begin(gps, "GPGSV", 6 + 4 * i); // offsets 6, 10, 14, 18
snr[i].begin(gps, "GPGSV", 7 + 4 * i); // offsets 7, 11, 15, 19
}
//We set the initial values for some of the variables employed throughout the loop
p = 0;
j = 0;
p = 0;
s = 1;
Num = 0;
count = 0;
//These variables indicate the minimum and maximum values of latitude and longitude on the displayed map
LatLim1 = 50;
LatLim2 = 55;
LonLim1 = 50;
LonLim2 = 60;
//These commands set the pin used on the programme, for the measurement of UV light intensity as input pins
pinMode (A7, INPUT);
pinMode (A4, INPUT);
pinMode (A6, INPUT);
//These commands initialise the push buttons in the Wio Terminal
pinMode(WIO_5S_PRESS, INPUT_PULLUP);
pinMode(WIO_KEY_A, INPUT_PULLUP);
pinMode(WIO_KEY_B, INPUT_PULLUP);
pinMode(WIO_KEY_C, INPUT_PULLUP);
pinMode(WIO_5S_LEFT, INPUT_PULLUP);
pinMode(WIO_5S_RIGHT, INPUT_PULLUP);
}
void loop() {
//These commands take the measurements from the SCD30 sensor
if (airSensor.dataAvailable())
{
tTemp = airSensor.getTemperature();
tHum = airSensor.getHumidity();
tCO2 = airSensor.getCO2();
}
//Since the UV sensor has an analog output, we read the signals form the pins where it has been connected
for (i=0; i<10; i++){
tUV = tUV + analogRead (A7);
}
tUV = tUV/10;
//We convert the environmental measurements to string variables by using the following command
//These will be the variables displayed on the screen
N_UV = String(tUV);
N_Temp = String(tTemp);
N_Hum = String(tHum);
N_CO2 = String(tCO2);
long N_mjd;
//Command to save the data from the sensors and the GPS to a SD card. This function will be executed every 6s
while (mySerial.available() > 0) {
char c = mySerial.read();
gps.encode(c);
}
//calculate the latitude and longitude values, and transform it to a string for the display
double lat0 = gps.location.lat();
double lat1 = (lat0 -int(lat0))*60;
double lat2 = (lat1 - int(lat1))*60;
String lat3 = String(int(lat0))+':' + String(int(lat1))+':'+String(lat2) + ' ' + String(ExtLat.value());
double lng0 = gps.location.lng();
double lng1 = (lng0 -int(lng0))*60;
double lng2 = (lng1 - int(lng1))*60;
String lng3 = String(int(lng0))+':' + String(int(lng1))+':'+String(lng2) + ' ' + String(ExtLng.value());
//calculate the time and transform it to a string for the display
int hr = gps.time.hour()+9;
if (hr>24) hr -= 24;
String hr0 = '0'+String(hr);
hr1 = hr0.substring(hr0.length()-2);
String min0 = '0'+String(gps.time.minute());
min1 = min0.substring(min0.length()-2);
String sec0 = '0'+String(gps.time.second());
sec1 = sec0.substring(sec0.length()-2);
hour0 = hr1+':'+min1+':'+sec1;
//Calculate date and transform it to a string for the display
if (gps.date.isUpdated()) {
int y = gps.date.year();
int m = gps.date.month();
int d = gps.date.day();
if(m<3){y--; m+=12;}
long mjd = int(361.7015*y)+int(y/400)-int(y/100)+int(30.59*(m-2))+d-678912;
if(gps.time.hour()>14)
N_mjd = 58580+(mjd-51412);
else
N_mjd = 58579+(mjd-51412);
long n = N_mjd+678881;
long a = 4*n+3+3*(4*(n+1)/146097+1);
long b = 5*((a % 1461)/4)+2;
N_y = int(a/1461);
N_m = int(b/153+3);
N_d = int((b % 153)/5+1);
if (N_m>12){N_y++; N_m-=12;}
N_date = String(N_y)+'/'+('0'+String(N_m)).substring(('0'+String(N_m)).length()-2)+'/'+('0'+String(N_d)).substring(('0'+String(N_d)).length()-2);
}
//When the user presses the pushbutton on the Wio terminal, the RS485 communications are triggered for the soil measurements
//The location where the measurements have been taken is also fixed and displayed on the Wio terminal screen
if (digitalRead(WIO_5S_PRESS) == LOW) {
//The Soil measurements will only take place if the Wio terminal is on the data display mode
if (menu ==1){
//This code saves the current position at the moment of initialising the measurement, for display in the lcd screen
lng0 = lng0*100;
Lng [p] = map(lng0, LonLim1, LonLim2, 0, 240);
Lat [p] = map (lat0, LatLim1, LatLim2, 0, 320);
lng0 = lng0/100;
//We perform the soil temperature and moisture measurements
for (i=0;i<10;i++){
tStemp = tStemp + analogRead (A4);
tMois = tMois + analogRead (A6);
}
tStemp = tStemp/10;
tStemp = tStemp*(-0.0826) + 108.65;
tMois = tMois/10;
tMois = tMois*5/1024;
N_Stemp = String (tStemp);
N_Mois = String (tMois);
Date[p] = N_date;
nhour0[p] = hour0;
Alt[p] = String(gps.altitude.meters());
Sat[p] = String(gps.satellites.value());
Temp[p] = tTemp;
Hum[p] = tHum;
CO2[p] = tCO2;
UV[p] = tUV;
Stemp[p] = tStemp;
Mois[p] = tMois;
Latitude[p] = lat3;
Longitude[p] = lng3;
//These lines determine the number of points that will be displayed on the map screen
p++;
count++;
if (p>10){
p = 0;
count = 10;
}
//The value of s determines the first time that the titles of the measurements are displayed on the Wio Terminal screen
s = 1;
}
}
//This condition will show the value of the measurements
if (menu == 1){
//The first time that the menu is displayed, we need to initialise the screen colour and the measurement titles
if (s==1){
tft.fillScreen (TFT_BLACK);
tft.setTextSize(3);
tft.drawString("GPS",50,3);
tft.drawString("SCD30",30,150);
tft.drawString("Soil",200,3);
tft.drawString("Light",200,150);
tft.setTextSize(1);
tft.drawString("Date",20,33);
tft.drawString("Time",20,53);
tft.drawString("LAT",20,70);
tft.drawString("LONG",20,87);
tft.drawString("ALT (m)",20,107);
tft.drawString("Satellites",20,127);
tft.drawString("Temp (oC)",20,180);
tft.drawString("Hum (%)",20,200);
tft.drawString("CO2 (ppm)",20,220);
tft.drawString("Temp (oC)",180,33);
tft.drawString("Moisture (V)",180,53);
tft.drawString("UV ",180,180);
}
if (N_date != p_date || s == 1) { //Displays the date
tft.fillRect(50,33,70,20,TFT_BLACK);
tft.drawString(N_date,50,33);
p_date = N_date;
}
if (hour0 != p_hour || s == 1) { //Displays the time
tft.fillRect(50,53,100,16,TFT_BLACK);
tft.drawString(hour0,50,53);
p_hour = hour0;
}
if (lat3 != p_lat || s == 1) { //Displays the latitude
tft.fillRect(50,70,110,10,TFT_BLACK);
tft.drawString(lat3,50,70);
p_lat = lat3;
}
if (lng3 != p_lng || s == 1) { //Displays the longitude
tft.fillRect(50,90,87,10,TFT_BLACK);
tft.drawString(lng3,50,90);
p_lng = lng3;
}
if (String(gps.altitude.meters()) != p_alt || s == 1) { //Displays the altitude
tft.fillRect(70,107,107,10,TFT_BLACK);
tft.drawString(String(gps.altitude.meters()),70,107);
p_alt = String(gps.altitude.meters());
}
if (String(gps.satellites.value()) != p_sat || s == 1) { //Displays the number of satellites
tft.fillRect(90,127,110,10, TFT_BLACK);
tft.drawString(String(gps.satellites.value()),90,127);
p_sat = String(gps.satellites.value());
}
tft.fillRect(0,140,320,2,TFT_YELLOW);
tft.fillRect(160,0,2,240,TFT_YELLOW);
if (N_Temp != p_Temp || s == 1){ //Displays the environmental temperature
tft.fillRect(80,180,32,16,TFT_BLACK);
tft.drawString(N_Temp, 80, 180);
p_Temp = N_Temp;
}
if (N_Hum != p_Hum || s == 1){ //Displays the air humidity
tft.fillRect(90,200,32,16,TFT_BLACK);
tft.drawString(N_Hum, 80, 200);
p_Hum = N_Hum;
}
if (N_CO2 != p_CO2 || s == 1){ //Displays the concentration of CO2
tft.fillRect(80,220,32,16,TFT_BLACK);
tft.drawString(N_CO2, 80, 220);
p_CO2 = N_CO2;
}
if (N_Stemp != p_Stemp || s == 1){ //Displays the temperature in soil
tft.fillRect(240,33,32,16,TFT_BLACK);
tft.drawString(N_Stemp, 240, 33);
p_Stemp = N_Stemp;
}
if (N_Mois != p_Mois || s == 1){ //Displays the volumetric soil water content
tft.fillRect(270,53,32,16,TFT_BLACK);
tft.drawString(N_Mois, 260, 53);
p_Mois = N_Mois;
}
if (N_UV != p_UV || s == 1){ //Displays the intensity from the UV sensor
tft.fillRect(200,180,80,16,TFT_BLACK);
tft.drawString(N_UV, 200, 180);
p_UV = N_UV;
}
s = 0;
}
if (menu == 2){
if (digitalRead(WIO_5S_RIGHT) == LOW) {
Num = Num + 1;
l = 1;
}
if (digitalRead(WIO_5S_LEFT) == LOW) {
Num = Num - 1;
l = 1;
}
if (Num<0){
Num = count;
}
if (Num>count-1){
Num = 0;
}
Dat = String(Num);
if (l == 1){
tft.fillScreen (TFT_BLACK);
tft.setTextSize(3);
tft.drawString("GPS",50,3);
tft.drawString("SCD30",30,150);
tft.drawString("Soil",170,3);
tft.drawString("Light",200,150);
tft.setTextColor(TFT_YELLOW);
tft.drawString("Sample",170,210);
tft.drawString(Dat,285,210);
tft.setTextColor(TFT_WHITE);
tft.setTextSize(1);
tft.drawString("Date",20,33);
tft.drawString("Time",20,53);
tft.drawString("LAT",20,70);
tft.drawString("LONG",20,87);
tft.drawString("ALT (m)",20,107);
tft.drawString("Satellites",20,127);
tft.drawString("Temp (oC)",20,180);
tft.drawString("Hum (%)",20,200);
tft.drawString("CO2 (ppm)",20,220);
tft.drawString("Temp (oC)",180,33);
tft.drawString("Moisture (%)",180,53);
tft.drawString("UV: ",180,180);
tft.fillRect(0,140,320,2,TFT_YELLOW);
tft.fillRect(160,0,2,240,TFT_YELLOW);
Dat = String (Date[Num]);
//Date
tft.drawString(Dat,50,33);
Dat = String (nhour0[Num]);
tft.drawString(Dat,50,53);
p_hour = hour0;
Dat = String (Latitude[Num]);
tft.drawString(Dat,50,70);
Dat = String (Longitude[Num]);
tft.drawString(Dat,50,90);
Dat = Alt[Num];
tft.drawString(Dat,70,107);
Dat = Sat[Num];
tft.drawString(Dat,90,127);
Dat = String(Temp[Num]);
tft.drawString(Dat, 80, 180);
Dat = String(Hum[Num]);
tft.drawString(Dat, 50, 200);
Dat = String(CO2[Num]);
tft.drawString(Dat, 80, 220);
Dat = String(Stemp[Num]);
tft.drawString(Dat, 240, 33);
Dat = String(Mois[Num]);
tft.drawString(Dat, 260, 53);
Dat = String(UV [Num]);
tft.drawString(Dat, 240, 180);
}
l = 0;
}
//We initialise the map display, to see our current position and the places where measurements have been taken
if (menu == 3){
delay (100);
if (k==1){
//Command to display the map, stored in the SD card memory
drawImage<uint16_t>("map.bmp", 0, 0);
//This function takes the coordinates,and the maximum coordinates indicated by the user to map them and show them on the screen
lng0 = lng0*100;
Latc = map (lat0, LatLim1, LatLim2, 0, 320);
Lonc = map (lng0, LonLim1, LonLim2, 0, 240);
lng0 = lng0/100;
if (l==1){
//We draw a green circle at the current position
tft.fillCircle(Latc, Lonc, 4, TFT_RED);
}
if (l==0){
//We draw a green circle at a past position (only if we are on menu 2)
tft.fillCircle(Lat[Num], Lng[Num], 4, TFT_BLUE);
}
delay (100);
}
k = 0;
}
//This codes are used to detect the input from the push buttons and change between the menus
if (digitalRead(WIO_KEY_C) == LOW) {
menu = 1;
l = 1;
s = 1;
k = 1;
}
else if (digitalRead(WIO_KEY_B) == LOW) {
menu = 2;
s = 1;
l = 1;
k = 1;
}
else if (digitalRead(WIO_KEY_A) == LOW) {
menu = 3;
s = 1;
k = 1;
}
delay (100);
}
Comments