Arduino aus Programm reseten?

du könntest auch mit einem Temperatursensor den du auf den Arduino setzt die Oberflächentemperatur des Controllers messen und bei Überschreitung einer Grenztemperatur einen Lüfter einschalten, falls Platz und geeignete Luftzufuhr das zulassen. Wäre vielleicht eine übertriebene Art, aber sollten bei einem Reset die Messdaten verloren gehen wäre Kühlkörper oder eben der Lüfter vielleicht eine bessere Alternative... ich weiß ja nicht wo der Arduino läuft in welcher Umgebung :wink:

Gruß,
Tobi

Für mich ist diese Diskussion immernoch sinnlos, da der Kontroller nur heiß wird, wenn ihm zuviel Strom abverlangt wird und in dem Fall passiert es innerhalb kurzer Zeit. Ein Reset nutzt da gar nichts außer das Programm durcheinanderzubringen.

Addi, was willst Du überhaupt bauen?

Grüße Uwe

Hab mir jetzt einen Lüfter gekauft und an den Arduino angebaut. Allerdings gibt es einen
Fehler in der Ansteuerung den ich mir nicht erklären kann. Ich lese die Temperatur aus und
wen die Temperatur ein Maximum überschreitet wird der Kühler angeschaltet(bei 18 °C). Der
Wert über die Serielle Schnittstelle ausgegeben. Wen der Wert nun 18°C erreicht springt die Temperatur
um 0.8° . Hier der Code:

int readTemperature() 
{
  ADCSRA |= _BV(ADSC); 
  while (bit_is_set(ADCSRA, ADSC)); 
  return (ADCL | (ADCH << 8)) - 342; 
}

float averageTemperature()
{
  readTemperature(); 

  float averageTemp; 
  for (int i = 1; i < 1000; i++) 
    averageTemp += ((readTemperature() - averageTemp)/(float)i); 

  return averageTemp; 
}

bool kern_temp(float max) {
float temp = averageTemperature();
if (temp >= max) {
  return true;
  } else {
  return false;
  }
}

void setup() 
{
  pinMode(13, OUTPUT);
  Serial.begin(9600); 
  ADMUX = 0xC8;  
  delay(10);
}

void loop() 
{
  Serial.print(averageTemperature()); 
  Serial.println(" C");
  bool hot = kern_temp(18);
  if (hot) {
  digitalWrite(13,HIGH);
  }
  else{
  digitalWrite(13,LOW);
  }
  delay(500); 
}

Hier ein Ausschnitt der Ausgabe im Seriellen Monitor:

17.99 C
17.99 C
18.00 C
18.00 C
17.99 C
18.00 C
18.71 C
18.83 C
18.90 C
18.88 C
18.84 C
(...)
18.04 C
18.03 C
18.02 C
18.03 C
18.01 C
17.63 C
17.41 C
17.32 C
17.25 C
17.23 C
17.19 C
17.16 C
17.06 C
17.19 C
17.29 C
17.26 C
17.28 C
17.32 C

Woran kann das liegen?
Edit: Hab gerade bemerkt, dass wenn ich den Lüfter abtrenne, bevor 18°C gemessen werden,
auf dem Seriellen Monitor keine Sprünge angezeigt werden.
Addi

Addi:
Woran kann das liegen?

Spannungsänderung Deiner Schaltung beim Einschalten des Lüfters.

Da Deine Temperaturmessung offenbar eine Spannungsmessung an einem Analogpin ist, führt jede Spannungsänderung an der Referenzspannung unmittelbar auch zu einer "Temperaturänderung".

Kann man das umgehen?

Addi

jurs:

Addi:
Woran kann das liegen?

Spannungsänderung Deiner Schaltung beim Einschalten des Lüfters.

Da Deine Temperaturmessung offenbar eine Spannungsmessung an einem Analogpin ist, führt jede Spannungsänderung an der Referenzspannung unmittelbar auch zu einer "Temperaturänderung".

Sollte eigentlich keine Rolle spielen, da Addi den AD-Wandler für die Chiptemperatur des Atmega abfragt und als Referenz die internen 1,1V nutzt. Das scheint mir eher ein Frage der Genauigkeit zu sein. Im Datenblatt wird 1mV/°C angegeben, das entspricht nur ungefähr 1Bit. Schau dir mal die ungemittelten Werte an. Die Genauigkeit wird nicht vergrößert über eine Mittelwertbildung.

Ich finde eine Mittelwertbildung über 999 Werte etwas sehr übertrieben.
Außerdem ist die Mittelwertbildung etwas kurios:
"averageTemp += ((readTemperature() - averageTemp)/(float)i); " oder anders gesagt:
mittelwert = mittelwert+ ((meßwert*-mittelwert)/i)*
Daß heißt, daß der erste Meßwert viel mehr Einfluß auf den Mittelwert hat weil er durch 1 geteilt wird, als der 999-ste Meßwert.
ist der Mittelwert nicht
mittelwert = (summe meßwert ) / 999
oder
mittelwert = mittelwert + ((meßwert*-mittelwert)/999)*
wobei i von 1 bis 999 gezählt wird.
Grüße Uwe

Hab den Code aus einem anderen Thread entnommen.

Addi

uwefed:
Außerdem ist die Mittelwertbildung etwas kurios:

Dass die Mittelwertbildung "kurios" ist, weil er irgendwie versucht einen "gleitenden Mittelwert" zu bilden (''wohl vermutlich weil seine Thermostatschaltung keine Hysterese beim Ein- und Ausschalten vorsieht), ist gar nicht mal das große Problem, die Mittelwertbildung ist aber sogar falsch, weil sie mit einer nicht initialisierten Variablen startet, hier mal mit ergänzten Kommentaren:

float averageTemperature()
{
  readTemperature(); // Wert lesen, Wert wegwerfen, wird nirgends ausgewertet
  float averageTemp;  // Deklariere eine nicht initialisierte Variable
  for (int i = 1; i < 1000; i++)  // und rechne im ersten Schleifendurchlauf mit dieser Variablen irgendwas aus!
    averageTemp += ((readTemperature() - averageTemp)/(float)i); 
  return averageTemp;  // Rückgabewert ==> Datenmüll, verbessert durch 1000-fache Iteration
}

Addi:
Hab den Code aus einem anderen Thread entnommen.

Es ist vielleicht eine gute Idee, guten und funktionierenden Code zu übernehmen.
Aber das ist bei dem Code nicht der Fall.

Du rechnest eine Durchschnittstemperatur aus, und im ersten Schleifendurchlauf ist diese Durchschnittstemperatur "irgendein Startwert", und mit 1000 Schleifendurchläufen wird dieser Startwert dann allmählich an den Messwert angenährt. Da kann nur besserer Datenmüll bei rauskommen.

In dem Fall kann der Sprung im Wert auch durch das Umschalten selbst verursacht sein: Da zwischendurch eine andere Funktion ausgeführt wird, liegt anderer Datenmüll im Speicher, aus dem der Mittelwert ermittelt wird.

Also entweder die Mittelwertbildung testweise mal ganz rausschmeissen:

float averageTemperature()
{
  return readTemperature(); 
}

Oder den Mittelwert vor der kuriosen Mittelwertbildung auf den tatsächlich gemessenen Wert setzen:

float averageTemperature()
{
  float averageTemp=readTemperature();
// Oder: float averageTemp=0;
  for (int i = 1; i < 1000; i++) 
    averageTemp += ((readTemperature() - averageTemp)/(float)i); 
  return averageTemp; 
}

Und dann mal sehen, ob beim Schaltvorgang immer noch ein Sprung auftritt.

BTW: Fehlende Hysterese!
Ein Thermostat darf nicht auf den Punkt ein- und ausschalten! Wenn der Messwert "gerade an der Grenze ist", und im Sekundentakt zwischen 17,99 und 18,00 hin- und herspringt, dann würde an diesem Schaltpunkt der Regler im Sekunden- oder Millisekundentakt ständig ein- und ausschalten, hunderte Schaltvorgänge in kurzer Zeit ausführen, und das Relais oder die Heizung in kurzer Frist ruinieren! Für Zweipunkt-Regler müßte immer eine "Hysterese" als "Einschaltbereich" (statt Einschaltpunkt) vorgesehen werden. Also wenn die Temperatur auf 18,00 Grad geregelt werden soll, dann wird die Kühlung beispielsweise bei überschreiten von 18,30 Grad eingeschaltet und erst bei Unterschreiten von 17,70 Grad wieder ausgeschaltet. Und in dem Bereich dazwischen wird immer der aktuelle Schaltzustand beibehalten.

Hab den Code jetzt angepasst, die Temperatursprünge bleiben trotzdem.

Addi

Addi:
Hab den Code jetzt angepasst, die Temperatursprünge bleiben trotzdem.

Schaltung?

Was erhälst Du, wenn Du keinen Mittelwert bildest sondern den Wert 1 mal liest und diesen dann verwendest?
Grüße Uwe

Schaltung ist relativ simpel: Lüfter mit Pin 13 und GND verbunden.
Wenn ich den Code zur Mittelwertbildung entferne bleiben die Temperatursprünge.

Addi

Aha zu hohe Stromhitze kühlen mit noch mehr Stromverbrauch.

Keine Gute Idee würde ich sagen

Addi:
Schaltung ist relativ simpel: Lüfter mit Pin 13 und GND verbunden.
Wenn ich den Code zur Mittelwertbildung entferne bleiben die Temperatursprünge.

Du jagst also den vom Lüfter verbrauchten Strom (wieviel Strom? Leistung des Lüfters?) durch den Controller.
Und Du misst die Temperatur im Controller.

Dass der Strom durch den Controller auch eine Verlustleistung erzeugt (genau deshalb dürfen die I/O Pins ja nur mit einem bestimmten Maximalstrom beaufschlagt werden), die zur Erwärmung des Controllers beiträgt, ist Dir aber schon klar?

jurs:
Du jagst also den vom Lüfter verbrauchten Strom (wieviel Strom? Leistung des Lüfters?) durch den Controller.

Der Lüfter braucht 12V bei einem Watt.

Addi

Addi:
Der Lüfter braucht 12V bei einem Watt.

Also bei Nennspannung 12V mal 1/12A = 1 Watt.

Bei 5V betrieben also 5/12 * 1/12 = 5/144 = 0,0347 A = rund ca. 35 mA.

Plus einiger Milliampere, die die Pin13 LED an Pin13 ja auch noch braucht, dürftest Du an Pin13 damit insgesamt knapp über die maximal am Pin zulässigen 40 mA kommen.

Wenn Du genau wissen möchtest, mit wieviel Milliwatt der Atmega beim Einschalten des Lüfters zusätzlich geheizt wird, müsstest Du mal den Spannungsabfall am Atmega messen, oder die Differenz bilden aus Board-Spannung und Spannung am Lüfter. Aber ein paar Milliwatt werden das bedingt durch den durch den Controller geleiteten Lüfterstrom durch den Atmega schon sein.

jurs:

Addi:
Der Lüfter braucht 12V bei einem Watt.

Also bei Nennspannung 12V mal 1/12A = 1 Watt.

Bei 5V betrieben also 5/12 * 1/12 = 5/144 = 0,0347 A = rund ca. 35 mA.

Plus einiger Milliampere, die die Pin13 LED an Pin13 ja auch noch braucht, dürftest Du an Pin13 damit insgesamt knapp über die maximal am Pin zulässigen 40 mA kommen.

Wenn Du genau wissen möchtest, mit wieviel Milliwatt der Atmega beim Einschalten des Lüfters zusätzlich geheizt wird, müsstest Du mal den Spannungsabfall am Atmega messen, oder die Differenz bilden aus Board-Spannung und Spannung am Lüfter. Aber ein paar Milliwatt werden das bedingt durch den durch den Controller geleiteten Lüfterstrom durch den Atmega schon sein.

Ein Motor ist kein linearer Widerstand. Diese Verhältnisrechnung kannst Du so nicht machen. Der Stromverbrauch hängt von den Verlusten im Motor, der Elektronik und der Belastung ab. Ein 12V Lüfter läuft an 5V gar nicht sicher an. Ich rate ab, den Lüfter direkt am Pin anzuschleißen. Es braucht immer einen Transistor und benutze einen 5V Lüfter.

Grüße Uwe

Hallo Uwe,
habe beim stöbern diesen Thread gefunden. Ich selbst möchte auch den Arduino via externem Processing Programm reseten.
Ich habe dies gefunden:

void(*resetFunc)(void) = 0;

Funktioniert, aber nicht immer. Ist Dein Vorschlag etwas anders, sprich besser? Und überhaupt, wo habt ihr diese Dinge her? :astonished: :slight_smile:

LG
Willi

Das ist brachial. Ein Funktionszeiger auf NULL. Ist mir auch schon aus Versehen passiert, aber es nicht etwas was man absichtlich machen sollte.

EDIT:
Das ist glaube ich nicht eine x-beliebige Funktion. Die Idee dahinter ist, dass er in den Reset Interrupt Vektor springt, der bei µC auf Adresse 0 ist...sollte es also theoretisch gehen.

Der absolut korrekte und sichere Weg ist über den Watchdog Timer:
http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_softreset

Man startet den Watchdog Timer, geht in eine Endlosschleife und 15ms später spring der Controller in den Reset Vektor, da der WTD nicht zurück gesetzt wird. Alles mit Mitteln die auch genau dafür vorgesehen sind und sich so verhalten wie definiert.

#include <avr/wdt.h>
...
#define soft_reset()        \
do                          \
{                           \
    wdt_enable(WDTO_15MS);  \
    for(;;)                 \
    {                       \
    }                       \
} while(0)

Muss auch kein Makro sein. Man kann das genauso in eine Funktion schreiben