You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

262 lines
7.0 KiB

  1. /*
  2. Pneumatische Zisternen-Füllstandsmessung.
  3. Start der Messung und Übertragung der Ergebnise über WLAN.
  4. Arduino-Bord: "NodeMCU 1.0(ESP-12E Module)"
  5. Autor Wolfgang Neußer
  6. Stand: 24.10.2021
  7. Hardware:
  8. DOIT ESP12E Motor Shield mit L293D Motortreiber
  9. Amica NODE MCU ESP8266 12E
  10. SparkFun Qwiic MicroPressure Sensor
  11. Druckpumpe und Entlüftungsventil aus Oberarm-Blutdruckmesser
  12. Messablauf:
  13. 1. Abluftventil schließen, Druckpumpe einschalten
  14. 2. Druck kontinuierlich messen
  15. Wenn Druckanstieg beendet -> Pumpe ausschalten
  16. 3. Beruhigungszeit
  17. 4. Aktueller Druck - atmosphärischen Druck = Messdruck
  18. Beispiel: 29810 Pa = 3040 mmH2O = 100% Füllstand
  19. 5. Abluftventil öffnen
  20. */
  21. #include <Wire.h>
  22. #include <SparkFun_MicroPressure.h>
  23. #include <LiquidCrystal_I2C.h>
  24. SparkFun_MicroPressure mpr;
  25. LiquidCrystal_I2C lcdDisplay = LiquidCrystal_I2C(0x27, 16, 2);
  26. // Zuordnung der Ein- Ausgänge
  27. #define VENTIL 5 // GPIO5 (PWM MotorA)
  28. #define DA 0 // GPIO0 (Richtung MotorA)
  29. #define PUMPE 4 // GPIO4 (PWM MotorB)
  30. #define DB 2 // GPIO2 (Richtung MotorB)
  31. #define SDA 12 // GPIO12 I2C
  32. #define SCL 13 // GPIO13 I2C
  33. #define AUF LOW // Ventil öffnen
  34. #define AUS LOW // Pumpe ausschalten
  35. #define ZU HIGH // Ventil schliessen
  36. #define EIN HIGH // Pumpe einschalten
  37. // An eigene Zisterne anpassen (zur Berechnung der Füllmenge)
  38. const int A = 3140; // Grundfläche der Zisterne in cm^2 (d * d * 3,14 / 4)
  39. const int maxFuellhoehe = 3040; // Füllhöhe der Zisterne in mm
  40. int atmDruck = 97400;
  41. /*
  42. * HELPERS FOR INPUT / OUTPUT
  43. */
  44. void initDisplay() {
  45. lcdDisplay.display();
  46. lcdDisplay.noBlink();
  47. lcdDisplay.noCursor();
  48. lcdDisplay.clear();
  49. lcdDisplay.backlight();
  50. }
  51. void disableDisplay() {
  52. lcdDisplay.noDisplay();
  53. }
  54. void printMsgToLCD(const String& line_one, const String& line_two) {
  55. lcdDisplay.clear();
  56. lcdDisplay.setCursor(0, 0);
  57. lcdDisplay.print(line_one);
  58. lcdDisplay.setCursor(0, 1);
  59. lcdDisplay.print(line_two);
  60. }
  61. void printDebugMsg(const String& type, const String& msg) {
  62. if (Serial.available()) {
  63. Serial.println(type + msg);
  64. }
  65. printMsgToLCD(type, msg);
  66. }
  67. void printMeasurements(const int& pressure) {
  68. const int wassersaeule = convertPressureToHeight(currentPressure);
  69. hoehe = String(wassersaeule / 10) + "cm";
  70. volumen = String((wassersaeule / 10) * A / 100) + "L";
  71. // Umrechnung Wassersäule in 0 - 100%
  72. fuellstand = String(map(wassersaeule, 0, maxFuellhoehe, 0, 100)) + "%";
  73. if (Serial.available()) {
  74. Serial.println("Füllhöhe: "+ hoehe);
  75. Serial.println("Volumen: " + volumen);
  76. Serial.println("Füllstand: " + fuellstand);
  77. }
  78. printMsgToLCD("Vol: " + volumen, "Stand: " + fuellstand);
  79. }
  80. void handleSerialInput() {
  81. static String inputString;
  82. if (Serial.available()) {
  83. char inChar = (char)Serial.read();
  84. if ((inChar == '\r') || (inChar == '\n')) {
  85. if (inputString == "?") {
  86. Serial.println("Kommandos: ");
  87. Serial.println("p1 = Pumpe EIN");
  88. Serial.println("p0 = Pumpe AUS");
  89. Serial.println("v1 = Ventil ZU");
  90. Serial.println("v0 = Ventil AUF");
  91. Serial.println("start = Messung starten");
  92. Serial.println();
  93. }
  94. else if (inputString == "p1") {
  95. Serial.println("Pumpe EIN");
  96. digitalWrite(PUMPE, EIN);
  97. }
  98. else if (inputString == "p0") {
  99. Serial.println("Pumpe AUS");
  100. digitalWrite(PUMPE, AUS);
  101. }
  102. else if (inputString == "v1") {
  103. Serial.println("Ventil ZU");
  104. digitalWrite(VENTIL, ZU);
  105. }
  106. else if (inputString == "v0") {
  107. Serial.println("Ventil AUF");
  108. digitalWrite(VENTIL, AUF);
  109. }
  110. else if (inputString == "start") {
  111. Measurement();
  112. }
  113. inputString = "";
  114. } else inputString += inChar;
  115. }
  116. }
  117. /*
  118. * FUNCTIONS FOR MEASUREMENT
  119. */
  120. int getPressureSensorValue() {
  121. static int measuredPressure = 0;
  122. static unsigned long messTakt = 0;
  123. // Messwert in Pascal auslesen und filtern - alle 10ms bei aufruf
  124. if (messTakt < millis()) {
  125. measuredPressure = ((measuredPressure * 50) + int(mpr.readPressure(PA))) / 51;
  126. messTakt = millis() + 10;
  127. }
  128. return measuredPressure;
  129. }
  130. int convertPressureToHeight(const int& pressure) {
  131. // Umrechnung Pa in mmH2O
  132. const int wassersaeule = (pressure - atmDruck) * 10197 / 100000;
  133. if (wassersaeule < 0) return 0;
  134. else return wassersaeule;
  135. }
  136. int setAtmosphericPressure() {
  137. static unsigned long messTakt = 0;
  138. if (messTakt < millis()) {
  139. if (!digitalRead(VENTIL) && !digitalRead(PUMPE)) {
  140. atmDruck = getPressureSensorValue();
  141. }
  142. messTakt = millis() + 1000;
  143. }
  144. }
  145. /*
  146. * MAIN MEASUREMENT ORCHESTRATOR
  147. */
  148. void Measurement() {
  149. initDisplay();
  150. printDebugMsg("Info: ", "Messung begonnen");
  151. int oldPressure = getPressureSensorValue();
  152. digitalWrite(VENTIL, ZU);
  153. digitalWrite(PUMPE, EIN);
  154. delay(500);
  155. while (true) {
  156. const int currentPressure = getPressureSensorValue();
  157. if (convertPressureToHeight(currentPressure) > (maxFuellhoehe + 200)) {
  158. digitalWrite(VENTIL, AUF);
  159. digitalWrite(PUMPE, AUS);
  160. printDebugMsg("Fehler: ", "Leitung verstopft");
  161. while(1);
  162. }
  163. if (currentPressure > oldPressure + 10) {
  164. oldPressure = currentPressure;
  165. delay(100);
  166. }
  167. else {
  168. break;
  169. }
  170. }
  171. const int finalPressure = getPressureSensorValue();
  172. digitalWrite(VENTIL, AUF);
  173. digitalWrite(PUMPE, AUS);
  174. printMeasurements(finalPressure);
  175. delay(5000);
  176. disableDisplay();
  177. }
  178. /*
  179. * SETUP AND LOOP FOR ARDUINO RUNTIME
  180. */
  181. void setup() {
  182. // Display initialisieren
  183. lcdDisplay.init();
  184. initDisplay();
  185. // Richtung Motor A
  186. pinMode(DA, OUTPUT);
  187. digitalWrite(DA, HIGH);
  188. // PWM Motor A
  189. pinMode(VENTIL, OUTPUT);
  190. digitalWrite(VENTIL, AUF);
  191. // Richtung Motor B
  192. pinMode(DB, OUTPUT);
  193. digitalWrite(DB, HIGH);
  194. // PWM Motor B
  195. pinMode(PUMPE, OUTPUT);
  196. digitalWrite(PUMPE, AUS);
  197. // enable serial console
  198. Serial.begin(115200);
  199. delay(10);
  200. // I2C initialisieren mit 400 kHz
  201. Wire.begin(SDA, SCL, 400000);
  202. // Drucksensor initialisieren
  203. // Die Default-Adresse des Sensors ist 0x18
  204. // Für andere Adresse oder I2C-Bus: mpr.begin(ADRESS, Wire1)
  205. if(!mpr.begin()) {
  206. printDebugMsg("Fehler: ", "Drucksensor");
  207. while(1);
  208. }
  209. printDebugMsg("Info: ", "System OK");
  210. delay(1000);
  211. disableDisplay();
  212. }
  213. void loop() {
  214. handleSerialInput();
  215. setAtmosphericPressure();
  216. // TODO: read button and start measurement
  217. // ensure valve is open and pump turned off
  218. digitalWrite(VENTIL, AUF);
  219. digitalWrite(PUMPE, AUS);
  220. }