Microsekundengenaues Timeout

Hallo,
ich versuche schon seit einiger Zeit einen Sketch mit sekundengenauem Timeout zu erstellen.
Das Problem ist wie folgt:

| ______ | < Neustart der Funktion|> ______
^ ^
Start ------------------------------------------------>1 Sek---------------------------->

  • Das heist ein periodischer Timer von einer Sekunde wird gestartet
  • Dann solle eine Funktion gestartet werden
  • die Funktion soll im Programm abgearbeitet werden.
  • Danach geht das Programm schlafen
  • ...und wird nach exakt nach einer Sekunde wieder geweckt

Ich habe schon mit der Watchdog-Funktion gearbeitet aber das Tut nicht richtig.

Such mal hier im Forum nach dem Nachtwächter (kein Scherz)

Micros auf Arduino zählt nur in 4er-Schritten. Wobei eine absolute Genauigkeit auf Microsekunden mit normalen Arduinos eine Illusion ist. So genau sind die Resonatoren nicht.

Da müssten schon mehr Infos zum Verwendungszweck kommen, um sinnvolle Wege aufzuzeigen.

Gruß Tommy

RTC und das 1 Hz Signal verwursten wäre mein 1. Ansatz.

Hallo,
vielen Dank für Eure Antworten.
@Klaus: Ich habe nicht vor weitere HW (RTC etc.) zu verwenden.
@Moko: Ich glaube dass die Nachtwächter-Funktion mein Problem nicht löst.
@Tommy56: Das stimmt. Die Uhr sollte aber etwas genauer gehen wie eine Kuckucksuhr. Also 1-2 Minuten/Woche
Mein Projekt sieht wie folgt aus:

  • Es soll eine elektromechanische Uhr werden die mit einer Batterie betrieben wird.
  • Diese sollte alle Sekunden einen Motor um ein Stück weiterdrehen.
  • Damit die Batterie nicht schon nach einem Tag aufgebraucht ist, also sollte der Arduino "schlafen gelegt" werden.
  • Das Heist es sollen alle Verbraucher abgeschaltet werden nur die Clock sollte weiterlaufen.

Ich habe mal versucht ein Diagram zu machen (siehe Anhang)
Da gibt es was wie:

power_adc_disable(); /* Analog-Eingaenge abschalten /
power_spi_disable(); / SPI abschalten /
power_timer0_disable(); / Timer0 abschalten /
power_timer2_disable(); / Timer0 abschalten /
power_twi_disable(); / TWI abschalten */

Damit habe ich rumexperimentiert.Es ist aber nix Vernünftiges dabei rausgekommen.
Hat damit schon jemand gearbeitet?

Watchdog-Timer.pdf (50 KB)

Hallo,

ich kann mit nicht vorstellen daß das was wird, selbst wenn du auf das "schlafen gehen" verzichtest wird das eine Eieruhr. Die Quarz Frequenzen sind zu ungenau, u.A. werden desshalb RTC verwendet. Man kann das sicher 1-2 Stunden laufen lassen müsste dann aber mal wieder synchronisieren. Sieihe NTP Uhren.

Heinz

Hallo noiasca,
die zeit für einen Sekundenschritt ist ca. 5 ms.
Zum Stromverbrauch kann ich bisher nichts sagen.

Es soll eine elektromechanische Uhr werden die mit einer Batterie betrieben wird.
Diese sollte alle Sekunden einen Motor um ein Stück weiterdrehen.
Damit die Batterie nicht schon nach einem Tag aufgebraucht ist, also sollte der Arduino "schlafen gelegt" werden.
Das Heist es sollen alle Verbraucher abgeschaltet werden nur die Clock sollte weiterlaufen.

Dann muss die Sekunde NICHT auf 1µs eingehalten werden.
Sondern nur im Mittel.

Im Grunde ist das doch ganz einfach....

  • Man nimmt einen nackten ATMega328P.
  • Lässt ihn mit 1 oder 8 MHz internem Takt laufen.
  • Timer2 läuft mit einem Uhrenquarz im asynchronen Modus.
  • Sleep, wenn nix zu tun ist.

Eine solche Kombination läuft bei mir schon seit ca 5 Monaten an einer CR2032.
Allerdings ohne Motor.

Und meine Heizkörper Thermostate beinhalten: Display Motor ATMega169P und 2 AA Batterien Uhrenquarz.
Laufzeit mit einem Satz Batterien ca 24 Monate.

Hier mal das Grundgerüst:

/**
 * 
 *  http://www.netzmafia.de/skripten/hardware/Arduino/Sleep/index.html
 *  
 */



#include <util/atomic.h>
#include <avr/sleep.h>
#include <CombiePin.h>
#define CriticalSection ATOMIC_BLOCK(ATOMIC_RESTORESTATE)


Combie::Pin::OutputPin<LED_BUILTIN> led;

volatile unsigned long uptime = 0; // in sec

unsigned long getUptime()
{
  unsigned long temp = 0;
  CriticalSection
  {
    temp = uptime;
  }
  return temp;
}


unsigned long millis()
{
  unsigned long temp = 0;
  byte counter;
  CriticalSection
  {
    counter = TCNT2;
    temp = uptime;
  }
  temp *= 1000;
  temp += (1000UL * counter) / 256; 
  return temp;
}

void goSleep()
{
  set_sleep_mode(SLEEP_MODE_PWR_SAVE);
  sleep_bod_disable();
  sleep_mode();
/* wake up here */
 // sleep_disable();
}

int main()
{
  led.init();
  ASSR   = (1<< AS2);             // Timer2 asynchron takten
  _delay_ms(1000);               // Einschwingzeit des 32kHz Quarzes
  TCCR2A = 0;
  TCNT2=0;
  TCCR2B = 5;                     // Vorteiler 1sec  Überlaufperiode
  while((ASSR & (1<< TCR2BUB)));  // Warte auf das Ende des Zugriffs
  TIFR2  &= ~(1<<TOV2);           // Interrupts löschen
  TIMSK2 |= (1<<TOIE2);           // Timer overflow Interrupt freischalten

  sei();

  for(;;)
  {
    goSleep();
    // hier Zeiger bewegen.
  }
}


ISR(TIMER2_OVF_vect) 
{
  sleep_disable();
  uptime++;
  led.toggle();  
}

Also.
Wenn Du es genau haben willst (sagen wir einige Sekunden pro Jahr bis zu einige Minuten pro Jahr) brauchst Du einen Quarz.
Die Möglichkeiten sind zB die von combie wo der Controller einen externen Uhrenquarz bekommt und dieser das Timing macht. Der Takt wird vom ungenauen RC Oszillator gemacht, aber der muß nicht genau sein.
Das bedeutet daß man die Platine selbst bauen muß.

Alternativen sind einen Arduino ohne Zusatzelektronik zu nehmen (Arduino MINI, PRO MINI oder MICRO) und eine RTC anzuschließen. Die meisten RCT haben die Genauigkeit von einigen Minuten pro Jahr; die DS3231 sind da genauer weil Temperaturkompensiert und man kommt schon auf Sekundenabweichungen. Der Vorteil von externen RTC ist, daß man die Uhrzeit und Datum zur Verfügung hat und somit den Motor auch auf eine bestimmte Stelle plazieren kann nachdem die Schaltung eingeschaltet wurde. Den Arduino kann man in sleepmodus bringen und durch ein 1Hz Signal des RTC aufwecken und den Motor bewegen.

Grüße Uwe

Man muss es ja nicht RTC nennen..

Ich meine der Ds3231 hat als Standard ein 32Khz Signal aktiviert das auf wenige Sekunden im Jahr genau ist..

Das Signal startet nach der Initialisierung, dafür benötigt man einmalig das i2C bis die Knopfzelle leer ist.

Ich lege das Signal nur für Timings auf einen Interrupt Eingang und Zähle für z.B. Sekunden 32768 Interrupts.

Hi

Wenn Du die RTC das Teilen überlässt (den Strom nimmt Die dafür eh), kannst Du auch immer +1 zählen und somit 32767 öfter schlafen (ok, eigentlich nur 1x, aber immerhin) - also die angesprochenen 1Hz.

MfG

Hallo,
Danke für Eure Beiträge.
ich habe mal noch ein bisschen recherchiert. Da bin ich auf folgende Lösung gestoßen:

#include <avr/power.h>

void setup() {
cli();//stop interrupts

//set timer1 interrupt at 1Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS10 bits for 1024 prescaler
  TCCR1B |= (1 << CS12) | (1 << CS10);  
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);

sei();//allow interrupts
}

void loop()
{
  //bleibt leer oder sonstiger Code.....
}

ISR(TIMER1_COMPA_vect){//timer1 interrupt 1Hz 
  //
  // ========================================================
  // Hier kommt der entscheidende Code der pro Sekunde ausgeführt werden soll
  // ========================================================
}

Wenn du jetzt etwas zum gegenmessen hättest könnte man den Timer Overflow Wert umrechnen damit es auf Zimmertemperatur hinkommt.

Angenommen der Crystal/Resonator schlägt 16.012.120 die sekunde.. macht dann schon 2-3 Sekunden die Stunde..

Hallo Schuppeste,
danke für den Hinweis. Ich glaube mit dieser Genauigkeit kann ich leben.
Den Begriff "sekundengenauesTimeout" habe ich gewählt um mögliche Lösungen wie "delay(xxx)" etc zu vermeiden.
Ich wollte, dass die Hardware die Kontrolle der Zykluslänge übernimmt. Daher die Verwendung des Timers.

Hi

Da delay() auch nur an einem Timer hängt, sehe ich hier keine Erklärung.
Der Arduino 'wartet' auch nur x ISRs ab, um millis um 1 zu erhöhen - mit der gleichen Genauigkeit, Die auch den anderen Timern gegeben ist.

MfG

kwhhSt:
Den Begriff "sekundengenauesTimeout" habe ich gewählt ...

Du hast "Microsekundengenaues Timeout" gefordert und das ist eine völlig andere Baustelle, als das, was Du jetzt behauptest.

Gruß Tommy