/*
Project: Aquarium Oscillating Pump
Description: Controls an oscillating pump, select from:
4 ranges of sweep
5 speeds of sweep
6 propeller speeds
Creation date: 9/10/23
Author: Icesythe7 (Team AF) / AnonEngineering /ShepardHA
https://discord.com/channels/420594746990526466/863150029182206002/1150144053208424498
License: Beerware
*/
#include <Servo.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C // See datasheet for Address; 0x3C for Wokwi 128x64
Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// pin constants
const uint8_t BTN_P_SPEED = 4;
const uint8_t BTN_S_SPEED = 10;
const uint8_t BTN_S_RANGE = 11;
const uint8_t PUMP_PIN = 6;
const uint8_t SERVO_PIN = 12;
// range / speed constants
const uint8_t P_SPD_MODES = 6;
const uint8_t S_SPD_MODES = 8;
const uint8_t SWEEP_MODES = 6;
const uint8_t SWEEP_RANGE[SWEEP_MODES][2] = { {0, 30}, {0, 45}, {0, 90}, {90, 130} , {90, 180}, {0, 180} };
const uint8_t PUMP_SPEED[P_SPD_MODES] = { 0, 16, 32, 64, 128, 255 };
const uint16_t SWEEP_SPEED[S_SPD_MODES] = { 150, 100, 50, 25, 10 };
Servo servo;
uint8_t getSweepSpeed() {
static uint8_t oldBtnState = HIGH;
static uint8_t sSpeed = 0;
uint8_t btnState = digitalRead(BTN_S_SPEED); // read the button state
if (btnState != oldBtnState) { // see if it changed
oldBtnState = btnState; // set old state to new state
if (btnState == LOW) { // if LOW it was just pressed
sSpeed++;
if (sSpeed >= S_SPD_MODES) sSpeed = 0;
Serial.print("Sweep speed: ");
Serial.println(SWEEP_SPEED[sSpeed]);
} else { // else it was just released
//Serial.println("Sweep speed button released");
}
delay(20); // short delay for button debounce
}
return sSpeed;
}
uint8_t getSweepRange() {
static uint8_t oldBtnState = HIGH;
static uint8_t sRange = 0;
uint8_t btnState = digitalRead(BTN_S_RANGE); // read the button state
if (btnState != oldBtnState) { // see if it changed
oldBtnState = btnState; // set old state to new state
if (btnState == LOW) { // if LOW it was just pressed
sRange++;
if (sRange >= SWEEP_MODES) sRange = 0;
Serial.print("Sweep range: ");
Serial.print(SWEEP_RANGE[sRange][0]);
Serial.print(", ");
Serial.println(SWEEP_RANGE[sRange][1]);
} else { // else it was just released
//Serial.println("Sweep range button released");
}
delay(20); // short delay for button debounce
}
return sRange;
}
uint8_t getPumpSpeed() {
static uint8_t oldBtnState = HIGH;
static uint8_t pSpeed = 0;
uint8_t btnState = digitalRead(BTN_P_SPEED); // read the button state
if (btnState != oldBtnState) { // see if it changed
oldBtnState = btnState; // set old state to new state
if (btnState == LOW) { // if LOW it was just pressed
pSpeed++;
if (pSpeed >= P_SPD_MODES) pSpeed = 0;
Serial.print("Pump speed: ");
Serial.println(PUMP_SPEED[pSpeed]);
} else { // else it was just released
//Serial.println("Pump speed button released");
}
delay(20); // short delay for button debounce
}
return pSpeed;
}
void setPump(int pumpSpeed) {
analogWrite(PUMP_PIN, PUMP_SPEED[pumpSpeed]);
}
void updateDisplay(uint8_t lowPos, uint8_t hiPos, uint16_t sweepSpeed, uint8_t pumpSpeed) {
oled.setCursor(10, 0);
oled.print("Sweep");
oled.setCursor(10, 20);
oled.print("Range");
oled.setCursor(10, 30);
oled.print(" ");
oled.setCursor(10, 30);
oled.print(lowPos);
oled.print(" - ");
oled.print(hiPos);
oled.setCursor(10, 40);
oled.print("Speed");
oled.setCursor(22, 50);
oled.print(sweepSpeed + 1);
oled.setCursor(90, 0);
oled.print("Pump");
oled.setCursor(90, 30);
oled.print("Speed");
oled.setCursor(102, 40);
oled.print(pumpSpeed);
oled.display();
}
void updateServo(int update_interval, int range) {
static uint32_t last_update = 0;
static uint8_t increment = 1;
static uint8_t pos = 0;
if (SWEEP_RANGE[range][0] >= pos) {
increment = 1;
pos = SWEEP_RANGE[range][0];
}
if (SWEEP_RANGE[range][1] <= pos) {
increment = -1;
pos = SWEEP_RANGE[range][1];
}
if ((millis() - last_update) >= SWEEP_SPEED[update_interval]) { // time to update
last_update = millis();
pos += increment;
//Serial.println(pos);
servo.write(pos);
if ((pos >= SWEEP_RANGE[range][1]) || (pos <= SWEEP_RANGE[range][0])) {
increment = -increment;
}
}
}
void setup() {
Serial.begin(115200);
servo.attach(SERVO_PIN);
pinMode(BTN_S_SPEED, INPUT_PULLUP);
pinMode(BTN_S_RANGE, INPUT_PULLUP);
pinMode(BTN_P_SPEED, INPUT_PULLUP);
pinMode(PUMP_PIN, OUTPUT);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if (!oled.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Don't proceed, loop forever
}
// Show initial display buffer contents on the screen --
// the library initializes this with an Adafruit splash screen.
//oled.display();
//delay(2000); // Pause for 2 seconds
// Clear the buffer
oled.clearDisplay();
oled.display();
oled.setTextSize(1); // Normal 1:1 pixel scale
oled.setTextColor(SSD1306_WHITE, BLACK); // Draw white text
oled.setCursor(25, 10); // Start at top-left corner
//oled.cp437(true); // Use full 256 char 'Code Page 437' font
Serial.println("Aquarium Pump Controller V1.00\n");
oled.print("Aquarium Pump");
oled.setCursor(35, 20);
oled.print("Controller");
oled.setCursor(45, 30);
oled.print("V1.00");
oled.display();
delay(2000);
oled.clearDisplay();
oled.display();
Serial.print("Pump speed: ");
Serial.println(PUMP_SPEED[0]);
Serial.print("Sweep speed: ");
Serial.println(SWEEP_SPEED[0]);
Serial.print("Sweep range: ");
Serial.print(SWEEP_RANGE[0][0]);
Serial.print(", ");
Serial.println(SWEEP_RANGE[0][1]);
Serial.println();
}
void loop() {
uint16_t sSpeed = getSweepSpeed();
uint8_t sRange = getSweepRange();
uint8_t pSpeed = getPumpSpeed();
updateServo(sSpeed, sRange);
updateDisplay(SWEEP_RANGE[sRange][0], SWEEP_RANGE[sRange][1], sSpeed, pSpeed);
setPump(pSpeed);
}