hallo, bin ein neueinsteiger in sachen µC, und habe da eine wohl ganz einfache frage an die heads. möchte meinen µC sozusagen in sleep modus fahren(wie ich es mache weiss ich auch noch nicht bis jetzt aber das kommt später) und zwar möchte ich ein timer programmieren der z.B. nach jeder 60s den µC aktiviert zum datenübertragung (z.B. temperatur), und nach der übertragung der µC wieder in sleep modus wechselt bis wieder ein zyklus von 60s vorbei ist und ein aktueller wert übermittelt wird. ist das schwer zu realisieren? kenne mich wie gesagt kaum mit µC aus. wäre über jede hilfe dankbar mfg gunter
Hi, das ist eigentlich nicht schwer zu realisieren, da moderne Controller Sleepmodi haben und das Aufwecken durch interne (timer) oder externe Interrupts unterstützen. Mit welcher µC-Familie willst du denn arbeiten?
Also bei den AVRs ist es so dass Interrupts bei (fast?) allen Sleep-Modi zugelassen werden. Du brauchst dir also darüber nicht den Kopf zerbrechen ob er die Daten dann auch schickt. Ich bin mir aber nicht sicher ob er dann auch wieder automatisch in den sleep mode zurück wechselt. Grundsätzlich wäre es aber ohnehin sinnvoll den sleep() befehl in die endlosschleife (While(1){ ... }) zu packen. Das funktioniert sicher. Wenn du genaueres über die Modi wissen möchstest (wann, wo, was aktiv ist) kann ich dir nur das manual zu herzen legen. da steht meist alles schön übersichtlich drin. also schwer ist das sicherlich nicht was du vor hast. wenns wo probleme gibt einfach melden :)
> Also bei den AVRs ist es so dass Interrupts bei (fast?) > allen Sleep-Modi zugelassen werden. Ganz so einfach ist es dann doch nicht. Man muss schon im Datenblatt nachschauen, ob der zum Aufwachen benötigte Interrupt überhaupt getriggert werden kann in einem bestimmten sleep-modus. Zum Beispiel werden die internen Timer recht schnell abgeschaltet, sodass nur "leichte" Sleep-Modi funktionieren. Mit externem, asynchronem Timer kann man auch tiefere Sleep-Modi benutzen. Beim tiefsten sind allerdings IIRC alle Taktquellen abgeschaltet, sodass nur noch ein Interrupt, der durch einen Interrupt-Pin verursacht wird, zum Aufwachen führt. Hängt aber alles vom konkreten AVR ab, man sollte also in jedem Fall im Datenblatt nachsehen.
Und da reicht nichtmal irgendein externer Int, sondern es muss ein Low-Level-Int aktiviert werden. Denn ein flankengetriggerter Int brauch den Prozessortakt, der aber im "Tiefschlaf" (Power-down) deaktiviert ist. Oder ein spezieller Timer mit externer Taktquelle (Timer2 mit Uhrenquarz bei einigen Megas). Wenn also der Sleep-Mode zum Stromsparen dienen soll, dann ist das nicht ganz so einfach. Es gibt aber noch die Möglichkeit, den Watchdog-Timer zum Wecken zu benutzen. Der kommt aber schon nach wenigen Sekunden, 60s dürften damit (in einem Stück) nicht erreichbar sein. ...
In deinem Falle geht es um's Stromsparen also ist der "tiefste" Sleepmodi gerade gut genug. In diesen Modi geht aber nur noch der Watchdog und dieser ist nicht sehr exakt, was aber nich stören dürfte bei dir. Deine Main() Procedure muß sofort am Anfang überprüfen ob sie durch einen Watchdog IQR aufgerufen wurde, das steht in einem Register des AVR's. Wenn ja inkrementierst du eine globale Variable um den Betrag an Sekunden die der Watchdog eingestellt wurde und arbeitest dann Main() normal weiter so daß dort in eine Endlosschleife geendet wird in der der Sleepmodus wieder aktiviert wird. Hier mal eine vereinfachte Darstellung: int Timer = 0; void Main(void) { _WDR_OFF(); if MCUCSR & (1 << WDRF) { Timer += 1; if Timer >= 60 { Timer = 0; sende Daten } } while (1) do { MCUCR = (1 << SM1) | (1 << SE); WDTCR = (1 << WDP2) | (1 << WDP1) | (1 << WDE); Sleep; } } an Hand des ATMega8 wird hier der Watchdog mit 1 Sekunde eingestellt und der Power Down Sleep Mode gewählt. Der Watchdog kann meistens nicht deine geforderten 60 Sekunden am Stück warten, ca. 2-3 Sekunden sind das Maximum. Gruß Hagen
hallo, danke erstmal für eure informativen antworten. genau wie ihr schon gesagt habt die Sleep-Mode soll zum Stromsparen dienen. habe eure antworten schnell überflogen da ich jetzt keine zeit habe mich damit auseinander zusetzen. werde es aber so schnell wie möglich nachholen. habe ehrlich gesagt nicht ganz verstanden wie es geschehen soll, auch nicht an dem code, kann auch kein assambler, dass wird der grund sein. also was klar ist das ich eine variable inkrementier bis sie = 60 ist dann sende ich die daten. so was ihr jetzt mit der while schleife meint ist mir noch nicht klar. könnt ihr mir die assambler spezifischen code kommentieren? z.B. int Timer = 0; void Main(void) 'Methode (void) { _WDR_OFF(); '??? if MCUCSR & (1 << WDRF) '??? { Timer += 1; 'inkrementierung +1 if Timer >= 60 'wenn>=60, timer =0 { Timer = 0; sende Daten 'routine sende Daten aufrufen? } } while (1) do '??? { MCUCR = (1 << SM1) | (1 << SE); '??? WDTCR = (1 << WDP2) | (1 << WDP1) | (1 << WDE); '??? Sleep; 'in sleep versetzen, bekannter befehl? } } also danke euch, sorry das das alles so wirr ist aber schreibe die nähsten tage klausuren und mache das parallel, was nicht heissen soll das es mich nicht beschäftigt, im gegenteil! gunter
Ehe man sich mit dem Stromsparen beschäftigt, sollte man sich erstmal klarmachen, was man damit erreichen will. Für den einen ist alles unter 1A sparsam, der andere will im Mittel möglichst unter 1µA bleiben. Also mal rüber mit konkreten Zahlen. Was willst Du ? Peter
P.S.: Es werden hier oft die hitzigsten Diskussionen geführt und dann stellt sich heraus, daß alle Annahmen falsch sind, also alles umsonst war. Und nur weil sich der Fragesteller keine Gedanken über das Wesentliche gemacht hat. Peter
@Peter, ich gebe dir grundsätzlich Recht, aber für manchen Fragenden ist der Weg zur richtigen Frage verschlungen :) @Gunter, als erstesmal ist mein obiger Code ein Pseudocode in C, nicht Assembler. Dies zeigt schon mal das du dir erstmal eine Programmiersprache aussuchen musst. Denn deine Frage "ist das schwer zu realisieren" kann nur beantwortet werden wenn man weis wie hoch dein Wissens- und Erfahrungsstand ist. Viele Cracks hier würden spontan antworten "Ja, absolut easy es gibt echt schweres". Viele Anfänger wiederum verstehen noch nichtmal die Antworten die hier gegeben werden. Die Cracks würden gutgemeint denoch immer am Anfänger vorbei reden :=) Dies ist auch der Grund für den Einwurf von Peter, denn um dir die Lösung deines Problemes leichter zu machen ist es am besten das Problem ansich einfacher zu gestalten. D.h. ist es überhaupt nötig für deine Schaltung bis in's letzte mA Strom sparen zu wollen. Im Normalfalle wirst du mit dem Sleepmodus ca. 20mA sparen können. Sollte also deine Peripherie schon 1A Ruhestrom verbrauchen so macht es keinen Sinn mit dem Sleepmodus anzufangen. Du würdest also das Pferd vom falschen Ende her aufzäumen. Ich glaube das meinte auch Peter. Nachdem du deine Software soweit programmiert hast das sie im Normalmode alle 60 Sekunden die Daten schickt, und das auch alles funktioniert ist es wirklich nur eine kleine Softwareänderung um mit dem Stromsparen anfangen zu können. Wichtig ist dabei nur das du dann aber auch das nötige Wissen hast und viele sich ganz von selber erklärt. Wir benötigen also mehr Input von dir. Nun zu meinem Pseudocode: Der Watchdog ist normalerweise ein Schutzmechanismus um Software die durch Programmierfehler sich aufhängt, sprich abnormal weiterläuft, wieder neu zu starten. Dabei ist der Watchdog ein langsamlaufender Timer der durch die Software regelmäßig zurückgesetzt werden muß. Falls dies nun nicht geschiet, das Program also hängt, muß der Watchdog->Wachhund darauf reagieren. Nun man geht davon aus das der Reset ein guter Weg ist dies zu tuen. Ein C Program landet nach einem Reset oder nach dem Einschalten des Processors immer in der Procedure Main(). Und exakt da springt auch der Watchdog hin wenn er auslösst. Man kann nun in Main() durch Auswertung verschiedener Flags des Prozessors unterscheiden ob Main() durch einen normalen Reset oder dem Watchdog aufgerufen wurde. Genau dies macht die erste IF Abfrage. Vorher sollte der Watchdog in deinem Falle deaktiviert werden, wasa ich mit _WDR_OFF() anzeigen wollte. Diese Funktion ist aber unterschiedlich auf den verschiedenen Compilern und für die genaue Vorgehensweise musst du unbedingt das Datenblatt lesen. Nungut, die meisten Main() Proceduren landen auf kurz oder lang in einer Endlossschleife in der der eigentliche Hauptcode läuft. Genau in dieser Schleife wird es eine Stelle geben in der der Prozessor in den Sleepmode geschickt wird. Das wäre im obigen Sourcecode die 3 Zeilen mit dem Sleep; Gruß Hagen
Kann man sich wirklich darauf verlassen, dass der Watchdog nur main() aufruft? Dann müssten doch (durch die avr-libc) sämtliche globalen Variablen, Ausgabepuffer, random-seed und sonstige interne Variablen der libc neu initialisiert werden. Wenn eine globale Variable nur als "int global;" deklariert wurde, dürfte sie das wohl überstehen. Aber schon ein "int global = 0;" (semantisch genau dasselbe wie vorhin) dürfte den Inhalt von global bei einem Watchdogreset leeren. Das erscheint mir sehr unintuitiv und riskant. Dann doch lieber einen externen Uhrenquarz zum Aufwecken. Wäre der Stromverbrauch damit so signifikant höher als beim Watchdog-Wecken? Oder täusch ich mich (ich kenn die avr libc ja nicht so gut)?
"Kann man sich wirklich darauf verlassen, dass der Watchdog nur main() aufruft?" Ja mit klitzekleinem nein :) Auch die Watchdog Routinen im Program könnte die Ursache sein das der Watchdog auslösst, es wird niemals den perfekten Schutz geben können. Aber die Wahrscheinlichkeit für solche Fehler sollte sehr sehr gring sein. Du kannst die also darauf Verlassen das der Watchdog an Address 0x0000 springt und dort steht der Sprungbefehl der auch bei einem Reset angesprungen wird. "Dann müssten doch (durch die avr-libc) sämtliche globalen Variablen, Ausgabepuffer, random-seed und sonstige interne Variablen der libc neu initialisiert werden." Ja, und dies geschiet ja auch, du SIEHST es nur nicht in deinem C Source. Wenn du mal die *.lst Datei erzeugst, sprich dir den erzeugten Assemblercode anschaust dann wirst du feststellen das dort besonders beim WinAVR gcc -> libc noch einiges an Arbeit mit Initalisierungen usw. erledigt wird. Erst ganz am Ende dieser Arbeit wird Main() aufgerufen. Vor den Aufruf von Main sind also alle globalen vorinitialisierten Variablen wieder auf ihren Resetzustand initialisiert. Aber Vorsicht dies gilt aber eben nicht für die Register im Prozessor, denn ein Watchdog IQR ist kein echter Reset. Der Inhalt des SRAMs und der meisten Register wird also durch den Watchdog nicht zwangsläufig zurückgesetzt. Dazu muß man das Datenblatt befragen. Gruß Hagen
also, was alles hinter der hardwaretechnischen sache steckt weiss ich nicht genau zur zeit und kenne mich da auch nicht mit aus. ich soll die softwaretechnische seite lösen.. das sind hier meine ersten shritte in dieser grossen komplexen welt. weiss also garnicht mit wieviel A ein µC normal und mit wieviel A ein µC im Sleep_Modus benötigt, wieviel man an datenmänge speichern bzw händeln kann. habe versucht ein datenblatt zu studieren, hab aber nur welche auf englisch gefunden und da bin ich eine niete. @Hagen habe den codes noch nicht ganz begriffen. was sagt die while (1) do schleife aus? ich verstehe nur daraus -> WENN 1 dann mach ...... also bis zu while ist klar, der watchdog meldet sich z.B. jede s und inkrementiert so den timer, wenn der = 60 sind halt die 60 s vorbei und die daten daten können gesendet werden(man müsste also den µC in der senden routine wieder aktivieren, geht das auch mit 3 zeilen dann?). und wie, wodurch weiss mein µC wann er wieder in Sleep modus gehen soll? das wäre ja z.B. nach einer bestimmten anzahl gesendeter datenmenge o. einer definierten zeit. macht das die while schleife? verstehe aber dann nicht sorecht wie? oder kann mann das auch mit einer condition schleife vergleichen? wo steckt dann aber die info das in slepp modus geschaltet werden soll. würde mich auch interessieren was die 3 zeilen genau aussagen, kann man das irgendwo nachschlagen? vielen dank für die hilfe. gunter
"weiss also garnicht mit wieviel A ein µC normal und mit wieviel A ein µC im Sleep_Modus benötigt" Das weiß auch kein anderer. Dazu müßtest Du Dich erstmal für einen entscheiden. Hagen hat ja den ATMega8 hellgesehen. Du weißt aber schon, wie man den benötigten Stromverbrauch ermittelt: Die Batterie hat xx Ah Sie soll xx h halten Andere Schaltungsteile (ohne den µC) benötigen xx mA Daraus ergibt sich ein mittlerer Stromverbrauch des µC von max xx mA Dann kann man mal weiter sehen, vorher ist alles nur Geschwafel. Peter
Tja und das ist das Problem :) Fragen, egal welche, sind niemals verkehrt oder dumm, es sei denn aus einer Frage werden lawinenartig immer mehr Fragen. "was alles hinter der hardwaretechnischen sache steckt weiss ich nicht genau zur zeit und kenne mich da auch nicht mit aus. ich soll die softwaretechnische seite lösen" Du willst auf MCU's entwickeln da gehört grundlegendes Wissen der Hardware dazu, es geht nicht ohne. Auf PC's mit .NET könnte ich verstehen das ein Softwareentwickler ganz ohne Hardwarekenntnisse auskommen kann, aber auf MCU ?? das geht nicht. Und damit du die HW kennst MUSST du auch english können, das brauchst du in der Programmierung wie auch zum Lesen der Datenblätter, es geht nicht ohne. Du kannst dir eine gewissen Zeit lang abhelfen indem du die Online Translatoren benutzt, hm aber wie lange ? "habe den codes noch nicht ganz begriffen. was sagt die while (1) do schleife aus?" Das diese Schleife eine Endloss-Schleife ist, sie wird also nur durch einen Reset/Watchdog/Stromausschalten beendet, und höchsten noch durch Interrupts unterbrochen. Alles was innerhalb dieser Schleife ist wird normalerweise ständig wiederholt ausgeführt. Allerdings steht in meinem Pseudocode (der den ATmega8 einfachmal als hyptothetische MCU angenommen hat:) ein Sleep; Vor dem Sleep wird aber noch der WatchDog und der Sleepmode ausgewählt. Im Falle eines ATMega8 wird der Watchdog auf 1 Sekunde gesetzt und der Sleepmode auf "Power down". Danach wird die MCU in den Sleep Modus versetzt. Alles, selbst der Quarz wird angehalten und im Normalfalle verbraucht der AVR dann nur wenige µA. Aus diesem Modus kann er nur durch wenige Interruptsourcen wieder aufgeweckt werden, eben ua. mit dem WatchDog. Wenn nun 1 Sekunde vergangen ist und der WatchDog Timer abgelaufen ist wird die MCU wieder "aufgeweckt" und beginnt bei Main() von vorne. Deshalb die erste IF Abfrage die nämlich überprüft ob der WatchDog den AVR aufgeweckt hat. Wenn ja wird der Timer erhöht und bei >= 60 Sekunden sendest du deine Daten. Du musst dort nicht mehr den AVR aktivieren oder sonstwas, denn der AVR IST dann schon längst aktiviert, heist nicht mehr im Power Down Sleep Mode. Nach senden deiner Daten gehts ganz normal mit der While(1) do Schleife weiter so als wäre nicht geschehen. Den Rest der Logik kannste dir nun selber denken. "und wie, wodurch weiss mein µC wann er wieder in Sleep modus gehen soll? das wäre ja z.B. nach einer bestimmten anzahl gesendeter datenmenge o. einer definierten zeit. macht das die while schleife? verstehe aber dann nicht sorecht wie? oder kann mann das auch mit einer condition schleife vergleichen? wo steckt dann aber die info das in slepp modus geschaltet werden soll." Ja, in meinem Pseudocode bin ich nur aus das WESENTLICHE eingegangen. Der AVR würde eigentlich immer und sofort in den Sleep Mode gehen und nur alle 60 Sekunden die "Daten Senden" Routine aufrufen. Willst du dies anders haben muß natürlich in der While do Schleife der Sleep Modus samt WatchDog anders konfiguriert werden. "würde mich auch interessieren was die 3 zeilen genau aussagen, kann man das irgendwo nachschlagen?" Ja, eben im Datenblatt das in englisch ist. Daran geht kein Weg vorbei. So, nun fange an an dir zu arbeiten, lerne C oder die Programmiersprache die du benutzen willst. Frage deine HW-Entwickler auf was für Hardware du entwickeln sollst, ohne diese Wissen kannst die für MCU keine Software programmieren. Ich sehe nämlich die Gefahr das du hier im Forum immer weniger Antworten erhälst da eventuell nicht jeder so geduldig ist wie ich zb. Ich weis das man als Anfänger nach einer beantworteten Frage immer mehr Fragen auftauchen sieht und so ein schieres Gewirr von Fragen entsteht. Du kannst leider nicht verlangen das nun andere ihre Zeit opfern um auf ALLE diese Fragen einzugehen. Du musst also uns entgegenkommen und mit konkreten Fragen aufwarten ansonsten wird keiner sich die Zeit nehmen wollen darauf zu antworten (es werden nach jeder Antwort immer mehr Fragen :) Und da dies hier ein Fachspezifisches Forum ist musst du dich auch selber in die fachspezifische Materie einarbeiten -> ergo: englisch, Programmiersprache, Datenblätter und ein bischen Elektronik. Gruß Hagen
@Peter "Dann kann man mal weiter sehen, vorher ist alles nur Geschwafel." Ja das ist im Grunde richtig. Aber wie soll ein Anfänger einen groben Überblick bekommen, zb. über die Randerfordernisse wie Englisch, Programmiersprachen usw. wenn nicht wir diejenigen sind die seine Fragen versuchen zu beantworten ? Vor nicht allzulanger Zeit war und bin auch ich Anfänger gewesen. Ok, ich hatte es viel leichter da ich eh schon seit 15 Jahren programmiere und englisch kann. Aber grundsätzlich hatte ich auch tausende Fragen und nach jeder wurden es mehr. Und ich weis nicht wie es dir ergangen ist, aber ich meinerseits wollte möglichst in 5 Minuten alles auf einmal wissen :=) Konstruktiv gesehen kommen bei solchen Threads keine fertigen HW/SW Lösungen raus, das dürfte klar sein. Aber man kann lernen was alles an Wissen benötigt wird und wo man wie am besten anfangen muß. Gruß Hagen
@Hagen, man muß vor allem das systematische Herangehen lernen. Es macht nunmal keinen Sinn sich Gedanken über die Farbe der Tapete zu machen, wenn man sich noch nicht mal über das Fundament im klaren ist. Und solange bleiben Diskussionen über die Farbe der Tapete eben nur Geschwafel. Also immer einen Schritt nach dem anderen. Und in diesem Fall ist der allererste Schritt eben das Aufstellen einer Energiebilanz. Peter
:) Peter, ich bin da absolut deiner Meinung, nur mit einem kleinen Unterschied: Wie soll ein Anfänger lernen was systematisches Vorgehen bedeutet wenn es ihm keiner sagt ? Deshalb versuche ich eben auch auf solche Fragen zu antworten, eben weil ich selber Anfänger war bzw. noch bin. Weist du, in fast allen Foren wird sich über unklare Fragen beschwert und immer wieder auf Datenblätter oder Forenregeln verwiesen, mehr nicht. Aber wie soll ein Anfänger ein Gefühl für gute Fragen erlernen wenn man es ihm nicht beibringt oder zumindestens erstmal eine Antwort leifert und er dann feststellen kann das er vorerst wichtigere Dinge lernen muß ? Mir persönlich ergeht es immer so mit Fragen zur Elektronik. Öfters sind es Fragen die jeder Elektroniker als Grundlagenwissen abtut und mit RTFM beantwortet. Es ist aber so daß ich zb, auf der einen Seite ein großes Fachwissen zb. in der Programmierung habe auf der anderen Seite noch nichtmal exakt weis wie ein MOSFET oder OPAMP im Detail funktioniert. Sogesehen ein Fach-idiot-experte, und dem helfen dann RTFM-Antworten überhaupt nicht weiter, denn ich verstehe die Datenblätter einfach nicht. Einfach eine fertige Sache nachbauen will ich aber auch nicht und einen Privatlehrer kann ich mir nicht leisten. Also bleibt mir nur eines übrig: ich stelle eventuell saublöde Fragen in einem Forum :) Gruß Hagen
moin, so ist es hagen, du hast recht, sprichst mir von der seele! danke für deine tips. mache mich gleich auf die suche nach einen guten c tutorial. falls ihr ein guten link habt bitte her damit. danke erstmal für die tips und infos werde mich melden wenn ich mehr weiss. mfg gunter
Hallo, ich muss mal diesen alten Beitrag wieder raus holen. Ich will meinen Atmega8 schlafen legen und per Watchdog wecken. Hier der Code: #include <lcd.c> #include <avr/io.h> #include <avr/delay.h> #include <avr/sleep.h> #include <avr/signal.h> #include <avr/interrupt.h> #include "avr/wdt.h" #define F_CPU 8000000 volatile int loop = 0; void pause (void); int main(void) { lcd_init(); lcd_print(0,0,"Start "); DDRB |= (1 << PINB0); ///led pause(); lcd_clear(); set_sleep_mode(SLEEP_MODE_IDLE); //set_sleep_mode(SLEEP_MODE_PWR_DOWN); ////////////////////////////////////////////////////////// wdt_disable(); if (MCUCSR & (1<<WDRF)){ loop++; lcd_print(0,0," %i ",loop); if (loop == 5){ PORTB |= (1<<PINB0); pause(); PORTB &=~ (1<<PINB0); pause(); loop = 0; } } for(;;){ MCUCSR &=~(1<<WDRF); wdt_enable(WDTO_2S) ; sleep_mode(); } } void pause (void){ for (char s=0;s<15;s++){ _delay_ms(10);} } Er springt auch schön immer wieder in die main. Das sehe ich weil auf dem LCD wieder start nach ca. 2sec. steht. Nur inkremiert er nicht die Variable loop. Die springt einmal auf eins und da bleibt sie, sodas meine LED gar nicht angesteuert werden???
Hallo Falk Brunner, ich habe versucht es mittels deines Links, nach zu vollziehen. Wenn ich das richtig verstehe, springt er nach meinem Watchdog reset, dirckt zur main. as heist meine Variable loop müßte doch noch bestehen?! Also auch hoch gezählt werden. Frank
Nein, der Watchdog führt einen kompletten Reset aus und der µC ist im selben Zustand wie nach einem normalen Reset. In einem C-Programm läuft er also mit der ganzen Initialisierung los und dann erst startet deine main. Am einfachsten geht es wenn du einen Watchdog-Interrupt einrichtest, den Watchdog auf Interrupt betrieb stellst und das was du im normalfall ausführen willst in eine schleife packst, an deren Ende der µC in den sleep-mode versetzt wird. Der Interrupt weckt den µC dann wieder auf und deine Schleife läuft weiter, dabei bleiben dann natürlich alle Daten erhalten. Für längere Wartezeiten als der Watchdog zulässt kannst du dann einfach einen Counter mit einbauen.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.