#include <Arduino.
h>
#include <EEPROM.h>
#include <HX711_ADC.h>
#include <MARCH_BTS7960.h>
#include <MARCH_Button.h>
#include <MARCH_Indicator.h>
#include <MARCH_LCD_I2C.h>
#define BUTTON 13
#define EN 11
#define LPWM 10
#define RPWM 9
#define SCK 5
#define DOUT 4
#define BUZZER 2
#define SENSOR A0
#define MAIN 0x00
#define SAMPLE 0x01
#define START 0x02
#define EXTRACT 0x03
#define STOP 0x04
#define CLICK1X 0
#define CLICK2X 1
#define ADDR 0x00
#define INTERVAL 1000
#define STABILIZE 2000
#define EXTRACTED (analogRead(SENSOR) > 0x3AF)
HX711_ADC loadcell(DOUT, SCK);
MARCH_BTS7960 hydraulic(EN, RPWM, LPWM);
MARCH_Button button(BUTTON);
MARCH_Indicator buzzer(BUZZER);
MARCH_LCD_I2C lcd(0x27, 16, 2);
int menu = 0;
int lastExtract = HIGH;
bool click = false;
bool doubleClick = false;
bool startBack = false;
bool started1 = false;
bool started2 = false;
unsigned long last;
unsigned long startMillis;
unsigned long lastMillis;
byte click1x[] = {
B00101,
B00010,
B00101,
B11000,
B01000,
B01000,
B01000,
B11100
};
byte click2x[] = {
B00101,
B00010,
B00101,
B11100,
B00100,
B01000,
B10000,
B11100
};
void initialize(void);
void mainDisplay(void);
void sampleDisplay(void);
void startDisplay(void);
void extractDisplay(void);
void stopDisplay(void);
void forceDisplay(void);
void errorDisplay(void);
void printPressure(void);
void turnBackHydraulic(bool);
void clickedCb(void);
void doubleClickedCb(void);
void longClickedCb(void);
bool clicked(void);
bool doubleClicked(void);
void setup() {
Serial.begin(9600);
float calibration;
EEPROM.get(ADDR, calibration);
button.attachClick(clickedCb);
button.attachDoubleClick(doubleClickedCb);
button.attachLongPressStart(longClickedCb);
button.setPressMs(2000);
pinMode(SENSOR, INPUT);
lcd.init();
lcd.backlight();
lcd.createChar(CLICK1X, click1x);
lcd.createChar(CLICK2X, click2x);
loadcell.begin();
loadcell.start(STABILIZE, true);
if (loadcell.getTareTimeoutFlag()) {
errorDisplay();
while(1);
} else loadcell.setCalFactor(calibration);
hydraulic.enable();
hydraulic.forceTurnLeft(255);
initialize();
void loop() {
button.tick();
switch (menu) {
case MAIN:
if (clicked()) {
sampleDisplay();
menu = SAMPLE;
break;
case SAMPLE:
if (clicked()) {
startDisplay();
menu = START;
} else if (doubleClicked()) {
mainDisplay();
menu = MAIN;
}
break;
case START:
if (clicked()) {
buzzer.on();
extractDisplay();
loadcell.tare();
} else if (doubleClicked()) {
sampleDisplay();
menu = SAMPLE;
if (loadcell.getTareStatus()) {
buzzer.off();
hydraulic.enable();
hydraulic.forceTurnRight(127);
menu = EXTRACT;
break;
case EXTRACT:
printPressure();
bool extracted = EXTRACTED;
if (extracted && !started1 && !started2) {
started1 = true;
delay(1000);
} else if (!extracted && started1 && !started2) {
started2 = true;
delay(1000);
} else if (extracted && started1 && started2) {
stopDisplay();
hydraulic.enable();
hydraulic.forceChangeRotation(LEFT);
hydraulic.forceChangePWM(255);
buzzer.on();
delay(3000);
buzzer.off();
started1 = false;
started2 = false;
startBack = true;
startMillis = millis();
menu = STOP;
break;
case STOP:
mainDisplay();
menu = MAIN;
break;
turnBackHydraulic(startBack);
}
void initialize() {
lcd.clear();
lcd.printCenter("WELCOME", 0);
hydraulic.enable();
hydraulic.forceTurnLeft(255);
delay(3000);
lcd.clear();
lcd.printCenter("BLOOD PLASMA", 0);
lcd.printCenter("EXTRACTOR", 1);
delay(3000);
lcd.clear();
lcd.printCenter("DEWI SARTIKA", 0);
lcd.printCenter("P320013", 1);
delay(3000);
hydraulic.forceTurnLeft(255);
hydraulic.disable();
mainDisplay();
void mainDisplay() {
lcd.clear();
lcd.printCenter("PLASMA EXTRACTOR", 0);
lcd.printCenter("CLICK TO START->", 1);
void sampleDisplay() {
lcd.clear();
lcd.printCenter("Put the sample!", 0);
lcd.setCursor(0, 1);
lcd.print("Back");
lcd.write(CLICK2X);
lcd.setCursor(11, 1);
lcd.write(CLICK1X);
lcd.print("Next");
void startDisplay() {
lcd.clear();
lcd.printCenter("Start Extraction?", 0);
lcd.setCursor(0, 1);
lcd.print("Back");
lcd.write(CLICK2X);
lcd.setCursor(10, 1);
lcd.write(CLICK1X);
lcd.print("START");
void extractDisplay() {
lcd.clear();
lcd.printCenter("EXTRACTING", 0);
}
void stopDisplay() {
lcd.clear();
lcd.printCenter("DONE!", 0);
void forceDisplay() {
lcd.clear();
lcd.printCenter("FORCIBLY", 0);
lcd.printCenter("TERMINATED", 1);
void errorDisplay() {
lcd.clear();
lcd.printCenter("LOADCELL ERROR!", 0);
void printPressure() {
static boolean newData = false;
if (loadcell.update()) newData = true;
if (newData) {
if (millis() - lastMillis >= INTERVAL) {
double pressure = loadcell.getData();
lcd.clearRow(1);
lcd.printCenter(String((abs(pressure) / 1000), 2) + " kg", 1);
Serial.println(pressure);
newData = false;
lastMillis = millis();
}
void turnBackHydraulic(bool start) {
if (start) {
if ((millis() - startMillis) >= 3000) {
hydraulic.forceStop();
hydraulic.disable();
startBack = false;
startMillis = millis();
void clickedCb() {
if (menu != EXTRACT) {
buzzer.start(BIP);
click = true;
void doubleClickedCb() {
if (menu != MAIN) {
buzzer.start(BIP2x);
doubleClick = true;
}
void longClickedCb() {
if (menu == EXTRACT) {
forceDisplay();
hydraulic.enable();
hydraulic.forceChangeRotation(LEFT);
hydraulic.forceChangePWM(255);
buzzer.on();
delay(3000);
buzzer.off();
started1 = false;
started2 = false;
startBack = true;
startMillis = millis();
menu = STOP;
bool clicked() {
if (click) {
click = false;
return true;
return false;
bool doubleClicked() {
if (doubleClick) {
doubleClick = false;
return true;
return false;