diff --git a/Arduino/MoistureSensorPrototype/MoistureSensorPrototype.ino b/Arduino/MoistureSensorPrototype/MoistureSensorPrototype.ino new file mode 100644 index 0000000..0c0fec7 --- /dev/null +++ b/Arduino/MoistureSensorPrototype/MoistureSensorPrototype.ino @@ -0,0 +1,208 @@ +// +// Grundaufbau des Systems: +// +// 1. Mehrere unabhängige Arduinos mit jeweils bis zu 6 Sensoren +// +// Jeder Arduino hat 1 Taster und je Sensor 1 LED. Bei Tastendruck wird für jeden Sensor, +// welcher einen "zu trockenen" Wert zurückgibt, die LED aktiviert. +// Der Arduino gibt per CAN-Bus mindestens 1x pro Minute aus: +// - Die aktuellen Werte jedes Sensors +// - Die Schnellwertkalibrierung jedes Sensors +// Der Arduino hat ein Konsoleninterface, mit dem die Kalibration eingestellt werden kann. +// Die Sensoren müssen wie folgt angeschlossen sein: +// - VCC jedes Sensors an Pin "5V" am Arduino +// - GND jedes Sensors an Pin "GND" am Arduino +// - AOut der Sensoren an die Pins "A0" bis "A5" am Arduino +// Das CAN-Modul MCP2515 wird so angeschlossen wie unter +// https://github.com/autowp/arduino-mcp2515 dokumentiert + + +// +// 2. Zentraler Arduino als Anzeigetafel +// +// Dieser Arduino soll anzeigen, auf welchem Beet gegossen werden muss (d. h. wo mindestens ein Sensor "zu trocken" ist). +// Zu diesem Zweck wird auf dem CAN-Bus "mitgelauscht". + + +// https://github.com/autowp/arduino-mcp2515 --> Auch zur Verkabelung des CAN-Moduls am Arduino nutzen! +#include +struct can_frame canMsg1; +struct can_frame canMsg2; +MCP2515 mcp2515(10); + +// Der persistente Speicher wird genutzt +#include +#include +#include + +#define EEPROM_MAGIC 0x76 +#define DEFAULT_ID 0x13 + +uint16_t threshold[6]; +uint8_t device_id; + +void write_threshold(int i_sensor, uint16_t value) { + eeprom_write_byte((uint8_t*)(1+2*i_sensor), (uint8_t)(value % 256)); // % == "Modulo" + eeprom_write_byte((uint8_t*)(2+2*i_sensor), (uint8_t)(value / 256)); +}; + + +void setup() { + // Start der seriellen Kommunikation + Serial.begin(9600); + Serial.println("Neustart"); + // Setup der digitalen Pins + pinMode(4, OUTPUT); // Anzeige für Sensor 1 + pinMode(5, OUTPUT); // f. Sensor 2 + pinMode(6, OUTPUT); + pinMode(7, OUTPUT); + pinMode(8, OUTPUT); + pinMode(9, OUTPUT); // f. Sensor 6 + pinMode(3, INPUT_PULLUP); // f. Taster + // Nutzung des persistenten Speichers um Schwellenwerte einzugeben + byte magicbyte = eeprom_read_byte(0); + // Der Speicher kann nur byteweise (0 bis 255) angesprochen werden, unsere Zahlenwerte sind aber bis zu 2 Byte (0 bis 16383) groß. + // Deshalb sind die Werte in zwei Kommandos anzusprechen. + if (magicbyte != EEPROM_MAGIC) { + // Wenn Speicher noch leer, wird die Zahl "470" als Defaultwert hineingeschrieben. + eeprom_write_byte(0, EEPROM_MAGIC); + for (uint8_t i = 0; i < 6; i++) { + write_threshold(i, 475); + } + eeprom_write_byte(13, DEFAULT_ID); + } + // Aus dem Speicher werden nun für jeden Sensor die hinterlegten Werte ausgelesen + // (ggf. auch die gerade gespeicherten Default-Werte) + for (uint8_t i = 0; i < 6; i++) { + threshold[i] = ((uint16_t)eeprom_read_byte((uint8_t*)(1+2*i))) + ((uint16_t)eeprom_read_byte((uint8_t*)(2+2*i)))*256; + } + device_id = eeprom_read_byte(13); + +// Initialisierung CAN-Message zur Kommunikation mit anderen Geräten + canMsg1.can_id = "0x40"; + canMsg1.can_dlc = 7; + + mcp2515.reset(); + mcp2515.setBitrate(CAN_5KBPS); + mcp2515.setNormalMode(); + +// Die Geräteinformationen werden ausgegeben + showinfo(); +} + + +// Methode zum Ausgeben von Werten +void print_values(uint16_t* values) { + + for (int i = 0; i < 6; i++) { // i = 0,1,2,3,4,5 + Serial.print("S"); + Serial.print((char)(0x31+i)); // ASCII: (0x30 = '0'), 0x31 = '1', 0x32 = '2', ... + Serial.print(": "); + Serial.print(values[i]); + Serial.print(" "); + } + Serial.println(); +} + + +uint8_t pause = 0; + +void loop() { + // Auslesen der aktuellen Sensorwerte, bis zu 6 Sensoren (Capacitive Soil + // Moisture Sensor v1.2 (Schwingkreis)) + uint16_t sensorwert[6]; + sensorwert[0] = analogRead(A0); + sensorwert[1] = analogRead(A1); + sensorwert[2] = analogRead(A2); + sensorwert[3] = analogRead(A3); + sensorwert[4] = analogRead(A4); + sensorwert[5] = analogRead(A5); + if (pause) + pause--; + else + print_values(sensorwert); + + bool led_ein = (digitalRead(3) == LOW); + + for (uint8_t i = 0; i < 6; i++) { // i = 0,1,2,3,4,5 + bool trocken = sensorwert[i] > threshold[i]; + if (trocken && led_ein) { + // falls Boden trocken und Taster gedrückt + digitalWrite(4+i, HIGH); // für Sensor "i+1" die LED einschalten + } + else + digitalWrite(4+i, LOW); // ansonsten die LED ausschalten + + // Angelehnt an das Beispiel für die Bibliothek mcp2515 + canMsg1.data[0] = device_id; + canMsg1.data[1] = i; + canMsg1.data[2] = trocken ? 0x0f : 0x00; + canMsg1.data[3] = sensorwert[i] % 256; + canMsg1.data[4] = sensorwert[i] / 256; + canMsg1.data[5] = threshold[i] % 256; + canMsg1.data[6] = threshold[i] / 256; + mcp2515.sendMessage(&canMsg1); + } + delay(1000); + shellinterface(); +} + +void showinfo() { + // Die Geräte-ID wird angezeigt + Serial.print("Geräte-ID: "); + Serial.println(device_id); + // Die Schwellwerte anzeigen unter Nutzung der Auslesemethode + Serial.print("Schwellenwerte: "); + print_values(threshold); + Serial.print("-------------\n"); +} + +void shellinterface() { + String line = Serial.readString(); + // Leere Eingaben zurückgeben + if (line.length() == 0) + return; + // Zeilenende löschen + if (line[line.length()-1] == '\n') + line = line.substring(0, line.length()-1); + else if (line[line.length()-1] == '\r') + line = line.substring(0, line.length()-1); + // Für Debuggingzwecke die Eingabe anzeigen + Serial.print("Received: "); + Serial.println(line); + // Ab hier werden die Kommandos definiert: + + if (line == "show") { + showinfo(); + } + else if (line == "pause") { + Serial.println("Stoppe Ausgabe für 60 Sekunden."); + pause = 60; + // Dieser Wert wird in der Loop-Methode dann jede Sekunde heruntergezählt + } + else if (line.startsWith("set S") && line.length() > 7 && line[6] == '=') { + // Sensorkanal auslesen, das ASCII-Zeichen für "0" abziehen um direkt die Zahl von 1 bis 6 zu erhalten + // Außerdem 1 abziehen, da die Sensor-Nummern 1 bis 6 den internen Sensornummern 0-5 entsprechen. + int i_sensor = line[5] - '0' - 1; + int new_threshold = line.substring(7).toInt(); + Serial.print("Setze den Schwellwert von Sensor S"); + Serial.print(i_sensor+1); + Serial.print(" von "); + Serial.print(threshold[i_sensor]); + Serial.print(" auf "); + Serial.println(new_threshold); + threshold[i_sensor] = new_threshold; + write_threshold(i_sensor, new_threshold); + } + else if (line.startsWith("set ID=")) { + int new_id = line.substring(7).toInt(); + + Serial.print("Setze die Geraete-ID von "); + Serial.print(device_id); + Serial.print(" auf "); + Serial.println(new_id); + device_id = new_id; + eeprom_write_byte(13, new_id); + } + else Serial.println("Kommando \"" + line + "\" nicht erkannt."); +}