/*
v2.02
Tipe Data Rerata: Float
4 Tahap: Awal, Pembacaan, Berhenti, Klasifikasi
*/
#include <EEPROM.h>
//#include "GravityTDS.h" // non-simulatable part
//GravityTDS sensorTDS; // non-simulatable part
#include <LiquidCrystal_I2C.h> // library untuk kontrol LCD I2C
LiquidCrystal_I2C lcd(0x27, 16, 2); // instansiasi objek LCD pada alamat 0x27 dengan ukuran 16x2
/* -------- PENDEFINISIAN KONSTANTA & VARIABEL -------- */
#define PIN_SENSOR_PH A0
#define PIN_SENSOR_TURBIDITY A1
#define PIN_SENSOR_TDS A2
#define PIN_SAKLAR_SENTUH 2 // D2
#define SAKLAR_TIDAK_DISENTUH 0
#define SAKLAR_DISENTUH 1
#define TAHAP_AWAL -1
#define TAHAP_PEMBACAAN_SENSOR_MULAI 0
#define TAHAP_PEMBACAAN_SENSOR_BERHENTI 1
#define TAHAP_KLASIFIKASI_SVM 2
#define JUMLAH_TAHAP_SISTEM 3
bool kondisiSaklarSentuh;
bool kondisiSaklarSentuhSebelumnya = SAKLAR_TIDAK_DISENTUH;
int tahapSistem = TAHAP_AWAL;
bool hasilKlasifikasi;
const String kelasStr[2] = {"Buruk", "Baik"};
/* ------------ KONFIGURASI SISTEM ------------ */
#define DURASI_TAMPILAN_JUDUL_TAHAP 1200 // ms
#define PERIODE_PEMBACAAN_PH 10
#define SUHU_KOMPENSASI_TDS 25
/* ------------ PENDEFINISIAN STRUKTUR DATA ------------ */
struct DataSensor {
float ph, v_turbidity, tds;
} dataSensor;
class Rerata {
private:
float *buffer = nullptr;
byte periode, ringIndeks;
bool penuh;
float jumlah;
public:
float rerata;
Rerata(byte periodeRerata){ // Constructor
periode = periodeRerata;
buffer = new float[periodeRerata]();
}
float insert(float dataBaru){
float dataLama = buffer[ringIndeks];
buffer[ringIndeks] = dataBaru;
jumlah = jumlah + dataBaru - dataLama;
ringIndeks++;
penuh = penuh || (ringIndeks>=periode);
rerata = (penuh) ? jumlah/periode: jumlah/ringIndeks;
ringIndeks %= periode;
return rerata;
}
void reset(){
for(byte i=0; i<periode; i++){ buffer[i] = 0; }
ringIndeks = jumlah = rerata = 0;
}
};
Rerata rerata_ph(PERIODE_PEMBACAAN_PH);
/* ------------------- PENDUKUNG ------------------- */
void tampilkan_judul_tahap_lcd(){
lcd.clear();
lcd.home();
if(tahapSistem == TAHAP_PEMBACAAN_SENSOR_MULAI){
lcd.print(F("Pembacaan Sensor"));
lcd.setCursor(0,1); lcd.print(F(" Dimulai"));
} else if(tahapSistem == TAHAP_PEMBACAAN_SENSOR_BERHENTI){
lcd.print(F("Pembacaan Sensor"));
lcd.setCursor(0,1); lcd.print(F(" Dihentikan"));
} else if(tahapSistem == TAHAP_KLASIFIKASI_SVM){
lcd.print(F(" Klasifikasi"));
lcd.setCursor(0,1); lcd.print(F(" SVM"));
}
delay(DURASI_TAMPILAN_JUDUL_TAHAP);
lcd.clear();
}
void tampilkan_header_lcd(){
lcd.home();
if(tahapSistem == TAHAP_AWAL){
lcd.println(F(" Sistem Siap"));
} else if(tahapSistem == TAHAP_KLASIFIKASI_SVM){
lcd.println(F("Hsl klasifikasi:"));
} else {
lcd.print(F("pH: T: "));
lcd.setCursor(0, 1); lcd.print(F(" TDS: "));
}
}
void tampilkan_data_sensor_lcd(){
lcd.setCursor(3, 0); lcd.print(dataSensor.ph, 2); lcd.print(F(" "));
lcd.setCursor(11, 0); lcd.print(dataSensor.v_turbidity, 2); lcd.print(F("v"));
lcd.setCursor(7, 1); lcd.print(dataSensor.tds, 0); lcd.print(F("ppm "));
}
void tampilkan_hasil_klasifikasi_lcd(){
lcd.setCursor(6,1); lcd.print(kelasStr[hasilKlasifikasi]);
}
/* --- FOR SIMULATION ONLY --- */
float noise(int range, float multiplier){
int acakan = random(0, range);
float ret = ((acakan)/2)*multiplier;
return ret;
}
/* ------------------- UTAMA ------------------- */
void pembacaan_sensor(){
/* non-simulatable part
// 1. Pembacaan Sensor pH
rerata_adc_ph.insert(analogRead(PIN_SENSOR_PH));
dataSensor.ph = (rerata_adc_ph.rerata-282.41)/14.901;
// 2. Pembacaan Sensor Turbidity
int adc_turbidity = analogRead(PIN_SENSOR_TURBIDITY);
dataSensor.v_turbidity = adc_turbidity*(5.0/1024.0);
// 3. Pembacaan Sensor TDS
sensorTDS.update(); // sample and calculate
dataSensor.tds = sensorTDS.getTdsValue(); // then get the value
*/
/* WIP */
bool cond = true; // simulation-only
cond = false; // simulation-only
if(cond){ // normal
int adc_sensor_ph = 387; // from analogRead()
float ph = ((adc_sensor_ph-282.41)/14.901)+noise(40, 0.01);
dataSensor.ph = rerata_ph.insert(ph);
//dataSensor.ph = 7.02 + noise(6, 0.01);
dataSensor.v_turbidity = 4.1 + noise(6, 0.01);
dataSensor.tds = 50 + noise(3, 1);
hasilKlasifikasi = true; // to be removed, use klasifikasi_svm() instead
} else { // abnormal
int adc_sensor_ph = 403; // from analogRead()
float ph = ((adc_sensor_ph-282.41)/14.901)+noise(40, 0.01);
dataSensor.ph = rerata_ph.insert(ph);
Serial.print(ph);
Serial.print(" ");
Serial.println(dataSensor.ph);
//rerata_adc_ph.insert(403 + noise(6, 1));
//dataSensor.ph = (rerata_adc_ph.rerata-282.41)/14.901;
//dataSensor.ph = 8.10 + noise(6, 0.01);
dataSensor.v_turbidity = 4.1 + noise(6, 0.01);
dataSensor.tds = 120 + noise(5, 1);
hasilKlasifikasi = false; // to be removed, use klasifikasi_svm() instead
}
}
void klasifikasi_svm(){
/* not implemented yet */
//hasilKlasifikasi = false;
}
/*------------------- PROSEDUR ARDUINO ------------------- */
void setup() {
Serial.begin(9600);
pinMode(PIN_SENSOR_PH, INPUT);
pinMode(PIN_SENSOR_TURBIDITY, INPUT);
pinMode(PIN_SENSOR_TDS, INPUT);
pinMode(PIN_SAKLAR_SENTUH, INPUT);
// Inisialisasi LCD
lcd.init();
lcd.clear();
lcd.backlight();
tampilkan_header_lcd();
/* Inisialisasi Sensor TDS */
/* non-simulatable part
sensorTDS.setPin(PIN_SENSOR_TDS);
sensorTDS.setAref(5.0); // reference voltage on ADC, default 5.0V on Arduino UNO
sensorTDS.setAdcRange(1024); // 1024 for 10bit ADC;4096 for 12bit ADC
sensorTDS.begin(); // initialization
sensorTDS.setTemperature(SUHU_KOMPENSASI_TDS);
*/
}
void loop() {
// 1. Pembacaan Kondisi Saklar Sentuh
bool kondisiSaklarSentuh = digitalRead(PIN_SAKLAR_SENTUH);
// 2. Pergantian Tahap Apabila Saklar Baru Disentuh
if(!kondisiSaklarSentuhSebelumnya && kondisiSaklarSentuh){ // baru disentuh
tahapSistem = ((tahapSistem+1)%JUMLAH_TAHAP_SISTEM); // pergantian tahap
tampilkan_judul_tahap_lcd(); // tampilkan judul tahap sebentar
tampilkan_header_lcd();
}
// 3. Eksekusi Tahapan Sistem
if(tahapSistem == TAHAP_PEMBACAAN_SENSOR_MULAI){
pembacaan_sensor();
tampilkan_data_sensor_lcd();
} else if(tahapSistem == TAHAP_PEMBACAAN_SENSOR_BERHENTI){
tampilkan_data_sensor_lcd();
} else if(tahapSistem == TAHAP_KLASIFIKASI_SVM){
klasifikasi_svm();
tampilkan_hasil_klasifikasi_lcd();
}
// 4. Outro
kondisiSaklarSentuhSebelumnya = kondisiSaklarSentuh;
delay(150);
}