hallo, hab schon seit längerem nix mehr mir mcu's gemacht. wollte dann heute mal in C (codevision) ein lcd ansteuern (hat KS0070B controller, is ja kompatibel zum standart) das ganze mit nem avr mega32. habs auch initialisieren können (schwarze balken sind verschwunden). konnte aber mit der codevision lib und lcd_puts nix darstellen. dann hab ich es mal wie in dem tut von dieser seite in asm probiert. folgender code: -------------------- .include "m32def.inc" .include "lcd-routines.inc" .def temp1 = r16 .def temp2 = r17 .def temp3 = r18 ldi temp1, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse out SPL, temp1 ldi temp1, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse out SPH, temp1 ldi temp1, 0xFF ;Port D = Ausgang out DDRD, temp1 rcall lcd_init ;Display initialisieren rcall lcd_clear ;Display löschen ldi temp1, 'T' ;Zeichen anzeigen rcall lcd_data ldi temp1, 'e' ;Zeichen anzeigen rcall lcd_data ldi temp1, 's' ;Zeichen anzeigen rcall lcd_data ldi temp1, 't' ;Zeichen anzeigen rcall lcd_data loop: rjmp loop ----------------- jedoch verschwinden bei diesem code nicht einmal die schwarzen balken, was ja eigentlich bei der init. passieren sollte (?!) hab ihr nen tipp für mich? PS: das kable vom controller zum lcd ist ca. 30 cm lang (flachband). ist das zu lang?
Also an der Länge kann es nicht liegen, meines ist locker mal 50cm lang. Du müsstest vielleicht mal die lcd-routines.inc mit angeben.
hier die routine. das ist die von der lcd tutorial seite hier. die steht da ganz unten auf der seite: http://www.mikrocontroller.net/tutorial/lcd.htm danke für die schnelle antwort! mfg raoul4
Also ich hab jetzt leider keine Zeit, aber hast du gemerkt das diese Routine für 4MHz geschrieben ist. Wenn deine höcher ist kann es zu Problemen kommen.
schade, dass du keine zeit hast. der mega läuft auch mit 4 mhz. gibt es für den compiler einen unterschied zw. .include "lcd-routines.inc" und .include "lcd-routines.asm" natürlich wenn es diese files auch gibt! mfg raoul4
du solltest die include anweisungen auch ans ende der datei schreiben. das include bedeutet nur, dass der code an dieser stelle komplett wie er ist eingefügt wird. in deinem fall kommt da nach dem reset was gehörig durcheinander weil kein definierter startpunkt vorliegt (spätestens beim ersten ret schmiert alles ab)
cool danke! es geht. aber kannst du mir das nochmal erklären? normalerweise includet man doch am anfang alles, damit alle befehle und funktionen wissen was sie tun sollen, oder etwa nicht?! mfg raoul4
Ja, vielleicht in C, wo es nur Funktionsprototypen o.ä. sind. Aber das include in ASM kannst du mit einem Präprozessor-makro vergleichen, was dir wirklich alles au der Datei an diese Stelle knallt. Nach einem RESET wird bei der Anweisung an der Speicheradresse 0x00 gestartet, und wenn du das Include am Anfang setzt, ist da auf einmal dein Unterprogramm. Also entweder alles hinten includen, oder aber zuerst den Interrupt-Vektor mit den richtigen Jumps, dann includen und dann das Hauptprogramm... ist Geschmackssache.
noch eine frage: wie kann ich nun in die 2. zeile kommen? mfg raoul4
ah nochwas ;) wie kann ich ganze wörter auf einmal schreiben? also nicht immer jeden buchstaben einzeln senden, das nervt ja.... mfg raoul4
Was meinst du mit "in die 2. Zeile kommen"? Meinst du Sprünge zu labels? Wenn du ganze Wörter schreiben willst, dann lege diese als Konstante im Flash ab und schreibe dir eine Routine, die z.B. im Z-Register die Adresse des ersten Zeichens übergeben bekommt und sie nacheinander ausgibt, bis das Null-Byte gelesen wird.
hallo, mit in die 2. zwile kommen meine ich, wie ich etwas in die 2. zeile meines displays reinschreiben kann. Zitat: "Wenn du ganze Wörter schreiben willst, dann lege diese als Konstante im Flash ab und schreibe dir eine Routine, die z.B. im Z-Register die Adresse des ersten Zeichens übergeben bekommt und sie nacheinander ausgibt, bis das Null-Byte gelesen wird." bahnhof?! verstehe nur das wort "wenn" ;) mfg raoul4
hallo zeile 2 im lch mußt du adressiern. ganze texte lise doch mal hir http://www.mikrocontroller.net/tutorial/memory.htm
"Wenn du ganze Wörter schreiben willst, dann lege diese als Konstante im Flash ab und schreibe dir eine Routine, die z.B. im Z-Register die Adresse des ersten Zeichens übergeben bekommt und sie nacheinander ausgibt, bis das Null-Byte gelesen wird." Aaaalso: Du willst ja am liebsten nur einen kurzen Aufruf, um einen festen Text auszugeben, ja? Da wir es hier nicht mehr mit C, sondern mit ASM zu tun haben, wird es hier ein printf("blabla") nicht tun. Wir müssen die Zeichen also Schritt für Schritt anzeigen. Damit wir das nicht bei jedem Mal extra schreiben müssen, können wir uns eine Routine überlegen, die wir dann nur noch mit CALL aufrufen müssen. Damit die Routine weiss, welchen Text sie ausgeben soll, müssen wir ihr das irgendwie mitteilen. Die verschiedenen Texte an sich müssen ja auch irgendwo gespeichert werden. Das passiert am besten im Programmspeicher (also im "Flash"-Speicher). Damit unsere tolle Routine für Texte beliebiger Länge funktioniert, muss sie wissen, wann das letzte Zeichen geschrieben wurde. Das kann man (übrigens wie auch mit C) durch eine Terminierung durch ein Null-Byte (ASCII-Wert: 0) machen. Also wenn unsere Routine 0 liest, dann macht sie Feierabend. Es ist also am besten, wenn wir der Routine die Anfangsadresse des auszugebenden Textes übermitteln, das kann man ganz gut im Z-Register machen (sind eigentlich zwei register: ZL = Z-low und ZH = Z-high). Lies dir am Besten folgendes durch, evtl. auch die vorhergehenden Kapitel: http://www.mikrocontroller.net/tutorial/memory.htm
hallo christoph, finde ich stark von dir, dass du dir so viel zeit nimmst! nur weiter so! danke. werde mal alles durchlesen. wenn ich dann fragen habe, werdet ihr sie hier nachlesen können ;) mfg raoul4
also: 1. muss man immer bevor man rjmp und call und ret und so benützen will den stack initialisieren? 2. muss man verstehn wie man den stack initialisiert, oder reicht es wenn man es einfach vom tutorial abschreibt? (ernstgemeinte frage, würde es schon gerne verstehen) 3. heißt RAMEND -> Ram End -> Ende des Rams? 4. wie kann man sich diesen stack vorstellen? alles was ich darüber weis ist, dass was als letztes draufgekommen ist auch wieder als erstes weggenommen wird, und dass da in diesem stack steht, wo er wieder "hin-returnen" soll (nach dem rcall befehl) 5. im tutorial steht: ------- ldi temp, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse out SPL, temp ldi temp, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse out SPH, temp ------- was bedeutet das? benötigt der stack den ganzen ramspeicher? also sagen diese zeilen dem stack, von welcher bis welcher adresse der ram speicher geht?! SCHONMAL DANKE IM VORAUS FÜR ANTWORTEN mfg roul4
Beim Stack gibt es nicht viel zu verstehen. Das Grundprinzip kennst du ja schon: Bei jedem Funktionsaufruf wird die Rücksprungadresse auf den Stack gelegt und beim Return wieder gelesen, um an die richtige Stelle zurückkommen zu können. Es sollte einleuchten, dass hier ein Stack sehr praktisch ist, vor allem, wenn man z.B. im Unterprogramm noch weitere Unterprogramme aufruft, die selbst evtl. wieder Unterprogramme aufrufen. Man kann auf dem Stack auch Register ablegen und vor dem ret wieder auslesen, damit das aufrufende Programm nach dem Aufruf alles unverändert wiederbekommt. Der Stack-Pointer zeigt immer auf die nächste leere Stelle im Speicher. Da Die Variablen generell "von unten" an allokiert werden, ist der Stack im SRAM "von oben" angelegt und wächst nach unten. Das Bedeutet, dass man den Stack Pointer ganz zu Anfang an die höchstmögliche Speicheradresse setzt (RAMEND) und jedes call und jedes push legt etwas auf den Stack und erniedrigt die Speicheradresse, so dass der Stack Pointer wieder auf die nächste freie Speicherstelle zeigt. Ein Problem, das dann entstehen kann ist natürlich, wenn der Stack zu voll wird und "unten" in den Datenbereich hereinwächst und Daten überschreibt. Daher sollte man z.B. Rekursionen vermeiden. Da viele AVRs mehr als 256 Byte Speicher haben, muss der Stack-Pointer mit entsprechend großen Adressen umgehen können, er kann also nicht nur 8 Bit breit sein. Daher ist der SP ganze 16 Bit breit, besteht also aus zwei 8-Bit register, nämlich SPH und SPL (SP-High und SP-Low).
vielen dank nochmals habs jetzt ein wenig verstanden. aber noch was: das problem wie ich in asm bei meinem 2 zeiligen display in die 2. zweil etw. reinschreiben kann ist immer noch nicht gelöst. mit conors satz: "zeile 2 im lch mußt du adressiern." kann ich leider nocht viel anfangen. bei dieser lcd routine gibt es den befehl lcd_comman. kann ich das mit dem vielleicht irgendwie anstellen? noch was grundlegendes: ist in einer mcu alles adressiert? also kann man sich das so vorstellen wie in einer großen stadt? (klingt ein bisschen komisch ;-) ) mfg raoul4
weis das wirklich keiner (kann ich mir nicht vorstellen)? möchte doch nur in die 2. zeile kommen! :-) :-) :-) mfg raoul4
steht im datenblatt zu jedem 08/15 lcd display. da solltest du einfach mal reinschaun
hallo, dem datenblatt (im anhang) nach zu folge müsste ich dann um in die zweite zeile zu kommen folgendes machen: ldi temp1, 0b00001010 ;temp1 ist r16 rcall lcd_data ;unterprogramm (ist in lcd-routines.inc) ist das richtig?
sag uns doch lieber was du laut datenblatt machst und nicht nur so eine zeile. ich glaub aber das wars nicht aber keine garantie, bin zu faul nachzuschaun...
Ist FAST richtig. Allerdings mußt Du nicht Daten zum LCD senden, sondern einen Befehl um direkt zum Anfang der zweiten Zeile zu kommen. Probier mal dieses: ;Setzen des LCD-Cursors an eine Adresse ;Befehl = 1xxxxxxx ;Adresse = xnnnnnnn ;Bei 64 = 11000000 ldi temp1, 0b11000000 rcall lcd_command ;unterprogramm (ist in lcd-routines.inc) ;Zeichen senden ldi temp1,"M" rcall lcd_data Im 2-Line-Mode beginnt die erste Zeile bei 0 und die zweite bei 64. Du kannst Dir natürlich eine Routine machen mit der Du eine ganze Zeile zum LCD sendest. Als Paramter in Z die Adresse des Textes (ACHTUNG: Adr*2, da Byte) und mit r16 oder r17 die Zeilennummer. Mit nen ATMega8 und größer einfach Zeilennummer * 64 mit "mul Rd,Rr" und aus R0 die Adresse holen mit nen kleinerer 6 mal nach links schieben. Studier Dir auch das "Busy-Verfahren". Man muß dann halt die R/W-Leitung doch an den Port D.6 z. B. anschließen. Man spart sich dann allerdings ne Menge Wartezeit des AVR´s der ja besseres zu tun haben könnte. Hier noch ein sehr gutes Datenblatt eines LCD-Controllers (KS0066): http://www.adamswann.com/projects/avr-lcd/KS0066U.pdf Bitte 10 mal durchlesen (Befehlsliste und Init-Verfahren). Gruß Andi
hallo andi, danke für deine ausführliche hilfe. dein bsp. funktioniert. aber mal ne frage dazu. du schreibst: ;Bei 64 = 11000000 was meinst du damit? in dem datenblatt was du angähngt hast ist auch so eine komsiche tabelle. genau wie in "meinem". die verstehe ich irgendwie nicht. ich meine die bei "deinem" auf seite 18 und bei "meinem" auf seite 4. mfg raoul4 P.S.:habe mir das datenblatt noch nicht 10 mal durchgelesen ;)
ach hab das mit den 64 doch gecheckt! du meinst die adresse, bei der die 2. zeile anfängt! mfg raoul4
Ja, genau! Der Befehlscode 1aaaaaaa bedeutet die Übergabe einer Cursor-Adresse wobei die 1 an Bit-Nr. 7 sein muß und in Bit 6 - 0 die Adress-Bit (0-127 möglich). Gruß Andi PS: Das mit den 10 mal lesen war nur ein Wink sich das ganze genau durchzulesen da man es bei 3 mal meist so wie so noch nicht kapiert hat.
Ach ja! Vor dieser "komischen" Tabelle ab Seite 13 sind die ganzen Befehle genauer beschrieben. Gruß Andi
das ist ja alles schön und gut ;) (2 von 3 problemen gelöst). jetzt bleicht halt nur noch das mit den wörtern/sätzen unkompliziert übertragen zu können. ----------- Als Paramter in Z die Adresse des Textes (ACHTUNG: Adr*2, da Byte) und mit r16 oder r17 die Zeilennummer. Mit nen ATMega8 und größer einfach Zeilennummer * 64 mit "mul Rd,Rr" und aus R0 die Adresse holen mit nen kleinerer 6 mal nach links schieben. ----------- bin ja noch sehr sehr neu in asm. also fragen zu deinem text: 1. wie kann ein text eine adresse haben? 2. (ACHTUNG: Adr*2, da Byte) was heißt das? zwei adressen? aber wenn die adresse des textes in das Z register soll, warum brauche ich dann 2 register?! passt in eins nicht ein byte rein?! 3. warum zeilennummer mal 64? 4. was "mul Rd,Rr" 5. jetzt kommt er mit R0 :-) mfg raoul4
Dachte eigentlich, Du bist in ASM schon recht firm! Sorry, aber an Deiner Stelle würde ich erst mal mit dem Grundsätzlichen anfangen (ASM-Befehle, Zugriffstechniken auf ROM und RAM mittels 2 8Bit-Register etc.). Lies Dir das AVR-Tut noch mal ordentlich von vorne bis hinten durch. Auch die Hilfe von AVR-Studio über die AVR-Befehle und zu guter letzt das PDF für Deinen µC können nicht schaden. Das alles hier jetzt zu erklären würde den Rahmen hier sprengen. Gruß Andi
ja das prob ist halt nur das ich in dem tut viele sachen nicht verstehe, und dann gleich wieder aufhöre, weil es mich so ankotzt. am rande noch eine frage: ist das z-register also 2 byte groß und besteht deswegen aus 2 reigstern (jeweils 1 byte groß)? also r25 low byte und r26 ist das high byte von z? kann man z überhaupt ein register nennen? mfg raoul4 PS: bei mir besteht ein byte aus 8 bit und ein bit kann entweder 0 oder 1 sein. wenn jetzt jmd sagt, dass das nicht stimmt, kann ich ja gleich aufhören mit mcu's zu experimentieren. :-(
Die AVR´s haben 32 8Bit-Register R0 bis R31, OK? Mit denen kann man alle Dinge mit 8Bit Datenbreite (Add, Sub, OR etc.) erledigen, also rechnen. Jetzt haben die letzten 6 Register, R26 - R31 eine Zusatzfunktion als "Adresspointer" im RAM um auf externen "Arbeitsspeicher" zugreifen zu können. Diese Register nennt man dann in Verbindung mit den Befehlen LD "Load" und ST "Store" dann X, Y und Z. X besteht dann aus den Registern R26 und R27 oder auch XL und XH. Y besteht aus den Registern R28 und R29 oder auch YL und YH. Z besteht aus den Registern R30 und R31 oder auch ZL und ZH. Um aus dem SRAM ein Byte zu lesen muß man z. B. folgendes machen: LDI ZL,low(Adresse) ;ZL = R30 LDI ZH,high(Adresse) ;ZH = R31 LD R16,Z ;Inhalt von Adresse "Adresse" nach R16 laden So weit zum Zugrif auf das SRAM was für alle 3 16Bit-Adresspointer, X, Y und Z, gleich ist. Jetzt gibt es aber nur einen Adresspointer mit dem man mit dem Spezialbefehl "LPM" ein Byte aus dem Flash-RAM lesen kann: Register Z. Hier ein Beispiel: LDI ZL,low(Adresse*2) ;ZL = R30; low-Byte der Adresse nach ZL LDI ZH,high(Adresse*2) ;ZH = R31; high-Byte der Adresse nach ZH LPM R16,Z ;Inhalt von Adresse "Adresse" nach R16 laden Jetzt ist das Problem, dass das Flash-RAM Word-Orientiert ist. Also Byte Nr. 0 und 1 ist Word-Adresse 0, Byte Nr. 1 und 2 ist Word-Adresse 1 etc. Deswegen muß man bei der Zuweisung einer Adresse in Z bzw. ZL und ZH die Adresse verdoppeln da die Word-Adresse 100 die Adresse in Byte (8Bit breit) 200 ist. Auch das AVR-Studio orientiert sich bei Adressierungen im Code-Segment (cseg) in Word-Adressen. Deswegen die Verdoppelung. So, jetzt wird schon fast ein neues TUT draus. Ich hoffe, Du verstehst das da oben. Gruß Andi
Shi..! Ein FEHLER! Hier richtig: Also Byte Nr. 0 und 1 ist Word-Adresse 0, Byte Nr. 2 und 3 ist Word-Adresse 1 etc. Gruß Andi
schönes tut! danke! frage dazu: (was sonst :)) LDI ZL,low(Adresse) ;ZL = R30 LDI ZH,high(Adresse) ;ZH = R31 LD R16,Z ;Inhalt von Adresse "Adresse" nach R16 laden ist das so: z = zl + zh ? dann ist das ja so: z = r30 + r31 also praktisch so (in der dritten zeile): r16 = r30 + r31 aber das geht doch nicht? in ein byte passen doch nicht 2 bytes rein? oder wie groß ist so eine adresse? und z zeigt auf diese adresse? oder ist das so: es gibt immer zwei adressen in dem speicher, bei der aber dann nur ein byte gespeichert ist hast du den msn messenger? dann könnten wir mal chatten, und ich könnte dich alles schneller fragen ;) falls du ihn hast: meine e-mail adresse oben ist auch zum adden. falls nicht: msn messenger ist sowas wie icq (messenger.msn.de) mfg raoul4 (noch verwirrter ;) )
Chatten ist ja gut und schön aber hier haben evtl. auch andere was davon. Die Register X, Y und Z bezeichne ich jetzt mal als "virtuelle Register" in Verbindung mit den Befehlen LD, ST und LPM. Bei Ausführung des Befehls "LPM R16,Z" werden die Register ZL und ZH vom µC zu einem 16Bit-Register zusammengefasst und als Zeiger (Adresspointer) auf das Flash-RAM benutzt. Deswegen muß man vor Ausführung des Befehls "LPM R16,Z" die Register ZL und ZH mit dem low- und high-Byte der Adresse, woraus ein Byte gelesen werden soll, laden. Die Register ZL und ZH sind auch nur umschreibungen für die Register R30 und R31 also in Wirklichkeit besteht das Virtuelle Register Z aus R30 und R31. Genauso mit XL, XH, YL und YH (R26, r27, R28 und R29). Gruß Andi
Ach ja! Man nennte das auch "indirekten Speicherzugriff". Die Adresse im Flash-RAM wird durch ZL und ZH (Z) gebildet. Nicht, das Du jetzt meinst, das "LPM R16,Z" heißt lade ZL und ZH nach R16 sondern lade das Byte, was an der Adresse die in ZL und ZH (Z) steht nach R16. Gruß Andi
ja aber warum lädt man in zl und zh adressen rein? wenn man jetzt in zl 20 und zh 10 lädt, welchen wert hat denn z? auf was zeigt der dann? auch 10 oder 20 oder dan ganzen zwischenraum? ich verstehe das alles nicht. bin ich zu dumm dafür? (16 jahre) mfg raoul4
Na ja, nicht zu dumm, zu unerfahren würd ich mal sagen. Mit den beiden Registern ZL und ZH wird dann aus 2 8Bit-Zahlen eine 16Bit-Zahl gebildet (low- und high-Byte). Und eine 16Bit-Zahl braucht man dann nun mal bei Zugiffen auf den Speicher (Flash-ROM und SRAM) da diese aus mehr als 256 Zellen bestehen. In Deinem Beispiel mit 20 und 10 in ZL und ZH hast Du dann eine 16Bit-Zahl von 2580 (high-byte*256 (10*256) + low-byte(20)). Wie gesagt, fang jetzt erst mal die Grundsätze an zu lernen (ASM-Befehle, Speicherzugriff etc.). Gruß Andi
Hier noch ein kleines Beispiel: ldi r16,1 ;LCD löschen rcall lcd_command ldi ZL,low(Text*2) ;lade das low-Byte der Adresse Text in ZL ldi ZH,high(Text*2) ;lade das high-Byte der Adresse Text in ZH rcall Print Halt: rjmp Halt Text: .db "Erster Versuch!",0 Print: lpm r16,Z ;Lade den Inhalt von Adresse bei Text in R16 tst r16 ;Ist das Zeichen ne 0? breq PrintEnd ;Dann Textende und raus rcall lcd_data ;Zeichen ausgeben adiw zh:zl,1 ;Verschiebe Z (ZH:ZL) auf das nächste Zeichen rjmp Print ;Nächstes Zeichen laden PrintEnd: ret ;Return So ne Art Algorhytmus sollte Dir selber einfallen aber vielleicht hilft es Dir beim verstehen. Viel Spaß! Gruß Andi
Eine extrem wichtige sache beim Herumbasteln ist: Geduld! Wenn du dir also ein Tutorial durchliest und du verstehst etwas nicht, dann darfst du nicht sofort aufgeben, sondern solltest es evtl. nochmal lesen und überlegen, was in deiner Vorstellung denn Sinn macht. Wenn du es dann immer noch nicht verstehst, dann kannst du immer noch hier konkret nach einer Formulierung fragen. Vielleicht ist im Tut ja auch etwas für den Anfänger missverständlich formuliert, so dass ein Hinweis darauf evtl. sogar anderen hilft, da man das Tut an der Stelle klarer formulieren kann. Für schnelle Fragen zwischendurch kannst du auch im IRC auf den server irc.euirc.net in den Raum #mikrocontroller.net kommen. Wenn du nicht allzu ungeduldig bist, dann wird da sicherlich immer jemand drin sein, der dir helfen kann. Allerdings ist es wichtig, dass du dann auch Eigeninitiative zeigst, und dazu gehört: Datenblatt, div. Tutorials zum Thema, google. Also nicht wundern, wenn du nicht direkt die Lösung für dein Problem bekommst, sondern einen Verweis darauf, wo du dir diese Lösung selbst erarbeiten kannst. Ich denke, du wirst mir zustimmen, dass du selbst mehr davon hast, wenn du dir etwas selbst erarbeitest, statt dass dir jemand etwas vorprogrammiert. Die zwei 8-Bit register von Z werden nicht, wie du vermutet hast, addiert o.ä., sondern nebeneinander gesetzt und als ein 16-Bit-Register gesehen. Also wenn ZH = 0b11100111 (dezimal 231) und ZL = 0b00011000 (dezimal 24) ist, dann besteht Z ja aus ZH und ZL aneinandergeknüpft, also Z = 1110011100011000 (binär), was dezimal 59160 entspricht. Rein mathematisch gilt: Z = ZH * 256 + ZL oder Z = ZH << 8 + ZL, wobei "<<" der Links-Shift-Operator ist (ein Linksshift entspricht der Multiplikation mit 2, und das 8 Mal durchgeführt ergibt eine Multiplikation mit 256.)
Ich habe zum Thema Adressierung beim AVR mal einen Artikel im Wiki geschrieben: http://www.mikrocontroller.net/wiki/Adressierung
Hi, hier war jemand so nett und hat ein schoenes AVR ASM Tutorial zusammengestellt. http://www.avr-asm-tutorial.net/avr_de/beginner/index.html Mfg Dirk
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.