Freitag, 2. August 2013

Keine Sonderzeichen...

Hier folgt der um Sonderzeichen revidierte Code. Jetzt kommt es spürbar seltener zu Displayproblemen.

#include <LiquidCrystal.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Ethernet.h>
#include <LCD.h>
#include <Keypad.h>
#include <Keypad_I2C.h>
#include <SPI.h>
#include <EthernetUdp.h> // für die NTP-Abfrage
#include <SD.h> // für die SD-Kartennutzung

// fuer das LCD
#define I2C_ADDR 0x27 // Define I2C Address where the PCF8574A is
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7

// für die SD Karte
File SD_Datei;


// für NTP
unsigned int localPort = 8888; // local port to listen for UDP packets
IPAddress timeServer(192, 53, 103, 108); // ntp1 ptb.de 192.53.103.108 Physikalisch-Technische Bundesanstalt (PTB), Braunschweig
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
EthernetUDP Udp; // A UDP instance to let us send and receive packets over UDP
boolean zeitpaket_angefordert=false;
boolean zeitpaket_geliefert=false;
unsigned long epoch=0;

int stunde=0;
int minute=0;
int sekunde=0;

// fuer COSM - Testversion
/*#define APIKEY "xxx" // your cosm api key
#define FEEDID 75484 // your feed ID - Arduino Testversion 2
#define USERAGENT "Cosm Arduino Example (75484)" // user agent is the project name
*/

#define APIKEY "xxxx" // your cosm api key
#define FEEDID 90041 // your feed ID- Arduino Testversion 1
#define USERAGENT "Heizduino (90041)" // user agent is the project name



// für das Keypad
#define ROWS 4
#define COLS 4 // sollte 4 sein!
#define PCF8574_ADDR 0x23 // Keypad Adresse
byte rowPins[4] = {0,1,2,3}; //connect to the row pinouts of the keypad
byte colPins[4] = {4,5,6,7}; //connect to the column pinouts of the keypad
char keys[4][4]={
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};

// I2C-Adressen der angeschlossenen Geräte
#define expander_keypad 0x23 //EXPANDER address, hier mit A0 und A1 auf HIGH, Adresse des Keypads
#define expander_relais 0x20 //EXPANDER address with 3 address pins grounded, Adresse der Relaiskarte

/*
// Der PCF8574 hat die Adresse 0x20
// einer ist für das Keyboard (Adresse: 0x20)
// einer ist für das Relaismodul (Adresse: 0x21, dazu A0 kurzschliessem; INT steht die Interrupts)

// Pins 0-5 sind an die Temp-Fühler (Erdungsfarbe) angeschlossen, braun an +, blau an -

// Update: Pin 0 und 1 sind beim Ethernet-Shield für die Nutzung von SD Card gedacht und liefern daher falsche Werte, daher Umlegung auf 8-13
// 8 = 300l-Boiler oben
// 9 = 300l-Boiler unten
// 10 = 500l-Boiler oben
// 11 = 500l-Boiler unten
// 12 = Vorlauf
// 13 = Rücklauf
*/


/*
// Relaisbyte
// ACHTUNG: Relais mit +/- nicht über Arduino versorgen, sondern ext. Stromquelle anzapfen!
// Achtung: Das Relaisboard ist so konstruiert, dass die einzelnen Relais imer unter Strom sind,
// Wird das Kanal auf LOW geschaltet (GND), dann fließt Strom und das Relais schließt.
// Folge: bei 11111110 schaltet das erste Relais, die anderen bleiben aus.
//
// Bit 0 - Zusatzpumpe für die Heizungsunterstützung, falls der Vorlauf z.B. über 95 Grad steigt
// Bit 1 - Pumpe UND Zwangsventil für die Aufheizung der Warmwasser-Boiler durch die Heizung ("befüllen")
// Bit 2 - für später
// Bit 3 - 3-Wege-Ventil für die Aufheizung: in kleinen oder großen Boiler
// Bit 4 - Umwälzpumpe UND Ventil für die Umwälzung der Wärme vom 500l-Solarboiler in den kleinen 300l-Boiler ("umwälzen")
// Bit 5 - für später
// Bit 6 - 3-Wege-Ventil für das Brauchwasser: 300l- vs. 500l-Boiler
// Bit 7 - für später

// dementsprechend werden die Relais zugeordnet!
*/

byte relais_byte; // darüber werden die Methoden gesteuert
byte relais_vorschlag_byte;
char test[4];
char tmp[10];
char tmpp[20];


boolean arbeitsmodus=0; // Setzen des Arbeitsmodus: entweder Manuell (=1) oder Autopilot (=0)
boolean neue_temp_da=0;

unsigned long time; // wird nach ca. X Tagen wieder auf Null gestezt
unsigned long time_z1=0; // Zwischenstand für temp_erfassung_ausgabe()
unsigned long time_z2=0; // Zwischenstände für regelmäßigen lcd_reset
unsigned long time_z3=0; // Zwischenstände für regelmäßigen Zeit-Ausgabe

unsigned long letzte_zeitanforderung; // Zwischenstände, gebraucht für die Zeitabfrage
unsigned long letzte_zeit; // Zwischenstände, gebraucht für die Zeitabfrage
unsigned long time_d; // Zwischenstände

unsigned int Heizung_3WV=0; // das hier ist das 3-Wege-Ventil

const unsigned int TEMP_SENSOR_PIN[6]={8, 9, 10, 11, 12, 13}; // Pinnummern zu Temp-Sensoren zuweisen, s.o.
unsigned int temp_3_alt=0; // Zwischenspeicher für die untere Boilertemperatur für die Feststellung des Sommers
const int Anzahl_Temp_Messungen=50; // Zahl der pro Durchgang gemachten Messungen an den Fühlern, je mehr, desto besser
// const int large_archiv_groesse=10; // Zahl der gespeicherten alten Temp-Werte, kommt später!

float TEMP_SENSOR[6]={0,1,2,3,4,5};
int TEMP_SENSOR_Reading[6][Anzahl_Temp_Messungen];
//float TEMP_SENSOR_L[6][large_archiv_groesse];
// und gleich die sechs passenden Zeiger
// int temp_pointer[6]; , kommt päter


const float max_B_temp=50; // Temperatur, die ein Boiler maximal erreichen darf, um keine Kalkablagerungen abzukriegen
const float max_temp_vorlauf=85; // ab hier schaltet die Zusatzpumpe
const float zusatzpumpen_hysteresis=5; // unterschreitet die temp die max_temp_vorlauf-Temp um diesen Wert, schaltet die Zusatzpumpe aus
const float sommer_temp_solarboiler=50; // angenommene Temp im gr. Boiler unten, wenn Sommer ist

char key;
byte key2;
byte key_i;

const float SUPPLY_VOLTAGE = 1.1; // Voltage für die interne Vergleichsspannung, nur beim MEGA 1,1!
const unsigned int BOUD_RATE = 38400; // Übetragungsrate zum ser. Monitor, warum nicht 9600 ... oder mehr?

// assign a MAC address for the ethernet controller.
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // 0xED zum Schluss ist für die Produktivversion gedacht
byte gateway[] = { 192,168,178,1};
byte subnet[] = { 255, 255, 255, 0};
IPAddress ip(192,168,178,44);// assign an IP address for the controller: // die 47 am Ende für die Produktivversion!
EthernetClient client;// initialize the library instance:
char server[] = "api.cosm.com"; //IPAddress server(216,52,233,121);

// Beschreibung der String-Lib: http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html
// und http://www.robotc.net/wiki/ARDUINO_328_Functions_Strings

char temp_string[200];
char temp_a_string[200];


unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
boolean lastConnected = false; // state of the connection last time through the main loop
const int postingInterval = 10000; //delay between updates to Pachube.com, in ms

/* Ende der Angaben für Pachube */

/* alt:
//The link:http://www.dfrobot.com/image/data/DFR0154/LiquidCrystal_I2Cv1-1.rar
//DFRobot.com
//Compatible with the Arduino IDE 1.0
//Library version:1.1

neu:
https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home
*/

#if defined(ARDUINO) && ARDUINO >= 100 // // keine Ahnung wofür
#define printByte(args) write(args);
#else
#define printByte(args) print(args,BYTE);
#endif;

// LCD Sonderzeichen definieren

/*
uint8_t boilerwand[8] = {
0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4};
uint8_t arrow_left[8] = {
0x4,0x4,0xc,0x1f,0xc,0x4,0x4,0x4};
uint8_t arrow_right[8] = {
0x4,0x4,0x6,0x1f,0x6,0x4,0x4,0x4};
uint8_t ecke_re[8] = {
0x0,0x0,0x0,0x7,0x4,0x4,0x4,0x4};
uint8_t ecke_li[8] = {
0x0,0x0,0x0,0x1c,0x4,0x4,0x4,0x4};
uint8_t linie[8] = {
0x0,0x0,0x0,0x1f,0x0,0x0,0x0,0x0};

uint8_t arrow_up[8] = {
0x4,0xe,0x1f,0x4,0x4,0x4,0x4};
uint8_t arrow_down[8] = {
0x4,0x4,0x4,0x4,0x1f,0xa,0x4};

uint8_t clock[8] = {
0x0,0xe,0x15,0x17,0x11,0xe,0x0};
uint8_t check[8] = {
0x0,0x1,0x3,0x16,0x1c,0x8,0x0};
uint8_t retarrow[8] = {
0x1,0x1,0x5,0x9,0x1f,0x8,0x4};
uint8_t bell[8] = {
0x4,0xe,0xe,0xe,0x1f,0x0,0x4};
*/

// LCD Instanz
LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

// Keypad Instanz
Keypad_I2C kpd = Keypad_I2C(makeKeymap(keys),rowPins,colPins,ROWS,COLS,PCF8574_ADDR); // für das Keypad


void lcd_init()
{
lcd.begin(20, 4);
// lcd.init(); // initialize the lcd
// lcd.backlight();
lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
lcd.setBacklight(HIGH);
lcd.home (); // go home

/*
lcd.createChar(0, boilerwand);
lcd.createChar(1, arrow_left);
lcd.createChar(2, arrow_right);
lcd.createChar(3, ecke_re);
lcd.createChar(4, ecke_li);
lcd.createChar(5, clock);

lcd.createChar(6, linie);
lcd.createChar(7, retarrow);
*/
}


void get_temperature()
{
long vol=0;
for (int i=0; i<Anzahl_Temp_Messungen; i++)
{
for (int j=0; j<=5; j++)
{
TEMP_SENSOR_Reading[j][i]=analogRead(TEMP_SENSOR_PIN[(j)]);
}
}

// nun die Mittelwert-Berechnung!
for (int i=0; i<=5; i++)
{
vol=0;
for (int j=0; j<Anzahl_Temp_Messungen; j++)
{
vol=vol+TEMP_SENSOR_Reading[i][j];
}
TEMP_SENSOR[i]=SUPPLY_VOLTAGE*vol/10.24/Anzahl_Temp_Messungen;
if (TEMP_SENSOR[i]>=99) TEMP_SENSOR[i]=99; // Absicherung gegen unerwünschte und unrealistische Readings
if (TEMP_SENSOR[i]<=0) TEMP_SENSOR[i]=0; // Absicherung gegen unerwünschte und unrealistische Readings
}
}


void zeit_lcd_ausgabe()
{
time=millis();
if (time>=time_z3)
{
time_d=time-time_z3;
}
else
{
time_d=4294967295-time_z3+time;
}

if (time_d>1000) // erst nach Ablauf einere Sek Zeit neu ausgeben
{
unixtime_umrechnen_aktualisieren();

if(zeitpaket_angefordert==false&&zeitpaket_geliefert==true)
{
lcd.setCursor(4, 1);
lcd.print(F("*"));
//lcd.printByte(5);
}
else
{ lcd.setCursor(4, 1);
lcd.print(F("O"));
}

lcd.setCursor(5, 1);
lcd.print(stunde);
lcd.print(F(":"));

if ( minute < 10 )
{
// In the first 10 minutes of each hour, we'll want a leading '0'
lcd.print(F("0"));
}
lcd.print(minute);
lcd.print(F(":"));

if ( sekunde < 10 )
{
// In the first 10 seconds of each minute, we'll want a leading '0'
lcd.print(F("0"));
}
lcd.print(sekunde);
}
}


void lcd_ausgabe()
{
byte bitmask;
Serial.println(F("lcd_ausgabe!"));
//lcd.clear();
//ZEICHNUNG
for (int i=0;i<=3;i++)
{
lcd.setCursor(2, i);
lcd.print(F("I"));
//lcd.write(uint8_t(0));
}
for (int i=0;i<=3;i++)
{
lcd.setCursor(15, i);
lcd.print(F("I"));
//lcd.write(uint8_t(0));
}
// kleiner Boiler-Temperatur
lcd.setCursor(0, 0);
lcd.print(TEMP_SENSOR[0],0);
lcd.setCursor(0, 3);
lcd.print(TEMP_SENSOR[1],0);
// großer Boiler-Temperatur
lcd.setCursor(16, 0);
lcd.print(TEMP_SENSOR[2],1);
lcd.setCursor(16, 3);
lcd.print(TEMP_SENSOR[3],1);
// Vorlauf- und Rücklauf-Temperatur
lcd.setCursor(3, 3);
lcd.print(F("v"));
lcd.print(TEMP_SENSOR[4],1);
lcd.setCursor(10, 3);
lcd.print(F("r"));
lcd.print(TEMP_SENSOR[5],1);

// Relaisfunktionen: vgl. byte relais_byte
bitmask=1<<0; //Zusatzpumpe: "+"
if ((bitmask & relais_byte)>0)
{
lcd.setCursor(8, 3);
lcd.print(F("+"));
}
else
{
lcd.setCursor(8, 3);
lcd.print(F(" "));
}

bitmask=1<<4; //Umwälzung zwischen den beiden Boilern
// Umwälzen und Aufheizen findet niemals zusammen statt, daher diese Abfrage zuerst
if ((bitmask & relais_byte)>0)
{
lcd.setCursor(2, 2);
lcd.print(F("<"));
//lcd.printByte(1);
for (int i=0;i<=11;i++)
{
lcd.print(F("-"));
//lcd.printByte(6);
}
lcd.print(F(">"));
//lcd.printByte(2);
}
else
{
lcd.setCursor(2, 2);
lcd.print(F("I"));
//lcd.write(uint8_t(0));
lcd.print(F(" "));
lcd.print(F("I"));
//lcd.write(uint8_t(0));
}

bitmask=1<<1; //Aufheizung: "|"
if ((bitmask&relais_byte)>0)
{
bitmask=1<<3; //Aufheizung des kl. (0) o. gr. (1) Boilers

if ((bitmask&relais_byte)==0)
{
lcd.setCursor(2, 2);
lcd.print(F("I"));
//lcd.write(uint8_t(0));
lcd.print(F(" "));
lcd.print(F("+"));
//lcd.printByte(3);
for (int i=0;i<=4;i++)
lcd.print(F("-"));
//lcd.printByte(6);
lcd.print(F(">"));
//lcd.printByte(2);
}
else
{
lcd.setCursor(2, 2);
lcd.print(F("<"));
//lcd.printByte(1);
for (int i=0;i<=5;i++)
{
lcd.print(F("-"));
//lcd.printByte(6);

}
lcd.print(F("+"));
//lcd.printByte(4);
lcd.print(F(" "));
lcd.print(F("I"));
//lcd.write(uint8_t(0));
}
}
else
{
}

bitmask=1<<6; //Entnahme aus kleinen (1) bzw. großen Boiler (0)
if ((bitmask & relais_byte)>0)
{
lcd.setCursor(2, 0);
lcd.print(F(">"));
//lcd.printByte(2);
lcd.print(F("WW"));
lcd.setCursor(13, 0);
lcd.print(F(" "));
lcd.print(F("I"));
//lcd.write(uint8_t(0));
}
else
{
lcd.setCursor(2, 0);
lcd.print(F("I"));
//lcd.write(uint8_t(0));
lcd.print(F(" "));
lcd.setCursor(13, 0);
lcd.print(F("WW"));
lcd.print(F("<"));
//lcd.printByte(1);
}

// und zum Schluss das Relais der Auffüllung zeigen, falls es auf 300 zeigt und damit umsonst arbeitet
bitmask=1<<3; //Entnahme aus kleinen (1) bzw. großen Boiler (0)
if ((bitmask&relais_byte)>0)
{
lcd.setCursor(9, 2);
lcd.print(F("<"));
//lcd.printByte(4);
}

if (arbeitsmodus == 0)
{
lcd.setCursor(7, 0);
lcd.print(F("Auto"));
}
else
{
lcd.setCursor(7, 0);
lcd.print(F("Man "));
}
}


void expanderWrite(byte data)
{ // Ansteuerung der Expander-Karte
Wire.beginTransmission(expander_relais);
Wire.write(data);
delay(100); // um evtl. Stromstösse o.ä. durch Relais ? abzuwarteb
Wire.endTransmission();
delay(300); // um evtl. Stromstösse o.ä. durch Relais ? abzuwarteb
// lcd_init(); // um das Kaulderwelsch zu beseitigen, nicht mehr nötig
}


void expanderWrite_o_delay(byte data)
{
Wire.beginTransmission(expander_relais);
Wire.write(data);
Wire.endTransmission();
}


byte expanderRead(int i2caddr)
{
int _data = -1; // Returnwert bei Fehlern ist "-1"!! // wäre abzufangen!
Wire.requestFrom(i2caddr, 1);
if (Wire.available())
{
_data = Wire.read();
}
return _data;
}


int byte_bit_abfragen(byte by, int stelle)
{
int bitmaske = 1 << stelle;
if ((bitmaske&by)>0)
return 1;
else
return 0;
}


byte relais_bit_setzen(byte rel_byte, unsigned int Position, boolean wert)
{
unsigned int bitmaske = 1 << Position;
byte vb=0;

if (wert==0)
{
vb=((~bitmaske)&rel_byte);
}
else
{
vb=(rel_byte|bitmaske);
}
return vb;
}


void relais_byte_senden_o_delay (byte vb)
{
vb=~vb; // Das Relaisbyte muss vor dem Senden invertiert werden, da nur bei bit=low das Relais schaltet!!
expanderWrite_o_delay(vb); //... und rüberschieben zur Relaiskarte
}


void relais_byte_senden (byte vb)
{
vb=~vb; // Das Relaisbyte muss vor dem Senden invertiert werden, da nur bei bit=low das Relais schaltet!!
expanderWrite(vb); //... und rüberschieben zur Relaiskarte
}


void temp_archivieren(int fuehler, float temp)
{
/*Serial.println("temp_archivieren!");
TEMP_SENSOR_L[fuehler][temp_pointer[fuehler]]=temp;
if ((temp_pointer[fuehler]+1)==large_archiv_groesse)
{
temp_pointer[fuehler]=0;
}
else
{
temp_pointer[fuehler]=temp_pointer[fuehler]+1;
}
*/
}


void temp_erfassung_ausgabe()
{
time=millis();
if (time>=time_z1)
{
time_d=time-time_z1;
}
else
{
time_d=4294967295-time_z1;
time_d=time_d+time;
}

if ((time_d>10000)) // wurde vor mehr als x Sek gemessen? Dann führe erneute Messung durch!
{
get_temperature();
//temp_archivieren(k,TEMP_SENSOR[k]);
time_z1=millis();
lcd_ausgabe();
neue_temp_da=1;
daten_ablegen_versenden(); // zusammenstoepseln passiert in derdem unterprg.; Daten zu Cosm schaffen
}
else
{
neue_temp_da=0;
}
}


float mittelwert_L_berechnen(int fuehler)
{
/* Serial.println("mittelwert_berechnen!");
float mittelwert=0;
for (int a=0;a<large_archiv_groesse; a++)
{
mittelwert=mittelwert+TEMP_SENSOR_L[fuehler][a];
}
return (mittelwert/large_archiv_groesse);
*/
}


char keypad_ergebnis() // Abfrage des Keypads; evtl. unnötig, wird z.Z. nicht benutzt
{
char k = kpd.getKey();
if (k != 0)
return k;
}


void temp_ausgabe_serial()
{
for (int i=0; i<=5; i++)
{
Serial.print(TEMP_SENSOR[i],1);
Serial.print(F(" ("));
// Serial.print(mittelwert_L_berechnen(i),2);
Serial.print(F(")"));
Serial.print(F(" - "));
}

Serial.print(F(" --- "));
Serial.write(itoa(relais_byte,test,10));
Serial.print(F(" --- "));
Serial.write(itoa(relais_vorschlag_byte,test,10));
Serial.println();
}


byte relais_bit_wechseln(byte vb, byte pos)
{
// Serial.println("relais_bit_wechseln!");
byte bitmask2=1<<pos;
vb=vb^bitmask2;
return vb;
}


boolean sommer_feststellen()
{
if (TEMP_SENSOR[3]>sommer_temp_solarboiler)
return 1;
if (TEMP_SENSOR[3]<45)
return 0;
}


void sendData() // zu COSM
{
// this method makes a HTTP connection to the server:
// if there's a successful connection:
if (client.connect(server, 80))
{
Serial.println(F("connecting..."));
// send the HTTP PUT request:
client.print(F("PUT /v2/feeds/"));
client.print(FEEDID);
client.println(F(".csv HTTP/1.1"));
client.println(F("Host: api.pachube.com"));
client.print(F("X-PachubeApiKey: "));
client.println(APIKEY);
client.print(F("User-Agent: "));
client.println(USERAGENT);

client.print(F("Content-Length: "));
client.println(strlen(temp_string), DEC);

// last pieces of the HTTP PUT request:
client.print(F("Content-Type: text/csv\n"));
client.println(F("Connection: close\n"));
Serial.print(F("Laenge des Strings: ")); // was kommt bei der Laenge des Contents heraus??
Serial.println(strlen(temp_string), DEC);

// here's the actual content of the PUT request:
Serial.println(temp_string);
client.println(temp_string);

Serial.print(F("Nun der Archiv-String: "));
Serial.println(temp_a_string);

// note the time that the connection was made:
lastConnectionTime = millis();
}
else
{
// if you couldn't make a connection:
Serial.println(F("connection failed"));
Serial.println();
Serial.println(F("disconnecting."));
client.stop();
}
}


void daten_ablegen_versenden()
{
// if there's incoming data from the net connection, send it out the serial port.
// This is for debugging purposes only:
while (client.available())
{
char c = client.read();
Serial.print(c);
}

// if there's no net connection, but there was one last time then stop the client:
if (!client.connected() && lastConnected)
{
Serial.println();
Serial.println(F("disconnecting.."));
client.stop();
}

// if you're not connected, and ten seconds have passed since
// your last connection, then connect again and send data:
// war: if (!client.connected() && (millis() - lastConnectionTime > postingInterval)) // soll ich das !client.connected() herausnehmen????
if (millis() - lastConnectionTime > postingInterval) // soll ich das !client.connected() herausnehmen????
{
cosm_daten_zusammenstoepseln();
sendData(); // temp_string wird verschickt
sd_karte_archivieren();
}

// store the state of the connection for next time through the loop:
lastConnected = client.connected();
}


void cosm_daten_zusammenstoepseln()
{
// Serial.println("daten_zusammenstoepseln!");

strcpy (temp_string,"sensor0"); strcat(temp_string,",");
strcat(temp_string,(dtostrf(TEMP_SENSOR[0],3,2,tmp)));
strcat(temp_string,"\n");

strcat (temp_string,"sensor1"); strcat(temp_string,",");
strcat(temp_string,(dtostrf(TEMP_SENSOR[1],3,2,tmp)));
strcat(temp_string,"\n");

strcat (temp_string,"sensor2"); strcat(temp_string,",");
strcat(temp_string,(dtostrf(TEMP_SENSOR[2],3,2,tmp)));
strcat(temp_string,"\n");

strcat (temp_string,"sensor3"); strcat(temp_string,",");
strcat(temp_string,(dtostrf(TEMP_SENSOR[3],3,2,tmp)));
strcat(temp_string,"\n");

strcat (temp_string,"sensor4"); strcat(temp_string,",");
strcat(temp_string,(dtostrf(TEMP_SENSOR[4],3,2,tmp)));
strcat(temp_string,"\n");

strcat (temp_string,"sensor5"); strcat(temp_string,",");
strcat(temp_string,(dtostrf(TEMP_SENSOR[5],3,2,tmp)));
strcat(temp_string,"\n");


strcat(temp_string,"relais0"); strcat(temp_string,",");
strcat(temp_string,(itoa(byte_bit_abfragen(relais_byte,0),test,10)));
strcat(temp_string,"\n");

strcat(temp_string,"relais1"); strcat(temp_string,",");
strcat(temp_string,(itoa(byte_bit_abfragen(relais_byte,1),test,10)));
strcat(temp_string,"\n");

strcat(temp_string,"relais3"); strcat(temp_string,",");
strcat(temp_string,(itoa(byte_bit_abfragen(relais_byte,3),test,10)));
strcat(temp_string,"\n");

strcat(temp_string,"relais4"); strcat(temp_string,",");
strcat(temp_string,(itoa(byte_bit_abfragen(relais_byte,4),test,10)));
strcat(temp_string,"\n");

strcat(temp_string,"relais6"); strcat(temp_string,",");
strcat(temp_string,(itoa(byte_bit_abfragen(relais_byte,6),test,10)));
strcat(temp_string,"\n");

strcat(temp_string,"manuell"); strcat(temp_string,",");
strcat(temp_string,(itoa(arbeitsmodus,test,10)));
strcat(temp_string,"\n");

// nun Archiv_string zusammenstoepseln
// unsigned long epoch2 = 1363644467; // ja, es geht :-)

unsigned long epoch2 = epoch + (millis()-letzte_zeit) / 1000;

strcpy(temp_a_string," "); strcat(temp_a_string,(ltoa(epoch2,tmpp,10)));

strcat(temp_a_string,","); strcat(temp_a_string,(dtostrf(TEMP_SENSOR[0],3,2,tmp)));
strcat(temp_a_string,","); strcat(temp_a_string,(dtostrf(TEMP_SENSOR[1],3,2,tmp)));
strcat(temp_a_string,","); strcat(temp_a_string,(dtostrf(TEMP_SENSOR[2],3,2,tmp)));
strcat(temp_a_string,","); strcat(temp_a_string,(dtostrf(TEMP_SENSOR[3],3,2,tmp)));
strcat(temp_a_string,","); strcat(temp_a_string,(dtostrf(TEMP_SENSOR[4],3,2,tmp)));
strcat(temp_a_string,","); strcat(temp_a_string,(dtostrf(TEMP_SENSOR[5],3,2,tmp)));

strcat(temp_a_string,","); strcat(temp_a_string,(itoa(byte_bit_abfragen(relais_byte,0),test,10)));
strcat(temp_a_string,","); strcat(temp_a_string,(itoa(byte_bit_abfragen(relais_byte,1),test,10)));
strcat(temp_a_string,","); strcat(temp_a_string,(itoa(byte_bit_abfragen(relais_byte,3),test,10)));
strcat(temp_a_string,","); strcat(temp_a_string,(itoa(byte_bit_abfragen(relais_byte,4),test,10)));
strcat(temp_a_string,","); strcat(temp_a_string,(itoa(byte_bit_abfragen(relais_byte,6),test,10)));
strcat(temp_a_string,","); strcat(temp_a_string,(itoa(arbeitsmodus,test,10)));
}


void lcd_reset()
{ // jede 600 Sek. = 10 Min
time=millis();
if (time>=time_z2)
{
time_d=time-time_z2;
}
else
{
time_d=4294967295-time_z2+time;
}
if (time_d>600000) // wurde vor mehr als XXX Sek gemessen? Dann führe erneute Messung durch!
{
lcd_init();
lcd.clear();
lcd_ausgabe();
zeit_lcd_ausgabe();
time_z2=millis();
}
}


int freeRam()
{
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}


void sd_karte_archivieren()
{

digitalWrite(10, HIGH); // deaktiviere Ethernet
digitalWrite(4, LOW); // aktiviere SD-Card

SD_Datei = SD.open("heizung.csv", FILE_WRITE); // hier ist der name der Datei auf der SD-Karte abgespeichert
if (SD_Datei)
{
Serial.print(F("Writing to FILE..."));
SD_Datei.println(temp_a_string);
// close the file:
SD_Datei.close();
Serial.println(F("done."));
}
else
{
// if the file didn't open, print an error:
Serial.println(F("error opening file on SD-card"));
}

digitalWrite(4, HIGH); // deaktiviere SD-Karte
digitalWrite(10, LOW); // aktiviere Ethernet

// vgl. http://macherzin.net/article27-Arduino-Kommunikation-Ethernet
// hier aber mit dem PIN 8, und nicht 4 - noch zu klären
}


unsigned long sendNTPpacket(IPAddress& address)
{
//send an NTP request to the time server at the given address
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;

// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer,NTP_PACKET_SIZE);
Udp.endPacket();
Serial.println(F("NTP-Paket gesendet" ));
}


void unixtime_umrechnen_aktualisieren()
{
unsigned long epoch2 = epoch + (millis()-letzte_zeit) / 1000;
stunde=(epoch2 % 86400L) / 3600 + 2; // Anpassung GMT an BERLIN
minute=(epoch2 % 3600) / 60;
sekunde=(epoch2 % 60); //
}


void zeitabfrage_ausgabe()
{
// Quelle: Sketch-Beispiel für die Zeit
if((millis()-letzte_zeitanforderung>1000)&&(zeitpaket_angefordert==true))
{
zeitpaket_angefordert=false; // gleich den Schalter zurücksetzen

if ( Udp.parsePacket() )
{
letzte_zeit=millis();
zeitpaket_geliefert=true;
// We've received a packet, read the data from it
Udp.read(packetBuffer,NTP_PACKET_SIZE); // read the packet into the buffer
//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, extract the two words:
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
Serial.print(F("Seconds since Jan 1 1900 = " ));
Serial.println(secsSince1900);

// now convert NTP time into everyday time:
Serial.print(F("Unix time = "));
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;
epoch = secsSince1900 - seventyYears; // subtract seventy years
Serial.println(epoch);

unixtime_umrechnen_aktualisieren();

// print the hour, minute and second:
Serial.print(F("The UTC time is ")); // UTC is the time at Greenwich Meridian (GMT)
Serial.print(stunde,DEC); // print the hour (86400 equals secs per day)
Serial.print(F(":"));
if ( ((epoch % 3600) / 60) < 10 )
{
Serial.print(F("0"));// In the first 10 minutes of each hour, we'll want a leading '0'
}
Serial.print(minute,DEC); // print the minute (3600 equals secs per minute)
Serial.print(F(":"));
if ( (epoch % 60) < 10 )
{
Serial.print(F("0"));// In the first 10 seconds of each minute, we'll want a leading '0'
}
Serial.println(sekunde,DEC); // print the second
}
else
{
zeitpaket_geliefert=false;
}
}

if((zeitpaket_angefordert==false)&&(millis()-letzte_zeit>600000))
{
Serial.println(F("Anforderung der ZEIT"));
sendNTPpacket(timeServer); // send an NTP packet to a time server
letzte_zeitanforderung=millis();
zeitpaket_angefordert=true;
lcd.clear(); // regelmaessig den screen säubern
lcd_ausgabe();
zeit_lcd_ausgabe();
}
}


void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(BOUD_RATE);
delay(500);

analogReference(INTERNAL1V1);

/* pinMode(8, INPUT);
pinMode(9, INPUT);
pinMode(10, INPUT);
pinMode(11, INPUT);
pinMode(12, INPUT);
pinMode(13, INPUT);
*/

Serial.println(F("Setup SD beginnt 1"));
// disable w5100 SPI while setting up SD
pinMode(4,OUTPUT);
pinMode(8,OUTPUT);
pinMode(10,OUTPUT);
pinMode(53, OUTPUT); // Nur MEGA: Pin 53 fuer SD-Card
Serial.println(F("Regulaeres Setup beginnt 2"));
digitalWrite(4, LOW); // aktiviere SD-Karte
digitalWrite(10,HIGH); // deaktiviere Ethernet

if(SD.begin(4) == 0)
Serial.println(F("SD failed"));
else
Serial.println(F("SD ok"));

digitalWrite(4, HIGH); // deaktiviere SD-Karte - oder doch die 6?
digitalWrite(10, LOW); // aktiviere Ethernet
Serial.println(F("SD-Card Setup beendet"));

// start the Ethernet connection:
if (Ethernet.begin(mac) == 0)
// Ethernet.begin(mac, ip, gateway, subnet); // starte Ethernet! verbaucht weniger platz
// delay(1000); // warten auf Ethernet
{
delay(1500);
Serial.println(F("Failed to configure Ethernet using DHCP"));
// DHCP failed, so use a fixed IP address:
Ethernet.begin(mac, ip, gateway, subnet);
delay(1500);
}
Serial.println(F("Success to configure Ethernet using DHCP"));


time_z1=time_z2=letzte_zeitanforderung=time_d=time=letzte_zeit=millis(); // alle Zwischenstände beim Start auf praktisch Null setzen

// -----------------------------------------

Wire.begin(); // für den Anschluss der Expander-Karte
delay(500);
Serial.println(F("setup1 erfolgreich"));

kpd.begin(); // Keypad initialisieren
delay(500);
Serial.println(F("setup2 erfolgreich"));
Udp.begin(localPort);// für UDP
delay(500);
Serial.println(F("setup3 erfolgreich"));
//Ansteuerungs-Byte der Relaiskarte auf null setzen
relais_byte=0;
relais_byte_senden(byte(0)); // für ein Reset alles auf 0!

Serial.println(F("setup4 erfolgreich"));

lcd_init(); // initialize the lcd
lcd.clear();
lcd_ausgabe();
zeit_lcd_ausgabe();

temp_3_alt=analogRead(TEMP_SENSOR_PIN[(3)]); // eine einfache Ermittlung reicht hoffentlich beim Setup

Serial.println(F("Success with whole setup"));

/*
for (int i=0; i<=5; i++)
{ //TEMP_SENSOR[i]=0; // aktuelle Werte auf Null setzen

temp_pointer[i]=0; // Pointer setzen!
for (int j=0;j<=large_archiv_groesse;j++)
{
TEMP_SENSOR_L[i][j]=0; // auch alle Archivwerte auf 0 setzen
}
}
*/

/* // damit wird die clock speed verändert!
// TWBR = 152;
TWBR = 158;
TWSR |= _BV (TWPS0); // inkl. prescaler! macht eine Freq von 12,5 kHz
*/

/* für die spätere Einbindung der SD-Karte
pinMode(4, OUTPUT); // PIN 4 fuer Kommunikation mit SD-Karte
pinMode(10, OUTPUT); // PIN 10 fuert Kommunikation mit Ethernet
pinMode(53, OUTPUT); // Nur MEGA: Pin 53 fuer SD-Card
*/
}


void loop()
{
relais_vorschlag_byte=relais_byte;
temp_erfassung_ausgabe(); // wird nur jede X Sek wirklich durchgeführt

zeitabfrage_ausgabe();
zeit_lcd_ausgabe();

key=0;
key=kpd.getKey(); // neu, war: key=keypad_ergebnis();


if (key==0 && neue_temp_da==0)
{
// leeren Key und keine Temp-Veränderung da nicht neu gelesen, abfangen!!
}
else
{
if (key=='A') { arbeitsmodus=0; lcd_reset(); lcd_ausgabe(); }
if (key=='B') { arbeitsmodus=1; lcd_reset(); lcd_ausgabe(); }
if (key=='D') // RESET des LCD und der Relaiskarte
{
lcd_reset();
lcd_ausgabe(); // vorläufig; hier detailliertere Infos ausgeben
zeit_lcd_ausgabe();
relais_byte_senden(relais_byte);
lcd.setCursor(4,2);
lcd.print(F("mem"));
lcd.print(freeRam());
}

if (arbeitsmodus==1) // MANUELL
{
if (key=='0' || key=='1' || key=='3' || key=='4' || key=='6')
{
key2=key-48;
relais_vorschlag_byte=relais_bit_wechseln(relais_vorschlag_byte, key2);
}
else
{
if (key=='A' || key=='B' || key=='D' || key==0 )
{
// zulässige Eingaben ausschliessen
}
else
{
lcd.clear(); // Fehlermeldung("Falsche Taste")
lcd.setCursor(0, 2);
lcd.print(F("Nur [0,1,3,4,6,A,B]"));
delay(1000); // obwohl es ein delay ist, ist es gerade hier richtig
lcd.clear();
lcd_ausgabe(); // aktuellen Zustand am LCD erneut anzeigen
zeit_lcd_ausgabe();
}
}
}

if (arbeitsmodus==0) // AUTOPILOT
{
if ((relais_byte&B00001000)==0) {Heizung_3WV=0;} else {Heizung_3WV=1;} // Heizung_3WV auf 1 bei 300l-, auf 0 bei 500l-Boiler
// Serial.print("Stellung des 3WV ist ermittelt: ");Serial.println(Heizung_3WV);
relais_vorschlag_byte=relais_byte; // sicherheitshalber
// Serial.print("gesetzt auf autopilot\n"); // gesetzt auf manuell
if (key=='D') // Reset des LCD und der Relaiskarte
{
lcd_reset();
lcd.clear();
lcd_ausgabe(); // vorläufig; hier detailliertere Infos ausgeben
zeit_lcd_ausgabe();
relais_byte_senden(relais_byte);
lcd.setCursor(4,2);
lcd.print(F("mem"));
lcd.print(freeRam());
}

// Prüfung der Vorlauftemperatur, um evtl. die Zusatzpumpe anzuwerfen

if (TEMP_SENSOR[4]>=max_temp_vorlauf) // falls Temp Vorlauf zu hoch, die Zusatzpumpe einschalten!
{
// Serial.print("Temp Vorlauf >= Temp B o !!");
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,0,1);
}
else
{
// Serial.print("Temp Vorlauf <= Temp B o !!");
if (TEMP_SENSOR[4]<=(max_temp_vorlauf-zusatzpumpen_hysteresis))
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,0,0);
}
}

// Boilerauswahl

if (TEMP_SENSOR[2]-TEMP_SENSOR[0]>0) // Temp des großen Boilers größer als die des Kleinen...
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,6,0); //... großen Boiler als WW-Quelle auswählen
}
else
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,6,1); // ... kleinen Boiler als WW-Quelle auswählen
}
if (TEMP_SENSOR[0]>45)
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,6,1); // ... kleinen Boiler als WW-Quelle auswählen
}

// Umwälzung der Boiler im Sommer

if ((relais_byte&B00010000)==0) // falls Boileraustausch nicht stattfindet (==0)
{
if ((sommer_feststellen()==1) && //Festlegung, wann es zur Umwälzung kommen soll: Falls Sommer und ...
((TEMP_SENSOR[2]-TEMP_SENSOR[1])>10) && //Temp.Differenz zwischen großen und kleinen Boiler >10 Grad und ...
(TEMP_SENSOR[2]>max_B_temp) && //Temp-Gr-Boiler > max. zulässige Temp und ...
(TEMP_SENSOR[0]<=60)) //Temp-Kl-Boiler <= max. zulässige Temp und ...
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,0); // Befüllung stoppen (falls sowoeso nicht gestoppt!)
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,4,1); // Umwälzung zw den Boilern beginnen
}
}

if ((relais_byte&B00010000)>0) // falls Boileraustausch stattfindet (>0)
{
if ((sommer_feststellen()==0) ||
((TEMP_SENSOR[2]-TEMP_SENSOR[1])<5) || // falls Temp-Differenz zw. Gr-Boiler und Kl-Boiler unter 5 Grad fällt oder...
(TEMP_SENSOR[2]<=50)) // || // falls Temp Gr-Boiler unter 45 Grad fällt oder ...
//TEMP_SENSOR[0]>max_B_temp) // falls Temp Kl-Boiler größer als max zulässige Boiler-Temp
// Festlegung, wann die Umwälzung aufhören soll! Sommer_feststellen wohl nicht erforderlich :-)
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,4,0); // Umwälzung zw den Boilern stoppen
}
}

// Aufheizung der Boiler im Winter

if ((relais_byte&B00000010)>0) // Prüfung, ob der Boiler gerade aufgeladen wird
{
// Serial.print("Die Aufheizung des Boilers laeuft.\n"); // Eine Meldung ausgeben
if (key=='#') // wenn Heizung manuell als Ziel ausgewählt wird
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,0); // Auffüllen des Boilers beenden, Relais schließen
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,3,0); // dazu das 3WV-Relais in den Ruhezustand schalten
// Serial.print("Sie haben # ausgewaehlt, Boiler wird geschlossen, das 3WV in Ruhezustand versetzt\n"); // Eine Meldung ausgeben
// temp_ausgabe_serial();
}

if (TEMP_SENSOR[(2-Heizung_3WV*2)]>max_B_temp) // falls die Temp des gerade befüllten Boilers oben größer als erlaubte Temp ...
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,0); // ... die Befüllung des Boilers beenden
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,3,0); // auch das 3WV-Relais in den Ruhezustand schalten
// Serial.print("Aufheizung des Boilers wird gleich unterbrochen werden, da die Temperatur des Boilers inzwischen groesser als erlaubt ist!\n");Serial.print(TEMP_SENSOR[(2-Heizung_3WV*2),2]); // Eine Meldung ausgeben
// evtl. später eine entsprechende LCD-Meldung einbauen
// temp_ausgabe_serial();
}

if (TEMP_SENSOR[4]<(TEMP_SENSOR[2-2*Heizung_3WV]+2)) // Vorlauf um 2 Grad kleiner als Temperatur des geschalteten Boilers oben?
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,0); // ... die Befüllung des Boilers beenden
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,3,0); // auch das 3WV-Relais in den Ruhezustand schalten
// Serial.print("Aufheizung des Boilers wird gleich unterbrochen werden, da der Vorlauf inzwischen nicht mehr ausreicht!\n"); // Eine Meldung ausgeben
// evtl. später eine entsprechende LCD-Meldung einbauen
// temp_ausgabe_serial();
}
}
else // falls der Boiler gerade nicht aufgeladen wird
{
// Serial.print("Die Aufheizung des Boilers findet nicht statt\n"); // Eine Meldung ausgeben
if (key=='#') // wenn Heizung als Ziel ausgewählt wird
{
// Serial.print("Sie haben # ausgewaehlt, Heizung ist jedoch bereits als Ziel ausgewaehlt\n"); // Eine Meldung ausgeben
// temp_ausgabe_serial();
}
if (key=='*') // wenn Boiler als Ziel ausgewählt wird
{
if ((TEMP_SENSOR[2]<=max_B_temp)&&((TEMP_SENSOR[2]+2)<TEMP_SENSOR[4])) // 500l-Boiler-Temp kleiner als max.Temp und kleiner als Vorlauf-Temp
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,3,0); // auch das 3WV-Relais in den Ruhezustand = 500l-Richtung schalten
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,1); // ... die Befüllung des entsprechenden Boilers beginnen
// Serial.print("Sie haben * ausgewaehlt, max. Temp des gr. Boilers ist noch nicht erreicht und der Vorlauf ist fuer den gr. Boiler warm genug, also wird der gr. Boiler aufgeladen\n"); // Eine Meldung ausgeben
// temp_ausgabe_serial();
}
else // falls Boiler befüllt werden soll und Gr-Boiler warm genug ODER der Vorlauf reicht zum Erwärmen des großen Boilers nicht aus
{
// Serial.print("Sie haben * ausgewaehlt, max. Temp des gr. Boilers ist bereits erreicht oder der Vorlauf ist fuer den gr. Boiler nicht warm genug (evtl. aber fuer den 300l-Boiler)\n"); // Eine Meldung ausgeben
if ((TEMP_SENSOR[0]<=max_B_temp)&&((TEMP_SENSOR[0]+2)<TEMP_SENSOR[4])) // 300l-Boiler-Temp kleiner als max.Temp und kleiner als Vorlauf-Temp
{
// Serial.print("Sie haben * ausgewaehlt, max. Temp des kl. Boilers ist noch nicht erreicht und der Vorlauf ist fuer den kl. Boiler warm genug, also wird der kl. Boiler aufgeladen\n"); // Eine Meldung ausgeben
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,3,1); // auch das 3WV-Relais in den Ruhezustand = 500l-Richtung schalten
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,1); // ... die Befüllung des entsprechenden Boilers beginnen
// temp_ausgabe_serial();
}
else
{
// Serial.print("Sie haben * ausgewaehlt, max. Temp auch des kl. Boilers ist bereits erreicht oder der Vorlauf ist fuer den kl. Boiler nicht warm genug, also wird auch er nicht aufgeladen\n"); // Eine Meldung ausgeben
// temp_ausgabe_serial();
}
}
}
}
} // Hier endet der Anweisungsblock für den Arbeitsmodus = 0

// Prüfung ob sich Daten geändert haben, wenn ja -> LCD neu zeichnen UND Byte setzen und schalten

if (relais_byte==relais_vorschlag_byte)
{
relais_byte_senden_o_delay(relais_byte); // ... und senden
// Serial.print("Keine Aenderng des Vorschlagsbytes eingetreten\n"); // gesetzt auf manuell, keine Änderung nötig
// temp_ausgabe_serial();
}
else // Relais_byte und Vorschlagsbyte sind ungleich
{
// Serial.print("Aenderng des Vorschlagsbytes eingetreten\n"); // gesetzt auf manuell
if (((relais_vorschlag_byte&B00000010)>0 && (relais_vorschlag_byte&B00010000))>0) // Kollision zwischen Auffüllen und Umwälzen abfangen, dann nichts machen!
{
relais_vorschlag_byte=relais_byte; // das manipulierte Vorschlag-Byte zurücksetzen auf den Ursprungswert
// Serial.print("Achtung: KOLLISION\n");
}
else
{ // wenn es aber keine Kollision gibt, Vorschlagsbyte als Relaisbyte übernehmen ...
// Serial.print("Keine KOLLISION\n");
relais_byte=relais_vorschlag_byte;
relais_byte_senden(relais_byte); // ... und senden
lcd_ausgabe();
}
} // Ende der Ausgabe
} // Ende der Verarbeitungsschleife, wenn key != 0
} // Ende der loop-Funktion

Keine Kommentare:

Kommentar veröffentlichen