- 12V Akku mit 280 Ah bauen         
Ergebnis 1 bis 8 von 8

Thema: Inkrementalgeber/Magnetgeber auswerten

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

    Inkrementalgeber/Magnetgeber auswerten

    Anzeige

    Praxistest und DIY Projekte
    Hallo liebe RoboterNETZ Gemeinde,

    momentan möchte ich gern einen Magnetgeber mit der Auflösung von 2 auswerten. Dazu benutze ich den Atmega88p und benutze HTerm um mir die Werte auszugeben. Nur leider funktioniert das noch nicht ganz.
    Ich möchte das Ganze so gestalten, dass ich diesem eine Messdauer von bspw. 200ms vorgebe. ( Da sehr geringe Auflösung, aber dann noch recht gut geregelt werden soll, wobei die Programmdauer nicht sehr kritisch ist ) Während der Messdauer soll der 8-Bit Timer 0 also laufen und beide externene Interrupteingänge INT 0 und INT 1 ( sind also 2 Geber ) sollen bei einer steigenden Flanke einen Impuls weiter zählen.
    Die 200ms habe ich versucht über einen Prescaler + mehrere Overflows einzustellen. Nur leider zeigt mein H-Term nur Kauderwelsch an, also so als würde es die Zeichen nicht interpretieren können. ( einmal Endekennung '\0' ) Es kommt auch nur ein einziges Mal ein Zeichen und nicht zyklisch wie die While Schleife es eigentlich machen söllte.

    ( Die Richtungsauswertung kommt erst im nachhinein, wenn wenigstens das funktioniert )

    Code:
    #define F_CPU 16000000UL
    
    #include <avr/io.h>
    #include <stdio.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    
    #define Baud 9600UL
    
    volatile uint16_t DRZ1, DRZ2; 
    volatile uint8_t TIM0_Overflow, Drehrichtung1, Drehrichtung2;
    
    void UARTinit(){
    	
    	UBRR0 = 103;			// Baudrate laut Datasheet
    	UCSR0B = (1<<TXEN0);	// Enable Senden
    	UCSR0C = (1<<UCSZ00) | (1<<UCSZ01); // Setze 8 Bit Datenlänge
    	
    	// Alles was 0 ist setzt Asynchron Modus, Normal Speed, 1 Stop Bit und keine Paritaet
    }
    
    int uart_send( unsigned char c)
    {
    	while (!(UCSR0A & (1<<UDRE0)))
    	{
    		// mach nichts
    	}
    	//senden
    	UDR0=c;
    	return 0;
    }
    
    void uart_puts (char *s)
    {
    	while (*s)
    	{   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
    		uart_send(*s);
    		s++;
    	}
    }
    
    ISR(INT0_vect)
    {
    	DRZ1++;
    }
    
    ISR(INT1_vect)
    {
    	DRZ2++;	
    }
    
    ISR(TIMER0_OVF_vect)
    {
    	TIM0_Overflow++;
    }
    
    uint16_t Inkrementalgeber(uint16_t* Drehzahl1, uint16_t *Drehzahl2)
    {
    											
    		TCNT0 = 0;
    		DRZ1 = 0;								// Alle Zählerwerte auf 0 zurücksetzen
    		DRZ2 = 0;
    		TIM0_Overflow = 0;
    		TCCR0B |= (1<<CS02) | (1<<CS00);		// Frequentvorteiler von 1024 --> 16MHz/1024 = 64us pro Tick UND TImer0 starten
    												// 200ms/64us = 3125 --> 8 Bit Timer = 255 --> 12 * 255 + 1 * 65 = 3125 --> TIM0_Overflow = 12 und TCNT0 = 65, damit mit 8 Bit Timer und Prescaler 200ms Messzeit erreicht
    		TIMSK0 |= (1<<TOIE0);					// Overflow_Flag enablen  
    		EICRA |= (1<<ISC11) | (1<<ISC01) | (1<<ISC00) | (1<<ISC10);	// INT0 und INT1 auf steigende Flanke triggern
    		EIMSK |= (1<<INT1) | (1<<INT0);			// INT1 und INT0 Interrupts enablen
    		sei();									// Globale Interrupts erlauben
    		
    		while (1)
    		{
    			if (TIM0_Overflow >= 12)
    			{
    				if (TCNT0 >=65)
    				{
    					break;
    				}
    				 
    			}
    			// tue nichts bis 200ms abgelaufen sind
    		}
    		
    		TCCR0B &= ~((1<<CS02) | (1<<CS00));		// Timer stoppen
    		
    		cli();									// Globale Interrupts ausschalten
    		
    		*Drehzahl1 = DRZ1;						// Werteübergabe der Drehzhalen an das Hauptprogramm
    		*Drehzahl2 = DRZ2; 
    		
    }
    
    int main(void)
    {
       uint16_t Drehzahl1, Drehzahl2;
       uint8_t KanalA, KanalB;
       
       DDRD &= ~((1<<PIND2) | (1<<PIND3));			// INT0 und INT 1 als Kanaleingänge für beide Inkrementalgeber auswählen
       DDRD |= (1<<PIND1);							// UART TX als Ausgang
       DDRD &= ~(1<<PIND0);
       
       TCCR0A &= ~((1<<WGM00) | (1<<WGM01));		// Normal Operation Mode für Timer0 auswählen
       TCCR0B &= ~(1<<WGM02);
       
       char s[30];
       uint16_t x;
       
        while (1) 
        {											
    		Inkrementalgeber(&Drehzahl1 , &Drehzahl2);
    							
    		Drehzahl1 = 150 * Drehzahl1;			// Drehzahl in 1/min = 60s * ( 1000ms / Messdauer[ms] ) * ( Anzahl Flanken / Imp. pro Umdrehung [ Auflösung ] )
    		Drehzahl2 = 150 * Drehzahl2;			// 60s * 1000/200 * DRZ/2 = 150*DRZ 
    		
    		KanalA = Drehzahl1 / 72;				// Untersetzung Getriebe einbringen
    		KanalB = Drehzahl2 / 72;
    		
    		x=KanalA;
    		sprintf(s, "Drehzahl 1: %.d 1/min \n", x);
    		uart_puts( s );
    		
    		//_delay_ms(200);
    		
    		x=KanalB;
    		sprintf(s, "Drehzahl 2: %.d 1/min \n", x);
    		uart_puts( s );
    	
    		//_delay_ms(200);
        }
    }
    Vielen Dank schonmal für eure Hilfe!

    Grüße,
    Bucki

  2. #2
    Erfahrener Benutzer Robotik Visionär Avatar von 021aet04
    Registriert seit
    17.01.2005
    Ort
    Niklasdorf
    Alter
    36
    Beiträge
    5.070
    Pullup Widerstände?

    Mfg Hannes

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    14.03.2017
    Beiträge
    14
    Weiß ich jetzt nicht genau wie das gemeint ist. Brauch ich an der Stelle doch nicht, wenn ich die High Flanke auswerten möchte oder? Dann doch eher Pull Down oder?

    MfG Bucki

  4. #4
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.687
    Pullup Widerstände? ..
    .. Brauch ich an der Stelle doch nicht, wenn ich die High Flanke auswerten möchte oder? Dann doch eher Pull Down oder? ..
    Wenn Du das nicht brauchst, ists doch ok - da hatte Dir sicher das Datenblatt des Encoders Auskunft gegeben. Oder verlangt der Encoder (sprich: das Datenblatt) nen Pull Down?

    Ich habe die Auswertung für die Encoder an meinem Selbstbau"Servo" mit Pullup gemacht. Die Auswertung wirst Du sicher anders machen, ist hier sehr speziell. Kann aber, wie erwähnt, für Deine Encoder anders verlangt werden, siehe zugehöriges Datenblatt. Belegt werden soll hier nur die Initialisierung der Pinne mit internem PullUp :
    Initialisierungen der Controllerpinns im main
    Code:
    /* >>
      Stand  ...\C4\C4\SVbby2\SVbby1p.c
     =============================================================================== =
      Target MCU        : ATmega 328p QFM
      Target Hardware   : babyorangutan und Micromotor als Servo mit Standardfunktion
      Target cpu-frequ. : 20 MHz Resonator
     =============================================================================== =
    . . . . Code gestrichen
     ============================================================================== */
    . . . . Code gestrichen
    // ============================================================================= =
    // ===  HAUPTProgramm ========================================================== =
    . . . . Code gestrichen
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // ===  Grundlegende Initialisierungen der Hardware, Portdefinition (PDIP !!)
    //         PCINT14,/RESET,PC6   1       28   PC5,ADC5,SCL,PCINT13
    //            PCINT16,RxD,PD0   2       27   PC4,ADC4,SDA,PCINT12
    //            PCINT17,TxD,PD1   3       26   PC3,ADC3,PCINT11
    //           PCINT18,INT0,PD2   4       25   PC2,ADC2,PCINT10
    //      PCINT19,OC2B,INT1,PD3   5       24   PC1,ADC1,PCINT9
    //         PCINT20,XCK,T0,PD4   6       23   PC0,ADC0,PCINT8
    //                        VCC   7       22   GND
    //                        GND   8       21   AREF
    //     PCINT6,XTAL1,TOSC1,PB6   9       20   VCC
    //     PCINT7,XTAL2,TOSC2,PB7  10       19   PB5,SCK,PCINT5
    //        PCINT21,OC0B,T1,PD5  11       18   PB4,MISO,PCINT4
    //      PCINT22,OC0A,AIN0,PD6  12       17   PB3,MOSI,OC2,OC2A,PCINT3
    //           PCINT23,AIN1,PD7  13       16   PB2,/SS,OC1B,PCINT2
    //       PCINT0,CLKO,ICP1,PB0  14       15   PB1,OC1A,PCINT1
    // - - - - - - - - - - - - - - -
    //  Initialisierung der BOARD!! Anschlüsse am babyorangutan mit mega328-TQFP:
    //                /RESET, PC6   1 EU  A 28   PC5                ============
    //              UART-RxD, PD0   2 EU  A 27   PC4                        ====
    //   rtUserLED, UART-TxD, PD1___3 EU  A 26___PC3          
    //     Encoder-1-A, INT0, PD2   4 EU  A 25   PC2, TASTEJ-GND
    //    Motor2B, OC2B,      PD3   5 EU EU 24   PC1, TASTEJ-In = PCINT9
    //  Encoder-1-B, PCINT20, PD4___6 EU  A 23___PC0          
    //                    +++ VCC   7 +   - 22   GND  ---     
    //                    --- GND   8 -   + 21   AREF ref     
    //                 XTAL1  PB6___9 A     20___AVCC         
    //                 XTAL2  PB7  10 A   A 19   PB5, SCK, PCINT5
    //    Motor1B, OC0B,      PD5  11 EU  A 18   PB4, MISO, (GND)-blaue-LED
    //    Motor1A, OC0A,      PD6__12 A   A 17___PB3, MOSI, OC2A, Motor2A
    //          Taste rechts, PD7  13 A   A 16   PB2, (+)-blaue LED
    //         (+)-heartbeat, PB0  14 A   A 15   PB1, (GND)-Heartbeat-LED
    // Anmerkungen zu den Motoren: die Controllerpins sind NUR über
    //      sind NUR über den Motortreiber (Wahrheitstabelle!!) zu erreichen
    // - - - - - - - - - - - - - - -
    // Ports als Ein- (0) oder Ausgänge (1) konfigurieren, Pins/Pull Ups (1) aktiv.
    //   A = Ausgang, E = Eingang ohne , EU = Eingang MIT PullUp, Belegung siehe oben
      DDRB  = 0b11101111;   // Heartbeat auf B0(+)/(GND -) 
      PORTB = 0b00010000;   //  PB5: PCI für Servopuls
                            //
      DDRC  = 0b00111101;   // PC0, PC2-5, PC6+7-Pin  H I E R  bei babyorangutan (MLF)
      PORTC = 0b11000010;   // PC0, PC2-5 sind aktuell Ausgänge ##>> KEIN Pullup !!
                            // 
      DDRD  = 0b01101011;   // RX/TX-PD0/1, PD5/PD6 = M1B/M1A, PD7 = Taste: PullUP !
      PORTD = 0b10010100;   //   Pull Ups aktivieren, mit pololuMot AUCH bei INT0/~1
                            //
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    . . . . Code gestrichen
    Build succeeded with 0 Warnings...
     ============================================================ */
    Initialisierungen und Auswertung der Encodereingänge
    Code:
    /* >> 
      Stand  ...\C4\SVbby1p\Sbby1p_motij.c
     =============================================================================== =
    . . . . Code gestrichen
     =============================================================================== =
      *** Versionsgeschichte:
     ====================
     x24 23Nov16 1450 Motor EINschalten erst nach Einstellung der "Hand auf für Geld"
    . . . . Code gestrichen
     ============================================================================== */
    
    
    // ============================================================================= =
    // ===  Initialisierung externer Interrupts bei m328, doc 8271I
    //      EXT_INT0 auf PORTD2  --  Encoder IencB0 auf PIND2
    // ============================================================================= =
      void XTI0_int( void )            // Initialisiere Interrupt 0, PD2, auf ANY edge
     {                              //  => EICRA ISC00 + ~10 auf 1                 S71
    // - - - - - - - - - - - - - - - -
    //      Initialisiere PD2 als externen Interrupt, ANY edge
      EICRA   |=  (1<<ISC00);       // INT0 triggert auf jede Flanke (any edge)
      EIMSK   |=  (1<<INT0);        // erlaube INT0
    // Initialisierung der Zeiten:   
      Iencdr0  =  Iz_diff0  =  Iz_yseci0  =  Iz_ysecv0  =  0;
      tmrE0    =  0;                // Timer für Drehzahlerfassung
                                    //
      Iencdr0       =  Iencdef0;    // Initialisiere Startwert Encoder (vgl. main)
      IencB0        =  IenBdef0;    // Initialisiere Startwert Encoder
                                    //
     }      // Ende von void XTI_0_1_init( void )
    // ============================================================================= =
    
    
    // ============================================================================= =
    // ===  Nicht unterbrechbare ISR für EXT_INT0(any edge auf mega328      ======== =
    //      Der Timer tmrE0 wird ausgelesen für Laufzeit des EXT_INT0 auf PD2.
    //      Enc-zähler Iencdr0 wird mit jedem Tick hochgezählt, ohne Richtung=any edge
    //      Encoder IencB0 wird richtungskonform hochgetickert => gesamte Fahrstrecke
    //              seit Rücksetzen (irgendwo); Aussage über Drehrichtung ist gegeben
    //      EXT_INT0 (Enc-spurA) triggert auf PORTD 2
    //       PCINT20 (ENC-spurB) triggert auf PORTD 4
    // ============================================================================= =
      ISR(INT0_vect)                // INT0-PD2 triggert ANY edge => lesen Iencdr0/A
     {                              //   => Bei Aufruf PORTD2 prüfen auf high/low
    // - - - - - - - - - - - - - - - -
    //251116  if ( Isecstrt ) return;       // Keine Messung in der Startphase
    //  ToggleBit ( PBLED, LBb );   // blLED toggeln, PORTB, blLED auf PB2
      Iz_diff0  = tmrE0;    // Hier die Zeit (in x 50µs-tupsi) seit letztem ISR-Aufruf
      tmrE0     =     0;    // Timer für Encoderinterupts auf Null  
      Iencdr0 ++;                   // Incrementiere Encodercounter, NUR aufwärts
      if ((IsBitSet (PIND, 2)) == (IsBitClr (PIND, 4))) IencB0++;
                                    // Rad treibt vorwärts,  math. negativ
      else                    IencB0--;     // Rad treibt rückwärts, math. positiv
     }      // Ende ISR(INT0_vect)
    // ============================================================================= =
    
    
    // ============================================================================= =
    // ===  Initialisierung Pin Change Interrupt bei m328, doc 8271I
    //      PCINT[23:16], PORT D4, any Edge <=> Für Zählung Encoderflanken Spur "B"
    //      Die zugehörige ISR tickert Iencdr0 und IencB0 rauf bzw. runter
    //              ==>>    Die Zeit-/Drehzahlerfassung bleibt NUR bei EXT_INT0/PB2
    // ============================================================================= =
      void PCI2_int( void )         // Initialisiere PCI 20, PB4, any edge     doc  74
     {                              //
    // - - - - - - - - - - - - - - - -
    //251116  if ( Isecstrt ) return;       // Keine Messung in der Startphase
      PCICR     |=  ( 1<<PCIE2 );   // Auswahl PCINT[23:16] ; hier PD4; siehe PCMSK2
                                    // PCI triggert auf jede Flanke (any edge)
      PCMSK2    |=  ( 1<<PCINT20 ); // Interrupt kommt von PB5
     }      // Ende von void XTI_0_1_init( void )
    // ============================================================================= = 
    
    
    // ============================================================================= =
    // ===  Nicht unterbrechbare ISR für PCINT0 auf PB5; mega328
    //      PCINT[7:0], PORTB5, any Edge <=> Für Pulszeitmessung Servopuls
    //      Die zugehörige ISR misst die Pulszeit tPULS für einen Servo in [tupsi]
    //              also die Zeit, in der der Servopuls auf high steht
    //      Siehe dazu ISR(TIMER1_COMPA..
    // ============================================================================= =
      ISR(PCINT2_vect)              // PCINT2 triggert ANY edge =>  lesen Iencdr0/B
     {                              //   prüfe ob PB5 = high, nur dann Wert übernehmen
    // - - - - - - - - - - - - - - - -
    //251116  if ( Isecstrt ) return;       // Keine Messung in der Startphase
    // ToggleBit ( PBLED, LBb );    // blLED aus, PORTB, blLED auf PB2
      Iz_diff0  = tmrE0;    // Hier die Zeit (in x 50µs-tupsi) seit letztem ISR-Aufruf
      tmrE0     =     0;    // Timer für Encoderinterupts auf Null  
      Iencdr0 ++;                   // Incrementiere Encodercounter, NUR aufwärts
      if ((IsBitSet (PIND, 2)) == (IsBitClr (PIND, 4))) IencB0--;
                                    // vgl. ISR(INT0_vect)
      else                    IencB0++;     // vgl. ISR(INT0_vect)
                                    //
     }              // Ende ISR(PCINT2_vect)
    // ============================================================================= =
    
    . . . . Code gestrichen
    
    // ============================================================================= =
    // =====  ENDE    Subroutinen  ================================================= =
    // ============================================================================= =
    Der Wert tmrE0 enthält die Anzahl der Zeiteinheiten für die Drehzahlmessung - wird von einem Timer geliefert.
    Ciao sagt der JoeamBerg

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    14.03.2017
    Beiträge
    14
    Hallo oberallgeier!

    Laut Datenblatt wird eigentlich nichts weiter verlangt, zur Sicherheit wurden aber Pull Down Widerstände verwendet. Einsehbar ist dieses hier: Daten Magnetgeber, dann im rechten Bereich unter Downloads "Gesamtüberblick" zu erreichen.

    Und sonst mache ich es ja ähnlich wie du, nur dass ich meine Regelung nicht andauernd unterbrechen möchte, nur um eine einzige Flanke zu messen. Deswegen möchte ich für den Roboter als Hauptprogrammstruktur: Init --> Joystick einlesen --> aktuelle Drehzahl einlesen --> Regeln --> Beginne wieder bei Joystick einlesen. Deßhalb das mit der vorgegebenen Messdauer ( Die auch recht hoch ist, aber dies liegt wie gesagt an der geringen Geberauflösung ).
    Am Oszi kommt alles wunderbar an und die Zeiten stimmen perfekt mit der angegebenen Leerlaufdrehzahl des Motors überein.
    Nur eben der UART gibt Quark aus. Er scheint irgendwie nach einer Ausgabe hängen zu bleiben oder diese nichtmal richtig tätigen zu können ( siehe einmalige Ausgabe von Endekennung '\0').

    Grüße
    Bucki

  6. #6
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.687
    .. Laut Datenblatt wird eigentlich nichts weiter verlangt .. Am Oszi kommt alles wunderbar an und die Zeiten stimmen ..
    Gut, oder - sorry, dass ich was anderes möglich gehalten habe

    .. Nur eben der UART gibt Quark aus. Er scheint irgendwie nach einer Ausgabe hängen zu bleiben oder diese nichtmal richtig tätigen zu können ..
    DIES ist nur eine sehr persönliche Meinung: HTerm verwende ich so gut wie garnicht (nur für EINE Spezialaufgabe) - ich finde das Ding s..mässig schlecht. Sorry. Ich verwende das Teminal von br@y - die Version v1.9b-20040714.

    Schau mal im Datenblatt des Controllers nach - Seite 85/86. Die Interrupts zu den UART-Funktionen sind in der Interrupttabelle total hinten priorisiert. Da könn(t)en die - hoch priorisierten - externen oder PinChange-Interrupts prächtig dreinpfuschen ?? fürchtete ich manchmal. Vielleicht probiers mal vor/hinter der UART-Ausgabe mit cli();/sei(); - dafür aber übernehm ich nun keine Garantie :-/
    Ciao sagt der JoeamBerg

  7. #7
    Neuer Benutzer Öfters hier
    Registriert seit
    14.03.2017
    Beiträge
    14
    Okay, danke dir, werde ich mal versuchen!

    Naja bisher hat es seine Dienste gut vollzogen, habe das ganze Prozedere schon erfolgreich für das Joystick einlesen und die Ultraschallsensor-Auswertung verwenden können, aber bei beiden hatte ich noch keine Interrupts verwendet bzw. global extra diese gesperrt. Wenn ich es recht überlege könnte es wirklich an sowas Mimligen hapern.
    Melde mich diesbezüglich nochmal! ( Kanns aber vielleicht erst morgen testen )

    Grüße
    Bucki

  8. #8
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    03.09.2009
    Ort
    Berlin (Mariendorf)
    Beiträge
    1.023
    Zitat Zitat von oberallgeier Beitrag anzeigen
    Die Interrupts zu den UART-Funktionen sind in der Interrupttabelle total hinten priorisiert. Da könn(t)en die - hoch priorisierten - externen oder PinChange-Interrupts prächtig dreinpfuschen ??
    @Bucki:
    Nicht wundern falls cli();/sei(); keinen Erfolg bringt. Interrupts dürften die UART-Hardware gar nicht stören können. Die Priorisierung betrifft nach meinem Verständnis nur das Handling der Sende- und Empfangsregister bzw. deren ISRs. Jedes neue Zeichen wird doch anhand des Start-Bits erkannt und vom UART ganz stur rausgetickert. Könnt noch sein, dass einzelne Zeichen gar nicht gesendet sondern schlicht vom nachfolgenden Zeichstrom überrollt werden.

Ähnliche Themen

  1. Inkrementalgeber mit TCST1103
    Von kellerkind im Forum Elektronik
    Antworten: 15
    Letzter Beitrag: 29.12.2009, 13:03
  2. Inkrementalgeber
    Von baensch im Forum Suche bestimmtes Bauteil bzw. Empfehlung
    Antworten: 2
    Letzter Beitrag: 16.07.2009, 17:37
  3. Inkrementalgeber
    Von bartolomeos im Forum Sensoren / Sensorik
    Antworten: 9
    Letzter Beitrag: 09.11.2005, 20:16
  4. inkrementalgeber
    Von curmet im Forum Sensoren / Sensorik
    Antworten: 8
    Letzter Beitrag: 17.06.2005, 22:11
  5. Inkrementalgeber
    Von demerzel im Forum Motoren
    Antworten: 2
    Letzter Beitrag: 25.06.2004, 21:53

Berechtigungen

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

Labornetzteil AliExpress