Forum: Mikrocontroller und Digitale Elektronik Taster über externe Stromquelle - GND verbinden?


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Christoph K. (christoph13524)


Angehängte Dateien:

Bewertung
-2 lesenswert
nicht lesenswert
Hallo!

Ich bin Anfänger mit Mikrocontroller und habe eine Frage, wo ich noch 
nichts im Internet auf die Schnelle gefunden habe.

Ich möchte wissen ob das funktioniert:
Mein Atmega8 ist ganz normal an einer 5V Stromversorgung angeschlossen.
Ich möchte einen Taster mit Pulldown-Widerstand von einer anderen 5V 
Stromquelle anschließen. Muss ich die GND-Leitungen der beiden 
Stromversorgungen verbinden oder nicht? Strom braucht ja immer einen 
Kreis.. aber hier bin ich mir nicht ganz sicher. Schadet natürlich 
nicht, aber ich würde gerne darauf verzichten, wenn möglich.
Vereinfachter Schaltplan ist angehängt.

Ich habe nämlich ein Problem mit irgendwelchen Störungen an einem 
Projekt, wo der Taster hin und wieder zufällig ausgelöst wird, wenn der 
Taster an der gleichen Stromversorgung, wie vom Mikrocontroller hängt. 
Erstmal wäre einfach eine kurze Antwort zur genannten Frage hilfreich. 
Wenn ich die GND verbinden muss, werde ich das Problem wahrscheinlich 
wieder haben. Dann kann ich das genauer beschreiben und vielleicht hilft 
mir wer dann bei der Problemsuche.

Danke erstmals,
Christoph

von Peter D. (peda)


Bewertung
1 lesenswert
nicht lesenswert
Galvanische Trennung geht gut mit einem AQY212 Halbleiterrelais.

von Thomas S. (thomas_s72)


Bewertung
1 lesenswert
nicht lesenswert
Ja!
Die Massen müssen verbunden sein, sonst funktioniert es nicht.
Falls das nicht gewünscht oder möglich ist kann man auch einen 
Optokoppler verwenden.

von HildeK (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Christoph K. schrieb:
> Ich möchte wissen ob das funktioniert:

Nein, das funktioniert nicht!
Die GNDs müssen verbunden sein.

von Christoph K. (christoph13524)


Bewertung
0 lesenswert
nicht lesenswert
Ok, danke für die Info - habe ich mir schon gedacht.

Wie funktioniert das mit dem Optokoppler? Kann den vielleicht wer in 
meinen Schaltplan einzeichnen? Der muss ja die GND verbinden aber auch 
galvanisch trennen? Check ich gerade nicht wirklich...

von Thomas S. (thomas_s72)


Bewertung
-1 lesenswert
nicht lesenswert

von HildeK (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Christoph K. schrieb:
> Wie funktioniert das mit dem Optokoppler?
          VCC
           +
           |
    .------+-----.     VCC
    |            |      +
    |            |      |       .-----------.
    |            |     .-.      |           |
    |            |     | |      |           |
    |            |     | |     .-.          |
    |            |     '_'     | |        | o
    |            |      |      | |      |=|>
    |            +------o      '-'        | o
    |            |      |       |           |
    |            |       \|     |           |
    |            |        |  <- V          ---
    |            |       <|     -           -
    '------+-----'      |  OK   |           |
           |            |       '-----------'
           |           ===
          ===          GND
          GND
(created by AACircuit v1.28.6 beta 04/19/05 www.tech-chat.de)

von Dussel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Vielleicht als Anmerkung: OK steht für Optokoppler. Das ist kein 
Transistor.
Vielleicht war ich einfach zu dumm, aber ich habe das erstmal als 
Bipolartransistor interpretiert und das OK als 'Ok, kann man so machen'. 
Dann habe ich mich gewundert, wie das funktionieren soll. ;-)

von MaWin (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Christoph K. schrieb:
> Strom braucht ja immer einen Kreis

Richtig.

Also eine Hin und eine Rückleitung.

Aber: was passiert wenn man GND verbindet ? Bei manchen Geräten kann es 
funken, weil sie schon woanders verbunden sind. Und bei anderen kann der 
Anschluss von weit entferntem sich Störungen einfangen.

Was passiert, wenn das eine Gerät eingeschaltet ist und das andere noch 
nicht ? Und andersrum.

Daher kann eine Trennung über Optokoppler oder Relais sinnvoll sein. 
Erzähle also mehr über die Geräte.

von Christoph K. (christoph13524)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Antworten.

Lassen wir mal das mit dem Optokoppler - ich hätte das eigentlich anders 
gemeint.

Jetzt zum ursprünglichen Problem eigentlich:
Angehängt ist der Schaltplan; grob und schlecht bzw. schematisch 
gezeichnet aber ich hoffe man versteht und erkennt alles - sonst bitte 
nachfragen. Die roten strichlierten Linien sind natürlich auch normale 
Leitungen...

Kurze Funktionserklärung:
Ich habe eine Silikonheizmatte, die von einem Temp.-Controller geregelt 
wird und einen Lüfter. Ich habe 4 Servomotoren, die ich (jeweils 2) 
ansteuere. Weiters noch einen motorisierten Kugelhahn, eine LED und eine 
Niveausonde (wenn Wasser steigt, fließt Strom und wird erkannt).
Alles zusammen wird von dem Atmega8 und Attiny45 gesteuert. Der Attiny 
war nur eine Notlösung, weil ich Probleme hatte, den ganzen Code nur auf 
den Atmega8 zu packen. Der Attiny harmoniert mit dem Atmega und steuert 
dann nur die LED an.
Einen Taster gibt es auch noch. Wenn ich den Taster drücke, schaltet die 
Heizung und Lüfter aus, der Kugelhahn schließt sich, die Servos springen 
kurz an und die LED leuchtet anders. Ein erneutes Drücken schaltet das 
ganze System wieder ein. So kann man sich das alles ungefähr vorstellen. 
Wenn die Niveausonde Kontakt mit Wasser hat, schließt diese nur den 
Kugelhahn.

Die beiden Widerstände an den Servoleitungen sind da, dass die Servos 
beim Stromausfall nicht kurz zucken - hilft etwas mit den Widerständen.

Alles funktioniert eigentlich einwandfrei nur es gibt 1 Problem: Der 
Taster wird komplett zufällig alle paar Minuten ohne irgendwelche 
Ereignisse geschalten. Ich habe schon so viel ausprobiert an was das 
liegen kann aber ich komme nicht drauf.

Was ich probiert habe, um das Problem zu beheben:

1. Taster mit Pullup-Widerstand gemacht - erfolglos
2. Den Taster einfach mal an 2 Signalleitungen (PB0 und PC0) gehängt (so 
wie es im Schaltplan derzeit eingezeichnet ist) - natürlich auch 
erfolglos
3. Das Problem tritt nicht auf, wenn ich die Silikonheizmatte abstecke! 
Ich denke es treten irgendwo Wirbelströme oder Magnetfelder auf, die den 
Taster willkürlich auslösen - durch den Wechselstrom irgendwie.
4. Taster funktioniert einwandfrei; Problem tritt auch ganz ohne Taster 
auf.

GND_1 und GND_2 sind nicht verbunden. Ist ja galvanisch getrennt durch 
das Relais. Könnte man aber ja machen.

Ist der Pulldown Widerstand am Taster zu groß/klein? Das Kabel vom 
Taster ist rund 2m lang. Habe gelesen, dass wenn der Pulldown zu groß 
ist, kein eindeutiges 0V-Signal am Mikrocontroller erkannt wird.

Ich bekomme einfach irgendeine Störung an die Leitung vom Taster von 
GND_1 über den Pulldown.

Kann irgendein Kondensator dort helfen?

Habt ihr Ideen bzw. seht ihr Fehler im Schaltplan?
Kann das Problem wirklich ein Magnetfeld/ Wirbelströme sein? Kann mir 
das schwer vorstellen. Aber es hat auf jeden Fall etwas mit der 
Heizmatte zu tun (denke ich, da das Problem nicht auftritt, wenn 
abgesteckt, wie gesagt).

Silikonheizmatte hat 400W 230VAC. Ist in keiner Spulenform gewickelt...

: Bearbeitet durch User
von Peter D. (peda)


Bewertung
1 lesenswert
nicht lesenswert
Christoph K. schrieb:
> Der
> Taster wird komplett zufällig alle paar Minuten ohne irgendwelche
> Ereignisse geschalten.

Das deutet auf einen typischen Softwarefehler hin. Der Taster wird mit 
einem externen Interrupt eingelesen und die Entprellroutine taugt 
nichts.

von Christoph K. (christoph13524)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Habe den Code als Datei angehängt.
Ist extrem schlecht und mit vielen Notlösungen geschrieben - das weiß 
ich selber. Ich hoffe, ihr kennt euch trotzdem irgendwie aus... Ich bin 
Anfänger. Es sollte einfach funktionieren und mehr nicht.

Habe den Taster einfach mit einem 20ms delay entprellt.

: Bearbeitet durch User
von Christoph K. (christoph13524)


Bewertung
0 lesenswert
nicht lesenswert
Hier nochmal der Code vom Atmega8 hier gepostet:

Ich bin mir nicht sicher, ob es ein Hardware- oder Softwareproblem ist.
#define F_CPU 8000000UL

#include <avr/io.h>
#include <avr/interrupt.h>        // für Servo
#include <util/delay.h>          // für Zeit

#define button_down    ((PINC & (1<<PINC0)) && (PINC & (1<<PINB0)))  // Taster gedrückt, wenn PC0 UND PB0 = high

// Der Prescaler muss so gewählt werden, dass der Ausdruck
// für MILLISEC_BASE einen Wert kleiner als 128 ergibt
// MILLISEC_BASE ist der Timerwert, der 1 Millisekunde Zeitdauer ergeben
// soll.
//
#define PRESCALER      128
#define PRESCALER_BITS ( 1 << CS22) | ( 1 << CS20 )

#define MILLISEC_BASE  ( F_CPU / PRESCALER / 1000 )
#define CENTER         ( MILLISEC_BASE / 2 )

//
// Konfiguration der Servoleitungen
//
#define NR_SERVOS      8
#define SERVO_DDR      DDRD
#define SERVO_PORT     PORTD
uint8_t ServoPuls[NR_SERVOS] = { 1<<PD1, 1<<PD2 };

// Werte für die Servoposition
// Gültige Werte laufen von 0 bis 2 * CENTER
// 0           ... ganz links
// CENTER      ... Mittelstellung
// 2 * CENTER  ... ganz rechts
//
volatile uint8_t ServoValue[NR_SERVOS];

ISR (TIMER2_COMP_vect)
{
  static uint8_t ServoId = 0;

  //
  // den Puls des aktuellen Servos beenden
  //
  SERVO_PORT &= ~ServoPuls[ServoId];

  //
  // welches ist das nächste aktuelle Servo?
  //
  if( ++ServoId >= NR_SERVOS )
  ServoId = 0;

  //
  // die Ausgangsleitung fuer dieses Servo auf 1; den Puls beginnen
  //
  SERVO_PORT |= ServoPuls[ServoId];

  //
  // den Timer so einstellen, dass bei Pulsende, die ISR erneut aufgerufen wird
  //
  OCR2 = MILLISEC_BASE + ServoValue[ServoId];
}

void InitServo()
{
  //
  // Die Servoleitungen auf Ausgang stellen
  //
  SERVO_DDR = ServoPuls[0] | ServoPuls[1] | ServoPuls[2] | ServoPuls[3] |
  ServoPuls[4] | ServoPuls[5] | ServoPuls[6] | ServoPuls[7];

  //
  // Timer auf CTC Modus konfigurieren
  //
  OCR2 = MILLISEC_BASE + ServoValue[0];
  TIMSK |= (1<<OCIE2);
  TCCR2 = (1<<WGM21) | PRESCALER_BITS;  // CTC mode
}

enum button {off, on} state;        // off=0, on=1

int main(void)
{
  InitServo();              // für Servos
  sei();                  // für Servos
  
  state = on;                // Zustand ist am Anfang AN (wegen Stromausfall)
  DDRD |= (1<<PD0);            // PD0 auf Ausgang (SSR)
  DDRD |= (1<<PD3);            // PD3 auf Ausgang (Wechsler)
  DDRB |= (1<<PB3);            // PB3 auf Ausgang (Signal an ATTINY für LED = weiß)
  DDRB |= (1<<PB4);            // PB4 auf Ausgang (Signal an ATTINY für LED = orange)
  DDRB |= (1<<PB5);            // PB5 auf Ausgang (Signal an ATTINY für LED = orange blinkend)
  DDRC &= ~(1<<PINC0);          // PC0 auf Eingang (Taster)  
  DDRB &= ~(1<<PINB0);          // PB0 auf Eingang (Taster)  
  DDRC &= ~(1<<PINC1);          // PC1 auf Eingang (Niveausonde)  
  
  uint8_t a = 0;
  uint8_t b = 0;
  
    while (1) 
    {  
    if (button_down)          // Wenn Taster gedrückt ist
    {
      _delay_ms(20);          // Prellzeit abwarten
      if (state == off)        // Wenn Zustand zuvor OFF war
      {
        state = on;
      }
      else if (state == on)      // Wenn Zustand zuvor ON war
      {
        state = off;
      }
      while (button_down);      // Warten bis Taster losgelassen wird
    }
    
    else if (state == on)        // System läuft
    {
      if (b == 0)
      {
        PORTD |= (1<<PD0);            // SSR an
        TCCR2 = (1<<WGM21) | PRESCALER_BITS;  // Timer an
        ServoValue[0] = 0.9 * CENTER;      // Servos 1 ZU
        ServoValue[1] = 1.93 * CENTER;      // Servos 2 ZU
        _delay_ms(2000);
        TCCR2 = 0;                // Timer aus
        b = 1;      
      }

      else if ( !(PINC & (1<<PC1)) )        // Wenn Niveausonde Kontakt hat
      {    
        PORTD &= ~(1<<PD3);            // Wechsler aus (Ventil ZU)            
        PORTB &= ~(1<<PB3);            // LED = weiß = aus
        PORTB &= ~(1<<PB5);            // LED = orange blinkend = aus
        PORTB |= (1<<PB4);            // LED = orange = an        
      }
      
      else if ( PINC & (1<<PC1) )          // wenn Niveausonde keinen Kontakt hat
      {
        PORTD |= (1<<PD3);            // Wechsler an (Ventil AUF)  
        PORTB &= ~(1<<PB5);            // LED = orange blinkend = aus
        PORTB &= ~(1<<PB4);            // LED = orange = aus
        PORTB |= (1<<PB3);            // LED = weiß = an      
      }
      a = 1;
    }
    
    else if (state == off)              // System steht
    {  
      if (a == 1)                  // damit die Schleife nur 1 mal durchlaufen wird
      {
      PORTD &= ~(1<<PD0);              // SSR aus
      PORTD &= ~(1<<PD3);              // Wechsler aus (Ventil ZU)      
      PORTB &= ~(1<<PB3);              // LED = weiß = aus        
      PORTB &= ~(1<<PB4);              // LED = orange = aus
      PORTB |= (1<<PB5);              // LED = orange blinkend = an
      _delay_ms(12000);              // Warten bis der Lüfter steht
      TCCR2 = (1<<WGM21) | PRESCALER_BITS;    // Timer an
      ServoValue[0] = 2.8 * CENTER;        // Servos 1 AUF
      ServoValue[1] = -0.8;            // Servos 2 AUF  
      PORTB &= ~(1<<PB5);              // LED = orange blinkend = aus  (LED bleibt aus)        
      _delay_ms(2000);            
      TCCR2 = 0;                  // Timer aus
      a = 2;
      b = 0;
      }
    }
    }
}

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Christoph K. schrieb:
> if (button_down)          // Wenn Taster gedrückt ist
>     {
>       _delay_ms(20);          // Prellzeit abwarten

Sowas hatte ich befürchtet. Planloses Delay ist noch lange kein 
Entprellen. Du müßtest mindestens danach nochmal prüfen, ob noch 
gedrückt oder nur Preller.
Am besten ist natürlich, sämtliche Eingänge parallel zu entprellen im 
Timerinterrupt. Dann kann sich das Main auf die Anwendung konzentrieren 
und wird übersichtlicher.

Christoph K. schrieb:
> if (state == off)        // Wenn Zustand zuvor OFF war
>       {
>         state = on;
>       }
>       else if (state == on)      // Wenn Zustand zuvor ON war

Das ist Unsinn. Wenn nur 2 Zustände möglich sind, dann liegt beim else 
automatisch der andere Zustand vor. Der 2. Test ist daher überflüssig.

von Christoph K. (christoph13524)


Bewertung
0 lesenswert
nicht lesenswert
Ok, danke für den Hinweis!
Ich weiß, dass es andere und bessere Entprell-Codes gibt, wollte es aber 
nicht zu schwierig für mich machen..

Wäre also das hier ok?
Nach den 20ms nochmal abfragen, ob der Taster immer noch gedrückt ist.
Und statt dem überflüssigen else if nur else geschrieben.
 
   if (button_down)          // Wenn Taster gedrückt ist
    {
      _delay_ms(20);          // Prellzeit abwarten
      if (button_down)          // Wenn Taster immer noch gedrückt ist
      {
        if (state == off)        // Wenn Zustand zuvor OFF war
        {
          state = on;
        }
        else                 // Wenn Zustand zuvor ON war
        {
          state = off;
        }
      }
      while (button_down);      // Warten bis Taster losgelassen wird
    }

Fehlt noch was? Braucht ein if immer ein else oder so?
LG

von Christoph K. (christoph13524)


Bewertung
0 lesenswert
nicht lesenswert
Hi,

es klappt einfach nicht, wie es soll.
Der Taster wird nun nach der Codeänderung nicht mehr ausgelöst, jedoch 
passieren wieder zufällig alle paar Minuten andere komische Dinge 
(gerade ist der Fehler erst nach 1 Stunde gekommen).

Die LED ist nun ausgegangen und ich konnte den Taster nicht mehr 
drücken. Einfach keine Funktion mehr... Lüfter und Heizung liefen jedoch 
weiter. Servos haben sich auch nicht verstellt.
Es ist im Code unmöglich, dass die LED ausgeht, ohne dass die Servos 
runter fahren...

Ich glaube nach wie vor, dass ich irgendeine Störung von der 230VAC 
Silikonheizmatte hinein bekomme. Wenn ich diese abstecke, habe ich die 
Probleme noch nie gehabt.

Hat wer eine Idee/Lösungsvorschläge?

Kann man (wenn das Problem wirklich die Heizmatte ist) die Heizmatte im 
Notfall mit Gleichstrom betreiben? Eventuell einfach einen Gleichrichter 
davor packen? Die ist nur ein Heizdraht ohne Elektronik mit 
Bimetall-Sicherung. Hat 400W. Verändert sich dann dadurch die Leistung? 
Wird sowieso auf niedrige 55°C geregelt.
#define F_CPU 8000000UL

#include <avr/io.h>
#include <avr/interrupt.h>        // f¸r Servo
#include <util/delay.h>          // f¸r Zeit

#define button_down    ((PINC & (1<<PINC0)) && (PINC & (1<<PINB0)))  // Taster gedr¸ckt, wenn PC0 UND PB0 = high

// Der Prescaler muss so gew‰hlt werden, dass der Ausdruck
// f¸r MILLISEC_BASE einen Wert kleiner als 128 ergibt
// MILLISEC_BASE ist der Timerwert, der 1 Millisekunde Zeitdauer ergeben
// soll.
//
#define PRESCALER      128
#define PRESCALER_BITS ( 1 << CS22) | ( 1 << CS20 )

#define MILLISEC_BASE  ( F_CPU / PRESCALER / 1000 )
#define CENTER         ( MILLISEC_BASE / 2 )

//
// Konfiguration der Servoleitungen
//
#define NR_SERVOS      8
#define SERVO_DDR      DDRD
#define SERVO_PORT     PORTD
uint8_t ServoPuls[NR_SERVOS] = { 1<<PD1, 1<<PD2 };

// Werte f¸r die Servoposition
// G¸ltige Werte laufen von 0 bis 2 * CENTER
// 0           ... ganz links
// CENTER      ... Mittelstellung
// 2 * CENTER  ... ganz rechts
//
volatile uint8_t ServoValue[NR_SERVOS];

ISR (TIMER2_COMP_vect)
{
  static uint8_t ServoId = 0;

  //
  // den Puls des aktuellen Servos beenden
  //
  SERVO_PORT &= ~ServoPuls[ServoId];

  //
  // welches ist das n‰chste aktuelle Servo?
  //
  if( ++ServoId >= NR_SERVOS )
  ServoId = 0;

  //
  // die Ausgangsleitung fuer dieses Servo auf 1; den Puls beginnen
  //
  SERVO_PORT |= ServoPuls[ServoId];

  //
  // den Timer so einstellen, dass bei Pulsende, die ISR erneut aufgerufen wird
  //
  OCR2 = MILLISEC_BASE + ServoValue[ServoId];
}

void InitServo()
{
  //
  // Die Servoleitungen auf Ausgang stellen
  //
  SERVO_DDR = ServoPuls[0] | ServoPuls[1] | ServoPuls[2] | ServoPuls[3] |
  ServoPuls[4] | ServoPuls[5] | ServoPuls[6] | ServoPuls[7];

  //
  // Timer auf CTC Modus konfigurieren
  //
  OCR2 = MILLISEC_BASE + ServoValue[0];
  TIMSK |= (1<<OCIE2);
  TCCR2 = (1<<WGM21) | PRESCALER_BITS;  // CTC mode
}

enum button {off, on} state;        // off=0, on=1

int main(void)
{
  InitServo();              // f¸r Servos
  sei();                  // f¸r Servos
  
  state = on;                // Zustand ist am Anfang AN (wegen Stromausfall)
  DDRD |= (1<<PD0);            // PD0 auf Ausgang (SSR)
  DDRD |= (1<<PD3);            // PD3 auf Ausgang (Wechsler)
  DDRB |= (1<<PB3);            // PB3 auf Ausgang (Signal an ATTINY f¸r LED = weifl)
  DDRB |= (1<<PB4);            // PB4 auf Ausgang (Signal an ATTINY f¸r LED = orange)
  DDRB |= (1<<PB5);            // PB5 auf Ausgang (Signal an ATTINY f¸r LED = orange blinkend)
  DDRC &= ~(1<<PINC0);          // PC0 auf Eingang (Taster)  
  DDRB &= ~(1<<PINB0);          // PB0 auf Eingang (Taster)  
  DDRC &= ~(1<<PINC1);          // PC1 auf Eingang (Niveausonde)  
  
  uint8_t a = 0;
  uint8_t b = 0;
  uint16_t i = 0;
  
    while (1) 
    {  
    if (button_down)                // Wenn Taster gedr¸ckt ist
    {
      _delay_ms(20);                // Prellzeit abwarten
      if (button_down)              // Wenn Taster immer noch gedr¸ckt ist
      {
        if (state == off)            // Wenn Zustand zuvor OFF war
        {
          state = on;
        }
        else if (state == on)          // Wenn Zustand zuvor ON war
        {
          state = off;
        }
      }  
      while (button_down);            // Warten bis Taster losgelassen wird
    }
    
    else if (state == on)              // System l‰uft
    {
      if (b == 0)
      {
        PORTD |= (1<<PD0);            // SSR an
        TCCR2 = (1<<WGM21) | PRESCALER_BITS;  // Timer an
        ServoValue[0] = 0.9 * CENTER;      // Servos 1 ZU
        ServoValue[1] = 1.93 * CENTER;      // Servos 2 ZU
        _delay_ms(2000);
        TCCR2 = 0;                // Timer aus
        b = 1;
        a = 1;    
      }

      if ( !(PINC & (1<<PC1)) )          // Wenn Niveausonde Kontakt hat
      {    
        PORTD &= ~(1<<PD3);            // Wechsler aus (Ventil ZU)            
        PORTB &= ~(1<<PB3);            // LED = weifl = aus
        PORTB &= ~(1<<PB5);            // LED = orange blinkend = aus
        PORTB |= (1<<PB4);            // LED = orange = an        
      }
      
      else if ( (PINC & (1<<PC1)) && (i == 0) )  // wenn Niveausonde keinen Kontakt hat; i damit nur alle 5 Minuten aufgerufen wird
      {
        PORTD |= (1<<PD3);            // Wechsler an (Ventil AUF)  
        PORTB &= ~(1<<PB5);            // LED = orange blinkend = aus
        PORTB &= ~(1<<PB4);            // LED = orange = aus
        PORTB |= (1<<PB3);            // LED = weifl = an      
      }
      
      i++;                    // i um 1 erhˆhen
      _delay_ms(10);
      
      if (i >= 30000)                // 10ms * 30000 Durchg‰nge = 5min 
      {
        i = 0;
      }    
    }
    
    else if ( (state == off) && (a == 1) )      // System steht; a == 1 damit die Schleife nur 1 mal durchlaufen wird
    {  
      PORTD &= ~(1<<PD0);              // SSR aus
      PORTD &= ~(1<<PD3);              // Wechsler aus (Ventil ZU)      
      PORTB &= ~(1<<PB3);              // LED = weifl = aus        
      PORTB &= ~(1<<PB4);              // LED = orange = aus
      PORTB |= (1<<PB5);              // LED = orange blinkend = an
      _delay_ms(12000);              // Warten bis der L¸fter steht
      TCCR2 = (1<<WGM21) | PRESCALER_BITS;    // Timer an
      ServoValue[0] = 2.8 * CENTER;        // Servos 1 AUF
      ServoValue[1] = -0.8;            // Servos 2 AUF  
      PORTB &= ~(1<<PB5);              // LED = orange blinkend = aus  (LED bleibt aus)        
      _delay_ms(2000);            
      TCCR2 = 0;                  // Timer aus
      a = 0;
      b = 0;
    }
    }
}

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Christoph K. schrieb:
> es klappt einfach nicht, wie es soll.

Das Problem wird sein, daß die Entprellerei fest mit dem restlichen Code 
verheiratet ist. Damit stören sämtliche Laufzeiten die Tastenabfrage. 
Die kleinsten Änderung an der Laufzeit der Mainloop und die Entprellung 
verhält sich völlig anders und unvorhersehbar.

Es hat schon seinen Grund, warum man Tasten im Timerinterrupt mit einem 
konstanten und definierten Intervall entprellt. Alles andere ist Murks.

Das Arbeiten mit Events ist nicht nur auf dem PC sinnvoll, es entkrampft 
auch vieles auf einem kleinen ATtiny13.

von Christoph K. (christoph13524)


Bewertung
0 lesenswert
nicht lesenswert
Ok danke! Bevor ich mich ran wage, den Taster nun richtig zu entprellen, 
möcht ich nochmal genau nachhaken:

Die genannten seltsamen Probleme treten auf, OHNE den Taster je gedrückt 
zu haben. Man schaltet die Stromquelle ein und das System ist ja so 
programmiert, dass gleich alles angeht.
Also ohne je den Taster gedrückt zu haben, passieren diese Dinge - das 
heißt ja, dass die derzeitige Entprellroutine nie aufgerufen wurde.
Ist dann deine Behauptung weiterhin möglich?

Hardwareseitig entprellen wäre auch eine Option...

Sonst muss ich mich an das für mich schwierige softwaretechnische 
Entprellen heranwagen - habe ja schon einen Timer für die Servos in 
Verwendung. Und der Attiny85 ist nur als Notlösung da, weil ichs damals 
auch nicht geschafft habe, einen zweiten Timer irgendwie zu starten. 
Naja was solls; muss dann wohl probieren aber brauche wahrscheinlich 
Unterstützung.

von Christoph K. (christoph13524)


Bewertung
-1 lesenswert
nicht lesenswert
Habe hier im Thread https://www.mikrocontroller.net/articles/Entprellung
den Punkt Flankenerkennung entdeckt.
Diese Art von Entprellung wäre doch auch möglich oder? Ganz ohne 
Interrupt.
Ich muss ja nichts zählen mit dem Taster. Der soll ja nur was schalten.

Jedoch verstehe ich nicht, wie bei dieser Methode die Entprellung 
funktioniert. Meiner Logik nach, entprellt hier nichts.
„Die Entprellung geschieht dabei durch die ganze Laufzeit des Programms. 
Die Routine gibt den Zustand 1 für steigende Flanke aus, sonst 0“.

Steigende Flanken habe ich jedoch mehrere während dem Prellen. Also 
schwankt doch der Zustand (rw) während dem Prellen mehrmals zwischen 1 
und 0. Also wird hier gar nichts entprellt? Wo ist mein Denkfehler?

von Christoph K. (christoph13524)


Bewertung
-1 lesenswert
nicht lesenswert
Edit:
Eigentlich bräuchte ich doch gar keine Entprellung.

Wenn der Taster gedrückt wird, führt dieser ja sofort bei der ersten 
Flankenänderung einen Befehl aus. Also schaltet das System gleich ein 
oder aus. Und dieses Ein- oder Ausschalten dauert sowieso deutlich 
länger (durch delays), als dass der Taster prellt.

von Joachim B. (jar)


Bewertung
0 lesenswert
nicht lesenswert
Christoph K. schrieb:
> Edit:
> Eigentlich bräuchte ich doch gar keine Entprellung.

kannst du ja glauben, vielleicht klappts, aber sauber geht anders!

PeDa hats erklärt und das funktioniert sicher!

https://www.mikrocontroller.net/articles/Entprellung

machs im Timer IRQ nach dannegger

von Christoph K. (christoph13524)


Bewertung
0 lesenswert
nicht lesenswert
Hab jetzt gar keine Entprellung im Code gemacht.
Soweit funktioniert alles wie gehabt. Also Taster kann man normal 
drücken usw.
...bis nach zufälliger Zeit wieder komische Dinge passieren.
.. z.B. Taster nicht mehr drückbar oder LED geht aus (was wie gesagt, 
nicht passieren kann, ohne dass die Servos herunter fahren).

Wenn ich jetzt gar keine Entprellung habe, weil ich diese einfach nicht 
brauche, wo ist der Fehler / wo ist die Störung?

Werde morgen die Silikonheizmatte mit einem Brückengleichrichter mit 
Gleichspannung betreiben. Bimetallschalter habe ich gelesen, darf man 
nicht mit Gleichspannung betreiben.
#define F_CPU 8000000UL

#include <avr/io.h>
#include <avr/interrupt.h>        // f¸r Servo
#include <util/delay.h>          // f¸r Zeit

#define button_down    ((PINC & (1<<PINC0)) && (PINC & (1<<PINB0)))  // Taster gedr¸ckt, wenn PC0 UND PB0 = high

// Der Prescaler muss so gew‰hlt werden, dass der Ausdruck
// f¸r MILLISEC_BASE einen Wert kleiner als 128 ergibt
// MILLISEC_BASE ist der Timerwert, der 1 Millisekunde Zeitdauer ergeben
// soll.
//
#define PRESCALER      128
#define PRESCALER_BITS ( 1 << CS22) | ( 1 << CS20 )

#define MILLISEC_BASE  ( F_CPU / PRESCALER / 1000 )
#define CENTER         ( MILLISEC_BASE / 2 )

//
// Konfiguration der Servoleitungen
//
#define NR_SERVOS      8
#define SERVO_DDR      DDRD
#define SERVO_PORT     PORTD
uint8_t ServoPuls[NR_SERVOS] = { 1<<PD1, 1<<PD2 };

// Werte f¸r die Servoposition
// G¸ltige Werte laufen von 0 bis 2 * CENTER
// 0           ... ganz links
// CENTER      ... Mittelstellung
// 2 * CENTER  ... ganz rechts
//
volatile uint8_t ServoValue[NR_SERVOS];

ISR (TIMER2_COMP_vect)
{
  static uint8_t ServoId = 0;

  //
  // den Puls des aktuellen Servos beenden
  //
  SERVO_PORT &= ~ServoPuls[ServoId];

  //
  // welches ist das n‰chste aktuelle Servo?
  //
  if( ++ServoId >= NR_SERVOS )
  ServoId = 0;

  //
  // die Ausgangsleitung fuer dieses Servo auf 1; den Puls beginnen
  //
  SERVO_PORT |= ServoPuls[ServoId];

  //
  // den Timer so einstellen, dass bei Pulsende, die ISR erneut aufgerufen wird
  //
  OCR2 = MILLISEC_BASE + ServoValue[ServoId];
}

void InitServo()
{
  //
  // Die Servoleitungen auf Ausgang stellen
  //
  SERVO_DDR = ServoPuls[0] | ServoPuls[1] | ServoPuls[2] | ServoPuls[3] |
  ServoPuls[4] | ServoPuls[5] | ServoPuls[6] | ServoPuls[7];

  //
  // Timer auf CTC Modus konfigurieren
  //
  OCR2 = MILLISEC_BASE + ServoValue[0];
  TIMSK |= (1<<OCIE2);
  TCCR2 = (1<<WGM21) | PRESCALER_BITS;  // CTC mode
}

enum button {off, on} state;        // off=0, on=1

int main(void)
{
  InitServo();              // f¸r Servos
  sei();                  // f¸r Servos
  
  state = on;                // Zustand ist am Anfang AN (wegen Stromausfall)
  DDRD |= (1<<PD0);            // PD0 auf Ausgang (SSR)
  DDRD |= (1<<PD3);            // PD3 auf Ausgang (Wechsler)
  DDRB |= (1<<PB3);            // PB3 auf Ausgang (Signal an ATTINY f¸r LED = weifl)
  DDRB |= (1<<PB4);            // PB4 auf Ausgang (Signal an ATTINY f¸r LED = orange)
  DDRB |= (1<<PB5);            // PB5 auf Ausgang (Signal an ATTINY f¸r LED = orange blinkend)
  DDRC &= ~(1<<PINC0);          // PC0 auf Eingang (Taster)  
  DDRB &= ~(1<<PINB0);          // PB0 auf Eingang (Taster)  
  DDRC &= ~(1<<PINC1);          // PC1 auf Eingang (Niveausonde)  
  
  uint8_t a = 0;
  uint8_t b = 0;
  uint16_t i = 0;
  
    while (1) 
    {  
    if (button_down)                // Wenn Taster gedr¸ckt ist
    {
//      _delay_ms(20);                // Prellzeit abwarten
//      if (button_down)              // Wenn Taster immer noch gedr¸ckt ist
//      {
        if (state == off)            // Wenn Zustand zuvor OFF war
        {
          state = on;
        }
        else if (state == on)          // Wenn Zustand zuvor ON war
        {
          state = off;
        }
//      }  
      while (button_down);            // Warten bis Taster losgelassen wird
    }
    
    if (state == on)                // System l‰uft
    {
      if (b == 0)
      {
        PORTD |= (1<<PD0);            // SSR an
        TCCR2 = (1<<WGM21) | PRESCALER_BITS;  // Timer an
        ServoValue[0] = 0.9 * CENTER;      // Servos 1 ZU
        ServoValue[1] = 1.93 * CENTER;      // Servos 2 ZU
        _delay_ms(2000);
        TCCR2 = 0;                // Timer aus
        b = 1;
        a = 1;    
      }

      if ( !(PINC & (1<<PC1)) )          // Wenn Niveausonde Kontakt hat
      {    
        PORTD &= ~(1<<PD3);            // Wechsler aus (Ventil ZU)            
        PORTB &= ~(1<<PB3);            // LED = weifl = aus
        PORTB &= ~(1<<PB5);            // LED = orange blinkend = aus
        PORTB |= (1<<PB4);            // LED = orange = an        
      }
      
      else if ( (PINC & (1<<PC1)) && (i == 0) )  // wenn Niveausonde keinen Kontakt hat; i damit nur alle 5 Minuten aufgerufen wird
      {
        PORTD |= (1<<PD3);            // Wechsler an (Ventil AUF)  
        PORTB &= ~(1<<PB5);            // LED = orange blinkend = aus
        PORTB &= ~(1<<PB4);            // LED = orange = aus
        PORTB |= (1<<PB3);            // LED = weifl = an      
      }
      
      i++;                    // i um 1 erhˆhen
      _delay_ms(10);
      
      if (i >= 30000)                // 10ms * 30000 Durchg‰nge = 5min 
      {
        i = 0;
      }    
    }
    
    else if ( (state == off) && (a == 1) )      // System steht; a == 1 damit die Schleife nur 1 mal durchlaufen wird
    {  
      PORTD &= ~(1<<PD0);              // SSR aus
      PORTD &= ~(1<<PD3);              // Wechsler aus (Ventil ZU)      
      PORTB &= ~(1<<PB3);              // LED = weifl = aus        
      PORTB &= ~(1<<PB4);              // LED = orange = aus
      PORTB |= (1<<PB5);              // LED = orange blinkend = an
      _delay_ms(12000);              // Warten bis der L¸fter steht
      TCCR2 = (1<<WGM21) | PRESCALER_BITS;    // Timer an
      ServoValue[0] = 2.8 * CENTER;        // Servos 1 AUF
      ServoValue[1] = -0.8;            // Servos 2 AUF  
      PORTB &= ~(1<<PB5);              // LED = orange blinkend = aus  (LED bleibt aus)        
      _delay_ms(2000);            
      TCCR2 = 0;                  // Timer aus
      a = 0;
      b = 0;
    }
    }
}

von Joachim B. (jar)


Bewertung
0 lesenswert
nicht lesenswert
Christoph K. schrieb:
> Wenn ich jetzt gar keine Entprellung habe, weil ich diese einfach nicht
> brauche, wo ist der Fehler / wo ist die Störung?

die kommt wenn du es nicht vermutest, mal eine Funkstörung, mal einen 
Puls auf der Installation.

Sicher geht anders, aber mach wie du denkst und dann komme bitte nicht 
mit unerklärliche sporadische Fehler!
Heulthreads gibts schon genug auf dieser Welt.
Beitrag "uC bleibt hängen - Ursache unklar - Fehler nicht reproduzierbar"

: Bearbeitet durch User
von Christoph K. (christoph13524)


Bewertung
-1 lesenswert
nicht lesenswert
Joachim B. schrieb:
> die kommt wenn du es nicht vermutest, mal eine Funkstörung, mal einen
> Puls auf der Installation.

und genau so eine Störung möchte ich gerne unterbinden, wenn das 
hardwaretechnisch möglich ist. Dafür reicht mein Wissen leider nicht 
aus.

Joachim B. schrieb:
> Heulthreads gibts schon genug auf diese Welt.

Gibt auch genug Threads, wo man seine Aggressionen raus lassen kann...
Immer das selbe hier mit manchen Leuten. Helft, oder lasst es doch 
einfach sein.

Joachim B. schrieb:
> Sicher geht anders,

Das weiß ich. Ich habe einfach nur die Entprellung rausgenommen, da ich 
wissen wollte, ob die das Problem ist oder nicht.
Und meines Wissens nach nicht, wenn ich mir die Ergebnisse anschaue; 
aber belehrt mich gerne anders.

Werde demnächst auch hardwareseitig mal entprellen probieren mit einem 
RC-Tiefpass inkl. 74HC14.

von georg (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Christoph K. schrieb:
> weil ichs damals
> auch nicht geschafft habe, einen zweiten Timer irgendwie zu starten

Must du auch nicht. In einer Timer-Routine mit 1 ms kannst du das 
Entprellen miterledigen. Ich habe oft einen Basis-Timer, der mehrere 
Aufgaben erledigt, je nachdem was gerade anliegt, es darf nur niemals 
länger dauern als die eingestellte Taktzeit.

Praktisch erledigt dieser Timer alles was im Hintergrund laufen soll, 
z.B. Datenempfang über UART, manchmal bleibt für die Main Loop kaum noch 
was übrig. Ausser z.B. auf eine Message die Antwort zusammenszustellen, 
wenn sie vollständig und fehlerfrei empfangen wurde. Gesendet wird die 
Antwort dann wieder im Time Interrupt.

Und der multiplext nebenbei die Anzeige, regelt eine Temperatur, 
schaltet einen Motor ein oder aus...

Georg

von HildeK (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Christoph K. schrieb:
> Ist der Pulldown Widerstand am Taster zu groß/klein? Das Kabel vom
> Taster ist rund 2m lang. Habe gelesen, dass wenn der Pulldown zu groß
> ist, kein eindeutiges 0V-Signal am Mikrocontroller erkannt wird.
>
> Ich bekomme einfach irgendeine Störung an die Leitung vom Taster von
> GND_1 über den Pulldown.
>
> Kann irgendein Kondensator dort helfen?

Ich habe nicht alles gelesen und erst recht nicht deinen Code. Gerade 
Entprellroutinen haben es in sich, man übersieht leicht was. Es gäbe da 
eine schöne und gut funktionierende Vorlage von Peter D.

Mit Hardwaremaßnahmen kann man aber auch eine Menge ausrichten. Auch mit 
der Leitungsführung, auch des GNDs.
Zu dem obigen Punkt ist natürlich 2m Kabel zum Taster eine perfekte 
Quelle für Einstreuungen. Insbesondere wenn du daneben noch kräftige 
Lasten schaltest.
Jedenfalls: die 10k Pulldown am Taster sind entschieden zu hoch. Nimm 1k 
oder sogar 500Ω.
Ein C (10n - 100n) parallel zum Eingang reduziert ebenfalls die 
Empfindlichkeit auf Einstreuungen. Einen 74C14 o.ä. brauchst du nicht, 
der ATMega hat Schmitttriggereingänge. Ich würde mal folgende 
Beschaltung vorschlagen:
            VCC              
.---------.  +               
|         |  |              
|     VCC o--o-----------------.          Taster, 2m abgesetzt
|         |                    |            .---.
|         |                    |            |   |
|         |         10k        |           /    o |
|         |          ___       'XXXXXXXXXXX       |=|
|     PB0 o-----o---|___|--o---'           \    o |
|         |     |          |                |   |
|         |     |          |                '---'
|         |     |         .-.
|         |    ===        | |
|         |     |  10n    | |500R...1k
|         |     |         '-'
|     GND o-----o          |
|         |     |          |
'---------'     o----------'
                |
               ===
               GND
(created by AACircuit v1.28.6 beta 04/19/05 www.tech-chat.de)
Die 'XXXXXX' sollen ein verdrilltes Kabel mit den 2m zum Taster 
darstellen.

Ich hoffe, du hast auch nahe an jedem µC die Entkoppelkondensatoren 
nicht vergessen. Ich sehe jedenfalls nur einen eingezeichnet und den 
auch noch eher am Netzteil. Dort könntest du 10µ anbringen und jeweils 
100nF direkt an den Versorgungspins der beiden µCs.

von Joachim B. (jar)


Bewertung
0 lesenswert
nicht lesenswert
Christoph K. schrieb:
> Helft, oder lasst es doch
> einfach sein.

was genau  hast du an:

Joachim B. schrieb:
> PeDa hats erklärt und das funktioniert sicher!
>
> https://www.mikrocontroller.net/articles/Entprellung
>
> machs im Timer IRQ nach dannegger

nicht verstanden?

Christoph K. schrieb:
> da ich
> wissen wollte, ob die das Problem ist oder nicht.
> Und meines Wissens nach nicht, wenn ich mir die Ergebnisse anschaue;

das muss ja nicht der Fehler sein, aber KÖNNTE und deswegen macht man es 
richtig und lässt es drin!
Dann ist zumindest EINE Fehlermöglichkeit schon mal ausgeschlossen!

dein:

Christoph K. schrieb:
> Und meines Wissens nach nicht, wenn ich mir die Ergebnisse anschaue;

ist wie die Momentaufnahme wenn der Chef zur Tür reinschaut und dich mit 
den Kollegen quatschen und kaffeetrinken sieht! aber nie sieht wie du 
schwitzend arbeitest!

von Christoph K. (christoph13524)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Antworten!

Dieses Entprellverfahren von Dannegger würde ich wenn möglich vermeiden, 
einfach nur, weil meine Fähigkeiten dafür derzeit nicht ausreichen. Da 
schreiben wir sicher Tage hin und her, bis das funktioniert. Vor allem 
weil ich schon einen Timer für die Servos am laufen habe und ich dafür 
auch fast kein Wort verstehe. Alles rauskopiert natürlich.
Würde dieses Entprellverfahren von Dannegger auch eben Störungen 
rausfiltern irgendwie oder ist dieses wirklich nur für das Entprellen 
da?

HildeK schrieb:
> die 10k Pulldown am Taster sind entschieden zu hoch. Nimm 1k
> oder sogar 500Ω.

Werde ich probieren! Das würde man machen, dass der Pin PB0 dann 
sozusagen sicherer mit GND verbunden ist?

Den 10kOhm Widerstand und den Kondensator, den du eingezeichnet hast, 
würde nur die Einstreuung reduzieren? Oder ist das auch als Entprellen 
gedacht? Durch den 10kOhm Widerstand ist man doch dann erst recht bei 
11kOhm dann wieder (10+1)?

Hab vorher schon ein bisschen recherchiert und bin zu dem gleichen 
Schaltplan mit anderen Werten gekommen - was einer Entprellung 
entsprechen sollte. Bild ist angehängt. Mit 1uF, 22kOhm und 10kOhm.

Kabel verdrillen ist ein guter Tipp.

Also morgen kommt der Gleichrichter, den ich probieren werde.
Die Wirbelströme sind dann (laut Recherche) nicht weg, aber kleiner und 
hochfrequenter, weil der Gleichstrom nicht geglättet ist (normaler 
Brückengleichrichter) - behebt eventuell das ganze Problem.

Vorher würde ich dann einfach nur den derzeitigen 10kOhm Pulldown 
austauschen gegen 1kOhm und zusätzlich Kabel verdrillen.

Kondensator hab ich derzeit leider nicht hier.

HildeK schrieb:
> Ich hoffe, du hast auch nahe an jedem µC die Entkoppelkondensatoren
> nicht vergessen. Ich sehe jedenfalls nur einen eingezeichnet und den
> auch noch eher am Netzteil.

Habe tatsächlich nur den 1 eingezeichneten eingebaut.. Den dafür nahe an 
den ATmega8 Kontakten. Der ATtiny ist aber nicht weit entfernt.. Ist das 
ein großes Problem? Hab gelesen, dass man bei "einfachen" Anwendungen 
sogar auf die verzichten kann.

Joachim B. schrieb:
> das muss ja nicht der Fehler sein, aber KÖNNTE und deswegen macht man es
> richtig und lässt es drin!
> Dann ist zumindest EINE Fehlermöglichkeit schon mal ausgeschlossen!

Ja daran wage ich mich, wenn alles scheitert.. wie gesagt, schwer für 
mich die Umsetzung

von Stefan ⛄ F. (stefanus)


Bewertung
0 lesenswert
nicht lesenswert
Christoph K. schrieb:
> Muss ich die GND-Leitungen der beiden Stromversorgungen verbinden?

Ja

> Strom braucht ja immer einen Kreis..

Genau deswegen.

Gegen deine Störungen wird wohl ein R/C Filter (Tiefpass) wirksam sein. 
Du hast zwei Schaltungsvorschläge dazu bekommen, ich finde sie beide OK, 
allerdings kommen mir die 10nF sehr klein bemessen vor. Ich hätte 
mindestens 100nF genommen.

10kΩ * 10nF ergeben nur ungefähr eine Millisekunde. Kürzere Impulse 
werden unterdrückt.

: Bearbeitet durch User
von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Du weißt aber schon, daß in den Wartezeiten 12s und 2s bei Dir keine 
Tasten abgefragt werden können. Das ist der Nachteil, wenn die Meinloop 
auch noch entprellen soll.

von Christoph K. (christoph13524)


Bewertung
0 lesenswert
nicht lesenswert
Ja das weiß ich. Das soll auch so sein - ist sogar gut so.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.