Hallo zusammen, ich habe einen IIR-Besselfilter gebaut und mit den Messwerten aus der Schaltung in Excel ausprobiert. Dort funktioniert der wunderbar. Nun hat der ATtiny85 meines Wissens keine Gleitkommaberechnung und nicht genug Platz für die double-Bibliothek, also habe ich noch ein Excelsheet und einen Tag drangehängt und die Berechnung komplett ohne negative Zahlen und ohne Gleitkomma möglich gemacht. Die habe ich dann ausführlich mit unechten und mit realen Messergebnissen getestet. Siehe da, rein theoretisch funktioniert es schon mal. Leider sehe ich keine Möglichkeit, das auch noch in 16 Bit reinzuquetschen. Und das ist der Haken. Die Filterkoeffizienten haben teilweise ein 10^-5 dranhängen. Sprich, ohne Kommazahlen merkt man erst dann was von dem Koeffizienten, wenn man die Berechnung mit ungefähr 10^5 multipliziert oder um 15 bis 16 Bit nach links schiebt. Wenn ich das mit den Messergebnissen mache, habe ich leider umgehend die 16 Bit gesprengt. Der Attiny85 ADC liefert mir 10 Bit Messergebnisse. Ich habe uint32_t verwendet. Meine Berechnung funktioniert scheinbar im Attiny nicht. Hier die Frage: Kann man mit dem Datentyp uint32_t auch rechnen? Wenn nicht, gibt es eine Bibliothek oder irgendwas zum runterladen, so dass man dem Attiny auch 32 Bit beibringen kann? Ich habe den ganzen Tag gegoogelt aber nichts gefunden. Vielleicht bin ich auch nur zu blind um den Baum im Wald zu finden. Kann mir einer von euch helfen?
Poste mal deinen Quelltest. Mit großer Wahrscheinlichkeit hast du bei der Umsetzung in C die klassischen Fehler gemacht. Der avr-gcc kann jedenfalls Maschinencode für Berechnungen mit uint32_t erzeugen!
Es sollte nicht allzu schwierig sein mit 32 bit auf einem Tiny 85 rechnen zu wollen. Solange es nicht allzu viele Koeffizienten sind...
Danke Hier ist der Code. Er ist ein bisschen lang mit seinen Kommentaren, darum habe ich ihn erstmal nicht gepostet gehabt.
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #include <inttypes.h> |
4 | |
5 | //PB2: ADC1 ist der Eingang für die Fotodiode.
|
6 | //PB0: ist der Ausgang für den Motor.
|
7 | //PB4: PCINT4 ist der Steuerausgang für die Fotodioden-Beleuchtung
|
8 | |
9 | // Wenn der Motor dreht, ziehen abwechselnd schwarze und weiße Streifen an
|
10 | // der Fotodiode vorbei. Bei sieben gezählten Streifen soll er wieder anhalten.
|
11 | #define ANZAHL_STREIFEN 7
|
12 | char schwarze_streifen; //Zähler für die schwarzen Streifen |
13 | char wirdsHeller; //wird es heller oder dunkler? |
14 | |
15 | |
16 | // Wenn der Motor steht, soll das Teil 5 Minuten Pause machen bis er wieder anfängt
|
17 | // zu drehen.
|
18 | #define PAUSENLAENGE 600 // halbe Sekunden
|
19 | unsigned int pausenzeit; //zähler für die halben Sekunden |
20 | |
21 | |
22 | // generelle Statemachine im Hauptprogramm
|
23 | #define WARTEN_AUF_MESSUNG 0
|
24 | #define MESSEN_STARTEN 2
|
25 | #define MESSEN_FERTIG 3
|
26 | |
27 | #define PAUSE_EINLAEUTEN 6
|
28 | #define PAUSE 4
|
29 | #define WEITERDREHEN 5
|
30 | |
31 | char cSREG; |
32 | |
33 | |
34 | //Filtervariablen
|
35 | uint32_t mess_hilf, mess_0, mess_1, mess_2, mess_3, mess_4; |
36 | uint32_t ergebnis_4, ergebnis_3, ergebnis_2, ergebnis_1, ergebnis_0; |
37 | uint32_t A, B; // Filter zwischenergebnisse |
38 | |
39 | char communication; //Statemachine Steuervariable |
40 | |
41 | |
42 | ISR(TIM1_COMPA_vect) // Timer 1 meldet einen OCR1A Vergleich |
43 | {
|
44 | cSREG = SREG; |
45 | // Interrupt Code
|
46 | if (communication == PAUSE) |
47 | {
|
48 | pausenzeit = pausenzeit + 1; |
49 | |
50 | if (pausenzeit >= PAUSENLAENGE) |
51 | {
|
52 | communication = WEITERDREHEN; |
53 | }
|
54 | }
|
55 | else
|
56 | {
|
57 | communication = MESSEN_STARTEN; //Messintervall vorüber |
58 | }
|
59 | |
60 | SREG = cSREG; |
61 | //TIFR = 0x7E;
|
62 | sei(); |
63 | }
|
64 | |
65 | //Der ADC meldet sich hier, wenn die Messung fertig ist.
|
66 | ISR (ADC_vect) |
67 | {
|
68 | communication = MESSEN_FERTIG; |
69 | sei(); |
70 | }
|
71 | |
72 | |
73 | void adc_einstellen(void); |
74 | void messwert_filtern(void); |
75 | |
76 | void timer1_einstellen(unsigned char); // umstellen von Pause zur Messen und andersherum |
77 | |
78 | void motor_ein(void); // ein |
79 | void motor_aus(void); // aus |
80 | |
81 | int main(void) |
82 | {
|
83 | // Initialisierungen: globale Variablen
|
84 | |
85 | //Vor-Initialisierung, damit der Filter schneller auf Stand kommt
|
86 | ergebnis_4 = 32768; |
87 | ergebnis_3 = 32768; |
88 | ergebnis_2 = 32768; |
89 | ergebnis_1 = 32768; |
90 | ergebnis_0 = 32768; |
91 | |
92 | //Statemachine initialisieren; mit "drehen" starten.
|
93 | communication = WEITERDREHEN; |
94 | |
95 | wirdsHeller = 2; //wird es heller oder dunkler? |
96 | schwarze_streifen = 0; //wie viele Streifen sind am Sensor vorbeigezogen? |
97 | pausenzeit = 0; //Aktuell verstrichene Pausenzeit |
98 | |
99 | // Initialisierungen: Clock, Ports, Timer, ADC, Interrupts
|
100 | // Clock
|
101 | // Der interne Takt ist eingestellt auf 8 MHz
|
102 | |
103 | |
104 | // Watchdog deaktivieren
|
105 | // WDTCR = 0x00;
|
106 | |
107 | |
108 | // Portpin
|
109 | DIDR0 = 0x00; |
110 | MCUCR = 0x00; // Pull Up Widerstände aktivieren |
111 | DDRB = 0x3F; // Data Direction Register, vorerst komplett als Ausgang |
112 | PORTB = 0x00; // Alle Pins auf Low |
113 | //PINB // Eingangsregister -> will ich nicht -> weggelassen
|
114 | |
115 | // nötige Peripherals einstellen
|
116 | timer1_einstellen(WEITERDREHEN); |
117 | adc_einstellen(); |
118 | pwm_einstellen(); |
119 | |
120 | // LED einstellen
|
121 | DDRB |= (1 << PB4); // Pin für LED auf "Ausgang" schalten |
122 | |
123 | |
124 | |
125 | // Timer-Interrupts aktivieren
|
126 | TIMSK = 0x40; // Timer 1 OCR1A Compare Match Interrupt enabled |
127 | SREG |= 0x80; |
128 | |
129 | |
130 | /*********************************************************************************/
|
131 | |
132 | |
133 | while(1) { |
134 | // Statemachine
|
135 | switch (communication) |
136 | {
|
137 | /**************************************************/
|
138 | case PAUSE: { |
139 | // Warte auf nächsten Zyklusstart;
|
140 | // State wird im Interrupt verändert
|
141 | |
142 | break; |
143 | }
|
144 | /**************************************************/
|
145 | case WEITERDREHEN: { // Start eines neuen Zyklus |
146 | // Sensorbeleuchtung starten
|
147 | PORTB |= (1 << PB4); // LED für den Sensor einschalten |
148 | // Timer 1 umstellen für Sensor Interrupts
|
149 | timer1_einstellen(WEITERDREHEN); |
150 | // Motor starten
|
151 | motor_ein(); |
152 | // Messung starten
|
153 | communication = MESSEN_STARTEN; |
154 | break; |
155 | }
|
156 | /**************************************************/
|
157 | case MESSEN_STARTEN: { //Messung starten |
158 | |
159 | ADCSRA |= (1<<ADSC); // ADSC auf 1 setzen startet den ADC |
160 | communication = WARTEN_AUF_MESSUNG; |
161 | break; |
162 | |
163 | }
|
164 | /**************************************************/
|
165 | case WARTEN_AUF_MESSUNG: { |
166 | // Wartet auf nächstes Messwert-Timer-Intervall oder auf
|
167 | // die Fertigstellung der Messung. Beide States werden
|
168 | // in den Interrupt Handlern gesetzt
|
169 | |
170 | break; |
171 | }
|
172 | /**************************************************/
|
173 | case MESSEN_FERTIG: //Messwert fertig gemessen |
174 | {
|
175 | |
176 | mess_0 = ADCL; |
177 | mess_hilf = ADCH; |
178 | mess_hilf = mess_hilf * 256; |
179 | mess_0 = mess_0 + mess_hilf; |
180 | messwert_filtern(); |
181 | if (ergebnis_0 > ergebnis_4) |
182 | {
|
183 | wirdsHeller = wirdsHeller + 1; |
184 | if (wirdsHeller == 4) //einige Male in Folge heller geworden? |
185 | { //-> Ein schwarzer Streifen ist vorbeigezogen. Zählen! |
186 | schwarze_streifen = schwarze_streifen + 1; |
187 | }
|
188 | if (wirdsHeller > 5) |
189 | {
|
190 | wirdsHeller = 5; |
191 | }
|
192 | |
193 | }
|
194 | if (ergebnis_0 < ergebnis_4) |
195 | { // Es wird dunkler |
196 | wirdsHeller = 0; |
197 | }
|
198 | if (schwarze_streifen >= ANZAHL_STREIFEN) |
199 | {
|
200 | communication = PAUSE_EINLAEUTEN; |
201 | }
|
202 | else communication = WARTEN_AUF_MESSUNG; |
203 | |
204 | break; |
205 | }
|
206 | /**************************************************/
|
207 | case PAUSE_EINLAEUTEN: |
208 | {
|
209 | // Motor stoppen
|
210 | motor_aus(); |
211 | // LED ausschalten
|
212 | PORTB &= ~(1 << PB4); // LED für den Sensor ausschalten |
213 | // Pause machen bis zum nächsten Mal
|
214 | communication = PAUSE; |
215 | // Timer 1 umstellen auf Pausenmodus
|
216 | timer1_einstellen(PAUSE); |
217 | communication = PAUSE; |
218 | break; |
219 | }
|
220 | /**************************************************/
|
221 | default : { |
222 | communication = PAUSE_EINLAEUTEN; |
223 | // Im Fehlerfall lieber den Motor stoppen und in sichere States gehen
|
224 | break; |
225 | }
|
226 | }
|
227 | }
|
228 | /***********************************************************************/
|
229 | return 0; |
230 | }
|
231 | |
232 | /*************************************************************
|
233 | Ausgelagerte ADC-Einstellen-Funktion für die Übersichtlichkeit
|
234 | *************************************************************/
|
235 | void adc_einstellen(void) |
236 | {
|
237 | /*
|
238 | #define ADMUX _SFR_IO8(0x07)
|
239 | #define REFS1 7
|
240 | #define REFS0 6
|
241 | #define ADLAR 5
|
242 | #define REFS2 4
|
243 | #define MUX3 3
|
244 | #define MUX2 2
|
245 | #define MUX1 1
|
246 | #define MUX0 0
|
247 | */
|
248 | ADMUX = 0xE1; //Interne 1.1V Referenz, ADLAR = 1 für linksbündige Ergebnisse, Pin PB2 (ADC1D) als ADC-Eingang |
249 | |
250 | /*
|
251 | ADCSRB
|
252 | Bit 7: Bei 1 wird bipolar gemessen. 0.
|
253 | Bit 5: Bei 1 wird der Eingang negativ gemessen. 0.
|
254 | Bits 2:0 : Auto Trigger Source. Brauche ich nicht, weil ADATE = 0 ist.
|
255 | */
|
256 | ADCSRB = 0x00; |
257 | // ADC1 Pin als Eingang schalten
|
258 | DIDR0 |= (1<<ADC1D); // Digital Input Disable Register; Bit 5 auf 1, damit der AD-Pin nicht digital verwendet wird. |
259 | DDRB &= ~(1<<ADC1D); //Pin ADC1D als Eingang |
260 | /*
|
261 | ADCSRA
|
262 | Bit 7, ADEN: ADC Enable. Auf 1.
|
263 | Bit 6, ADSC: ADC Start Converstion. Auf 1 zum Initialisieren vom AD
|
264 | Bit 5, ADATE: ADC Auto trigger enable: Bei bestimmten Ereignissen automatisch starten. 0 für Aus.
|
265 | Bit 4, ADIF: ADC Interrupt Flag, wird automatisch beschrieben wenn der ADC fertig ist
|
266 | Bit 3, ADIE: ADC Interrupt Enable, auf 1 wenn ein Interrupt nach der Wandlung ausgeführt werden soll. 1.
|
267 | Bit 2:0, ADPS2:0, ADC Prescaler Bits für System Clock. 110 für 8MHz geteilt durch 64 = 125kHz
|
268 | */
|
269 | ADCSRA = 0xCE; //führt auch gleich die erste Konversion für die Initialisierung mit durch |
270 | }
|
271 | |
272 | /*************************************************************
|
273 | Ausgelagerte Motor-Steuern-Funktion für die Übersichtlichkeit
|
274 | Benötigt OCR0A als PWM Ausgang vor-eingestellt
|
275 | *************************************************************/
|
276 | |
277 | void motor_ein(void) |
278 | {
|
279 | PORTB |= (1 << PB0); //Eins auf den Motorpin |
280 | }
|
281 | void motor_aus(void) |
282 | {
|
283 | PORTB &= ~(1 << PB0);//Null auf den Motorpin |
284 | }
|
285 | |
286 | /*************************************************************
|
287 | Ausgelagerte Pausentimer-Einstellen-Funktion für die Übersichtlichkeit
|
288 | Der Pausentimer soll messen, wann die Pause vorbei ist.
|
289 | Er soll außerdem den ADC Takt vorgeben wenn keine Pause ist.
|
290 | Die Funktion soll nur aufgerufen werden um den Timer-Modus umzustellen!
|
291 | *************************************************************/
|
292 | void timer1_einstellen(unsigned char state) |
293 | {
|
294 | if (state == PAUSE) |
295 | {
|
296 | GTCCR = 0x80; // Stoppen vom Timer via setzen von 1 im TSM Bit |
297 | TCCR1 = 0x8F; // Clear on compare match mit OCR1C; Sysclock/16384 ist die Timer Clock (488 Hz) |
298 | OCR1A = 0x0A; // 0x0A = 10; an dieser Zählmarke wird der OCR1A-Interrupt aktiviert. |
299 | OCR1C = 244; // Nach 244 Zählern wird der Timer rückgesetzt -> 2 Interrupts / sec |
300 | GTCCR = 0x00; // kein PWM B, kein Output force, kein löschen von TCCR1, 0 ins TSM Bit -> restart |
301 | }
|
302 | else
|
303 | {
|
304 | GTCCR = 0x80; // Stoppen vom Timer via setzen von 1 im TSM Bit |
305 | TCCR1 = 0x8A; // Clear on compare match mit OCR1C; Sysclock/512 ist die Timer Clock (15625 Hz) |
306 | OCR1A = 0x0A; // 0x0A = 10; an dieser Zählmarke wird der OCR1A-Interrupt aktiviert. |
307 | OCR1C = 31; // Nach 31 Zählern wird der Timer rückgesetzt -> 504 Interrupts / sec |
308 | GTCCR = 0x00; // kein PWM B, kein Output force, kein löschen von TCCR1, 0 ins TSM Bit -> restart |
309 | }
|
310 | }
|
311 | |
312 | |
313 | /****************************************************************************
|
314 | Messwerte filtern
|
315 | |
316 | Benötigt:
|
317 | - 5 Ergebnisvariablen mit uint32_t
|
318 | - 5 Messwertvariablen mit uint32_t
|
319 | - Messwerte 16 Bit breit linksbündig (sorry)
|
320 | - Abtastfrequenz 500Hz
|
321 | - Filtervariablen 32 Bit breit
|
322 | |
323 | Die Filterkoeffizienten wurden mit dem Excel aus dem Projektordner bestimmt.
|
324 | Es handelt sich um ein IIR Filter mit einer Grenzfrequenz von 12,5Hz
|
325 | und 4 Filterstufen nach Butterworth
|
326 | |
327 | *****************************************************************************/
|
328 | void messwert_filtern(void) |
329 | {
|
330 | |
331 | A = 12 * mess_0; //TAP 0 |
332 | A = A + 50 * mess_1; //TAP 1 |
333 | A = A + 75 * mess_2; //TAP 2 |
334 | A = A + 50 * mess_3; //TAP 3 |
335 | A = A + 12 * mess_4; //TAP 4 |
336 | |
337 | A = A + 50; // Faktor entfernen I: die Hälfte vom Faktor drauflegen gegen Rundungsfehler |
338 | A = (int)(A/100); //Faktor entfernen II: Teilen und abrunden |
339 | |
340 | B = 14359 * ergebnis_1; //TAP 1 |
341 | B = B - 19405 * ergebnis_2; //TAP 2 |
342 | B = B + 11696 * ergebnis_3; //TAP 3 |
343 | B = B - 2652 * ergebnis_4; //TAP 4 |
344 | |
345 | ergebnis_0 = A + B + 2000;// Faktor entfernen I: die Hälfte vom Faktor drauflegen gegen Rundungsfehler |
346 | ergebnis_0 = (int)(ergebnis_0 / 4000); //Faktor entfernen II: Teilen und abrunden |
347 | |
348 | //Messwerte durch die TAPs schieben
|
349 | mess_4 = mess_3; |
350 | mess_3 = mess_2; |
351 | mess_2 = mess_1; |
352 | mess_1 = mess_0; //mess0 wird vom ADC gefüllt |
353 | |
354 | //Ergebnisse durch die TAPs schieben
|
355 | ergebnis_4 = ergebnis_3; |
356 | ergebnis_3 = ergebnis_2; |
357 | ergebnis_2 = ergebnis_1; |
358 | ergebnis_1 = ergebnis_0; //ergebnis_0 wird weiter oben berechnet. |
359 | }
|
ich würde dir zum einen das http://www.mikrocontroller.net/articles/Festkommaarithmetik empfehlen und dann mal die frage sind adcl und adch nicht uint16_t ???
Fuer sowas nimmt man die sogenannten Q-Formate. http://en.wikipedia.org/wiki/Q_%28number_format%29 Auch darf die Samplefrequenz und deine hoechste Signalfrequenz nicht zu weit auseinander liegen. Je weiter die auseinander liegen um so kleiner werden deine Filterkonstanten.
0. Wichtige Regeln - erst lesen, dann posten! > Groß- und Kleinschreibung verwenden > Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang 1. Erzähl doch mal bitte in Prosa, was das Ding machen soll. 2. Es erscheint mir alles viel zu kompliziert hingeschrieben. Meine Meinung: man kann das ganze Problem in 30 Zeilen lösen. 3. IIR zum "Entprellen" der Fotozelle? Warum machst Du nicht gleich noch eine Fourie-Analyse? In diesem Fall reicht doch ein Einfachst-Filter. Oder übersehe ich etwas? 4. > A = (int)(A/100); //Faktor entfernen II: Teilen und abrunden > ergebnis_0 = (int)(ergebnis_0 / 4000); //Faktor entfernen II Beitrag "Re: Möglichst Resourcenschonend programmieren" Beitrag "Re: sinus LUT über Interrupt auslesen" --> > A = (int)(A/128); //Faktor entfernen II: Teilen und abrunden > ergebnis_0 = (int)(ergebnis_0 / 4096); //Faktor entfernen II Die vorherigen Faktoren müssen natürlich ebenfalls angepasst werden.
Das mit der Festkommaarythmetik/Q-Format finde ich gut. Danke für den Tipp, die waren mir nicht bekannt. @Helmut: Leider muss ich den Filter so gestalten wie er ist, da ich sonst falsche Ergebnisse bekomme. Das habe ich bereits in meinem Excel ausführlich getestet. Wenn ich die Grenzfrequenz näher an die Samplefrequenz heranschiebe oder die Samplefrequenz verringere, verschwinden die Störsignale nicht so vollständig wie gewünscht. @eProfi: 1. und 4. Es dreht einen Motor. Der Motor dreht eine Scheibe. Auf der Rückseite der Scheibe sind schwarze und weiße Streifen. Diese Streifen schaut sich ein Sensor an, während sie vorbeiziehen. Es sind ca 1 bis maximal 3 schwarze Streifen pro Sekunde. Nach sieben Streifen (ungefähr 420° Drehung) soll der Motor stoppen und fünf Minuten lang ruhig sein. Ein LDR war mein erster Ansatz, der war aber zu langsam. (ich habe es erst nicht geglaubt, aber es ist so.) Also wurde es eine Fotodiode. Die Fotodiode ist schnell genug. Die schaut sich natürlich auch die 50Hz aus der Energiesparlampe, die 150Hz aus meiner Osram Neonröhre und die Schaltungsinternen Störfrequenzen aus dem Motor mit an. Deshalb soll vernünftig gefiltert werden. Ein Einfachst-Filter (gleitender Durchschnitt oder sowas) kann das NICHT. Da erscheinen die Störfrequenzen an der Abtastrate gespiegelt unvorhersehbar irgendwo - falls die Abtastrate in der Nähe der Störfrequenz liegt. Bei dieser Anwendung wäre das leiter nötig. Daher baue ich lieber gleich einen echten Filter. Von der Geschwindigkeit und Rechenkapazität und Speicherkapazität kann der Attiny85 das ganz locker. Klar soweit? Die Filterauslegung braucht man heutzutage nicht mehr rechnen, das machen online Tools wie dieses hier: http://www.dsptutor.freeuk.com/IIRFilterDesign/IIRFiltDes102.html ganz kostenlos und einfach für dich. Deshalb ist das auch überhaupt kein großer Aufwand - Rechenkapazität braucht es vergleichbar viel wie ein guter gleitender Durchschnitt, es funktioniert nur viel besser. 2. Ich bin der Meinung dass es mit einigen Subfunktionen und viel Kommentar später leichter für mich verständlich ist. Ich verwende meine Subs in späteren Programmen wieder, und da ist es gut wenn sie von vornherein freigeschnippelt und kommentiert sind. Der Compiler löscht den überflüssigen Kram schließlich, der AVR kriegt davon nicht viel mit. 3. Klar, das ist sinnvoll Zweierpotenzen zu nehmen. Das setze ich um. Danke.
Ich habe den möglichen Fehler gefunden, ich komme aber nicht darauf weshalb das so ist. Ich habe herausgefunden: Er verwendet die beiden ISRs. Er geht in die States - Weiterdrehen - Messen_starten - Warten_auf_Messung Was er anscheinend nicht tut: Obwohl er in die ISR vom ADC geht, geht er hinterher nicht in den State Messen_fertig. Hat einer eine Ahnung warum? Habe ich den Interrupt falsch programmiert? Hier noch mal in kürze der C Code von der ISR
1 | //Der ADC meldet sich hier, wenn die Messung fertig ist.
|
2 | ISR (ADC_vect) |
3 | {
|
4 | communication = MESSEN_FERTIG; |
5 | sei(); |
6 | }
|
Muss das ADC Int Flag gelöscht werden, oder wird das automatisch bei Auslösen der Int Prozedur erledigt? Hab jetzt gerade kein Datenblatt zur Hand. Grüße
Und setz mal communication auf volatile, damit der Compiler da "Bescheid" weiß.
GCC (und die anderen C Compiler wohl auch) kümmert sich schon selbst um das retten des SREG, und das SEI am Ende der ISR ist auch nicht nötig aber eventuell gefährlich. Das Interrupt-flag vom AD wird schon beim Aufruf der ISR vom µC gelöscht.
Entweder war es der Volatile oder der Sei()... jedenfalls geht es jetzt. Vielen Dank euch allen!
Kleiner Tipp übrigens, setzte die Abtastrate auf ein größeres Vielfaches der Störfrequenz. Dann falten sich die Störungen tendenziell eher auf höhere Frequenzen. Davor muss aber ein Filter rein.
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.