logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Jak sprawić by return w funkcji zmieniał stan diody LED na PC6 AVR?

Marek K80 27 Sie 2020 00:12 834 9
  • #1 18891034
    Marek K80
    Poziom 12  
    Witam, mam problem z poniższym programem, program nie działa zgodnie z oczekiwaniami, mianowicie jako znacznik flagę posługuję się diodą LED na pinie PC6.
    Podprogram ma za zadanie zareagować na przycisk/-i bądź (nie dodawałem zabezpieczeń przed drganiem styków bo to nie jest istotą problemu) poprzez zmianę stanu diody PC6. Wyekstrahowałem nie zbędne linie. O ile jeśli zmiana toggle jest zapisana w ciele funkcji readKeyboard wszystko działa. Ale jeśli zmiana ma nastąpić w main.c na skutek zwrócenia wartości przez return funkcji to program nie działa zgodnie z oczekiwaniami. Nie mam głowy, co zrobiłem źle, ślęczę już nad tym sporo czasu. Może zrobiłem jakiś szkolny błąd.
    
    #include <avr/io.h>
    #include <util/delay.h>
    
    uint8_t readKeyboard();
    
    int main(void)
    {
    	DDRA=0xff;
    	DDRC|=(1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC3)|(1<<PC6);
    	DDRC&=~((1<<PC5)&(1<<PC4));
    	PORTC|= (1<<PC5)|(1<<PC4);
    	PORTC&=~((1<<PC0)&(1<<PC1)&(1<<PC2)&(1<<PC3)&(1<<PC6));
    	PORTA = 0xff;
    
        uint8_t key;
    
    	while(1)
    	{
    		key = readKeyboard();
    		if (key==0)
    			{
    //				PORTC^=(1<<PC6); //tu nie działa
    			}
    		if (key==1)
    			{
    //				PORTC^=(1<<PC6); //tu nie działa
    			}
    		if (key==2)
    			{
    			}
    	}
    }
    
    uint8_t readKeyboard()
    {
    	#define KEY1 (1<<PC4)
    	#define KEY2 (1<<PC5)
    
    	if (!(PINC&KEY1))
    
    		{
    		 	PORTC^=(1<<PC6); //tu działa
    			return 0;
    		}
    	if (!(PINC&KEY2))
    		{
    		  	PORTC^=(1<<PC6); //tu działa
    			return 1;
    		}
    	return 2;
    }
    

    do preparowania HEX używam AVR-Eclipse 2.3.4
  • #3 18891364
    hajy
    Poziom 21  
    Witam

    Mnie nie podobają się te linijki.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    powinno być tak
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Pozdrawiam Romek

    Dodane
    Mimo że te linijki są błędne nie wpływają na działanie programu, zamysłem autora było wyzerowanie bitów w rejestrach, a że te bity po resecie są wyzerowane...
  • #4 18891401
    ex-or
    Poziom 28  
    Marek K80 napisał:
    nie dodawałem zabezpieczeń przed drganiem styków bo to nie jest istotą problemu

    Skąd wiesz? IMHO, właśnie to jest istotą problemu.
  • #5 18892771
    Marek K80
    Poziom 12  
    Podejmuje kolejne próby uruchomienia programu. Dziękuję wszystkim za podpowiedzi - zostawiłem linie ustawiające bity w portach, może są błędne ale nie mają wpływu na działanie programu, poprawię je jak program zadziała. Odnośnie uwagi kolegi ex-or, zakładałem, iż jeśli nie ma zabezpieczenia dla drgania styków to powinna być bynajmniej jakaś losowa reakcja LED PC6, a jej nie ma w ogóle, co dla mnie na ten moment jest nie wytłumaczalne. Przerobiłem program na wersję bez funkcji lecz z mechanizmem blokującym drganie styków - zaczerpnąłem sposób z mirekk36.blogspot.com (znawcy wiedzą o co chodzi)
    
    #include <avr/io.h>
    #include <util/delay.h>
    uint8_t readKeyboard();
    
    int main(void)
    {
    	DDRA=0xff;
    	DDRC|=(1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC3)|(1<<PC6);
    	DDRC&=~((1<<PC5)&(1<<PC4));
    	PORTC|= (1<<PC5)|(1<<PC4);
    	PORTC&=~((1<<PC0)&(1<<PC1)&(1<<PC2)&(1<<PC3)*(1<<PC6));
    	PORTA = 0xff;
    
        uint8_t key1_lock=0, key2_lock=0;
    
    	while(1)
    	{
    		// ******* KLAWISZ 1
    		if( !key1_lock && !(PINC & (1<<PC4) ) )
    		{
    			key1_lock=1;
    			// reakcja na PRESS (wcinięcie przycisku)
    			PORTC^=(1<<PC6);
    		}
    		else
    	    if( key1_lock && (PINC & (1<<PC4) ) ) key1_lock++;
    
    		// ******* KLAWISZ 2
    		if( !key2_lock && !(PINC & (1<<PC5) ) )
    			key2_lock=1;
    		else
    			if( key2_lock && (PINC & (1<<PC5) ) )
    			{
    				if( !++key2_lock )
    				{
    					// reakcja na PUSH_UP (zwolnienie przycisku)
    					PORTC^=(1<<PC6);
    				}
    			}
    	}
    }
    


    program działa flaga LED na 6 bicie zmienia stan zgodnie z zamierzeniem, rzekłbym chodzi jak złoto. Gdy mechanizm eliminacji drgania styków zadziałał w kolejnym programie w outowałem go do funkcji

    
    #include <avr/io.h>
    #include <util/delay.h>
    uint8_t readKeyboard();
    
    int main(void)
    {
    	DDRA=0xff;
    	DDRC|=(1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC3)|(1<<PC6);
    	DDRC&=~((1<<PC5)&(1<<PC4));
    	PORTC|= (1<<PC5)|(1<<PC4);
    	PORTC&=~((1<<PC0)&(1<<PC1)&(1<<PC2)&(1<<PC3)&(1<<PC6));
    	PORTA = 0xff;
    
    	uint8_t key;
    
    	while(1)
    	{
    		    key = readKeyboard();
    			if (key==0)
    			{
    //				PORTC^=(1<<PC6);	//tu nie działa
    			}
    			if (key==1)
    			{
    //				PORTC^=(1<<PC6);	//tu nie działa
    			}
    			if (key==2)
    			{
    			}
    	}
    }
    
    uint8_t readKeyboard()
    {
    	#define KEY1 (1<<PC4)
    	#define KEY2 (1<<PC5)
    
    	static uint8_t key1_lock=0, key2_lock=0;
    
    	// ******* KLAWISZ 1
    	if( !key1_lock && !(PINC & KEY1 ) )
    	{
    	   key1_lock=1;
    	   // reakcja na PRESS (wcinięcie przycisku)
    		PORTC^=(1<<PC6); //tu działa chaotycznie
    	   return 0;
    	}
    	else
    		if( key1_lock && (PINC & KEY1 ) ) key1_lock++;
    
    	  // ******* KLAWISZ 2
    	 if( !key2_lock && !(PINC & KEY2 ) )
    		 key2_lock=1;
    	 else
    		 if( key2_lock && (PINC & KEY2 ) )
    		 {
    			 if( !++key2_lock )
    			 {
    				PORTC^=(1<<PC6); //tu nie działa
    				return 1;
    	    // reakcja na PUSH_UP (zwolnienie przycisku)
    	    	 }
    	     }
    	 return 2;
    }
    


    rezultat jest następujący - zakomentowane PORTC^=(1<<PC6) linie w pętli głównej brak całkowity reakcji (podobnie jak w moim pierwszym poście), natomiast gdy zaczniemy zmieniać stan PC6 w funkcji, to w przypadku jednego przycisku działanie chaotyczne, a w przypadku drugim całkowity brak reakcji,
    mam pytanie czy można w funkcji zmieniać stany pinów, czy stan rejestru wyjściowego nie zostanie przywrócony po wyjściu z funkcji do stanu z przed momentu wywołania funkcji ze stosu
    nie wiem co źle się dzieje w funkcji, iż ona nie działa - w przypadku pierwszego mojego postu i teraz
  • #6 18892845
    Konto nie istnieje
    Poziom 1  
  • #7 18893291
    ex-or
    Poziom 28  
    Te Kardasiowe wynalazki :roll: ! Dawno temu też się tym bawiłem i coś tam pamiętam, że też miałem problemy. Dajmy na to ten kod:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    czasem może działać tak a czasem inaczej. Gałąź po else, wydaje się, ma być formą deboucingu oraz zabezpieczeniem przed wykonywaniem się kodu w gałęzi if przy ciągłym naciśnięciu przycisku. Ale wyobraźmy sobie przycisk, który generuje długi ciąg stanów nieustalonych. Przy częstym wywoływaniu tego kodu, zmienna key_lock może się przepełnić i gałąź if może się wykonać ponownie. Z drugiej strony, przy niezbyt częstym wywołaniu kodu, po zwolnieniu przycisku i ponownym wciśnięciu zmianna key_lock może nie zdążyć się przepełnić i gałąź if się nie wykona. Kod, który działa tak albo inaczej w zależności od warunków na które nie ma się wpływu jest niewart funta kłaków.
    Kodu dla drugiego przycisku (jest inny) nie chce mi się analizować bo zakładam, że jest równie "wartościowy".
    Zrób debouncig jak się należy (tu dobry artykuł: https://www.embedded.com/my-favorite-software-debouncers/) bo naprawdę szkoda czasu.
  • #8 18894455
    StaryVirus_e_Wiarus
    Poziom 21  
    Cześć
    Nie analizowałem dogłębnie kodu Autora, ale mam wrażenie, jakby kod miał wykonywać "masło - maślane". To widać z pinami PC5 i PC6.
  • #9 18894767
    Marek K80
    Poziom 12  
    zmartwiliście mnie, ja ten kod analizowałem iteracja po iteracji i myślałem, że nie może zawieść, jeszcze jak by zawodził i w pętli głównej i w funkcji to on zawodził tylko w funkcji. Wprowadziło mnie to w błąd.
    Piny PC5 i PC6 realizują niby to samo, ale tak jak pisałem celem jest zmiana stanu wyjścia w pętli głównej na podstawie odczytu stanu wejścia w funkcji
  • #10 18894911
    StaryVirus_e_Wiarus
    Poziom 21  
    Ta zmiana następuje na pinach PC5 i PC6, ale wykonana jest w milionowych częściach ułamka sekundy. Nie sposób to zauważyć przez oczy człowieka.

    Dodano po 1 [minuty]:

    I zmiana następuje na ten sam stan, tak wynika z kodu, wg mnie.
REKLAMA