Witaj SP9LAP, pytasz jak to coś działa - o tak:
Po pierwsze jest pętla:
Kod:
while(1)
{
/*zrób cośtam*/
}
Program sprawdza wyrażenie wewnątrz nawiasów () i oblicza jego wartość logiczną - czy jest to prawdz, czy fałsz.
W języku C przyjęta jest konwencja, że "fałsz" oznaczany jest wartością 0 (zero), "prawda"to wartość niezerowa.
Jeśli wartość wyrażenia logicznego wewnątrz nawiasów jest niezerowa (prawdziwa) to wykonuje polecenia wewnątrz nawiasów {}. Po wykonaniu kodu w {} ponownie obliczana jest wartość wyrażenia logicznego. Jeśli zostanie stwierdzona wartość 0 - program pominie kod pomiędzy nawiasami {} i zacznie wykonywać kolejne polecenia poniżej, jeśli wyliczy w () wartość niezerową - ponownie wykona kod w {}. I tak dalej w pętli.
W tym konkretnym wypadku mamy while(1), czyli "zawsze prawda" - więc polecenia wewnątrz {} będą wykonywane w nieskończonej pętli - aż do zaniku zasilania procesora.
Oznacza to, że efektywnie będą wykonywały się instrukcje
Kod:
if(bit_is_clear(PINB, 0))
{
PORTA=PORTA^0b00000001;
_delay_ms(160);
} //if
//tu sprawdzi sobie warunek logiczny pętli - while(1) - prawda - więc wykona ponownie:
if(bit_is_clear(PINB, 0))
{
PORTA=PORTA^0b00000001;
_delay_ms(160);
} //if
//tu sprawdzi sobie warunek logiczny pętli - while(1) - prawda - więc wykona ponownie:
if(bit_is_clear(PINB, 0))
{
PORTA=PORTA^0b00000001;
_delay_ms(160);
} //if
//tu sprawdzi sobie warunek logiczny pętli - while(1) - prawda - więc wykona ponownie:
... itd. aż nam się znudzi i wyciągniemy wtyczkę.
Teraz przyjrzyjmy się co to oznacza.
Kod:
if(bit_is_clear(PINB, 0)) - sprawdza stan pinu - czy wciśnięty klawisz - jeśli tak, to wykonuje to co w {}
{
PORTA=PORTA^0b00000001;
_delay_ms(160);
} //if
Cała zabawa tkwi w linijce PORTA=PORTA^0b00000001;. Oznacza ona: do portu PORTA wstaw to, co masz w chwili obecnej na porcie PORTA bitowo XORowane z 0b00000001. Operatory bitowe wykonują operacje na odpowiadających sobie bitach operandów wejściowych - bit 0 pierwszego z bitem 0 drugiego, bit 1 z bitem 1, itd - jak w wyjaśnieniu Marcina SP4EJT pod kodem programu. Zauważmy jedną bardzo ciekawą właściwość. 1^0 daje 1, 0^0 daje 0. Wniosek - XORowanie "czegokolwiek" z zerem daje taką samą wartość jak to "cokolwiek". 1^1 daje 0, 0^1 daje 1. Wniosek kolejny - XORowanie "czegokolwiek" z jedynką zmienia wartość na przeciwną.
Tutaj robimy PORTA=PORTA^0b00000001;. Jako drugi operand mamy liczbę 0b00000001 - 7 najstarszych bitów to zera i jedna jedynka. Na PORTA mamy jakąś wartość. XORujemy odpowiadające sobie bity. Chcemy zamrugać wylącznie jednym wyprowadzeniem. Na 7 najstarszych bitach XORujemy z zerem - co nie zmienia wartości tych bitów (nie robimy krzywdy wystawionemu tam stanowi logicznemu), na najmłodszym bicie robimy XOR z jedynką. Jeśli była tam jednynka, to 1^1=0, jeśli było zero, to 0^1=1 - czyli zmieniamy stan ostatniego bitu na przeciwny. Tak właściwie ta linijka robi jedną rzecz - zmienia najmłodszy - ostatni bit PORTA na przeciwny. Wartość po zmianie jest z powrotem wpisywana do rejestru PORTA.
Po tej operacji odczekujemy chwilkę poleceniem _delay_ms - żeby wszystko nie działo się tak szybko.
I... właśnie doszliśmy do końca kodu w pętli while(1) - więc wykonamy te operacje od nowa, i od nowa, i od nowa itd...W kolejnych wejściach procedura zmieni stan ostatniego bitu 1-0-1-0-1-0-itd. - czyli po prostu będzie mrugać.
Pojaśniłem trochę czy zamotałem jeszcze bardziej?
73 de SQ8MHI
Tomek