-
        

Ergebnis 1 bis 5 von 5

Thema: ADXL202 problem

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    03.07.2006
    Beiträge
    143

    ADXL202 problem

    Anzeige

    Hallo Zusammen!
    mein ADXL will einfach nicht laufen..
    Ich habe zwei Interrupts, einmal für den X Ausgang des ADXL's und einmal für den Y Ausgang.
    der ADXL generiert bei beiden Ausgängen ein PWM Signal.

    Wenn ich in meinem Progamm nun nur einen Interrupt aktiviere funktioniert alles wunderbar.

    bei INT1 kommt der Y wert, bei INT0 der X Wert.
    Beide zusmammen wollen aber nicht so richtig.

    kann mir jemand weiterhelfen?
    Vielen Dank!!

    Code:
    #include <inttypes.h> 
    #include <avr/interrupt.h>
    
    #define F_CPU 8000000      /* 8Mhz */
    #include <util/delay.h>    /* definiert _delay_ms() ab avr-libc Version 1.2.0 */
    #include "twimaster.c"
    
    #include "LCD.h"
    
    volatile int t2_y,t2_x;
    volatile int t1_y,t1_x;
    volatile int x1,x0; // Temp Variablen für adxl und main
    
    int result;
    long count_y, count_x;
    
    char ziel[5];
    
    ISR(SIG_INTERRUPT1){ 
    
      if(x1==1){
        x1=0;				
    	if(x0==1) 		MCUCR = (1<<ISC11 | 1<<ISC10 | 1<<ISC01 | 1<<ISC00);
    	else MCUCR = (1<<ISC11 | 1<<ISC10 | 1<<ISC01 | 0<<ISC00);
        t1_y = count_y;
      }
      
      else{
        x1=1;			
    	if(x0==1)		MCUCR = (1<<ISC11 | 0<<ISC10 | 1<<ISC01 | 1<<ISC00);
    	else MCUCR = (1<<ISC11 | 0<<ISC10 | 1<<ISC01 | 0<<ISC00);
        t2_y = count_y;
        count_y = 0;
    	}
    }
    
    ISR(SIG_INTERRUPT0){ 
     
     if(x0==1){
        x0=0;				
    	if(x1==1) 		MCUCR = (1<<ISC01 | 1<<ISC00 | 1<<ISC01 | 1<<ISC00);
    	else MCUCR = (1<<ISC01 | 1<<ISC00 | 1<<ISC01 | 0<<ISC00);
        t1_x = count_x;
      }
      
      else{
        x0=1;				
    	if(x1==1)		MCUCR = (1<<ISC01 | 0<<ISC00 | 1<<ISC01 | 1<<ISC00);
    	else  MCUCR = (1<<ISC01 | 0<<ISC00 | 1<<ISC01 | 0<<ISC00);
        t2_x=count_x;
        count_x = 0;
      }
    
    }
    
    ISR (SIG_OUTPUT_COMPARE1A){
    count_y++;
    count_x++;
    }  
    
    void Timer_Inits(void){
    
        TCCR1A = 0;
        TCCR1B = (1 << WGM12) | (1 << CS10); 
      
      	OCR1A = (uint16_t) ((uint32_t) F_CPU / 50000); //100000
    
        TIMSK |= (1 << OCIE1A); 	// Interrupt wenn Timer Vergleichswert erreicht
    
     //	GIMSK = (1<<INT0 | 1<<INT1);		//Int0,1 aktiv
    	GIMSK = (1<<INT0);		//Int0,1 aktiv
    } 
    
    
    int main (void){
    	DDRC = 0x00;    //alles als Eingan def.
    	PORTC =0x00;	//PullUp's aus
    
    	DDRD  =0x00;	//alles Eingang
    	PORTD =0x00;	//PullUp's aus
    	
    	Timer_Inits();
    	sei();
    	i2c_init(); 
    	_delay_ms(1000);
    	lcd_init();
    	_delay_ms(1000);
    
    
    for(;;){
    
    _delay_ms(100);
    clear();
    
    (int) result = (((((float)t1_y/(float)t2_y)*1000)-481)*1000)/125;
    
    sprintf(ziel,"%d",result);
    stringout ("y=");
    stringout (ziel);
    
    (int) result = (((((float)t1_x/(float)t2_x)*1000)-481)*1000)/125;
    
    sprintf(ziel,"%d",result);
    stringout (" x=");
    stringout (ziel);
    
    
    //	if(result>4)	PORTC|=(1<<PC3); //LED2 anschalte
    
    //	else   PORTC&=~(1<<PC3); 
    //	if(result>6000)	PORTC|=(1<<PC2); //LED1 anschalte
    //	else   PORTC&=~(1<<PC2); 
    
    //	if(result>7)	PORTC|=(1<<PC1); //LED0 anschalte
    //	else   PORTC&=~(1<<PC1); 
    
    //	if(result>8)	PORTC|=(1<<PC0); //LED0 anschalte
    //	else   PORTC&=~(1<<PC0); 
       }
    }

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    • Der Zugriff auf deine volatiles t1_x, t2_x, t1_y, t2_y (zumindest die aus dem Hauptprogramm) muss atomar erfolgen. Ich glaub zwar nicht, daß dein Problem damit behoben ist, aber es gibt sonst (sporadische) Fehler.
      → [wiki="Fallstricke bei der C-Programmierung"]
    • INT0 resp. INT1-Flags nach Anfassen von MCUCSR clearen?
    • Mache nicht Variablen global, die besser lokal sind! (z.B. result)
    • float ist hier -- wie fast immer -- ziemlich sicher Overkill und kann in 32-Bit Fix-Arithmetik übertragen werden.
    Disclaimer: none. Sue me.

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    03.07.2006
    Beiträge
    143
    Vielen Dank für deine Antwort!
    Ich habe deine Vorschläge befolgt.
    leider bisher ohne erfolg

    Ich nicht genau was du mit "INT0 resp. INT1-Flags nach Anfassen von MCUCSR clearen?" meinst?

    und was kann ich anstelle der float's machen?

    Vielen Dank!
    Chris


    der Code im moment:
    Code:
    #include <inttypes.h> 
    #include <avr/interrupt.h>
    
    #define F_CPU 8000000      /* 8Mhz */
    #include <util/delay.h>    /* definiert _delay_ms() ab avr-libc Version 1.2.0 */
    #include "twimaster.c"
    
    #include "LCD.h"
    
    volatile long t2_y,t2_x;
    volatile long t1_y,t1_x;
    
    volatile int x1,x0; // Temp Variablen für adxl und main
    
    int count_y, count_x;
    
    
    char ziel[5];
    
    ISR(SIG_INTERRUPT1){ 
    cli();
      if(x1==1){
        x1=0;				
    	if(x0==1) 		MCUCR = (1<<ISC11 | 1<<ISC10 | 1<<ISC01 | 1<<ISC00);
    	else MCUCR = (1<<ISC11 | 1<<ISC10 | 1<<ISC01 | 0<<ISC00);
        t1_y = count_y;
      }
      
      else{
        x1=1;			
    	if(x0==1)		MCUCR = (1<<ISC11 | 0<<ISC10 | 1<<ISC01 | 1<<ISC00);
    	else MCUCR = (1<<ISC11 | 0<<ISC10 | 1<<ISC01 | 0<<ISC00);
        t2_y = count_y;
        count_y = 0;
    	}
    sei();
    }
    
    ISR(SIG_INTERRUPT0){ 
    cli();
     if(x0==1){
        x0=0;				
    	if(x1==1) 		MCUCR = (1<<ISC01 | 1<<ISC00 | 1<<ISC01 | 1<<ISC00);
    	else MCUCR = (1<<ISC01 | 1<<ISC00 | 1<<ISC01 | 0<<ISC00);
        t1_x = count_x;
      }
      
      else{
        x0=1;				
    	if(x1==1)		MCUCR = (1<<ISC01 | 0<<ISC00 | 1<<ISC01 | 1<<ISC00);
    	else  MCUCR = (1<<ISC01 | 0<<ISC00 | 1<<ISC01 | 0<<ISC00);
        t2_x=count_x;
        count_x = 0;
      }
    sei();
    }
    
    ISR (SIG_OUTPUT_COMPARE1A){
    count_y++;
    count_x++;
    }  
    
    void Timer_Inits(void){
    
        TCCR1A = 0;
        TCCR1B = (1 << WGM12) | (1 << CS10); 
      
      	OCR1A = (uint16_t) ((uint32_t) F_CPU / 50000); //100000
    
        TIMSK |= (1 << OCIE1A); 	// Interrupt wenn Timer Vergleichswert erreicht
    
     	GIMSK = (1<<INT0 | 1<<INT1);		//Int0,1 aktiv
    //	GIMSK = (1<<INT1);		//Int0,1 aktiv
    
    } 
    
    int main (void){
    	DDRC = 0x00;    //alles als Eingan def.
    	PORTC =0x00;	//PullUp's aus
    
    	DDRD  =0x00;	//alles Eingang
    	PORTD =0x00;	//PullUp's aus
    	
    	Timer_Inits();
    	sei();
    	i2c_init(); 
    	_delay_ms(10000);
    	lcd_init();
    	_delay_ms(10000);
    
    for(;;){
    
    _delay_ms(90000000);_delay_ms(90000000);_delay_ms(90000000);
    clear();
    
    
    int result;
    
    (int)result = (((((float)t1_y/(float)t2_y)*1000)-481)*1000)/125;
    
    sprintf(ziel,"%d",result);
    stringout ("a_y=");
    stringout (ziel);
    
    result = (((((float)t1_x/(float)t2_x)*1000)-481)*1000)/125;
    sprintf(ziel,"%d",result);
    stringout (" a_x=");
    stringout (ziel);
    
    
    //	if(result>4)	PORTC|=(1<<PC3); //LED2 anschalte
    
    //	else   PORTC&=~(1<<PC3); 
    //	if(result>6000)	PORTC|=(1<<PC2); //LED1 anschalte
    //	else   PORTC&=~(1<<PC2); 
    
    //	if(result>7)	PORTC|=(1<<PC1); //LED0 anschalte
    //	else   PORTC&=~(1<<PC1); 
    
    //	if(result>8)	PORTC|=(1<<PC0); //LED0 anschalte
    //	else   PORTC&=~(1<<PC0); 
       }
    }

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Nö, der erste Punkt steht genauso da wie vorher auch!
    Damit während des Lesens von t1_x keine ISR ausgeführt wird, in der t1_x geändert wird, müsste so was gemacht werden:
    Code:
    cli();
    result = (((((float)t1_x/(float)t2_x)*1000)-481)*1000)/125; 
    sei();
    bzw.
    Code:
    {
       uint8_t sreg = SREG;
       cli();
       result = (((((float)t1_x/(float)t2_x)*1000)-481)*1000)/125; 
       SREG = sreg;
    }
    Dann wären allerdings während der kompletten float-Berechnung (also sehr lange) die IRQs deaktiviert! Also:

    Code:
    {
       uint8_t sreg = SREG;
       cli();
       long t1x = t1_x;
       long t2x = t2_x;
       SREG = sreg;
       result = (((((float)t1x/(float)t2x)*1000)-481)*1000)/125; 
    }
    Mit der Berechnung willst du wohl nen Winkel rausbekommen bzw. den arcus-Tangens dessen. Sieht etwas spanisch aus, weil nicht mal sichergestellt ist, daß t2_x != 0 ist!

    Die float- in eine fix-Rechnung zu übertragen ist ne reine Effizienzgeschichte, mehr nicht. Da kannst du immer noch ran wenn's denn läuft...

    Was MCUCR angeht: Ich weiß nicht was du da machst...ich schätze mal die Flankentriggerung von INTx umstellen. Wenn du das machst kann es AFAIK sein, daß eine IRQ getriggert wird, ohne daß ein INTx-Ereignis vorliegt. Daher nach Änderung der INTx-Flanken bzw. AKtivierung von INTx erst die entsprechenden Flags resetten.

    Nochwas: So wie du es jetzt hast können verschachtelte IRQs auftreten. Ich vermute mal, das ist nicht das, was du willst? Wirf das cli und sei aus des ISRs raus.
    Disclaimer: none. Sue me.

  5. #5
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    03.07.2006
    Beiträge
    143
    Juhhu, es Funktioniert
    Ich habe die ganze Flankentriggerung weggelassen und die Interrupts nun heiss auf "any logical change" gemacht...

    Vielen Dank nochmals für dienen Hilfe!

    Hier der funktionierende Code:
    Code:
    #include <inttypes.h> 
    #include <avr/interrupt.h>
    
    #define F_CPU 8000000      /* 8Mhz */
    #include <util/delay.h>    /* definiert _delay_ms() ab avr-libc Version 1.2.0 */
    #include "twimaster.c"
    
    #include "LCD.h"
    
    volatile long t2_y,t2_x;
    volatile long t1_y,t1_x;
    
    volatile int x1,x0; // Temp Variablen für ISR's
    
    int count_y, count_x;
    char ziel[5];
    
    ISR(SIG_INTERRUPT1){ 
    GIFR = 0;
      if(x1==1){
        x1=0;	
        t1_y = count_y;
      }
      
      else{
        x1=1;
      	t2_y = count_y;
        count_y = 0;
    	}
    }
    
    ISR(SIG_INTERRUPT0){ 
    GIFR = 0;
      if(x0==1){		 
        x0=0;	
        t1_x = count_x;
      }
      
      else{
        x0=1;
        t2_x = count_x;
        count_x = 0;
    	}
    }
    
    ISR (SIG_OUTPUT_COMPARE1A){
    count_y++;
    count_x++;
    }  
    
    void Timer_Inits(void){
    
        TCCR1A = 0;
        TCCR1B = (1 << WGM12) | (1 << CS10); 
      
      	OCR1A = (uint16_t) ((uint32_t) F_CPU / 50000); //100000
    
        TIMSK |= (1 << OCIE1A); 	// Interrupt wenn Timer Vergleichswert erreicht
    
    	//Jede logische änderung von INT0 oder INT1 löst Interrupt aus
    	MCUCR = (0<<ISC11 | 1<<ISC10 | 0<<ISC01 | 1<<ISC00);
    
     	GIMSK = (1<<INT0 | 1<<INT1);		//Int0 u. 1 aktiv
    
    } 
    
    int main (void){
    	DDRC = 0x00;    //alles als Eingan def.
    	PORTC =0x00;	//PullUp's aus
    
    	DDRD  =0x00;	//alles Eingang
    	PORTD =0x00;	//PullUp's aus
    	
    	Timer_Inits();
    
    	i2c_init(); 
    	_delay_ms(10000);
    	lcd_init();
    	_delay_ms(10000);
    
    	sei();
    
    for(;;){
    
    _delay_ms(90000000);
    clear();
    
    //A(g) = ((T1/T2) / 0.5)/12.5%
    
    int resultx,resulty;
    
       uint8_t sreg = SREG;
       cli();
    
       long t1x = t1_x;
       long t2x = t2_x;
       long t1y = t1_y;
       long t2y = t2_y;
       SREG = sreg;
    
       if(t2x!=0) resultx = (((((float)t1x/(float)t2x)*1000)-481)*1000)/125; 
       else resultx=0;
    
       if(t2y!=0) resulty = (((((float)t1y/(float)t2y)*1000)-481)*1000)/125; 
       else resulty=0;
       sei();
    
    	sprintf(ziel,"%d",resultx);
    	stringout ("ay=");
    	stringout (ziel);
    
    	sprintf(ziel,"%d",resulty);
    	stringout (" ax=");
    	stringout (ziel);
       }
    }

Berechtigungen

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