Wie µC Haupttakt im Sketch ändern?

Hallo,

habe verschwommen in Erinnerungen, dass man den Takt von 16MHz auf 8 oder 1MHz live im Sketch ändern kann. Nur wie geht genau? Dafür muß man doch bestimmt am “CLKPR – Clock Prescale Register” rumfummeln.

Trifft das genau dafür zu? Bin mir nicht sicher. Hab nur das gefunden im Netz.

http://playground.arduino.cc/Main/PowerSaving

int oldClkPr = CLKPR;  // save old system clock prescale
  CLKPR = 0x80;    // Tell the AtMega we want to change the system clock
  CLKPR = 0x08;    // 1/256 prescaler = 60KHz for a 16MHz crystal
  delay( .... warte .... );    // since the clock is slowed way down, delay(n) now acts like delay(n*256)
  CLKPR = 0x80;    // Tell the AtMega we want to change the system clock
  CLKPR = oldClkPr;    // Restore old system clock prescale

Mit Prescaler 256 würde der µC mit 62,5kHz weiter takten? Ausgehend von 16MHz.

Für 1MHz müßte ich
CLKPR = 0x04; // 1/16 prescaler für 1MHz
setzen ?

Mehr muß man nicht machen? Irgendwelche Wartezeiten einfügen für das umschalten?

http://www.nongnu.org/avr-libc/user-manual/group__avr__power.html

Hallo,

Beschreibung war die gleiche, also hab ich ausprobiert. Auf Tastendruck schaltet der Takt um. Geile Sache !!! :slight_smile:
Nur die serielle funktioniert nicht solange der Takt 1 MHz ist. Benötige ich aber in dem Fall dann auch nicht.
Ist eine reine Sicherheitssache die ich bei mir einbauen werde.

/*
 
 Arduino Mega 2560

 Bounce2 Library
 https://github.com/thomasfredericks/Bounce-Arduino-Wiring/tree/master/Bounce2

*/

#include <Bounce2.h>

#define Taster_LED  2
#define Takt_LED    3

byte Taster_Clocktakt = 6;             // Clocktakt umschalten auf Tasterdruck an Pin 6 
byte _Taster_Clocktakt_Zustand = LOW;  // nur erneutes Taster drücken, Low Pegel, wird detektiert

Bounce debouncer2 = Bounce();          // Instantiate a Bounce object Nr.2 (2. Taster Clocktakt)

void setup()  {
  
  pinMode(Takt_LED, OUTPUT);        
  digitalWrite(Takt_LED, LOW);  
  
  pinMode(Taster_LED, OUTPUT);        
  digitalWrite(Taster_LED, LOW);
    
  debouncer2.attach(Taster_Clocktakt);
  debouncer2.interval(30);                        // Entprellzeit 30ms
        
  // digitalen Eingang mit PullUp aktivieren  

  pinMode(Taster_Clocktakt, INPUT);               // setzt Pin als Eingang
  digitalWrite(Taster_Clocktakt, HIGH);           // und aktiviert dessen PullUp Widerstand 
    
}   // Ende setup


void loop(void) {
  
  Clocktakt_umschalten();  
  
  LED_blinken();
 
}   // Ende loop

/* ------------------------------------------------------------------------------------------------ */

boolean Clocktakt_umschalten ()
{
  boolean stateChanged_2 = debouncer2.update();
  int state_2 = debouncer2.read();
  static boolean state_Clock = LOW;
  static int old_ClkPr = 0;
  
  // wenn LOW Signal vom Taster erkannt, schalte Takt um
  if ( stateChanged_2 && state_2 == LOW ) {
    if ( state_Clock == LOW ) {
      state_Clock = HIGH;
      // Takt umschalten auf 1MHz
      old_ClkPr = CLKPR;     // save old system clock prescale
      CLKPR = 0x80;          // Tell the AtMega we want to change the system clock
      CLKPR = 0x04;          // 1/16 prescaler = 1MHz for a 16MHz crystal
      digitalWrite(Taster_LED, state_Clock);  
      } 
      else {
        state_Clock = LOW;
        // Takt umschalten auf 16MHz
        CLKPR = 0x80;        // Tell the AtMega we want to change the system clock
        CLKPR = old_ClkPr;   // Restore old system clock prescale
        digitalWrite(Taster_LED, state_Clock);  
      }   
  }
}


void LED_blinken()
{
  static boolean state_LED = LOW;
  static unsigned long millis_LED = 0;
    
  // lasse LED blinken, je nach Takt 1:1 oder es dauert die 16fache Zeit
                  
     if (state_LED == LOW && millis() > millis_LED )  {
       digitalWrite(Takt_LED, HIGH);        // LED einschalten für
       millis_LED = millis() + 100;         // 100ms
       state_LED = HIGH;
     }
     if (state_LED == HIGH && millis() > millis_LED )  {
       digitalWrite(Takt_LED, LOW);         // LED ausschalten für
       millis_LED = millis() + 600;         // für 600ms
       state_LED = LOW;
     }   
}

Edit:
Kommentare im Sketch geändert, stand noch alter Mist da, von meinem anderen Sketch

Wieso brauchst Du das denn?
Grüeß Uwe

Hallo,

mein Mega wird mal von einem Akku versorgt, deshalb auch der Sleepmode. Erinnerst Du Dich? Jetzt bin ich dran, wenn die Versorgungsspannung sinkt, sprich der Akku leer wird, dass sich der µC erstmal runtertaktet, weil dann kann er mit geringer Spannung erstmal noch sicher weiterarbeiten. Sämtliche Peripherie wird natürlich nicht mehr bedient. Vorallendingen werden sofort sämtliche Zugriffe auf die SD-Karte gesperrt.

Das ich jetzt mit Taster umschalte dient ja nur zum testen. Im Code wird dann an Hand der gesunken Ub die Taktsenkung ausgelöst. Ich wollte den Testcode nur erstmal jeden zur Verfügung stellen, als Bsp., interessiert vielleicht noch mehr Leute. Ich versuche ja nicht nur zu fragen, sondern wenn möglich hier und da Lösungen anzubieten, soweit ich mir sicher bin das es funktioniert. Ich teste immer erstmal neue Dinge im kleinen Rahmen bevor ich sie im großen Projekt übernehme.

Es hat keinen Sinn einen ganzen Arduino im Slepmodus zu betreiben. Die Elektronik die zusätzlich zum ATmega2560 vorhanden ist wird nicht in den Sleepmodus versetzt und verbraucht darum munter weiter Strom. Damit der Sleepmodus Sinn hat mußt Du einen Standalone bauen.
Das Datenblatt sagt nichts über den Betriebmodus den Du verwenden willst aus (Niedrige Frequenz durch Prescaler und niedrige Versorgungspannung). Darum weiß ich nicht ob dieser so zulässig ist.

Es sit sinnvoller Du verwendest einen stromsparenden DC/DC Converter und versorgst die Schaltung konstant mit 3,3V. Alle Periferie muß in Sleepmodus geschaltet werden können oder abgeschaltet werden. Zum Abschalten braucht es eine dafür geeignetes Schaltungsdesign.

Grüße Uwe

Hallo,

warum soll das keinen Sinn machen? Ich gehe da anders ran. Warum soll ich mir die Mühe machen eine Platine mit nackten µC aufzubauen, wenn ich dann eh viele Dinge die schon da sind drumherum bauen muß. Da baue ich lieber Dinge ab die nicht benötigt werden.

Siehe http://forum.arduino.cc/index.php?topic=258307.new;topicseen#new

Vielleicht haste das ja nicht mehr in Erinnerung gehabt. Nehme ich jetzt mal stark an. Der Spannungsregler ist schon runter und der 16U2 wird in Reset gehalten. Letzteres hatte den größten Effekt. Dann benötigt der Arduino nur noch 9,9mA. Davon gehen dann nochmal 2mA weg, wenn die Power LED auch noch entfernt wurde.

Skoby wollte seinen nackten 2560er mal vermessen. Darauf warte ich heute noch. :slight_smile: Dann könnte man sehen was es bringen würde, wenn der 16U2 ganz weg wäre. Oder kannst Du mir das sagen? Ansonsten ist aus meiner Sicht nichts weiter drauf auf der Arduino Platine.

Mein Arduino Mega2560 läuft ja ansonsten im Sleepmode, wird aufgeweckt, macht paar Messungen, speichert diese und legt sicher hin. Und für den Fall das der Akku schwach wird, takte ich ihn sicherheitshalber sofort runter, sodass er noch arbeiten kann und bring ihn in eine Endlosschleife wo er nichts mehr machen kann. Bis ich den Akku gewechselt bzw. geladen haben und einen Reset gemacht habe. Der einzigste Großverbraucher wäre das Bluetooth-Modul, was ich aber per High-Side Switch komplett lahm lege, wenn ich es nicht benötige. Ein 3,3V DC/DC Wandler hilft mir nicht, weil nicht alles 3,3V kompatibel ist.

Und wegen Deinen Bedenken zum Betriebsmodus. Laut Datenblatt arbeitet er bei max. 2MHz bis runter auf 1,8V. Wobei aber schon der Code im Bootloader auf 2,7V eingestellt sein soll zum "abschalten".

Einwände? Bedenken?

Hallo,

hab den Code noch vervollständigt zum rumspielen. Wird ein Schwellwert unterschritten, taktet er sich runter und eine andere LED blitzt. Ist Ub wieder größer, taktet er wieder normal und es blinkt wieder die erste LED vor sich hin. Einfach geil! :smiley:
Wenn es genau werden soll, muß man seine interne 1,1V Referenz ausmessen und den Wert im Code ändern. Für eine genaue Schwellwertumschaltung.

Clocktakt_aendern_004.ino (4.7 KB)

Ich denke, Uwe fragt, was der runtergetaktete µC denn noch machen soll, ohne Serial, ohne SD, ohne andere Peripherie ?

Na gut, ein "Batterie Low" Warnblitzer evtl, aber viel besser als komplett abschalten zum Batterie schonen ist es nicht...

Aber trotzdem Danke, hab ich nicht gewusst, dass sich der Takt so einfach im laufenden Betrieb runtersetzen lässt.

Ich frag mich eher: Macht es einen Unterschied, ob man bei niedrigem Takt schläft oder bei normalem. Hangt evtl. auch vom Schlaf-Modus ab.

Hallo,

ich dachte ich hätte das schon ausführlich beschrieben, mit dem wofür. Ich lege den Arduino komplett lahm, sobald die Ub zu niedrig ist. Und das ich sehe das etwas nicht stimmt, lasse ich eine LED blitzen, solange wie Ub noch etwas Saft hat. Und das die LED auch blitzen kann, und nur das darf er noch machen, muß der µC ja weiterhin funktionieren in seiner gefangenen Endlosschleife. Deswegen takte ich runter. Laut Datenblatt kann dann die Ub weiter abfallen bis 1,8V bei max. 2MHz. Erst dann ist wirklich Ende im Gelände. Laut Bootloadercode schaltet er aber schon bei 2,7V ab. Meiner schaltet wirklich bei ca. 2,7V ab. Ab ca. 3Volt fängt er wieder an, wenn ich die Spannung wieder langsam hoch drehe.

Man kann den dann auch noch mit einem Pin selbst im Code reseten. Wenn man das möchte.

Im großen "Projektcode" lasse ich den Arduino natürlich nicht wieder selbstständig anlaufen. Muß ja eh Hand anlegen zum Akku wechseln o.ä.

Aber wenn jemand bei irgendwelchen kurzzeitigen Spannungsschwankungen in eine Art Save-Mode gehen will, könnte er den Code so als Basis nehmen.

Jetzt verständlicher?

Verzeih mir, daß ich nicht alles im Kopf behalte was ich hier lese und was Du bereits an Informazionen bezüglich Deines Projekts geschrieben hast.

Daß der Atmega bei 2,7V abschaltet wird der Brown-out Reset sein, der via Fuse auf verschiedene Schaltschwellen gestellt werden kann. Die mögliche Grenzwerte sind 1,8V, 2,7V und 4,3V

Damit Du noch mehr Strom sparst muß Du auf dem Arduino auch den Operationsverstärker ablöten. Außerden nehmen es die meisten Schaltkreise bzw Module die Böse wenn Du die Versorgungsspannung kapst aber die Signale immernoch vorhanden sind. Diese müssen ebenfalls entweder LOW sein oder hochohmig.

Wie Machst Du die Pegelumsetzung von 5V auf 3,3V?

Viel Grüße Uwe

Brownout Detection kann man auch per Software abschalten. Siehe die BODS und BODSE Bits im MCUCR Register.

  // turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);  // turn on brown-out enable select
  MCUCR = bit (BODS);        // this must be done within 4 clock cycles of above
  sleep_cpu ();              // sleep within 3 clock cycles of above

EDIT:
Das ist aber glaube ich nur temporär während dem Schlafen. Um es permanent auszuschalten muss man wie gesagt die Fuses anfassen.

Hallo,

ich bin niemanden böse. Du kannst nicht von jedem Typen hier seine Basteleien abspeichern und Status merken.

Der Arduino schaltet also bei 2,7V intern ab. Okay, hab kein Problem damit. Läßt mir genügend Luft.

Du meinst den LMV358 OPV IC7? Kann es sein, dass wenn ich den auslöte, ich den Arduino nicht mehr per USB wie gewohnt flashen und betreiben kann? Weil der unten im Teilschaltplan dann die USB 5V nicht mehr durchschaltet? Die Versorungsspannung wäre mir im Grunde egal. Gehe später eh direkt ran. Nur jetzt zum programmieren wäre USB nicht verkehrt.

Du meinst, wenn ich das BT-Modul abschalte aber die Datenleitungen noch verbunden sind. Den Hinweis hattest Du schon gegeben :slight_smile: , ich habe 1kOhm Widerstände in der seriellen Leitung. Wobei das BT-Modul einen MAX232 davor geschalten hat. Der sollte das abkönnen. :slight_smile:

Pegelumsetzung? Ich habe selbst keine Pegelumsetzung. Beim BT-Modul, SD-Karten Modul und RTC sind die Spannungs/Signalpegel-Wandler schon drauf.

Kann ich den Arduino Mega2560 irgendwie so programmieren, dass er Standardmäßig mit 8MHz arbeitet und dennoch alle Timings im Sketch stimmen wie angegeben ohne umzurechnen und so weiter?. Wegen den millis, die serielle und SPI und I2C Schnittselle usw. Das würde mir noch mehr Luft mit der Spannungsversorgung verschaffen bis 2,7V runter. Die IDE hat leider keine vordefinierte 8MHz Variante in der Boardauswahlliste.

Ich habe mir nämlich zur Akkuversorung folgendes z.Z. überlegt. Ich könnte so ein Smartphone Akkupack nehmen. Die haben eine große Kapazität zum günstigen Preis mit USB und Ladeschaltung alles drin. Bevor ich mir eine nackte Lipo zulege und das drumherum beachten muß. Ich weis nur noch nicht wie dessen Ausgangsspannung behandelt wird wenn intern der Akku zur Neige geht. Ob hart abgeschalten wird, wäre blöd für mich oder ob noch Luft nach unten bleibt.

Bei 16MHz muß ich sicher gehen, das bei weniger wie 4,5V ich das schnell mitbekomme. Meine loop ist meistens in niedrigen einstelligen ms durch, nur wenn die Dallas DS18.... ausgelesen werden dauert's paar ms länger. Außerdem frage ich die µC Ub sofort nach aufwecken ab und direkt vorm SD-Karten Zugriff. Das sollte sicher genug sein. Meinen Schwellwert im Code könnte ich nahe "Kante" festlegen, so 4,8V. Sollte reichen. Oder ich muß den Lade-Akkupack öffnen und zusätzlich die echte Akkuspannung abgreifen zum messen. Da wird ja intern bestimmt ein DC-DC Wandler drin sein zwischen Akku und USB Buchse.

Der Arduino schaltet also bei 2,7V intern ab. Okay, hab kein Problem damit. Läßt mir genügend Luft.

Er schaltet nicht ab sondern geht in Reset und bleibt dort bis die Spannung über einen gewissen Wert steigt (weiß nicht den genuen Wert weil einen Hysterese drin ist).

LMV358

Muß den Schaltplan nochmal kontrollieren, Heute Abend. Notfalls ist der Transistor auch zu überbrücken. Wie versorgst Du den Arduino genau? Über den 5V pin??

Wobei das BT-Modul einen MAX232 davor geschalten hat. Der sollte das abkönnen.

Hast Du kein BT Modul gefunden, das kein RS232 Schnittstelle hat? Wäre sinnvoller im Bezug auf Batteriestromersparnis.

Pegelumsetzung? Ich habe selbst keine Pegelumsetzung. Beim BT-Modul, SD-Karten Modul und RTC sind die Spannungs/Signalpegel-Wandler schon drauf.

Wenn das über Spannungsteile gemacht ist dann haben diese eine Verlustleistung. Ok wenn Du das Modul nicht mehr mit Spannung versorgst dann hast Du auch nicht mehr diese Verluste. Für Batteriebetrieb ist diese Wahl aber nicht die beste.

Ich könnte so ein Smartphone Akkupack nehmen.

Das müßte 5V geben und dann abschalten. Du kannst immernoch einen Kabel an den +Pol der Batterie anschließen und so die Batteriespannung ablesen.

Grüße Uwe

Hallo,

LMV358
Lohnt sich der Ausbau wirklich? Laut Datenblatt genehmigt er sich nur paar µA. Im Vergleich zur Sleepmode Stromaufnahme von 9,9mA (ohne Power LED 7,9) ist das eigentlich ohne Effekt.

Aber gut, falls doch. Der OPV steuert ja den FDN340P an. Da mein 5V Spannungsregler eh schon fehlt, zieht der OPV das Gate jetzt schon dauerhaft auf 0V. Ist doch richtig? Entweder ich lege Gate dann mit einer Brücke auf Masse oder ich bauen den Mosfet auch noch aus und verbinde "Drain-Source" mit einer Brücke.

Den Arduino ohne Spannungsregler versorge ich nach dem flashen (über USB) mit 5V direkt am Power 5V Pin.

BT Modul
Zum damaligen Kaufzeitpunkt hatte ich mir noch keine Gedanken ums Strom sparen gemacht. Nur verwenden alle RS232. Da ich aber nicht ständig BT nutzen werden, nur bei Bedarf, sollte das keine Rolle spielen.

Hallo,
naja, ohne Spannungsregler im Sleepmode hatte ich 9,9mA.
Mit Ausbau vom IC7 (OPV) und T1 (Mosfet) komme ich nun auf 9,6mA. Bei 4,96V gemessen direkt am Arduino.
Brachte nicht so viel. Zwar sinnvoll, aber war nicht der erhoffte Bringer.
Da bleibt doch wirklich nur noch der Ausbau vom 16U2? Der sich im Reset-Zustand bestimmt immer noch wenige mA gönnt. Oder? Wie seht ihr das?

Und warum ist der Schwellwert für die Brownout Detection mit 2,7V so niedrig angesetzt? Hab ich mir gerade überlegt. Wenn der µC mit 16MHz mindestens 4,5V benötigt.