Skocz do zawartości

[C] Problem z enkoderem inkrementalnym na LPC1114 na zestawie uruchomieniowym ZL32ARM


JacekW

Pomocna odpowiedź

Witam,

otóż uwidziało mi się ostatnio pobawić enkoderem optycznym wyprutym z drukarki. Stwierdziłem ze kod napisze na przerwaniach z GPIO (żeby nie zamulać procą ciągłym sprawdzaniem stanu)

Umyślało mi się przerwania wyzwalać na oba zbocza.

Z racji ze debugger Keil'a nie bardzo radzi sibie z symulowaniem tychże przerwań, w celu sprawdzenia jak działają, napisałem krótka obsługę przerwań zapalającą diodę w zależności

od kanału z którego system przyjmuje przerwania. Jak dotad działało, wraz z odpalaniem, kolejnego kanału, następowała zmiana świecenia się diodek zestawu. Kod obsługi przerwania poniżej:


__irq void PIOINT3_IRQHandler(void){


if(LPC_GPIO3 -> MIS == mENCODER_CHNLL_A){
	LedCtrl(LED1);
	LPC_GPIO3 -> IC = mENCODER_CHNLL_A;		
}
else if(LPC_GPIO3 -> MIS == mENCODER_CHNLL_B){
	LedCtrl(LED2);
	LPC_GPIO3 -> IC = mENCODER_CHNLL_B;
}
else if(LPC_GPIO3 -> MIS == (mENCODER_CHNLL_A | mENCODER_CHNLL_B)){
	LPC_GPIO3 -> IC = (mENCODER_CHNLL_A|mENCODER_CHNLL_B);	
};
};

Problem zaczął pojawiać, gdy stwierdziłem ze zliczę ilość zapalania się kanału A enkodera wraz z obrotem, napisałem bardzo prostą funkcję:

volatile int iCtr = 0;
__irq void PIOINT3_IRQHandler(void){


if(LPC_GPIO3 -> MIS == mENCODER_CHNLL_A){
	LPC_GPIO3 -> IC = mENCODER_CHNLL_A;
		iCtr ++;
}
else if(LPC_GPIO3 -> MIS == mENCODER_CHNLL_B){
	LPC_GPIO3 -> IC = mENCODER_CHNLL_B;
}
else if(LPC_GPIO3 -> MIS == (mENCODER_CHNLL_A | mENCODER_CHNLL_B)){
	LPC_GPIO3 -> IC = (mENCODER_CHNLL_A|mENCODER_CHNLL_B);	
};
if(iCtr >= 1000){
	LedCtrl(LED1);
};
};

Z racji ze przerwania odpalały się na zbocza, naiwnie wierzyłem ze obracając w tę samą stronę stan w którym wartość iCtr jest inkrementowana, wyzwoli się raz na impuls enkodera. Efekt był taki ze może po 30 impulsach enkodera zapalała się dioda sygnalizująca osiągniecie przez licznik wartości 1000...

W tym miejscu nadmienię, że sam enkoder połączony jest z uC buforem hc573N(kanał) enkodera podłaczony równolegle do 2 wejść scalaka), jedno wyjście scalaka podpięte są przez dzielnik(2 rezystory po jedem MOhm)dając na wyjściu 2,5 V które leci do enkodera. 2 wyjście bufora podpięte do diody LED, przez co umożliwiłem sobie obserwowanie stanu enkodera. Sam enkoder połaczony jest z płytką bufora metrowej długości przewodem, natomiast płytka z zestawem uruchomieniowym za pomocą kabelków goldpin.

Z racji ze działanie programu sypało się już w tym miejscu napisana przezemnie funkcja obsługi enkodera działała sobie jak chciała...


// Encoder Reg Values
#define mENCODER_REG_CHANNEL_A 0x01
#define mENCODER_REG_CHANNEL_B 0x02
#define mENCODER_CHNG_VAL  0x04

struct sEncoder{
int iEncoderPosition;
char ucEncoderReg;
/*
*  Bit      Function                                                    
*		0		Encoder Channel A                  
*		1		Encoder Channel B                   
*		2		Encoder Change Value             
*/
};

__irq void PIOINT3_IRQHandler(void){

if(LPC_GPIO3 -> MIS == mENCODER_CHNLL_A){
	if(sEncoder1.ucEncoderReg == mENCODER_REG_CHANNEL_A|mENCODER_CHNG_VAL){
		sEncoder1.iEncoderPosition++;
		sEncoder1.ucEncoderReg &= ~mENCODER_CHNG_VAL;
	};
	sEncoder1.ucEncoderReg = mENCODER_REG_CHANNEL_A;
	LPC_GPIO3 -> IC = (mENCODER_CHNLL_A);
}
else if(LPC_GPIO3 -> MIS == mENCODER_CHNLL_B){
	if(sEncoder1.ucEncoderReg == mENCODER_REG_CHANNEL_B|mENCODER_CHNG_VAL){
		sEncoder1.iEncoderPosition--;
		sEncoder1.ucEncoderReg &= ~mENCODER_CHNG_VAL;
	};
	sEncoder1.ucEncoderReg = mENCODER_REG_CHANNEL_B;
	LPC_GPIO3 -> IC = (mENCODER_CHNLL_B);
}
else if(LPC_GPIO3 -> MIS == (mENCODER_CHNLL_A | mENCODER_CHNLL_B)){
	if(sEncoder1.ucEncoderReg == mENCODER_REG_CHANNEL_A){
		sEncoder1.iEncoderPosition--;
	}
	else if(sEncoder1.ucEncoderReg == mENCODER_REG_CHANNEL_B){
		sEncoder1.iEncoderPosition++;
	};
	sEncoder1.ucEncoderReg |=mENCODER_CHNG_VAL;
	LPC_GPIO3 -> IC = (mENCODER_CHNLL_A|mENCODER_CHNLL_B);
}
else if(LPC_GPIO3 -> MIS == (LPC_GPIO3 -> MIS)&~(mENCODER_CHNLL_A | mENCODER_CHNLL_B)){
	sEncoder1.ucEncoderReg &= ~(mENCODER_REG_CHANNEL_A|mENCODER_REG_CHANNEL_B|mENCODER_CHNG_VAL);
	LPC_GPIO3 -> IC = (mENCODER_CHNLL_A|mENCODER_CHNLL_B);
};
};

Sama inicjalizacja przerwań :


#define mENCODER_CHNLL_A 0x00000010
#define mENCODER_CHNLL_B 0x00000020
#define mCLEAR_INTERRUPT_REGISTER 0x00000001
#define mENABLE_CLK_GPIO 0x00000040
#define mPULL_DOWN_ENABLE  0x00000000
#define mPORT_ENC_BITS 0x00000030

void Init_Encoder(void){

LPC_SYSCON  -> SYSAHBCLKCTRL |= mENABLE_CLK_GPIO;

LPC_IOCON   -> PIO3_4 = mPULL_DOWN_ENABLE;
LPC_IOCON   -> PIO3_5 = mPULL_DOWN_ENABLE;

LPC_GPIO3 -> DATA &= ~mPORT_ENC_BITS;
LPC_GPIO3 -> DIR  &= ~( mENCODER_CHNLL_A | mENCODER_CHNLL_B );
LPC_GPIO3 -> IS  &= ~( mENCODER_CHNLL_A | mENCODER_CHNLL_B ); //GPIO as edge sensitive
LPC_GPIO3 -> IBE |=  (mENCODER_CHNLL_A | mENCODER_CHNLL_B );//Both edges trigerring an interrupt
LPC_GPIO3 -> IE = mENCODER_CHNLL_A | mENCODER_CHNLL_B;
NVIC_EnableIRQ(EINT3_IRQn); 

};

Podsumowując, zastanawiam się gdzie spaprałem kod + to czy przypadkiem nie spaprałem dodatkowo elektroniki. dodam ze na przewodzie enkodera nie ma dławika. Gdyby ktoś był na tyle uprzejmy przebić się przez mój post i podać kilka sugestii byłbym dozgonnie wdzięczny.

Pozdrawiam

Link do komentarza
Share on other sites

Ooops, zapomniałem wyczyścić komentarze 😉.

Zmiana wartości nie rozwiązała, wydaje mi się ze sęk leży w samych przerwaniach.

Skróciłem procedure w celu zaobserwowania kiedy wartość będzie inkrementowana, obwarunkowałem tak żeby w teorii przeskoczył cały cykl enkodera (inkrementacja przy stanie 11, wraz z zapaleniem flagi ze inkrementacja nastąpiła, aby nie powtarzając jej w nieskończoność, gaszenie flagi przy stanie 11)

__irq void PIOINT3_IRQHandler(void){

if(((LPC_GPIO3 -> DATA)&(mENCODER_CHNLL_A|mENCODER_CHNLL_B)) == mENCODER_CHNLL_A){
	if(sEncoder1.ucEncoderReg <1){	
	sEncoder1.iEncoderPosition++;
	sEncoder1.ucEncoderReg++;
	};



}
else if(((LPC_GPIO3 -> DATA)&(mENCODER_CHNLL_A|mENCODER_CHNLL_B)) == mENCODER_CHNLL_B){

}
else if(((LPC_GPIO3 -> DATA)&(mENCODER_CHNLL_A|mENCODER_CHNLL_B)) == (mENCODER_CHNLL_A | mENCODER_CHNLL_B)){
sEncoder1.ucEncoderReg=0;
}
else if(((LPC_GPIO3 -> DATA)&(mENCODER_CHNLL_A|mENCODER_CHNLL_B)) == 0 ){

};
LPC_GPIO3 -> IC = (mENCODER_CHNLL_A|mENCODER_CHNLL_B);

};

W mainie ustawiłem żeby zapalił diodę po 100 cyklach.

Efekt jaki uzyskałem to zapalenie diody może po 4 czy pięciu przejściach... Zawsze pozostaje opcja ze coś w elektronice jest nie halo...

Pozdrawiam

[ Dodano: 04-11-2012, 02:21 ]

Ok, rozwiązałem problem, leżał w skopanym algorytmie. Dziekuję uprzejmie za pomoc 🙂

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.