-         

Ergebnis 1 bis 5 von 5

Thema: Problem bei Taster Abfrage mit ADC

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    10.07.2006
    Beiträge
    7

    Problem bei Taster Abfrage mit ADC

    Anzeige

    Guten Morgen

    schon seit einiger zeit bin in nun an einem kleinen Projekt von mir dran, komme aber leider nicht weiter.

    Die Problemstellung ist, ich habe einen ADV mit Spannungswandler nach +5V, der gegen Masse geschaltet wird. Die Werte dazu habe ich berechnet und scheint auch ganz gut zu funktionieren. Habe es kurz getestet.
    Nun sollen diese 3 möglichen Felder, verschiedene funktionen haben, 2 Felder wie ein Taster und eines soll unterscheiden zwischen kurz gedrückt und gedrückt gehalten. Nun bin ich auf eure Tutorial "Taster-Abfrage in C" gestoßen. Diese ist genau das was ich suche. Also habe ich es mit meiner AD-Wandler abfrage kombiniert. Nur leider funktioniert so garnichts :/

    Könnte sich vieleicht bitte mal wer meinen Code ansehen und mir vieleicht tips geben ?

    Code:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    /* Wir haben 3 Taster, in taster.h wird also angepasst zu
    #define NUM_TASTER 3
    */
    #include "taster.h"
    
    #define ADC_VREF_TYPE 0x00
    
    // Read the AD conversion result
    unsigned int read_adc(unsigned char adc_input)
    {
    ADMUX=adc_input|ADC_VREF_TYPE;
    // Start the AD conversion
    ADCSRA|=0x40;
    // Wait for the AD conversion to complete
    while ((ADCSRA & 0x10)==0);
    ADCSRA|=0x10;
    return ADCW;
    }
    
    
    /* Bei 1MHz Grundtakt läuft Timer0 alle 256µs über.
     * Um auf rund 10ms zu kommen, rufen wir get_taster nur
     * jedes 39. mal auf. */
    SIGNAL (SIG_OVERFLOW0)
    {
        static unsigned char count_ovl0;
        unsigned char ovl0 = count_ovl0+1;
    
        if (ovl0 >= 39)
        {
    
    		unsigned int result = read_adc(0); 
    	
    		get_taster (0, ((result >= 700) && (result <= 790)) ? 1:0);
    		
    		get_taster (2, ((result >= 800) && (result <= 880)) ? 1:0);
    	
    		get_taster (1, ((result >= 890) && (result <= 940)) ? 1:0);
        
            ovl0 = 0;
        }
    
        count_ovl0 = ovl0;
    }
    
    void ioinit()
    {
        /* Timer0 ohne Prescaler starten */
        TCCR0 = 1 << CS00;
    
    
        /* Timer0-Overflow-Interrupt aktivieren */
        TIMSK |= (1 << TOIE0);
    }
    
    int main()
    {
        ioinit();
    
    	// ADC initialization
    	// ADC Clock frequency: 500,000 kHz
    	// ADC Voltage Reference: AREF pin
    	ADMUX=ADC_VREF_TYPE;
    	ADCSRA=0x81;
    
     
        /* Taster konfigurieren (#define NUM_TASTER 3 in taster.h) */
        tasten[0].mode = TM_SHORT;
        tasten[1].mode = TM_LONG;
        tasten[2].mode = TM_SHORT;
     
        /* Interrupts global aktivieren */
        sei();
    
    	// Input/Output Ports initialization
    	// Port B initialization
    	// Func7=In Func6=Out Func5=In Func4=In Func3=In Func2=Out Func1=Out Func0=Out 
    	// State7=T State6=0 State5=T State4=T State3=T State2=0 State1=0 State0=0 
    	PORTB=0x00;
    	DDRB=0x47;
    
        /* Hauptschleife */
        while (1)
        {
            signed char tast = taster;
      
            switch (tast)
            {
                default:
                case NO_TASTER:
    				PORTB &= ~((1<< PINB6) | (1 << PINB2) | (1 << PINB1) | (1<< PINB0));
                    break;
                case 0:
                    /* Taster 0 */
    				PORTB = (1 << PINB0);		    // PB0 amschalten
                    break;
        
                case 1:
                    /* Taster 1 kurz gedrueckt */
    				PORTB = (1 << PINB2);		    // PB2 amschalten
                    break;
        
                case 1+TASTER_LONG:
                    /* Taster 1 lange gedrueckt */
    			//	PORTB = (1 << PINB6);
                    break;
        
                case 2:
                    /* Taster 2 */
    				PORTB = (1 << PINB1);		    	// PB1 amschalten
                    break;
            }
    
            if (tast != NO_TASTER)
                taster = NO_TASTER;
    
            /* ********************************** */
            /* Weiterer Code in der Hauptschleife */
        }
    }
    
    taster.h:
    #ifndef _TASTER_H_
    #define _TASTER_H_
    
    /* Wert fuer taster, wenn nichts gedrückt wurde */
    #define NO_TASTER (-1)
    
    /* Maximale Anzahl der Taster */
    #define NUM_TASTER 3
    
    /* 0 --> Taster sind low-aktiv */
    /* 1 --> Taster sind high-aktiv */
    #define TASTER_LEVEL 1
    
    /* Dieser Offset wird zur Tasten-Nummer addiert, */
    /* wenn eine Taste lange gedrückt wurde */
    #define TASTER_LONG 16
    
    /* Zeitverzögerung (in Ticks), bis zum Beginn von auto-repeat */
    #define TASTER_REPEAT_DELAY (60)
    
    /* Zeitverzögerung (in Ticks), bis zum nächsten auto-repeat */
    #define TASTER_REPEAT       (15)
    
    /* Ab dieser Dauer wird der Tastendruck 'lange' */
    #define TASTER_DELAY_LONG   (80)
    
    typedef struct 
    {
        /* private */
        const unsigned char delay, old;
    
        /* Mode des Tasters aus: TM_SHORT, TM_LONG, TM_REPEAT */
        unsigned char mode;
    } taste_t;
    
    extern taste_t tasten[];
    
    /* In dieser Variable kann abgefragt werden, welche Taste gedrückt wurde.
       --> NO_TASTER:
           es wurde nichts gedrückt
       --> 0..NUM_TASTER-1:
           Taster Numero 'taster' wurde (kurz) gedrückt
       --> TASTER_LONG ... TASTER_LONG + NUM_TASTER-1:
           Taster Numero 'taster-TASTER_LONG' wurde lange gedrückt
    */   
    extern volatile signed char taster;
    
    extern void get_taster (const unsigned char num, unsigned char tast);
    
    enum
    {
        TM_SHORT,
        TM_LONG,
        TM_REPEAT
    };
    
    #endif /* _TASTER_H_ */
    Wäre sehr nett danke schonmal

    Ach was ich vergessen habe, Ich benutze einen ATMega8 und an den Ausgängen PB0,PB1,PB2,PB6 hängt ein Relais Treiber mit 4 Relais.

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Funktioniert es denn, wenn du normale digitale I/O-Ports nimmst anstatt ADC-Inputs?

    Was mir auffllt ist daß du in der Tioer0-ISR ne Warteschleife auf den ADC hast (in read_adc), und zwar sogar 3 mal. Das ist nicht so toll. Wenn das dauert bekommst du die nächste Timer0-IRQ schon, wenn du noch in der Timer0-ISR bist. Dann geht kaum mehr was.

    Besser wäre den ADC im free runnong mode zu betreiben und in einer ADC-ISR die Werte zu merken und den Port ein weiter zu schalten.

    Nochwas zu Code: Lass die magischen Zahlen wie 0x40 weg, es ist klarer, wenn du sie Bit-Namen verwendes -- nicht nur für andere, auch für dich.
    Disclaimer: none. Sue me.

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    10.07.2006
    Beiträge
    7
    mit i/o ports läuft es.

    was meinst du mit free runnong mode ? Fange grade erst an mit µC programmierung, und das ist mein erstes Projekt.

    Meinst du das ich einen 2. Timer nehmen soll und dann einfach eine globale variable dazu ?

    Die magischen Zahlen habe ich nur drin weil ich zu faul war, habe die mit dem CodeVisionAVR generiert :P

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Zitat Zitat von ATmega8, pp.195
    In Free Running mode, the ADC is constantly sampling and updating the ADC Data Register. Free Running mode is selected by writing the ADFR bit in ADCSRA to one. The first conversion must be started by writing a logical one to the ADSC bit in ADCSRA. In this mode the ADC will perform successive conversions independently of whether the ADC Interrupt Flag, ADIF is cleared or not.
    Aber das macht wohl nicht ganz das, was du willst...

    Besser ist wohl single shot. in main (Prinzip):
    1. ADC-Port wählen
    2. Konvertierung starten (single shot)
    3. Wert wegwerfen
    4. ADC-IRQ-Flag resetten
    5. ADC-IRQ erlauben
    6. sei()
    7. Konvertierung starten (single shot)
    8. Hauptschleife


    In der ADC-ISR:
    1. ADC-Wert sichern
    2. ADC-Port wählen
    3. ADC starten (single shot)


    In deinem Fall hast du 3 ADC-Werte, die zu sichern sind.

    ::EDIT::

    Nochwas: Der ADC sollte nich über 200kHz getaktet sein.
    Disclaimer: none. Sue me.

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    10.07.2006
    Beiträge
    7
    Ich denke du meinst das Beispiel was auch beim Roboternetz im Artikel bereich ist oder ?

    Code:
    uint16_t readADC(uint8_t channel) {
    	uint8_t i;
    	uint16_t result = 0;
    	
    	// Den ADC aktivieren und Teilungsfaktor auf 64 stellen
    	ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
    
    	// Kanal des Multiplexers waehlen
    	ADMUX = channel;
    	// Interne Referenzspannung verwenden (also 2,56 V)
    	ADMUX |= (1<<REFS1) | (1<<REFS0);
    	
    	// Den ADC initialisieren und einen sog. Dummyreadout machen
    	ADCSRA |= (1<<ADSC);
    	while(ADCSRA & (1<<ADSC));
    	
    	// Jetzt 3x die analoge Spannung and Kanal channel auslesen
    	// und dann Durchschnittswert ausrechnen.
    	for(i=0; i<3; i++) {
    		// Eine Wandlung
    		ADCSRA |= (1<<ADSC);
    		// Auf Ergebnis warten...
    		while(ADCSRA & (1<<ADSC));
    		
    		result += ADCW;
    	}
    	
    	// ADC wieder deaktivieren
    	ADCSRA &= ~(1<<ADEN);
    	
    	result /= 3;
    	
    	return result;
    }

    habs mal eins zu eins kopiert, habe aber einen angepassten source (für die Parameter) noch da, nur auf dem anderen PC :P

    tut mir leid das ich erst so spät wieder antworte, war leider eine Zeitlang krank im bett

Berechtigungen

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