Forum: Mikrocontroller und Digitale Elektronik Wie lange dauert ein Schleifendurchgang


von Christoph A. (shadowrunner93)


Lesenswert?

Hi Leute.

Ich möchte eine unkomplizierte Methode zum Überprüfen, wie lange ein 
bestimmter Portpin auf low/high ist.
Meine Idee wäre eine for-Schleife, die eine Variable hinaufzählt. Da ich 
aber nicht weiß wieviele Clock-Schläge die Schleife benötigt um einmal 
durchzulaufen, stehe ich vor einem Problem.
1
for(i=0;PB0 == 0;i++);

Auch für das Problem hätte ich einen Lösungsvorschlag. Im Datenblatt des 
ATmega32 stehen so ziemlich am Ende die Dauer aller Assembler-Befehle. 
Da ich in Assembler nun gar nicht bewandert bin, wollte ich euch fragen 
wieviele Clock-Schläge der obige Code pro Durchlauf braucht.

Ich hoffe ihr versteht mein Anliegen und könnt mir helfen =)

Mfg
Christoph

von (prx) A. K. (prx)


Lesenswert?

Christoph A. schrieb:

> for(i=0;PB0 == 0;i++);

Da PB0 fest für den Wert 0 steht dauert diese Schleife ewig.

von Peter (Gast)


Lesenswert?

hm.. einfach ein Timer und ein externer Interrupt geht nicht?

von Christoph A. (shadowrunner93)


Lesenswert?

A. K. schrieb:
> Christoph A. schrieb:
>
>> for(i=0;PB0 == 0;i++);
>
> Da PB0 fest für den Wert 0 steht dauert diese Schleife ewig.

Ändert sich der Wert des Pins nicht wenn der Eingang sich ändert?
Sollte ich PORTB verwenden?

Ja ginge natürlich schon, aber da müsste ich mich in die Interrupts 
einearbeiten. Ich suche hier eine unkomplizierte Lösung.. ^^

von Sven P. (Gast)


Lesenswert?

Christoph A. schrieb:
> A. K. schrieb:
>> Christoph A. schrieb:
>>
>>> for(i=0;PB0 == 0;i++);
>>
>> Da PB0 fest für den Wert 0 steht dauert diese Schleife ewig.
>
> Ändert sich der Wert des Pins nicht wenn der Eingang sich ändert?
Doch, das tut er.

> Sollte ich PORTB verwenden?
PINB wäre sinnvoller.

> Ja ginge natürlich schon, aber da müsste ich mich in die Interrupts
> einearbeiten. Ich suche hier eine unkomplizierte Lösung.. ^^
Du wirst dich wohl auch in 'Grundlagen AVR' einarbeiten müssen.
Schleifen sind unberechenbar, daher eigenen sie sich nicht zur 
Zeitmessung.

von (prx) A. K. (prx)


Lesenswert?

Christoph A. schrieb:

> Ändert sich der Wert des Pins nicht wenn der Eingang sich ändert?

Tut er. Aber PB0 ist nur die Nummer des Pins, nicht dessen Zustand. 
Folglich steht da
  for(i=0;0 == 0;i++);

von Christoph A. (shadowrunner93)


Lesenswert?

Okay dankeschön!

Ich habe ja irgendwie schon damit gerechnet dass ich nicht drumrum 
komme, etwas neues zu lernen.

Mfg
Christoph

von Christoph A. (shadowrunner93)


Lesenswert?

A. K. schrieb:
> Christoph A. schrieb:
>
>> Ändert sich der Wert des Pins nicht wenn der Eingang sich ändert?
>
> Tut er. Aber PB0 ist nur die Nummer des Pins, nicht dessen Zustand.
> Folglich steht da
>   for(i=0;0 == 0;i++);

Sry, keine Ahnung was ich da für einen Blödsinn gedacht habe.

von FlipFlop (Gast)


Lesenswert?

Hallo,
kenne mich mit Assembler zwar nicht aus, deshalb wirst du wohl selbst im 
datenblatt nachsehen, wie lange so ein einzelner befehl dauert, aber 
lange zeit abstände wirst du damit nicht messen können, bevor die 
variable überläuft, würde mal bei 1Mhz takt auf eine knappe millisekunde 
tippen.

while(PINB&0x01)i++;
  44:  01 96         adiw  r24, 0x01  ; 1
  46:  b0 99         sbic  0x16, 0  ; 22
  48:  fd cf         rjmp  .-6        ; 0x44 <__SREG__+0x5>

von Vlad T. (vlad_tepesch)


Lesenswert?

das beste wär den pin in einem Timerinterupt mit geeigneter Auflösung zu 
pollen und dort eine ausreichend breite Variable hochzuzählen

von JojoS (Gast)


Lesenswert?

geht es um AVRs? Die Ausführungszeiten zeigt der Simulator im AVR Studio 
wunderschön an, in Takten und in µs.

von Christoph A. (shadowrunner93)


Lesenswert?

Danke schonmal für die Ideen!

Ich mache es folgendermaßen:

Ich schaue zuerst ob die Flanke nach unten geht ( ich möchte die Dauer 
eines low-levels messen). Wird dieses Interrupt ausgelöst, so fängt der 
Counter an zu zählen. Geht die Flanke nach oben wird wieder ein 
INterrupt ausgelöst. Die Zeit des Counters wird danach abgelesen und 
fertig.


Eine Frage hätte ich noch: Was genau ist das I/O Clock? Im Datenblatt 
steht, dass ich diese Art von Clock benötige um diverse Interrupts 
möglich zu machen.

Mfg
Christoph

von Vlad T. (vlad_tepesch)


Lesenswert?

Christoph A. schrieb:
> Ich schaue zuerst ob die Flanke nach unten geht ( ich möchte die Dauer
> eines low-levels messen). Wird dieses Interrupt ausgelöst, so fängt der
> Counter an zu zählen. Geht die Flanke nach oben wird wieder ein
> INterrupt ausgelöst. Die Zeit des Counters wird danach abgelesen und
> fertig.

das sagt dir ja aber nicht viel über die Zeit, da du ja nicht weißt, 
wieviele Takte ein Schleifendurchlauf  braucht. Man könnte sich 
höchstens das assembly anschauen und nachzählen.

von S. T. (cmdrkeen)


Lesenswert?

es kommt auch immer ganz darauf an wie genau man eine Messung 
durchführen will.

man kann das auch ohne weiteres in einer Pollingschleife machen.
Um die Zeit von einem Polling-aufruf zum nächsten zu messen, nimmt man 
einfach den AVR-Simulator, setzt sich einen Haltepunkt beim 
Polling-aufruf und schaut wieviel Taktzyklen zwischen den 
Polling-aufrufen liegen.
Deine Zeitliche Auflösung ist dann halt diese Zeit und messen kannst du 
so lange, bis deine Zählvariable überläuft.

Compileroptminierung würde ich ausschalten, weil die manchmal auch gerne 
schleifen optimiert in einer Weise, die nicht optimal ist :P

von Christoph A. (shadowrunner93)


Lesenswert?

Vlad Tepesch schrieb:
> Christoph A. schrieb:
>> Ich schaue zuerst ob die Flanke nach unten geht ( ich möchte die Dauer
>> eines low-levels messen). Wird dieses Interrupt ausgelöst, so fängt der
>> Counter an zu zählen. Geht die Flanke nach oben wird wieder ein
>> INterrupt ausgelöst. Die Zeit des Counters wird danach abgelesen und
>> fertig.
>
> das sagt dir ja aber nicht viel über die Zeit, da du ja nicht weißt,
> wieviele Takte ein Schleifendurchlauf  braucht. Man könnte sich
> höchstens das assembly anschauen und nachzählen.

Bei dieser Methode gibt es keine Schleifen^^
Es werden nur Interrupts angewendet. Natürlich gehen für den Aufruf des 
Interrupts auch ein paar Clock-Schläge drauf, aber so extrem genau muss 
das Ergebnis nicht sein. Im 100 µs Bereich bei 8 Mhz reicht das locker 
=)

von Rolf Magnus (Gast)


Lesenswert?

> Eine Frage hätte ich noch: Was genau ist das I/O Clock? Im Datenblatt
> steht, dass ich diese Art von Clock benötige um diverse Interrupts
> möglich zu machen.

Der Takt, der für die I/O-Hardware da ist. In manchen Stromsparmodi ist 
dieser ausgeschaltet.

> Compileroptminierung würde ich ausschalten, weil die manchmal auch gerne
> schleifen optimiert in einer Weise, die nicht optimal ist :P

Würde ich nicht tun. Besser ist es, zu verstehen, warum diese 
Optimierungen gemacht werden und - sofern man das wirklich mal brauchen 
sollte - wie man sie umgeht.

von JojoS (Gast)


Lesenswert?

jetzt habe ich glaube verstanden was du willst, das Zauberwort ist ICP, 
Input Capture Pin. Der Zählerstand von einem freilaufenden Counter (per 
internem Hardwaretakt) wird bei Flanken am ICP in einem Register 
eingefroren. Das ist dann die genaueste Möglichkeit mit dem µC 
Pulse/Pausenzeiten zu messen.

von Christoph A. (shadowrunner93)


Lesenswert?

JojoS schrieb:
> jetzt habe ich glaube verstanden was du willst, das Zauberwort ist ICP,
> Input Capture Pin. Der Zählerstand von einem freilaufenden Counter (per
> internem Hardwaretakt) wird bei Flanken am ICP in einem Register
> eingefroren. Das ist dann die genaueste Möglichkeit mit dem µC
> Pulse/Pausenzeiten zu messen.

Exakt genau das habe ich gesucht!

Gibts das schon fertig wie du es beschrieben hast, oder muss man sich 
das so wie ich es beschrieben habe selbst mit Interrupts 
"zusammenbasteln"?

von JojoS (Gast)


Lesenswert?

hängt von dem µC ab den du nutzt, welcher ist es denn? Die meisten 
ATMegas haben das in der Hardware drin, ein Blick ins Datenblatt hilft. 
Ist in der Timer Beschreibung drin.

von Christoph A. (shadowrunner93)


Lesenswert?

JojoS schrieb:
> hängt von dem µC ab den du nutzt, welcher ist es denn? Die meisten
> ATMegas haben das in der Hardware drin, ein Blick ins Datenblatt hilft.
> Ist in der Timer Beschreibung drin.

Ich nutze den ATmega32.
Laut Datenblatt hat der sowas wie ICP.
Nja, da werde ich mich jetzt einarbeiten ;)

Falls es nicht auf Anhieb klappt, werde ich hier weiterfragen. Wäre nett 
wenn ein paar diesen Thread sich abonnieren könnten.

Vielen Dank für eure Hilfe!

Mfg
Christoph

von Christoph A. (shadowrunner93)


Lesenswert?

Hier bin ich wieder^^

Ich hätte da eine ganz kleine Frage, bezogen auf das Datenblatt des 
ATmega32.
Dieser besitzt ja einen 16bit Counter, und dess Register müsste man laut 
Datenblatt in Assembler geteilt auslesen. Bei "C" ist das anscheindend 
nicht der  Fall?

"Note that when using “C”, the compiler handles the 16-bit
access."

Ist das für jeden Compiler gleich bzw. funktioniert das auf meinem?
(AVR GCC)

Vielen Dank im Voraus!

Mfg

von Klaus (Gast)


Lesenswert?

>"Note that when using “C”, the compiler handles the 16-bit
access."

Das heisst auf deutsch: Bei "C" kümmert sich der Compiler darum.

Dadurch ist es EINFACHER.

Klaus

von Christoph A. (shadowrunner93)


Lesenswert?

Klaus schrieb:
>>"Note that when using “C”, the compiler handles the 16-bit
> access."
>
> Das heisst auf deutsch: Bei "C" kümmert sich der Compiler darum.
>
> Dadurch ist es EINFACHER.
>
> Klaus

Ja ich kann auch Englisch ;)

Meine Frage war aber ob das jetzt bei jedem C-Compiler so ist?

Mfg

von JojoS (Gast)


Lesenswert?

>Meine Frage war aber ob das jetzt bei jedem C-Compiler so ist?

schwer zu sagen, wer kennt schon 'jeden' Compiler? Aber die meisten 
Compiler haben die Option ein Assemblerlisting zu generieren, das ist 
meist sehr hilfreich und gibt hier eine eindeutige Antwort. Der gcc zum 
Beispiel 'kennt' den AVR und macht es richtig.

von JojoS (Gast)


Lesenswert?

hier ist mal ein Schnippsel um die Zeiten zwischen Flanken in einem 
Array zu sammeln (ohne Gewähr, und verwendet noch die _BV() Makros die 
jetzt nicht mehr in sind):
1
uint16_t   Timestamps[MAX_TIMESTAMPS];
2
int8_t   TimestampCount;
3
uint16_t   TimestampOld;
4
5
void init_decoder(void)
6
{
7
  TimestampCount = -1;
8
  TimestampOld = 0;
9
10
  TCCR1B |=  _BV(CS11) | _BV(CS10) | _BV(ICNC1) | _BV(ICES1);
11
12
  TIMSK |= _BV(TICIE1); 
13
}
14
15
16
//
17
// Interrupt handler for Input Capture
18
//
19
20
ISR(TIMER1_CAPT_vect)
21
{
22
  uint16_t val = ICR1;    // read timer value
23
  uint16_t diff = val - TimestampOld;
24
  TimestampOld = val;
25
26
  TCCR1B ^= _BV(ICES1);  // toggle rising/falling edge detection
27
28
  if (TimestampCount < MAX_TIMESTAMPS)
29
    Timestamps[TimestampCount++] = diff;
30
}

von Christoph A. (shadowrunner93)


Lesenswert?

Hier mein erster Code mit Interrupts. Die folgenden Fehler bringe ich 
nicht weg. Mein erster Verdacht war, dass der Interrupt-Vector falsch 
ist, aber dieser stimmt laut Datenblatt...
Die Zeile ist mit einem Kommentar markiert, um euch die Suche zu 
erleichtern.

../DS1820.c:102: error: expected identifier or '(' before numeric 
constant
../DS1820.c:102: error: expected identifier or '(' before numeric 
constant

1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h> 
4
5
#define TRANS PB3  //Transistorsteuerung
6
#define BUS    PB2  //Busleitung
7
#define PORTx PORTB  //PORT
8
#define DDRx  DDRB  //I/O Richtungssteuerung
9
10
11
#ifndef F_CPU
12
#define F_CPU 8000000  //Taktfrequenz definieren
13
#endif
14
15
16
void ResetPulse();
17
void EnableInterrupt();
18
void DisableInterrupt();
19
void ConfigInterruptICP();
20
void ConfigInterruptExt();
21
22
volatile char helpvar=0;
23
//Ist die Periode abgeschlossen?
24
25
uint16_t time;
26
//Zeit, in der das Signal low ist
27
28
29
void main()
30
{    
31
  DDRx = 0x00;
32
  DDRx = (1 << TRANS) | (1 << BUS); 
33
  // Anfangszustand
34
  
35
  DDRD = 0xFF;
36
  PORTD= 0xFF;
37
  //Alle STK500 LED's bleiben aus  
38
39
40
  PORTx=0xFF;
41
  //LED's 
42
43
  PORTx |= (1 << BUS);
44
  //Bus wird anfangs nicht auf low gezogen 
45
  
46
  ConfigInterruptExt();
47
  //Interrupt wird richtig konfiguriert
48
49
  EnableInterrupt();  
50
51
  ResetPulse();
52
  //Gibt einen Reset Pulse  
53
  
54
  while(1);
55
}
56
57
void EnableInterrupt()
58
{
59
  sei();
60
}
61
void DisableInterrupt()
62
{
63
  cli();
64
}
65
66
/*void ConfigInterruptICP()
67
{
68
  TCCR1A = 0x00;
69
  //Alles in diesem Register ist überflüssig =)
70
  
71
  TCCR1B = (1<<ICNC1) | (1<<CS10);
72
  //Reaktion auf negative Flanke
73
  //Interner Clock Prescaler auf 1
74
}
75
*/
76
void ConfigInterruptExt()
77
{
78
  MCUCSR &= ~(1<<ISC2);
79
  //Auf negative Flanke wird reagiert
80
  GICR = (1<<INT2);
81
  //Ext.Interrupt wird auf INT2 aktiviert
82
}
83
84
void ResetPulse()
85
{
86
  int i;
87
88
  PORTx &= ~(1 << BUS);
89
  //Bus auf low ziehen
90
    
91
  for(i=0;i<50;i++)
92
    _delay_us(10);
93
  //Reset Impuls
94
  
95
  PORTx |= (1 << BUS);
96
  //Bus auf wieder high
97
98
  DDRx &= ~(1 << BUS);
99
  //Buspin als Eingang  
100
}
101
102
ISR(INT2)  //Hier meldet der Compiler 2 Fehler im Code
103
{
104
  //Eine negative Flanke wurde erkannt
105
  if(helpvar%2)
106
    PORTD=0x00;
107
  else
108
    PORTD=0xFF;
109
  
110
  helpvar++;    
111
}

Mfg
Christoph

von Walter (Gast)


Lesenswert?

was soll INT2 bedeuten?

von Christoph A. (shadowrunner93)


Lesenswert?

Walter schrieb:
> was soll INT2 bedeuten?

Der InterruptVector für den Externen Interrupt am Pin INT2. Stimmt der 
nicht?

von Rolf Magnus (Gast)


Lesenswert?

>> was soll INT2 bedeuten?
>
> Der InterruptVector für den Externen Interrupt am Pin INT2. Stimmt der
> nicht?

Wie der Compiler dir schon sagt, stimmt der nicht. In der Doku der 
avr-libc steht, wie dieser Interrupt-Handler eigentlich heißen muß.

von Christoph A. (shadowrunner93)


Lesenswert?

Rolf Magnus schrieb:
>>> was soll INT2 bedeuten?
>>
>> Der InterruptVector für den Externen Interrupt am Pin INT2. Stimmt der
>> nicht?
>
> Wie der Compiler dir schon sagt, stimmt der nicht. In der Doku der
> avr-libc steht, wie dieser Interrupt-Handler eigentlich heißen muß.

Dankesehr!

Der Handler heisst wirklich: "EXT_INT2"

Noch eine Anmerkung:
Des Delay ist soo ein Schwachsinn, dass macht echt was es will..
Ich habe mit meinem Oszilloskop nachgemessen, der Wert stimmt weit 
nicht.

Mfg
Christoph

von Klaus (Gast)


Lesenswert?

Christoph A. schrieb:
> Noch eine Anmerkung:
> Des Delay ist soo ein Schwachsinn, dass macht echt was es will..
> Ich habe mit meinem Oszilloskop nachgemessen, der Wert stimmt weit
> nicht.

Hast du auch brav die Optimierung eingeschaltet, die richtige 
Prozessorfrequenz eingetragen und die richtige Clock-Source ausgewählt??

von Christoph A. (shadowrunner93)


Lesenswert?

Klaus schrieb:
> Christoph A. schrieb:
>> Noch eine Anmerkung:
>> Des Delay ist soo ein Schwachsinn, dass macht echt was es will..
>> Ich habe mit meinem Oszilloskop nachgemessen, der Wert stimmt weit
>> nicht.
>
> Hast du auch brav die Optimierung eingeschaltet, die richtige
> Prozessorfrequenz eingetragen und die richtige Clock-Source ausgewählt??

Die Optimierung ist standartmäßig eingeschaltet oder?
Prozessorfrequenz wurde definiert (siehe Code oben)
Würde nicht die richtige Clock-Source ausgwählt, so würde der ATmega 
garnicht laufen oder?^^

von Christoph A. (shadowrunner93)


Lesenswert?

Ein weiterer Fehler in meinem Code:

Der Interrupt-Handler ist falsch. Er sollte heissen: "INT2_vect".
Nun funktioniert auch mein Programm hervvoragend =)

Und ich glaube der Grund warum dass Delay bei mir nicht funktioniert hat 
ist folgender:

Ich habe F_CPU erst nach dem Einbinden der Delay-Bibliothek definiert. 
Jetzt habe ich util/delay erst nachher eingebunden. Ich kann leider 
nicht mehr überprüfen ob es funktioniert, man braucht ja auch seinen 
Schlaf.

von Klaus (Gast)


Lesenswert?

Christoph A. schrieb:
> Die Optimierung ist standartmäßig eingeschaltet oder?

Wenn man einen Fehler sucht, besser alle Fehlermöglichkeiten 
ausschließen, als sich auf Standardwerte zu verlassen ;)

> Würde nicht die richtige Clock-Source ausgwählt, so würde der ATmega
> garnicht laufen oder?^^

Kommt drauf an. Es gibt Fälle, wo der uC dann einfach zu langsam läuft 
und es einem deshalb erstmal nicht auffällt:  Wenn man nämlich einen 
externen Oszillator oder Quarz von z.B. 16Mhz anschließt, aber den 
internen 8MHz Oszillator auswählt.

> Ich habe F_CPU erst nach dem Einbinden der Delay-Bibliothek definiert.
> Jetzt habe ich util/delay erst nachher eingebunden. Ich kann leider
> nicht mehr überprüfen ob es funktioniert

Richtig, das ist auch ein möglicher Fehler. Allerdings sollte in dem 
Fall auch eine Warnung kommen.

> man braucht ja auch seinen Schlaf.

Ich wünsche eine gute Nacht ;)

von Christoph A. (shadowrunner93)


Lesenswert?

Dieser Tag hat schonmal gut angefangen =). Das Delay-Problem ist gelöst 
(es war tatsächlich der von mir genannte Fehler schuld) und die 
Flankenerkennung funktioniert wie sie soll.

Für alle die es noch nicht erraten haben: Es geht um den DS1820 ^^

Mein nächster Schritt ist die Messung der Zeit in der das Signal low 
ist. Dafür werde ich den Input-Capture-Pin verwenden, der laut 
Datenblatt einen Timer losrennen lässt, bis das Signal ein bestimmtes 
Flankenverhalten aufweist.

Mfg
Christoph

von Christoph A. (shadowrunner93)


Lesenswert?

Klaus schrieb:
>> Ich habe F_CPU erst nach dem Einbinden der Delay-Bibliothek definiert.
>> Jetzt habe ich util/delay erst nachher eingebunden. Ich kann leider
>> nicht mehr überprüfen ob es funktioniert
>
> Richtig, das ist auch ein möglicher Fehler. Allerdings sollte in dem
> Fall auch eine Warnung kommen.
>

Es ist auch eine Warnung gekommen, ich habe sie nur ignoriert und dachte 
das wird schon passen^^.

von Rolf Magnus (Gast)


Lesenswert?

> den Input-Capture-Pin verwenden, der laut Datenblatt einen Timer
> losrennen lässt, bis das Signal ein bestimmtes Flankenverhalten
> aufweist.

Nicht so ganz, zumindest kenne ich die Funktion so nicht. Den Timer 
lässt du einfach frei rennen. Ein Input-Capture-Ereignis löst dann ein 
Kopieren des aktuellen Timer-Werts in ein separates Register aus. Da 
kannst du dann taktzyklengenau auslesen, wann das Ereingis passiert ist.

> Es ist auch eine Warnung gekommen, ich habe sie nur ignoriert und dachte
> das wird schon passen^^.

Dann hast du jetzt eine wichtige Lektion zum Thema Warnungen gelernt, 
hoffe ich. ;-)

von Christoph A. (shadowrunner93)


Lesenswert?

Rolf Magnus schrieb:
>> den Input-Capture-Pin verwenden, der laut Datenblatt einen Timer
>> losrennen lässt, bis das Signal ein bestimmtes Flankenverhalten
>> aufweist.
>
> Nicht so ganz, zumindest kenne ich die Funktion so nicht. Den Timer
> lässt du einfach frei rennen. Ein Input-Capture-Ereignis löst dann ein
> Kopieren des aktuellen Timer-Werts in ein separates Register aus. Da
> kannst du dann taktzyklengenau auslesen, wann das Ereingis passiert ist.

Reicht diese Funktion um den Counter und ICP zu konfigurieren?
Wie erreiche ich dass der Counter zu zählen beginnt oder habe ich dass 
mit der Prescaler Einstellung schon gemacht?
1
void ConfigInterruptICP()
2
{
3
  TCCR1A = 0x00;
4
  //Ganz normaler Modus
5
  
6
  TCCR1B = (1<<ICNC1) | (1<<CS10) | (1<<ICES1);
7
  //Reaktion auf positive Flanke
8
  //Interner Clock Prescaler auf 1
9
}

>> Es ist auch eine Warnung gekommen, ich habe sie nur ignoriert und dachte
>> das wird schon passen^^.
>
> Dann hast du jetzt eine wichtige Lektion zum Thema Warnungen gelernt,
> hoffe ich. ;-)

Habe ich definitiv =)

Mfg
Christoph

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.