immer wieder finde ich im Netz tolle Codes. Nach ersten Tests folgt jedoch oftmals die Ernüchterung, wenn ich den Code dann in bestehende Sketche von mir einbauen möchte, da sie lästige delay-Anweisungen enthalten und somit alles blockieren. >:(
Habt ihr mir Tipps, wie man bestehende Codes delayfrei umbaut?
Mein momentanes Problem ist das hier:
#include <SPI.h>
#include <Ethernet.h>
// this must be unique
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x59, 0x67 };
// change network settings to yours
IPAddress ip( 192, 168, 2, 2 );
IPAddress gateway( 192, 168, 2, 1 );
IPAddress subnet( 255, 255, 255, 0 );
char server[] = "smtpcorp.com";
int port = 2525;
EthernetClient client;
void setup()
{
Serial.begin(115200);
pinMode(4,OUTPUT);
digitalWrite(4,HIGH);
Ethernet.begin(mac, ip, gateway, gateway, subnet);
delay(2000);
Serial.println(F("Ready. Press 'e' to send."));
}
void loop()
{
byte inChar;
inChar = Serial.read();
if(inChar == 'e')
{
if(sendEmail()) Serial.println(F("Email sent"));
else Serial.println(F("Email failed"));
}
}
byte sendEmail()
{
byte thisByte = 0;
byte respCode;
if(client.connect(server,port) == 1) {
Serial.println(F("connected"));
} else {
Serial.println(F("connection failed"));
return 0;
}
if(!eRcv()) return 0;
Serial.println(F("Sending hello"));
// replace 1.2.3.4 with your Arduino's ip
client.println("EHLO 1.2.3.4");
if(!eRcv()) return 0;
Serial.println(F("Sending auth login"));
client.println("auth login");
if(!eRcv()) return 0;
Serial.println(F("Sending User"));
// Change to your base64 encoded user
client.println("xxxx");
if(!eRcv()) return 0;
Serial.println(F("Sending Password"));
// change to your base64 encoded password
client.println("yyyy");
if(!eRcv()) return 0;
// change to your email address (sender)
Serial.println(F("Sending From"));
client.println("MAIL From: <me@mydomain.com>");
if(!eRcv()) return 0;
// change to recipient address
Serial.println(F("Sending To"));
client.println("RCPT To: <you@yourdomain.com>");
if(!eRcv()) return 0;
Serial.println(F("Sending DATA"));
client.println("DATA");
if(!eRcv()) return 0;
Serial.println(F("Sending email"));
// change to recipient address
client.println("To: You <you@yourdomain.com>");
// change to your address
client.println("From: Me <me@mydomain.com>");
client.println("Subject: Arduino email test\r\n");
client.println("This is from my Arduino!");
client.println(".");
if(!eRcv()) return 0;
Serial.println(F("Sending QUIT"));
client.println("QUIT");
if(!eRcv()) return 0;
client.stop();
Serial.println(F("disconnected"));
return 1;
}
byte eRcv()
{
byte respCode;
byte thisByte;
int loopCount = 0;
while(!client.available()) {
delay(1);
loopCount++;
// if nothing received for 10 seconds, timeout
if(loopCount > 10000) {
client.stop();
Serial.println(F("\r\nTimeout"));
return 0;
}
}
respCode = client.peek();
while(client.available())
{
thisByte = client.read();
Serial.write(thisByte);
}
if(respCode >= '4')
{
efail();
return 0;
}
return 1;
}
void efail()
{
byte thisByte = 0;
int loopCount = 0;
client.println(F("QUIT"));
while(!client.available()) {
delay(1);
loopCount++;
// if nothing received for 10 seconds, timeout
if(loopCount > 10000) {
client.stop();
Serial.println(F("\r\nTimeout"));
return;
}
}
while(client.available())
{
thisByte = client.read();
Serial.write(thisByte);
}
client.stop();
Serial.println(F("disconnected"));
}
Also das Delay im Setup brauchst du ja damit die Ethernet Verbindung Zeit hat sich aufzubauen. Ansonsten ist doch alles ok, hab kein weiteres Delay gefunden.
Leider gibt es keinen 1:1 Ersatz delay() gegen millis().
Und das Problem ist auch genaugenommen weniger das delay(1), als die 10000-Schleife aussenrum.
Statt dessen muss jede Funktion ( wie hier sendEmail() ) ausser OK / Fehler auch "noch in Arbeit" zurückmelden. Und muss wieder aufgerufen werden können, um zu prüfen, ob es inzwischen weiter gegangen ist. So wäre zumindest mein Ansatz.
Die "tollen Codes" zeigen dir nur das Prinzip wie etwas generell geht. Wie man das dann mit dem "tollen BlinkWithoutDelay" kombiniert, ist eine andere Sache.
Was macht die Funktion? Hast du an der schon rumgespielt? Ich sehe den Einsatz von respCode und thisByte nicht.
Eine Funktionsbeschreibung wäre ebenfalls nicht verkehrt.
byte eRcv()
{
byte respCode;
byte thisByte;
int loopCount = 0;
while(!client.available()) {
delay(1);
loopCount++;
// if nothing received for 10 seconds, timeout
if(loopCount > 10000) {
client.stop();
Serial.println(F("\r\nTimeout"));
return 0;
}
}
Die Funktion kann man besser aufbauen,
/* Funktion liefert den Wert 1, wenn dieser sich die letzen 10000 nicht zurückgemeldet hat */
int8_t eRcv()
{
static uint16_t error;
const uint16_t max_error = 10000;
// Abfrage, ob Client erreichbar ist, wenn nicht, Wert inkrementieren
if(!client.available()) error++;
else error = 0;
if(error >= max_error) return 1;
else return 0;
}
In der Loop rufst du dann diese Funktion jede ms einmal auf. Sollte die Funktion 1 zurückliefern, stoppst du die Verbindung.
So wie ich das sehe, ist das senden einer Mail (mal wieder) eine Aufgabe für einen endlichen Automaten b.z.w. einer Schrittkette. Und im Zuge des Umbaus auf einen solchen Automaten, kann man dann auch alle Schleifen und Delays entfernen.
Chris72622:
Was meinst Du mit "Schrittkette"?
Switch/case?
Durchaus!
Gibt aber noch mehr Möglichkeiten.
Funktionspointer, Sprungtabellen(Tabelle mit Funktionspointern)
Eigentlich meine ich die Idee, das Konzept, Schrittkette.
Wie man das dann im einzelnen realisiert, ist fast egal.
Ah, jetzt sehe ich es wie du das gedacht hast.
Ist sehr nett, aber eigentlich nicht zwingend nötig. Damit spart man nur ein paar Aufrufe der Funktion. Ansonsten hat man break -> Funktion beenden -> beim nächsten Aufruf kommt sowie das nächste Case dran.
Bau vielleicht mal mehr Debug Ausgaben ein, damit du siehst in welcher Reihenfolge der Code durchlaufen wird. Du lassen sich auch mit millis() verzögern wenn nötig. So lässt sich das schlecht sagen.