209 lines
6.7 KiB
Arduino
209 lines
6.7 KiB
Arduino
|
//
|
||
|
// 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 <mcp2515.h>
|
||
|
struct can_frame canMsg1;
|
||
|
struct can_frame canMsg2;
|
||
|
MCP2515 mcp2515(10);
|
||
|
|
||
|
// Der persistente Speicher wird genutzt
|
||
|
#include <inttypes.h>
|
||
|
#include <avr/eeprom.h>
|
||
|
#include <avr/io.h>
|
||
|
|
||
|
#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.");
|
||
|
}
|