Witam. Robię obsługę czujnika przyspieszenia firmy MEMSIC MXD7202 (równoważnik ADXL202) przy użyciu mikrokontrolera ATmega8(kwarc zewnetrzny 8MHz).
Czujnik mam z wyjściami cyfrowymi i pomiar dwóch wyjść tego czujnika polega na pomiarze współczynniku wypełnienia tego sygnału. Np. 50% współczynnik wypełnienia odpowiada przyspieszeniu 0g (g-przysp.ziemskie).
Sposób pomiaru obmyśliłem sobie taki, że wyjścia z czujnika idą na piny przerwań INT0 na INT1. Przerwanie reaguje na to, kiedy sygnał podłączony do INT0 albo INT1 jest na zboczu narastającym.
Czasy kiedy sygnał jest w stanie wysokim lub w stanie niskim mierzę przez TIMER1.
ALgorytm pomiaru jest taki, że najpierw mierzę sygnał z INT0, potem po pełnym odczytaniu tego sygnału, mierze sygnał z INT1. To wynika z zapewnienia poprawnosci odczytu wartości czujnika.
Częstotliwość sygnału do zmierzenia wynosi 100Hz (czyli nie tak duzo).
No i napotykam na pierwszy poważny problem.
Po podłączeniu wyjść czujnika do wejść INT0 i INT1, mikrokontroler przestaje ogarniać i prawdopobnie gdzieś przekracza pamięć (w efekcie na wyswietlaczu LCD pojawiaja sie rozne krzaki). Ogólnie coś sie zawiesza.
Czy ma ktoś na to poradę?
W załączniku przesyłam kod tego co do tej pory zrobiłem. Mam tam jeszcze obsługe przetwornika A/C do termometru, ale to działa. W kodzie jest kilka funkcji dotyczacych obslugi LCD, ale tym sie nie nalezy przejmować.
Czujnik mam z wyjściami cyfrowymi i pomiar dwóch wyjść tego czujnika polega na pomiarze współczynniku wypełnienia tego sygnału. Np. 50% współczynnik wypełnienia odpowiada przyspieszeniu 0g (g-przysp.ziemskie).
Sposób pomiaru obmyśliłem sobie taki, że wyjścia z czujnika idą na piny przerwań INT0 na INT1. Przerwanie reaguje na to, kiedy sygnał podłączony do INT0 albo INT1 jest na zboczu narastającym.
Czasy kiedy sygnał jest w stanie wysokim lub w stanie niskim mierzę przez TIMER1.
ALgorytm pomiaru jest taki, że najpierw mierzę sygnał z INT0, potem po pełnym odczytaniu tego sygnału, mierze sygnał z INT1. To wynika z zapewnienia poprawnosci odczytu wartości czujnika.
Częstotliwość sygnału do zmierzenia wynosi 100Hz (czyli nie tak duzo).
No i napotykam na pierwszy poważny problem.
Po podłączeniu wyjść czujnika do wejść INT0 i INT1, mikrokontroler przestaje ogarniać i prawdopobnie gdzieś przekracza pamięć (w efekcie na wyswietlaczu LCD pojawiaja sie rozne krzaki). Ogólnie coś sie zawiesza.
Czy ma ktoś na to poradę?
W załączniku przesyłam kod tego co do tej pory zrobiłem. Mam tam jeszcze obsługe przetwornika A/C do termometru, ale to działa. W kodzie jest kilka funkcji dotyczacych obslugi LCD, ale tym sie nie nalezy przejmować.
volatile uint8_t pomiarX;
volatile uint8_t pomiarY;
volatile uint16_t x_high=0,x_low=0,y_high=0,y_low=0;
//obsluga przerwania ADC0
SIGNAL(SIG_ADC)
{
value_low = ADCL;
value_high = ADCH;
value = ((value_high<<2)|(value_low>>6));
itoa(value,(char *)temp,10);
ADCSRA = _BV(ADEN)|_BV(ADIE)|_BV(ADSC)|_BV(ADPS2)|_BV(ADPS1);
}
//obsługa przerwania INT0
SIGNAL(SIG_INTERRUPT0)
{
cli();
if (pomiarX==0x00)
{
TCNT1 = 0x00;
//poczatek pomiaru x_high
TCCR1B &= ~_BV(CS12);
TCCR1B &= _BV(CS11);
TCCR1B &= ~_BV(CS10);
// Przestawienie przerwania na zbocze opadajace
MCUCR = 0;
MCUCR &= _BV(ISC01);
MCUCR &= ~_BV(ISC00);
pomiarX = 0x01;
}
else if (pomiarX==0x01)
{
x_high=TCNT1;
TCNT1 = 0x00; //teraz licz x_low
// Przestawienie przerwania na zbocze narastajace
MCUCR = 0;
MCUCR &= _BV(ISC01);
MCUCR &= _BV(ISC00);
pomiarX = 0x02;
}
else if (pomiarX==0x02)
{
x_low=TCNT1;
TCCR1B=0x00;//koniec pomiaru osi X
pomiarY=0x01; //teraz nastepuje pomiar osi Y
pomiarX=0x03; //zeby nie robił pomiaru osi X bez pomiaru osi Y
}
else
{
}
sei();
}
//obsluga przerwania INT1
SIGNAL(SIG_INTERRUPT1)
{
cli();
if (pomiarY==0x00)
{
}
else if (pomiarY==0x01)
{
TCNT1 = 0x00;
//poczatek pomiaru y_high
TCCR1B &= ~_BV(CS12);
TCCR1B &= _BV(CS11);
TCCR1B &= ~_BV(CS10);
// Przestawienie przerwania na zbocze opadajace
MCUCR = 0;
MCUCR &= _BV(ISC11);
MCUCR &= ~_BV(ISC10);
pomiarY = 0x02;
}
else if (pomiarY==0x02)
{
y_high=TCNT1;
TCNT1=0x00; //teraz licz y_low
// Przestawienie przerwania na zbocze narastajace
MCUCR = 0;
MCUCR &= _BV(ISC11);
MCUCR &= _BV(ISC10);
pomiarY = 0x03;
}
else if (pomiarY==0x03)
{
y_low=TCNT1;
TCCR1B=0x00; //koniec pomiaru osi Y
pomiarY = 0x04;
pomiarX = 0x00; //teraz ponownie moze nastapic pomiar osi X, i tak w
nieskonczonosc :)
}
else
{
}
sei();
}
int main(void)
{
/*konfiguracja portow*/
//konfiguracja portu B - output(lcd)
PINB = 0xFF;
PORTB = 0x00;
//konfiguracja portu C - input (tem)
PINC= 0x00;
PORTC = 0xFF;
//konfiguracja portu D - PD0 i PD1 jako output(uart), reszta jako input
Dir_SW=0x03;
PORTD=0xFC;
/*obsluga przerwan i licznika*/
//ADC0
ADMUX = _BV(ADLAR);
ADCSRA = _BV(ADEN)|_BV(ADIE)|_BV(ADSC)|_BV(ADPS2)|_BV(ADPS1);
//Obsluga INT0, INT1, T0, T1
GICR |= (1<<INT0)|(1<<INT1); //wlaczenie zewn przerwania na INT0 i INT1
MCUCR=0;
MCUCR |= (1<<ISC11)|(1<<ISC10)|(1<<ISC01)|(1<<ISC00); //narastajace zbocze
generuje obsluge przerwania
TCCR1A = 0; //wlaczenie T1,T/C1 w trybie
czasomierza
//ustawienie T1 - preskaler 8
TCCR1B &= ~_BV(CS12);
TCCR1B &= _BV(CS11);
TCCR1B &= ~_BV(CS10);
//TIMSK = (1<<TOIE1);
//Przerwania wlaczone
sei();
//Obsluga menu
LCDinit();
LCDcursorOFF();
menu_powitalne();
_delay_ms(1000);
LCDclr();
LCDGotoXY(2,0);
LCDstring(warX,2);
LCDGotoXY(2,1);
LCDstring(warY,2);
pomiarX=0x00;
pomiarY=0x00;
while (1)
{
sreg = SREG; //zczytanie ustawien SREG
cli(); //wylaczenie obslugi przerwań
//przesylanie wartosci na lcd
LCDGotoXY(4,0);
itoa(x_high-x_low,(char*)Xlevel,10);
LCDstring(Xlevel,5);
LCDGotoXY(4,1);
itoa(y_high-y_low,(char*)Ylevel,10);
LCDstring(Ylevel,5);
SREG = sreg; //powrot do ustawien SREG
}
return 0;
}