-         

Ergebnis 1 bis 10 von 10

Thema: Tasten an einem ADCPin, Versuch zu entprellen

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    24.06.2008
    Beiträge
    14

    Tasten an einem ADCPin, Versuch zu entprellen

    Anzeige

    Hallo Leute,
    ich versuche grade drei Tasten die ich an einem ADC pin eines Tiny 85
    angehägt habe zu entprellen.
    (Tastenwert) wird duch eine ADKanallesenfunktion bestimmt und liegt
    zwischen 0 und 5
    zuerst habe ich die 3 Zustände in einer funktion definiert

    uint8_t Tastenabfrage(void){
    uint8_t Taste;

    Taste = 0;
    if (Tastenwert > 4) Taste=1; //Werte grösser als 4, schalter mit
    einem KOhm wurde gedrückt
    else if (Tastenwert > 2) Taste=10;//Werte grösser als 2, schalter mit
    10 KOhm wurde gedrückt
    else if (Tastenwert > 1) Taste=33;//Werte grösser als 1, schalter mit
    33 KOhm wurde gedrückt
    else Taste = 0;
    return Taste;
    }

    danach habe ich versucht die Tasten so zu entprellen sodass ein
    Tastendruck was ein Wert zwischen 0 und 5 erbit nicht erkannt wird,
    er wird erst dann erkannt wenn der Wert zweimal rauskommt, und dann
    wird 10 ms gewartet und letzendlich werden Taste als definiert.
    Das Prozessflag definiert mehrere Zustände. Für Jeden Zustand wird ein
    Bit reserviert in einem 8 Bit.
    Ich habe das folgende Code geschrieben.

    void TastenEntprellung(){

    if((Tastenabfrage()==1)||(Tastenabfrage()==10)||(T astenabfrage()==33)){
    // wenn nur einmal gedrückt (KeineTaste)
    Anreiz=KeineTaste;

    if(Tastenabfrage()==1){// zweimal erkannt TasteEins
    _delay_ms(10);
    Anreiz=TasteEins;
    Prozessflag|= Benutzeroberflaeche;
    }

    if(Tastenabfrage()==10){// zweimal erkannt TasteZwei
    _delay_ms(10);
    Anreiz=TasteZwei;
    Prozessflag|=Benutzeroberflaeche;
    }

    if(Tastenabfrage()==33){// zweimal erkannt TasteDrei
    _delay_ms(10);
    Anreiz=TasteDrei;
    Prozessflag|=Benutzeroberflaeche;
    }
    }
    }

    Kann mir jemand sagen ob es richtig ist und ob es
    Verbesserungsvorschläge gibt.
    Mein bessten Dank

  2. #2
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    24.02.2006
    Ort
    3. Planet eines kleinen Sonnensystems in einem Seitenarm der Milchstraße
    Alter
    63
    Beiträge
    622
    Hallo,

    da Du nur einen Auszug Deines Codes eingestellt hat, ist keine Aussage möglich. Z.B. ist nicht klar, wann der A/D-Wandler-Kanal gelesen wird, wo Du "Anreiz" deklarierst und wo und wie "Anreiz" ausgewertet wird.

    Wenn Du noch einen Timer frei hast, schlage ich vor, Du "baust" Dir einen Zustandsautomaten ("state machine"): alle 10-20ms per Timer einen Zustand (in "main()" auswerten!) setzen, der dann zu einer A/D-Wandlung führt. Dann mit dem Ergebnis der letzten A/D-Wandlung vergleichen, wie Du es oben beschreibst.

    Denk' auch an die Möglichkeiten der "switch()"-Funktion in C!

    Viele Grüße

    Fred
    Only entropy comes easy. - Anton Checkhov

  3. #3

  4. #4
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    15.11.2004
    Ort
    Aachen
    Alter
    32
    Beiträge
    246
    Es gibt da noch einen Denkfehler in TastenEntprellung().
    Wenn die erste Auswertung von Tastenabfrage() 1 ergibt, und die zweite 10, dann wertet es dein Programm so aus, als würde zweimal die 10 rauskommen.

    Code nächstes mal am besten in [c o d e]-Blocks packen:
    Code:
    void TastenEntprellung(){
    
    if((Tastenabfrage()==1)||(Tastenabfrage()==10)||(Tastenabfrage()==33)){
    // wenn nur einmal gedrückt (KeineTaste)
    Anreiz=KeineTaste;
    
    if(Tastenabfrage()==1){// zweimal erkannt TasteEins
    _delay_ms(10);
    Anreiz=TasteEins;
    Prozessflag|= Benutzeroberflaeche;
    }
    
    if(Tastenabfrage()==10){// zweimal erkannt TasteZwei
    _delay_ms(10);
    Anreiz=TasteZwei;
    Prozessflag|=Benutzeroberflaeche;
    }
    
    if(Tastenabfrage()==33){// zweimal erkannt TasteDrei
    _delay_ms(10);
    Anreiz=TasteDrei;
    Prozessflag|=Benutzeroberflaeche;
    }
    }

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    24.06.2008
    Beiträge
    14
    Hi,
    //Wenn die erste Auswertung von Tastenabfrage() 1 ergibt, und die zweite 10, //dann wertet es dein Programm so aus, als würde zweimal die 10 //rauskommen.

    ich habe vercuht nur die Fälle auseinander zu halten, wenn es nicht mit 1,10,33 geht kann ich dafür Zeichen nehmen, oder 1,2,3.


    hier sind die Codes.
    Danke

    ADKanallesen
    Code:
    #include <avr/io.h>
    #include "Initialisierung.h"
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    
      //variablen
      uint16_t  U_analog;
      uint16_t  Tastenwert;
      uint16_t  Stromwert;
      extern uint8_t Prozessflag;
    
      //Funktion zur A/D-Wandlung
      uint16_t ADkanalLesen() {
    
      uint8_t i; 
      uint16_t ergebnis = 0;//A/D-Wert
      unsigned char Durchlaeufe =4;
    
    
    
    
    	for (i=0; i<Durchlaeufe; i++) 
    	{ 
    	   ADCSRA |= (1<<ADSC); //Startet eine A/D-Wandlung (Single Conversion)
    
    while (ADCSRA & (1<<ADSC)) 
    { 
    ; // auf Abschluss der Konvertierung warten
    }
      ergebnis += ADCW; // Wandlungsergebnisse werden aufaddieren 
    
    }
     
      ADCSRA &= ~(1<<ADEN); //A/D-Wandler wird deaktiviert
    
      ergebnis /= Durchlaeufe; // Summe durch 4 teilen (Mittelwert) 
    
      U_analog = (ergebnis*u_ref)/1024;
    
     return U_analog; //Analogwert
    }
    Intteruptroutine

    Code:
    #include <avr/io.h>
    #include "Initialisierung.h"
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    
    extern uint8_t Prozessflag;
    //Globale Variable
    uint8_t Zustand;
    uint8_t Anreiz;
    uint16_t Zaehler=0;
    extern uint16_t Tastenwert;
    extern uint16_t Stromwert;
    
    // InterruptVectoren
    	ISR( TIM0_OVF_vect ){ // Interruptroutine bei Timeroverflow
     		TCNT0 = TCNT0init; //Counter zurück auf Startwert 58 gesetzt
     		ADCSRA |= (1<<ADEN) |  (1<<ADPS2) | (1<<ADPS0)| (1<<ADIE); //AD-Wandler aktiviert(ADEN), Prescaler auf 32(ADSPSO,ADPS2) 
    		    							   //Interrupt enable aktiv
    		ADMUX |= (0<<REFS1) | (0<<REFS0); // Vcc als  Referenzspannung die getrennt von AREF ist 
       		                                  // Kanal waehlen und Vcc als Referenzspannung
       if(Zaehler%2){//bei 50ms und in einem 100ms Zeitabstand eine ADWandlung ausführen und ein ADInterrupt auszulösen
      	ADMUX|=PINTASTEN; // Kanal auswählen(PIn wo die Tasten angehängt sind)
    		ADCSRA |= (1<<ADSC) ;  //Startet eine A/D-Wandlung (Single Conversion)
    		 	}
    						Zaehler++;
    							}
    
    	ISR( ADC_vect){
    		if(Zaehler%2){
    			Tastenwert=ADkanalLesen();//Tastenwert nimmt den Wert von der ADWandlung an (analogwert)
          			Prozessflag|= Tasten;//Prozessflag wird auf Tasten gesetzt (fragt die tasten ab bei der Funktion Tastenabfrage)
          				}
    					}

    initialisierung.h

    Code:
    #include <avr/io.h>
    #include <stdint.h>
    
    /Prozessflags
    
    
    #define Benutzeroberflaeche (1<<0)
    #define Tasten              (1<<1)
    #define Rechnen             (1<<2)
    
    // Tasten //
    
    
    #define KeineTaste       1
    #define TasteEins        1
    #define TasteZwei        2
    #define TasteDrei        3
    in initialisierung sind andere Funktionen deklariert die ich da nicht zugefügt habe

  6. #6
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    24.02.2006
    Ort
    3. Planet eines kleinen Sonnensystems in einem Seitenarm der Milchstraße
    Alter
    63
    Beiträge
    622
    Hallo,

    ich mache es sehr kurz: das hat rein gar nichts mehr mit Entprellen zu tun, wonach Du im ersten Posting gefragt hast. Du bildest Mittelwerte aus den A/D-Ergebnissen; wenn es dann beim Tastendruck prellt, bekommst Du einfach total verkehrte Resultate. Hast Du die Idee mit dem Entprellen ganz aufgegeben?

    Ansonsten gilt immer noch der Rat, der Dir mehrfach in dem anderen Thread gegeben worden ist. Einfach Code hier einzustellen mit der Bitte, dass andere herausfinden,
    ob es richtig ist
    , funktioniert nicht gut. Wenn etwas konkret nicht läuft oder Du fassbare Fragen hast, dann bekommst Du sicher bessere Antworten. Zum Testen gibt es
    • 1. Hardware und
      2. den Simulator!


    Viele Grüße

    Fred

    PS: Gerade sehe ich, dass Du Deine Fragen schon gestern in einem anderen Forum gestellt hast. Ich schlage vor, den Thread dort fortzusetzen.
    Only entropy comes easy. - Anton Checkhov

  7. #7
    Erfahrener Benutzer Roboter Experte Avatar von BurningWave
    Registriert seit
    22.12.2007
    Ort
    nahe Stuttgart
    Alter
    23
    Beiträge
    656
    Wieso machst du denn alles so kompliziert???
    Nehm doch einfach einen größeren µC (z.B. einen AtTiny2313 oder AtTiny26), dann kannst du für jede Taste eine eigene Pin nehmen und die dann mit _delay_ms() entprellen.

    mfg

  8. #8
    Erfahrener Benutzer Robotik Einstein Avatar von Felix G
    Registriert seit
    29.06.2004
    Ort
    49°32'N 8°40'E
    Alter
    34
    Beiträge
    1.780
    ich mache es sehr kurz: das hat rein gar nichts mehr mit Entprellen zu tun, wonach Du im ersten Posting gefragt hast. Du bildest Mittelwerte aus den A/D-Ergebnissen; wenn es dann beim Tastendruck prellt, bekommst Du einfach total verkehrte Resultate. Hast Du die Idee mit dem Entprellen ganz aufgegeben?
    Ähm...
    also eine gleitende Mittelung (moving average) würde sich sehr wohl zum entprellen eignen, sowas ist nämlich im Allgemeinen auch als Tiefpass bekannt der die hochfrequenten Anteile (Prellen) einfach wegfiltert. Wenn man die Grenzfrequenz sinnvoll wählt, und bei der weiteren Auswertung noch eine Hysterese mit einbaut, sollte das eigentlich recht zuverlässig funktionieren.


    Allerdings, newbie1982, ist das so leider noch keine gleitende Mittelung.

    Ich würde es etwa so implementieren (dient nur als Beispiel)
    Code:
    #define AD_EXP		4	//Mittelung über 16 Werte
    #define AD_BUF_LEN	(1 << AD_EXP)
    
    volatile uint16_t AD_Result;
    
    SIGNAL(SIG_ADC)
    {
    	uint8_t n;
    	static uint8_t Buffer_index = 0;
    	static uint16_t AD_Buffer[AD_BUF_LEN];
    	
    	// Buffer zyklisch beschreiben
    	AD_Buffer[Buffer_index++] = ADCW;
    	Buffer_index = Buffer_index % AD_BUF_LEN;
    	
    	// Mittelung
    	ADC_Result = 0;
    	for(n=0;n<AD_BUF_LEN;n++)
    		AD_Result += AD_Buffer[n];
    	
    	AD_Result >>= AD_EXP;
    }
    So hast du in AD_Result immer den aktuellen gefilterten Wert, und kannst im Hauptprogramm ganz bequem darauf zugreifen.

    In diesem Beispiel wird jeweils über 16 Werte gemittelt, ob das sinnvoll ist oder nicht, hängt vom ADC-Takt ab. Wenn dieser bekannt ist, kannst du die Grenzfrequenz des TP berechnen (im Prinzip könnte man da problemlos auf 10Hz runter gehen, wer muss schon 10x pro Sekunde auf so eine Taste drücken?).



    PS: wenn der Buffer bei der richtigen Grenzfrequenz zu groß wird, würde ich ihn als globale volatile Variable auslagern, und ihn in der ISR zwar zyklisch beschreiben, jedoch die Mittelung lieber im Hauptprogramm durchführen (damit die ISR nicht zu lange braucht). Diese Mittelung könnte man ja dann auch in eine nette kleine Funktion verpacken, irgendwas wie "getadc()" oder so, dann ist es auch sehr bequem zu nutzen.
    So viele Treppen und so wenig Zeit!

  9. #9
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    24.02.2006
    Ort
    3. Planet eines kleinen Sonnensystems in einem Seitenarm der Milchstraße
    Alter
    63
    Beiträge
    622
    Hi,
    wenn man wie der OP mehrere Tasten abfragen möchte, wobei jede Taste durch einen Widerstand (=verschiedene Spannungen am A/D-Wandler) repräsentiert wird, ist die Mittelwertbildung zum Zwecke der Entprellung (zumindestens bei der Abtastrate, die der OP verwendet hat) unsinnig, da jedes Prellen den Mittelwert verändert, so dass schließlich ein anderes Ergebnis als das gewünschte herauskommen kann (=falsche Taste). Natürlich könnte man über eine so lange Zeit mitteln, dass das kaum noch einen Faktor darstellt; aber da sind andere Methoden doch besser geeignet.

    Trotzdem schlage ich noch einmal vor, die Diskussion im anderen Forum weiterzuführen, wo der OP seine Frage zuerst gestellt hat.

    Gruß

    Fred
    Only entropy comes easy. - Anton Checkhov

  10. #10
    Neuer Benutzer Öfters hier
    Registriert seit
    24.06.2008
    Beiträge
    14
    Danke erstmal,
    im Code von Felix habe ich s nicht so kapiert, wie die Werte dann aus dem ADwandler abgeholt werden

    ist es mit //static uint16_t AD_Buffer[AD_BUF_LEN];
    da ich eine Funktion dafür habe ADKanallesen()

    danke nochmal.

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •