Seuraa alla olevaa videota nähdäksesi, miten asennat sivustomme verkkosovelluksena aloitusnäytöllesi.
Huom: This feature may not be available in some browsers.
/*
PumpController.ino – V1.4 (raw‑pressure logic + shield‑pin remap)
-----------------------------------------------------------------
• Relay‑shield kanavat 4‑7 → käytämme kanavaa 2 (IN=6) pumpulle.
• Painikkeet siirretty vapaille navoille: Start=D8, Pause=D9.
• Priming‑aika 5 s.
*** UUTTA V1.4 ***
‑ Logiikka käyttää **raakapainetta (pressureBarRaw)**; filtteröity
arvo (filtPressureBar) on vain näytölle → nopeat muutokset huomioidaan
heti eikä NaN‑häiriö voi viivästyttää pysäytystä.
*/
#include <LiquidCrystal_I2C.h>
#include <Bounce2.h>
/* ---------------- Hardware ---------------- */
const byte FLOW_PIN = 2; // INT0 – flow sensor pulses
const byte PRESSURE_PIN = A0; // 0‑100 psi pressure
const byte RELAY_PIN = 6; // Relay‑shield channel 2 (pump)
const byte BTN_START_PIN = 8; // Start / Stop
const byte BTN_SET_PIN = 9; // Pause length select
LiquidCrystal_I2C lcd(0x27, 20, 4);
Bounce debStart, debSet;
/* ------------ Constants ------------- */
const float PULSES_PER_LITER = 595.0;
const float PSI_TO_BAR = 0.0689476f;
const float FULL_SCALE_PSI = 100.0;
const float VOLT_MIN = 0.5;
const float VOLT_MAX = 4.5;
const float ADC_TO_VOLT = 5.0 / 1023.0;
const float DRY_PRESS_BAR = 1.0;
const float DRY_FLOW_LPM = 10.0;
const uint32_t DRY_TIMEOUT_MS = 3000;
const float FULL_PRESS_BAR = 2.8;
const uint32_t FULL_TIMEOUT_MS = 2000;
const uint32_t PRIMING_MS = 5000; // 5 s priming
const uint16_t pauseTable[] PROGMEM = {15,30,60,120,240,480,960};
const byte PAUSE_COUNT = sizeof(pauseTable)/sizeof(pauseTable[0]);
byte pauseIdx = 4; // 240 min
uint32_t pauseRemainingMs;
/* ---------- Runtime vars ----------- */
volatile uint32_t pulseCount = 0;
uint32_t lastBucketMs, lastDisplayMs, lastBlinkMs;
uint32_t pulses1s = 0;
float filtPressureBar = 0.0f; // only for display
const float ALPHA = 0.20f;
float lastVolumeLitres = 0.0f;
float thisVolumeLitres = 0.0f;
uint32_t pumpStartMs;
uint32_t dryDetectMs = 0, fullDetectMs = 0;
bool blinkFlag = false;
enum State { WAITING, PUMPING } state = WAITING;
enum StopReason { NONE, BOOT, SHORTAGE, FILLED, MANUAL } stopReason = BOOT;
enum StartCause { PAUSEOVER, MANUALSTART } startCause = PAUSEOVER;
/* ---------- Helper: clear one LCD row ---------- */
void clearLine(byte row){ lcd.setCursor(0,row); lcd.print(F(" ")); lcd.setCursor(0,row);} // 20 spaces
/* ---------- Prototypes ---------- */
void enterWaiting();
void enterPumping(StartCause);
void flowISR(){ pulseCount++; }
/* ---------- Setup ---------- */
void setup(){
pinMode(FLOW_PIN,INPUT_PULLUP);
pinMode(PRESSURE_PIN,INPUT);
pinMode(BTN_START_PIN,INPUT_PULLUP);
pinMode(BTN_SET_PIN,INPUT_PULLUP);
pinMode(RELAY_PIN,OUTPUT); digitalWrite(RELAY_PIN,LOW);
attachInterrupt(digitalPinToInterrupt(FLOW_PIN),flowISR,RISING);
debStart.attach(BTN_START_PIN); debStart.interval(20);
debSet.attach(BTN_SET_PIN); debSet.interval(20);
lcd.init(); lcd.backlight(); lcd.print(F("Pump Controller")); delay(1500); lcd.clear();
pauseRemainingMs = (uint32_t)pgm_read_word(&pauseTable[pauseIdx])*60000UL;
lastBucketMs = lastDisplayMs = lastBlinkMs = millis();
}
/* ---------- Loop ---------- */
void loop(){
uint32_t now = millis();
/* --- Buttons --- */
debStart.update(); debSet.update();
if(debStart.fell()) {
if(state==WAITING) enterPumping(MANUALSTART); else { stopReason = MANUAL; enterWaiting(); }
}
if(debSet.fell() && state==WAITING) {
pauseIdx = (pauseIdx + 1) % PAUSE_COUNT;
pauseRemainingMs = (uint32_t)pgm_read_word(&pauseTable[pauseIdx])*60000UL;
}
/* --- 1‑s flow bucket --- */
if(now - lastBucketMs >= 1000) {
lastBucketMs += 1000;
pulses1s = pulseCount; pulseCount = 0;
if(state == PUMPING) thisVolumeLitres += pulses1s / PULSES_PER_LITER;
}
float flowLPM = (pulses1s * 60.0f) / PULSES_PER_LITER;
/* --- Pressure reading --- */
int adc = analogRead(PRESSURE_PIN);
float voltage = adc * ADC_TO_VOLT;
float pressureBarRaw;
if (voltage < VOLT_MIN - 0.05 || voltage > VOLT_MAX + 0.05) pressureBarRaw = 0.0f; // invalid → 0
else {
pressureBarRaw = (voltage - VOLT_MIN) * (FULL_SCALE_PSI * PSI_TO_BAR) / (VOLT_MAX - VOLT_MIN);
if (pressureBarRaw < 0) pressureBarRaw = 0;
}
// simple display filter
filtPressureBar = filtPressureBar * (1.0f - ALPHA) + ALPHA * pressureBarRaw;
/* --- State machine --- */
if(state == PUMPING) {
// dry‑run detection after priming
if(now - pumpStartMs > PRIMING_MS) {
if(pressureBarRaw < DRY_PRESS_BAR && flowLPM < DRY_FLOW_LPM) {
if(!dryDetectMs) dryDetectMs = now;
if(now - dryDetectMs >= DRY_TIMEOUT_MS) { stopReason = SHORTAGE; enterWaiting(); }
} else dryDetectMs = 0;
}
// tank‑full detection using raw pressure
if(pressureBarRaw >= FULL_PRESS_BAR) {
if(!fullDetectMs) fullDetectMs = now;
if(now - fullDetectMs >= FULL_TIMEOUT_MS) { stopReason = FILLED; enterWaiting(); }
} else fullDetectMs = 0;
} else {
if(now - pumpStartMs >= pauseRemainingMs) enterPumping(PAUSEOVER);
}
/* --- Display (1 Hz) --- */
if(now - lastDisplayMs >= 1000) {
lastDisplayMs += 1000;
if(state == WAITING) {
uint16_t pauseSet = pgm_read_word(&pauseTable[pauseIdx]);
uint32_t remMin = (pauseRemainingMs - (now - pumpStartMs)) / 60000UL;
clearLine(0); lcd.print(F("WAITING: ")); lcd.print(pauseSet); lcd.print(F(" min "));
clearLine(1); lcd.print(F("To start: ")); lcd.print(remMin); lcd.print(F(" min "));
clearLine(2); lcd.print(F("REASON: "));
switch(stopReason) {
case NONE: lcd.print(F("- ")); break;
case BOOT: lcd.print(F("Boot ")); break;
case SHORTAGE: lcd.print(F("Shortage ")); break;
case FILLED: lcd.print(F("Tank filled")); break;
case MANUAL: lcd.print(F("Manual pause")); break;
}
clearLine(3); lcd.print(F("Last: ")); lcd.print(lastVolumeLitres,0); lcd.print(F(" l"));
} else {
if(now - lastBlinkMs >= 500) { lastBlinkMs += 500; blinkFlag = !blinkFlag; }
clearLine(0); lcd.print(blinkFlag ? F(">> PUMP RUNNING >>") : F(" >> PUMP RUNNING >>"));
clearLine(1); uint16_t runMin = (now - pumpStartMs) / 60000UL; lcd.print(runMin); lcd.print(F(" min / ")); lcd.print(thisVolumeLitres,0); lcd.print(F(" l"));
clearLine(2); lcd.print(startCause == PAUSEOVER ? F("REASON: Pause over") : F("STARTED MANUALLY"));
clearLine(3);
lcd.print(flowLPM,1); lcd.print(F(" l/min ")); lcd.print(filtPressureBar,1); lcd.print(F(" bar"));
}
}
}
/* ---------- State helpers ---------- */
void enterWaiting(){
state = WAITING;
digitalWrite(RELAY_PIN, LOW);
lastVolumeLitres = thisVolumeLitres;
thisVolumeLitres = 0.0f;
pumpStartMs = millis();
pauseRemainingMs = (uint32_t)pgm_read_word(&pauseTable[pauseIdx]) * 60000UL;
dryDetectMs = fullDetectMs = 0;
}
void enterPumping(StartCause c){
state = PUMPING;
startCause = c;
stopReason = NONE;
digitalWrite(RELAY_PIN, HIGH);
thisVolumeLitres = 0.0f;
blinkFlag = false;
dryDetectMs = fullDetectMs = 0;
pumpStartMs = millis();
}
// END OF FILE
Nykyään on kyllä vaikka mitä höpönhalpaa raketti-insinöörinörttitason teknologiaa saatavilla. Arduino sattui löytymään varmuusvarastoista ja anturit kun olivat lähinnä viisivolttisia, niin kyhäsin sillä. Mutta onhan tuosta menty jo viuhuen tekniikassa ohi oikealta ja vasemmalta.on tarjolla edullisesti esim. ESP32:sta
Mylläsin varmuusvarastoja ja taisin löytää 12V osia, joilla kenties saisi tuota häiriönsietoa parannettua. Pitää nyt funtsia, räjäyttäisikö tuon vielä osasiksi. Eihän siinä kovin mahdoton työ olisi. Yhdet pienet hakkurikortit pitäisi vielä löytää.jolloin tulee jonkinsorttinen glitch in the matrix
Eräs tuttava joka asuu kaupungissa, on jo varmaan 30 vuotta kastellu kesämökin kasvihuoneen kasvit jollain pikkupumpulla ja sadettimella joka pyörii tietyn määrän vuorokaudessa kellokytkimen ohjaamana, järvestä ottaa veden. Joku sille näitä täsmäkastelu-altakastelujuttuja yritti tuputtaa, totes että kasvit tykkää sateesta...200l taas kannutettu 20,neen lavakaulus kehikkoon a" 20l/kehikko lämmentynyttä vettä, täytyy kyllä suunnitella joku automatic järjestelä niilekkin.
Pistä pumppu tuuppaamaan tihkuletkuihin, katot viiniä nautiskellen kauanko kestää vesitornin tyhjentyminen tai tarvittavan vesimäärän pumppautuminen niihin tihkuletkuihin ja laitat ajan kellokytkimeen, ei se sen vaikeempata ole ainakaan mun mielestä.20 kymmenessä kasvillavassa "joissa 2 kaulusta päälekkäin" on tihkukastelu letkut, mutta 2m,ä ylempänä olevan vesitornin aikaansaama paine ei riitä tihkuttamaan. Kastelu veden täytyy olla hapetettua - lämmintä ei helvetinkylmää syvästä kaivosya suoraan pumpattua.
Pitää nyt funtsia, räjäyttäisikö tuon vielä osasiksi. Eihän siinä kovin mahdoton työ olisi. Yhdet pienet hakkurikortit pitäisi vielä löytää.
Se ei näe säiliöveden määrää kuin uimuriventtiilin vastapaineesta. Kapine saa tietoa vain virtauksesta ja paineesta ja sen perusteella tekee päätökset. Eli on pakko kokeilla, onko painetta vastassa vai ei.eikö se riitä että se katsoo onko säiliössä paljon vettä, jos on niin ei täytetä![]()
Luo tili tai kirjaudu sisään kommentoidaksesi
Sinun täytyy olla jäsen voidaksesi jättää kommentin.
Luo käyttäjätili
Liity Konekansalaiseksi. Se on helppoa ja ilmaista! Rekisteröityneenä et näe mainoksia, voit käyttää hakua, näet alueita, joita nyt ovat piilossa...jne.