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

[atmega8][c]nieoczywista funkcja

Andrzej_m8 20 Wrz 2008 20:32 1289 4
REKLAMA
  • #1 5554566
    Andrzej_m8
    Poziom 2  
    Witam. Przerabiam kurs z Edw Pana Koppel-a i mam pytanie do osób lepiej znających ode mnie C. Nie wiem dlaczego wewnątrz pierwszego elementu tablicy w funkcji WyswietlHex:

    g_DaneWyswietlacza[0] = pgm_read_byte(&g_WzorCyfr[var>>(3*4)])


    znajduje się w [] nawiasach var>>(3*4) - jest to przesunięcie o 12 miejsc w prawo? Skoro tak to dlaczego akurat o 12, skoro jest 16 cyfr do wyświetlenia, a mimo wszystko program działa prawidłowo. Parametrem funkcji jest 16 bitowa zmienna g_Licznik.

    Dlaczego kolejne wyrazy tablicy mają odpowiednio w [] nawiasach 2*4, 1*4 oraz czemu indexy 1,2,3 dodatkowo są porównywane z 0xf.
    Oto cały kod (autorstwa Pana Koppela) do obsługi wyświetlacza LED - wypisywanie na kolejnych wyświetlaczach liczb szesnastkowych.

    #define LED_A 0
    #define LED_B 1
    #define LED_C 2
    #define LED_D 3
    #define LED_E 4
    #define LED_F 5
    #define LED_G 6
    #define LED_DP 7
    #define LEDPORT PORTB
    #define LEDDDR DDRB
    #define COM1 6
    #define COM2 5
    #define COM3 4
    #define COM4 3
    #define COMPORT PORTD
    #define COMDDR DDRD
    
    uint8_t g_AktWyswietlacz = 0; 
    uint8_t g_DaneWyswietlacza[4]; 
    prog_uint8_t g_DaneCom[4] = 
    	{~(1<<COM1), ~(1<<COM2), ~(1<<COM3), ~(1<<COM4)}; 
    
    prog_uint8_t g_WzorCyfr[16] = 
    	{
    		~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_E | 1<<LED_F), // 0	
    		~(1<<LED_B | 1<<LED_C), // 1
    		~(1<<LED_A | 1<<LED_B | 1<<LED_G | 1<<LED_E | 1<<LED_D), // 2
    		~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_G), // 3
    		~(1<<LED_B | 1<<LED_C | 1<<LED_G | 1<<LED_F), // 4
    		~(1<<LED_A | 1<<LED_F | 1<<LED_G | 1<<LED_C | 1<<LED_D), // 5
    		~(1<<LED_A | 1<<LED_F | 1<<LED_E | 1<<LED_D | 1<<LED_C |1<< LED_G), // 6
    		~(1<<LED_A | 1<<LED_B | 1<<LED_C), // 7
    		~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_E | 1<<LED_F | 1<<LED_G), // 8
    		~(1<<LED_G | 1<<LED_F | 1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D), // 9
    		~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_E | 1<<LED_F | 1<<LED_G), // A
    		~(1<<LED_C | 1<<LED_D | 1<<LED_E | 1<<LED_F | 1<<LED_G), // B
    		~(1<<LED_A | 1<<LED_D | 1<<LED_E | 1<<LED_F), // C
    		~(1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_E | 1<<LED_G), // D
    		~(1<<LED_A | 1<<LED_D | 1<<LED_E | 1<<LED_F | 1<<LED_G), // E
    		~(1<<LED_A | 1<<LED_E | 1<<LED_F | 1<<LED_G) // F
    	}; 
    
    uint16_t g_Licznik = 0; 
    
    
    // Funkcja wyświetla w kodzie heksadecymalnym podaną liczbę
    void WyswietlHex(uint16_t var)
    {
    [b]	g_DaneWyswietlacza[0] = pgm_read_byte(&g_WzorCyfr[var>>(3*4)]); 
    	g_DaneWyswietlacza[1] = pgm_read_byte(&g_WzorCyfr[(var>>(2*4))&0xf]);
    	g_DaneWyswietlacza[2] = pgm_read_byte(&g_WzorCyfr[(var>>(1*4))&0xf]);
    	g_DaneWyswietlacza[3] = pgm_read_byte(&g_WzorCyfr[var&0xf]);
    }
    
    // Start
    int main(void)
    {
    	/////////////////////////////
    	// inicjacja
    	LEDDDR = 0xff; 
    	COMDDR = 1<<COM1 | 1<<COM2 | 1<<COM3 | 1<<COM4; 
    	// Timer0
    	TCCR0 = 1<<CS01|1<<CS00; 
    	TIMSK = 1<<TOIE0; 
    	// Globalne zezwolenie na przerwania
    	sei(); 
    	// koniec inicjacji
    	/////////////////////////////
    	
    	
    	for(;;)
    	{
    		WyswietlHex(g_Licznik); 
    		_delay_loop_2(0xffff); 
    		g_Licznik++; 
    	}
    
    	return 0; 
    }
    
    //_________________________________________________________________________________
    // Obsługa przerwań
    SIGNAL(SIG_OVERFLOW0)
    {
    	// Wpisanie do licznika początkowej wartości
    	TCNT0 = 128; 
    	// Wygaszenie wyświetlaczy
    	COMPORT |= 1<<COM1 | 1<<COM2 | 1<<COM3 | 1<<COM4; 
    	// Wysłanie odpowiedniej danej
    	LEDPORT = g_DaneWyswietlacza[g_AktWyswietlacz]; 
    	// Włączenie odpowiedniego wyświetlacza
    	COMPORT &= pgm_read_byte(&g_DaneCom[g_AktWyswietlacz]); 
    	// Zwiększenie stanu zmiennej wskazującej na obsługiwany wyświetlacz
    	++g_AktWyswietlacz; 
    	if(g_AktWyswietlacz > 3)
    		g_AktWyswietlacz = 0; 
    }
  • REKLAMA
  • #2 5554584
    BoskiDialer
    Poziom 34  
    "a >> b" jest przesunięciem "a" o "b" bitów w prawo. "&" to nie porównanie tylko maskowanie (iloczyn logiczny) bitów. Wyrażenie "var>>(3*4)" przesunie zmienną o 12 bitów w prawo, czyli zwróci czwarty nibble (trzeci licząc od zera - stąd trójka, nibble ma 4 bity, stąd czwórka). "(var>>(2*4))&0xf" przesunie zmienną o 8 bitów w prawo i zamaskuje 4 najniższe bity z wyniku pośredniego. "var&0xf" zwróci 4 najniższe bity. Poczytaj o operatorach w C.
  • REKLAMA
  • #3 5554706
    Andrzej_m8
    Poziom 2  
    W takim razie mam pytanie raczej z programowania w C, a nie AVRów. Czy tak wygląda przesunięcie zmiennej var o wartości 1 o 12 miejsc w prawo, taki jest wynik działania?

    0000 0000 0000 0001 >> 12 jest równa 0000 0000 0000 0000

    Czytałem trochę o operatorach w Symfonii i może będzie to głupie pytanie ale nie rozumiem dlaczego mimo wszystko wartość 1 pozostaje w nawiasie kwadratowym w miejscu var>> (3*4) skoro po przesunięciu w prawo zmiennej unsigned o wartości 1 o 12 miejsc powstaje liczba 0 .

    Również dla wartości 2,3,4,..15 jest identycznie.
  • REKLAMA
  • #5 5555218
    Andrzej_m8
    Poziom 2  
    Problem rozwiązany - nie przypatrzyłem się, że odwrotnie mam ponumerowane wyświetlacze do "mej" koncepcji.
REKLAMA