Forum: Mikrocontroller und Digitale Elektronik Anfängerfrage zu Timern und Interrupts in AVR Studio unter c


von pitti (Gast)


Lesenswert?

Hallo!
Ich habe eine Schaltung mit einem Atmega. An PortA Pin0 soll ein 
Eingangssignal liegen. Das Signal liegt dort an mit ca.15-500 
Signalen/Sekunde.
Diese Signale will ich Zählen. Ich kann ja keinen Interrupt-Event auf 
pina0 schreiben (kann ich doch? wie?) und muss darum vermutlich so etwas 
wie eine while-Schleife benutzen.


int fSig()
{
  int iTime1=0; //store last timer value here
  int iTime2=0; //store time value at tick here
  int iCS=0;  //count signals
  int iCE=0; //count no signal to leave while if no signal
  int iSig=0;  //store time between two signals here
  DDRA = (0 << DDA0); //pin a0 = input
  TCCR0 |= (1<<CS00)|(1<<CS02); //start timer w clock/1024

  while(iCS<10) //try and collect 10 signals
    {
    if ( PINA & (1<<PINA0)) //if pina0 is high
    {
      iTime2=TCNT0; //get current timer value
      if(iTime1>iTime2)iTime1=255-iTime1+iTime2; //passed overflow?
      else iTime1=iTime2-iTime1; //calculate diff
      if(iSig<1)iSig=iTime1; //if first signal set iSig to iTime1
      iSig=(iSig+iTime1)/2; //get average
      iTime1=iTime2; //set iTime1 to last ticker Timer value
      iCS++;
    }
    else
    {
      iCE++;
      if(iCE>20)
      {
        iCS++;
        iCE=0;
      }
    }
  }

  return iSig;
}


Was ich wollte ist vermutlich erkennbar. Wie ich dahinkomme für mich 
noch fraglich. Zusätzlich verpasse ich doch die Genauigkeit immer um ein 
paar Takte oder?
Hauptproblem im Moment ist, dass das Ding die ganze Zeit Werte ausspuckt 
obwohl an pina0 nichts angeschlossen ist. Zunächst zeigt es mir artig 
eine Null an aber nach einer Weile geht es los mit unsinnigen Werten 
zwischen 1 und ein paar hundert. Und zwar ohne

Wäre nett, wenn mir jemand sagen könnte, was ich falsch mache, was an 
dem Ansatz doof ist und wieso und wie ichs besser machen kann.
Grüße!

von Latissimo (Gast)


Lesenswert?

Wie sieht das Signal aus?

Digital? Welche Amplitude? Du musst bestimmte Pegel auf einen Eingang 
geben.
Zu erst müssen die Pins/der Pin als digitaler Eingang konfiguriert 
werden.
Dann besitzt der yC eine Funktion(müsste IOC heißen) Interrupt on Change
d.h. dass bei einem Flankenwechsel am Pin ein Interrupt ausgeführt wird. 
Im Interrupt inkrementierst du dann den Zähler.

Das wars schon!

So brauchst du keine While-Schleife(du fragst ja nicht immer an den 
"richtigen Stellen" im Signal ab) Dazü müsste das Signal eine feste 
Frequenz haben und mit dem Polling synchronisiert werden. Viel zu 
Aufwändig. Also nen Interrupt on Pinchange. Siehe Datenblatt des yCs 
unter Interrupt enable und Interrupt on Change.

von Latissimo (Gast)


Lesenswert?

ps: das mit den Pegeln sollte heißen, dass ein yC erst ab einer 
bestimmten Eingangsspannung ein HI-Signal interpretiert. Deswegen die 
Frage nach der Amplitude deines Signals. ggf. brauchst du ja noch einen 
Pegelwandler oder halt nen Vorwiderstand als Spannungsteiler.

von pitti (Gast)


Lesenswert?

bin ich doof. unbeschaltet ist nicht = low, oder?
grr ;)
wenn ich das ganze auf masse lege siehts schon besser aus.
ich schau mir mal das datasheet an und hoffe, ich kann einen interrupt 
auf jedem beliebigen pin auslösen lassen. es ist nämlich leider so, dass 
ich die pins 1-20 schon komplett unter verwendung habe...
das signal ist pseudo-digital. ein analogsignal, welches ich auf den 
richtigen pegel gebracht habe. wenn das ungenau wird, dann muss noch n 
optokoppler dazwischen. das soll aber erst mal nicht die sorge sein 
sondern die software-seite...
danke & grüße!

von Johannes M. (johnny-m)


Lesenswert?

pitti wrote:
> Hallo!
> Ich habe eine Schaltung mit einem Atmega. An PortA Pin0 soll ein
> Eingangssignal liegen. Das Signal liegt dort an mit ca.15-500
> Signalen/Sekunde.
> Diese Signale will ich Zählen. Ich kann ja keinen Interrupt-Event auf
> pina0 schreiben (kann ich doch? wie?)
Das hängt davon ab, was für einen ATMega Du hast. Die neueren Modelle 
haben sogenannte Pin Change Interrupts (@Latissimo: Beim AVR heißen die 
nicht "interrupt on change" oder so...), die älteren (ATMega8, 16, 32) 
haben das noch nicht.

> und muss darum vermutlich so etwas
> wie eine while-Schleife benutzen.
Generell musst Du Flanken (also Pegelwechsel) zählen, d.h. wenn Du 
keinen Interrupt verwenden kannst, dann musst Du bei der Abfrage jeweils 
den letzten Zustand speichern und mit dem aktuellen vergleichen.

Wenn Du die Frequenz des Signals bestimmen willst, solltest Du 
vielleicht besser die Input Capture-Funktion eines Timers verwenden 
(dann ermittelst Du den Abstand zweier Flanken).

von pitti (Gast)


Lesenswert?

Hmm...
Ich geh dann an T1 oder ICP1 oder kann man beides relaisieren?
Das Problem ist, dass ICP1 schon belegt ist. Und wenn ich ihn 
freischaufle, dann gibts noch immer ein Problem: ich muss zwei Sensoren 
auswerten. Der zweite hat zwar eine noch niedrigere Frequenz - das 
befreit mich aber nicht von der Strukturproblematik.
Es handelt sich um einen Atmega32. Ist also essig mit Interrupt on 
Pinchange?!
Wie geh ich das Problem denn jetzt an? Ick steh uffem Schlauch...
Grüße!

von Latissimo (Gast)


Lesenswert?

Also den Interrupt on Pinchange würde ich nicht aus den Augen verlieren. 
Wenn du die möglichkeit hast(also wenn noch ein so konfigurierbarer Pin 
frei ist) dann solltest du das auf jeden Fall in Betracht ziehen. Dann 
bekommste bei jedem pos ODER negativen Flankenwechsel nen Interrupt.
In diesem zählst du einfach nen Zähler hoch.


Falls die Frequenz bestimmt werden soll, dann geb ich dem "Johannes M" 
recht, dann ist es sinvoll, wenn man die Inp. Capture Fkt. nutzt.

Weitere Fragen?

von Latissimo (Gast)


Lesenswert?

Welche Pins sind denn frei? Also mit welchen Funktionen?

von pitti (Gast)


Lesenswert?

So. Ein bisschen googlen später hat sich mein Konzept geändert.
Es gibt 2 Pins um Timer mit externer Quelle laufen zu lassen und einen 
ICP.
Alle drei taugen zur Frequenzmessung, wenn ich nicht schief gewickelt 
bin.
Ich hab mich für pin1 (b0) entschieden. Das ist T0. Gute Idee?
Jedenfalls: diese Funktion gibt Werte >0 aus, wenn kein Signal angelegt 
ist.
Wieso frag ich mich. Was sagt ihr denn sonst so zu dem Ansatz? Besser?
Der Atmega ist mit 4mhz quarzoszi getaktet. Der TCCR1B kann doch so hoch 
zählen, oder?!

int sig()
{
  uint16_t Sig=0;

  TCNT0 = 0; //reset timer
  TCNT1 = 0; //reset timer

  TCCR0 |= (1 <<CS02) | (1 <<CS01) | (1 <<CS00); //external clock
  TCCR1B |= (1<< CS12) | (0<<CS11) | (1 << CS10); //cpu/1024

  while(TCNT1<4096) //chill a second and count
  {
  }

  TCCR0 &= ~(1 <<CS02) | ~(1 <<CS01) | ~(1 <<CS00); //stop timer0
  TCCR1B &= ~(1 << CS10); //stop timer1

  Sig = TCNT0; // counted signals in 1 second
  return Sig;
}

von pitti (Gast)


Lesenswert?

Achso. Auf ICP hängt derzeit mein LCD. Kann ich natürlich ändern aber 
dann fehlt mir ja immer noch ein Messpin. Darum über T0/T1.
Überhaupt wieder posten tu ich übrigens, weil die Funktion da oben mir 
völligen Quatsch ausspuckt.
Hilfe!
Grüße!

von Johannes M. (johnny-m)


Lesenswert?

>  TCCR0 &= ~(1 <<CS02) | ~(1 <<CS01) | ~(1 <<CS00); //stop timer0
Das macht aber nicht das, was im Kommentar steht. Die Bitmasken müssen 
erst verODERt werden und am Ende wird das Bitkomplement von allem 
gebildet!

>  TCCR1B &= ~(1 << CS10); //stop timer1
Und was ist mit CS12?

von Johannes M. (johnny-m)


Lesenswert?

> TCCR1B |= (1<< CS12) | (0<<CS11) | (1 << CS10); //cpu/1024
                         ^^^^^^^^^
Das ist auch sinnfrei. Entweder das "|" vor dem "=" weg, oder den 
Quatsch einfach weglassen. Eine Null kannst Du schieben sooft Du willst, 
sie bleibt eine 0 und kann sich in so einem Fall als schöne Fehlerquelle 
betätigen. Wenn Du "der Übersicht wegen" alle Bits unbedingt 
hinschreiben willst, dann eben ohne verODERung, weil ODER mit einer 0 
keinerlei Änderung bringt...

von Johannes M. (johnny-m)


Lesenswert?

Übrigens: Wie ist der dazugehörige Portpin initialisiert? Wenn der 
keinen Pull-Up hat und offen ist, dann ist auch klar, dass da alles 
Mögliche passieren kann.

von Johannes M. (johnny-m)


Lesenswert?

pitti wrote:
> Der Atmega ist mit 4mhz quarzoszi getaktet.
Bei 4 Millihertz musst Du aber erheblich länger als eine Sekunde 
warten, bis das TCNT1 4096 erreicht!

Bedenke auch, dass TCNT0 nur bis 255 zählen kann und dann überläuft! 
Desahlb reicht als Rückgabewert auch ein uint8_t.

von pitti (Gast)


Lesenswert?

Da hab ich wohl was übersehen. Kann mir vielleicht irgendjemand sagen, 
wie der oben stehende Code aussehen muss, damit es funktioniert? Die 
Messdauer soll natürlich später runtergesetzt werden.
Grüße!

von pitti (Gast)


Lesenswert?

Groß und Kleinschreibung... ist aber klar, dass ich keinen 4 milliHz 
Quarzoszi habe, oder? Wär mir zumindest neu, dass es so etwas überhaupt 
gibt ;)
Hab den Pin als Eingang initialisiert. Jetzt mit Pull up. Nun bekomm ich 
0 raus. ist ja in etwa das, was ich wollte ;)
Kann ich zur Simulation einfach in der while Schleife ab und an nen 
anderen Pin kurz high und wieder low schalten und diesen an T0 hängen um 
die Signale zu zählen oder zählt der Atmega sich nicht gern selbst?
Wüsste gern, obs bis hierher klappt...

{
  DDRB  &= ~(1<<DDB0);  //b0 als eingang
  PORTB |= (1<<PB0);    //internen pull up aktivieren

  uint16_t Sig=0;

  TCNT0 = 0; //reset timer
  TCNT1 = 0; //reset timer

  TCCR0 |= (1 <<CS02) | (1 <<CS01) | (1 <<CS00); //external clock 
TCCR1B |= (1<< CS12) | (0<<CS11) | (1 << CS10); //cpu/1024

  while(TCNT1<(4096*3)) //chill and count
  {
  }

  TCCR0 &= ~(1 <<CS02) | ~(1 <<CS01) | ~(1 <<CS00); //stop timer0
  TCCR1B &= ~(1 << CS10) | ~(1 << CS11) | ~(1 << CS12); //stop

  Sig = TCNT0; // counted signals
  return Sig;
}

Von Hand mit nem Kabel auf dem PIN rumwackeln bringts nicht ;)

von pitti (Gast)


Lesenswert?

hab einfach mal pin a0 mit pin b0 gebrückt und die funktion so 
umgestaltet:

  DDRB  &= ~(1<<DDB0);  //b0 als eingang
  PORTB |= (1<<PB0);    //internen pull up aktivieren

  DDRA = (1 << DDA0);  //a0 als ausgang

  uint16_t Sig=0;

  TCNT0 = 0; //reset timer
  TCNT1 = 0; //reset timer

  TCCR0 |= (1 <<CS02) | (1 <<CS01) | (1 <<CS00); //external clock pin 1
  TCCR1B |= (1<< CS12) | (0<<CS11) | (1 << CS10); //cpu/1024

  while(TCNT1<(4096*3)) //chill and count
  {
  PORTA |= (1<<PA0); //a0 high
  _delay_ms(2);
  PORTA |= (0<<PA0); //a0 low
  _delay_ms(2);
  }

  TCCR0 &= ~(1 <<CS02) | ~(1 <<CS01) | ~(1 <<CS00); //stop timer0
  TCCR1B &= ~(1 << CS10) | ~(1 << CS11) | ~(1 << CS12); //stop timer1

  Sig = TCNT0; // counted signals
  return Sig;


macht:nix. kann mir nicht mal jemand den schlauch unter den füßen 
wegziehn?
Danke&Grüße!

von Johannes M. (johnny-m)


Lesenswert?

>   TCCR0 &= ~(1 <<CS02) | ~(1 <<CS01) | ~(1 <<CS00); //stop timer0
>   TCCR1B &= ~(1 << CS10) | ~(1 << CS11) | ~(1 << CS12); //stop timer1
Aua! Oben war nur die erste Zeile falsch, jetzt beide! Ich habe doch 
oben genau beschrieben, wie das mit dem Bit-Löschen geht... Erst 
verODERn, dann Bitkomplement! Kann doch nicht so schwer sein.
1
TCCR0 &= ~((1 <<CS02) | (1 <<CS01) | (1 <<CS00)); //usw...

von pitti (Gast)


Lesenswert?

ääh codezeile muss natürlich PORTA &= ~(1<<PA0);  //a0 low heissen
nun machts was. das problem ist nur, dass die funktion nie wieder 0 
liefert, nachdem sie einmal was gemessen hat..
grüße!

von Johannes M. (johnny-m)


Lesenswert?

pitti wrote:
> ääh codezeile muss natürlich PORTA &= ~(1<<PA0);  //a0 low heissen
> nun machts was. das problem ist nur, dass die funktion nie wieder 0
> liefert, nachdem sie einmal was gemessen hat..
> grüße!
Siehe oben....

von pitti (Gast)


Lesenswert?

Ehrlich gesagt doch. Ich wälze mal noch ein bisschen Literatur. Hab die 
Zeilen übrigens wie von Dir vorgeschlagen geändert. Ändert leider nichts 
am Problem.
Grüße!

von pitti (Gast)


Lesenswert?

Ich weiss auch gar nicht, wieso das Ergebnis davon betroffen sein 
sollte. Ich kann den Timer auch so anhalten, oder?

  TCCR0 |= (0 <<CS02) | (0 <<CS01) | (0 <<CS00); //stop timer
  TCCR1B |= (0 << CS10) | (0 << CS11) | (0 << CS12);

Aber wie gesagt. Ich kann ja TCNT0 auch vorher auslesen. Zu Beginn der 
Funktion wird TCNT0=0 gesetzt und wenn dann kein Signal am Pin anliegt, 
wie kommt dann der Wert zustande? Versteh ich nicht...

von Johannes M. (johnny-m)


Lesenswert?

pitti wrote:
> Ich weiss auch gar nicht, wieso das Ergebnis davon betroffen sein
> sollte. Ich kann den Timer auch so anhalten, oder?
>
>   TCCR0 |= (0 <<CS02) | (0 <<CS01) | (0 <<CS00); //stop timer
>   TCCR1B |= (0 << CS10) | (0 << CS11) | (0 << CS12);
Das habe ich doch auch oben schon geschrieben: Wenn Du irgendetwas mit 
einer 0 verODERst, dann ändert sich gar nichts ! Schau Dir mal die 
Wahrheitstabellen der grundlegenden logischen Operatoren an.

Im AVR-GCC-Tutorial steht eigentlich auch alles, was man wissen 
muss.

von pitti (Gast)


Lesenswert?

Nun. Was Du mit dem or meinst, leuchtet mir langsam ein. Ich habe aber 
trotzdem auch dann noch das Problem, wenn ich die Zeilen entsprechende 
Deines Vorschlages einfüge.
Ich finde im Tutorial sind nicht ausreichend Code-Beispiele. Man 
versteht zwar, wie etwas funktioniert aber dadurch noch lange nicht, wie 
man es anwendet. Ist zu theoretisch für blutige Anfänger.
Ich finds auch super, dass Du mir zur Selbsthilfe verhelfen willst. Es 
wäre nur vielleicht sinnvoll, mir in diesem Fall die Lösung meines 
Problemes zu stellen.
Wie auch immer. Danke soweit!

von Johannes M. (johnny-m)


Lesenswert?

Dann zeig doch mal Deinen aktuellen Code (mit den entsprechenden 
Korrekturen). Am besten auch vernünftig formatiert, damit es besser 
lesbar ist. Schließlich bietet dieses Forum extra die Möglichkeit dazu.

> PORTA |= (0<<PA0); //a0 low
Dass das genauso sinnfrei ist, wie das oben angesprochene ist denk ich 
mal klar...

von Karl H. (kbuchegg)


Lesenswert?

pitti wrote:

> Ich finde im Tutorial sind nicht ausreichend Code-Beispiele. Man
> versteht zwar, wie etwas funktioniert aber dadurch noch lange nicht, wie
> man es anwendet. Ist zu theoretisch für blutige Anfänger.


Welchen Teil des Abschnitts verstehst du nicht?
1
Verändern von Registerinhalten 
2
Einzelne Bits setzt und löscht man "Standard-C-konform" mittels logischer (Bit-) Operationen.
1
 x |= (1 << Bitnummer);  // Hiermit wird ein Bit in x gesetzt
2
 x &= ~(1 << Bitnummer); // Hiermit wird ein Bit in x geloescht
1
Es wird jeweils nur der Zustand des angegebenen Bits geändert, der vorherige Zustand der anderen Bits bleibt erhalten. 
2
3
Beispiel:
1
#include <avr/io.h>
2
...
3
#define MEINBIT 2
4
...
5
PORTA |= (1 << MEINBIT);    /* setzt Bit 2 an PortA auf 1 */
6
PORTA &= ~(1 << MEINBIT);   /* loescht Bit 2 an PortA */
1
Mit dieser Methode lassen sich auch mehrere Bits eines Registers gleichzeitig setzen und löschen. 
2
3
Beispiel:
1
#include <avr/io.h>
2
...
3
DDRA &= ~( (1<<PA0) | (1<<PA3) );  /* PA0 und PA3 als Eingaenge */
4
PORTA |= (1<<PA0) | (1<<PA3);      /* Interne Pull-Up fuer beide einschalten */
1
In Quellcodes, die für ältere Version den des avr-gcc/der avr-libc entwickelt wurden, werden
2
einzelne Bits mittels der Funktionen sbi und cbi gesetzt bzw. gelöscht. Beide Funktionen sind nicht mehr erforderlich.

von pitti (Gast)


Lesenswert?

Also... der Code sieht derzeit wie folgt aus:
1
uint16_t fSig()
2
{
3
  DDRB  &= ~(1<<DDB0);  //b0 als eingang
4
  PORTB |= (1<<PB0);    //internen pull up aktivieren
5
6
  DDRA = (1 << DDA0);  //a0 als ausgang
7
8
  uint16_t Sig=0;
9
10
  TCNT0 = 0; //reset timer
11
  TCNT1 = 0; //reset timer
12
13
  TCCR0 |= (1 <<CS02) | (1 <<CS01) | (1 <<CS00); 
14
         //external clock pin 1
15
  
16
         TCCR1B |= (1<< CS12) | (0<<CS11) | (1 << CS10); 
17
         //cpu/1024
18
19
  while(TCNT1<1024) //chill and count
20
  {
21
    _delay_ms(20);
22
    PORTA |= (1<<PA0); //a0 high
23
    _delay_ms(20);
24
    PORTA &= ~(1<<PA0);  //a0 low
25
  }
26
27
  TCCR0 &= ~((1 <<CS02) | (1 <<CS01) | (1 <<CS00));
28
  TCCR1B &= ~((1 << CS10) | (1 << CS11) | (1 << CS12)); 
29
30
         Sig = TCNT0; // counted signals
31
32
  return Sig;
33
}

Grüße!

von Karl H. (kbuchegg)


Lesenswert?

Sieht erst mal nicht so schlecht aus.

> dass die funktion nie wieder 0
> liefert, nachdem sie einmal was gemessen hat..

Woher weißt du das? Oder anders ausgedrückt, was machst du mit
dem Ergebnis?

von pitti (Gast)


Lesenswert?

Damit mache ich das hier:
1
      iSig=fSig();    
2
      itoa(iSig,sSig,10);
3
      lcd_gotoxy(9, 0);
4
      lcd_puts("S:");
5
      lcd_puts(sSig);

Wenn ich resette Hab ich S:0 auf dem Display. Lege ich nun die Pins 
aufeinander, dann bekomme ich einen Wert >700.
Dieser Wert verringert sich um 700, wenn ich die Verbindung wegnehme und 
erhöht sich auch wieder um 700, wenn die Verbindung wieder da ist.
Dabei schwankt der Wert um ca. 70 (mal 012<->712, mal 032<->732,...). 
Das passiert aber sicher beim Anlegen des Kabels, oder?
Grüße!

von pitti (Gast)


Lesenswert?

Hab noch was witziges festgestellt:
Wenn ich das Ding beschaltet in Betrieb nehme, dann zeigt er mir 7 an.
Nehm ich das Kabel dann weg, 0.
Das spiel kann ich ein paar mal wiederholen dann geht er wieder nicht 
mehr auf 0 und macht die 70er Sprünge. Was er aber auch kann, sind 700er 
Sprünge. Insgesamt fällt auf, dass es sich um 7*10^0, 7*10^1, 7*10^2 
handelt.
Der Messwert von 7 als Faktor bleibt konstant. Lediglich die Potenz 
ändert sich. Das finde ich merkwürdig.
Beim schreiben kam mir die Idee. Der Messwert ist 7 bzw 0.
Beim Anlegen des Signals wird er aber schon mal höher. Ich schreibe dann 
zB. S:102 aufs Display. Dann wird der Messwert konstant 7 und ich 
schreibe S:7 darüber. Nun steht dort also S:702. Wird der Messwert nun 
0, dann steht immer noch 002 da. Ist also ein Fehler bei der Ausgabe. 
Ich werde den Wert nun also noch bearbeiten und mit leading spaces 
versehen sodass immer die maximal benötigten fünf Stellen geschrieben 
werden.
Dummer Fehler. Typisch Anfänger. Vielen Dank an Alle, die mir geholfen 
haben!!
Grüße!

von Karl H. (kbuchegg)


Lesenswert?

pitti wrote:

> Dabei schwankt der Wert um ca. 70 (mal 012<->712, mal 032<->732,...).

Was hier passiert ist etwas völlig anderes.
Auf deinem Display kann nicht 012 stehen, weil itoa keine
führenden Nullen einbaut.

Was hier passiert ist Folgendes:
Dein Programm schreibt 712 hin.
Der nächste Messwert der geliefert wird sei meinetwegen 0.
Den schreibst du über die 712 drüber. Aber da 0 weniger Stellen
braucht als 712, überschreibst du nur die 7. Die 12 bleiben
stehen. Daher zeigt deine Anzeige 012.

Mach mal folgendes:

      iSig=fSig();
      itoa(iSig,sSig,10);
      lcd_gotoxy(9, 0);
      lcd_puts("S:");
      lcd_puts(sSig);
      lcd_puts( "  " );

also einfach ein paar Leerzeichen zusätzlich ausgeben.

von pitti (Gast)


Lesenswert?

Klar, hatte ich ja oben schon geschrieben. Was ich jetzt gemacht habe 
ist, strlen und dann ein while, welches spaces vor die Zahl packt, bis 
sie 5 Zeichen lang ist.
Funktioniert soweit. Nur, dass sie bei 0 folgendes ausgibt: "  0 0" - 
bekomm ich aber sicher noch in den griff.
Danke!

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
Noch kein Account? Hier anmelden.