PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ADXL202 problem



ChRiZ
13.07.2006, 12:14
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!!


#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);
}
}

SprinterSB
13.07.2006, 13:05
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.

ChRiZ
13.07.2006, 21:08
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:

#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);
}
}

SprinterSB
14.07.2006, 09:31
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:

cli();
result = (((((float)t1_x/(float)t2_x)*1000)-481)*1000)/125;
sei();
bzw.

{
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:


{
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.

ChRiZ
16.07.2006, 13:38
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:

#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);
}
}