Uwaga! Ta strona wysyła Ci "ciasteczko".
Użytkowników online:
2
Kursy>Kurs AVR-GCC>Kurs AVR-GCC, cz.2
printer_icon

Kurs AVR-GCC cz.2

30.11.2008 ABXYZ

Pan jesteś zerem W pierwszej części kursu instalowaliśmy na komputerze pakiet programów WinAVR, uczyliśmy się kompilować kody źródłowe programów oraz zapisywać programy do pamięci flash mikrokontrolera AVR. Teraz zaczniemy pisać proste programy w języku C - nauczymy się jak używać portów równoległych wejścia/wyjścia AVRa. Zaczynamy od naprawdę prostych przykładów :), zupełnie od zera. Jeśli i tak coś w tekście będzie niezrozumiałe, to nie należy szybko się zniechęcać, w trakcie dalszej lektury kursu powinno się wyjaśnić.

Zakładam, że czytelnik zrobił zadanie domowe, które zadałem na zakończenie pierwszej części kursu:) Należało poczytać w internecie na temat zapisu liczb w systemach dwójkowym i szesnastkowym oraz o funkcjach logicznych AND, OR, NOT i XOR.

Równoległe porty wejścia/wyjścia

Układ atmega8 w obudowie DIP28, na którym będziemy uruchamiać przykładowe programy, posiada 28 wyprowadzeń, z których 23 mogą służyć jako uniwersalne binarne wejścia/wyjścia. Linie we/wy atmega8 podzielone są na trzy grupy, nazwane: PORTB, PORTC i PORTD. Mikrokontrolery AVR w obudowach DIP40(atmega16, atmega32) posiadają cztery porty: A,B,C,D; natomiast attiny2313 w obudowie DIP20, posiada: PORTA (tylko PA0..PA2), PORTB i PORTD(PD0..PD6).

PORTB układu atemga8 posiada osiem linii we/wy (PB0..PB7), ale jeśli zamierzamy podłączyć do mikrokontrolera rezonator, to linie PB6 i PB7 odpadają. Z kolei wyprowadzenia: 17(PB3), 18(PB4) i 19(PB5) wykorzystywanie są przy programowaniu szeregowym ISP pamięci flash mikrokontrolera. PORTC uC atmaga8 posiada 7 linii we/wy (PC0..PC6), ale wyprowadzenie 1(PC6) normalnie pełni rolę wejścia sygnału reset mikroprocesora. Aby wykorzystywać wyprowadzenie 1(PC6) atmeg8 jako kolejną linię portu we/wy, potrzeba zaprogramować fuse-bit RSTDISBL (na temat fuse-bitów będę pisał), lecz w ten sposób pozbawimy się możliwości programowania szeregowego ISP pamięci FLASH mikrokontrolera. PORTD atmega8 posiada 8 linii we/wy (PD0..PD7).

obrazek
Rozkład wyprowadzeń mikrokontrolera ATmega8

Każda z wymienionych linii we/wy układu atmega8 może zostać indywidualnie skonfigurowana jako binarne wejście lub wyjście. Domyślnie wszystkie ustawione są wejściami z wyjątkiem wyprowadzenia 1 (RESET|PC6), które jest normalnie w atmega8 wejściem sygnału RESET mikroprocesora.

Program kontroluje układy peryferyjne mikrokontrolera AVR poprzez "rejestry I/O", 64 8-bitowe rejestry I/O znajdują się w przestrzeni adresowej pamięci danych - program może zapisywać do "rejestrów I/O" lub odczytywać z nich jakby korzystał z pamięci RAM. W zbiorze instrukcji języka maszynowego uC AVR istnieją też specjalne rozkazy służące do odczytu(zapisu) zawartości rejestrów I/O, także rozkazy do manipulowani poszczególnymi bitami rejestrów. W jaki sposób można w AVR-GCC odczytywać i  zapisywać rejestry I/O pokażę za chwilę, przy objaśnianiu przykładowych programów.

Z każdym z równoległych portów we/wy: A,B,C,D powiązane są po trzy rejestry I/O, o nazwach: DDRx, PORTx, PINx, gdzie x to oczywiście litery A,B,C,D. Stan poszczególnych bitów rejestrów DDRx (Port Data Direction Register) decyduje czy odpowiadające im linie są wejściami, czy wyjściami (0-wejście, 1-wyjście).

Jeśli dana linia we/wy pracuje jako wyjście, wtedy ustawiając na wartość 1 odpowiadający tej linii bit w rejestrze PORTx (Port Data Register), wymuszamy na wyprowadzeniu stan wysoki napięcia, a ustawiając wartość bitu na 0, oczywiście stan niski.

Jeśli linię we/wy skonfigurowano jako wejście, poziom napięcia na wyprowadzeniu, niski czy wysoki, sprawdza się odczytując wartość odpowiadającego tej linii bitu w rejestrze PINx (Port Input Pins Address), oczywiście wartość 0 oznacza stan niski, 1 stan wysoki. Dodatkowo, gdy linia jest wejściem i odpowiadający tej linii bit w rejestrze PORTx ma wartość 1, wtedy wyprowadzenie jest wewnętrznie podciągnięta do napięcia zasilania.

DDRx.nPORTx.nPx.n
00wejście
01wejście z podciągnięciem do VCC
1Xwyjście
Konfiguracja równoległych portów we/wy mikrokontrolerów AVR

A teraz przykład konfiguracji portu B, patrzymy na ilustrację poniżej.

obrazek
Przykład konfiguracji portu B

Cztery pierwsze bity rejestru DDRB mają wartość "0", zaś pozostałe cztery bity wartość "1", więc linie PB3..PB0 są skonfigurowane jako wejścia, a linie PB7..PB4 jako wyjścia. Dodatkowo bity numer 1 i 0 w rejestrze PORTB ustawione zostały na wartość 1, zatem linie PB1 i PB0 będą pracować jako wejścia z wewnętrznym podciągnięciem do napięcia zasilania. Zmieniając wartości bitów 7..4 rejestru PORTB można wymusić oczekiwane stany napięcia(wysoki lub niski) na wyprowadzeniach PB7..PB4. Natomiast stan wejść (PB3..PB0) sprawdzamy odczytując bity 3..0 rejestru PINB. W przykładzie do wyprowadzeń PB3..PB0 podano poziomy napięć L H L H, więc w rejestrze PINB bity 3..0 mają wartości 0101. Bity 7..4 rejestru PORTB ustawiono na wartości 1001, zatem na wyprowadzeniach PB7..PB4 pojawiły się stany napięć H L L H.

Schematy połączeń

Oprócz mikro_kontrolera AVR, dla uruchomienia przykładowych programików, potrzebne będą: osiem diod LED, cztery miniaturowe przyciski monostabilne oraz buzzer z generatorem. Diody LED przyłączone będą do portu D, przyciski do linii PC0..PC3, a buzzer do PB1. Każda z ośmiu diod LED, wraz z rezystorem ograniczającym prąd, przyłączona jest między wyprowadzenie portu a masę, więc będzie się świecić, kiedy do odpowiedniego bitu rejestru wpiszemy wartość "1".

Przyciski przyłączone są do linii we/wy portu C w taki sposób, że przy wciśnięciu zwierają dane wyprowadzenie układu z masą, więc przy wciśniętym przycisku z rejestru PINC odczytamy wartość odpowiedniego bitu "0", a przy zwolnionym przycisku, odczytamy "1". Linie we/wy z przyłączonymi w ten sposób przyciskami należy skonfigurować jako wejścia z podciągnięciem do VCC.

obrazek
Sposób przyłączenia przycisku do portu we/wy uC AVR

Dla przejrzystości schemat połączeń rozdzieliłem na dwa. Pierwszy schemat przedstawia sposób przyłączenia do atmega8 zasilania, resetu oraz programatora ISP, na drugim schemacie widać sposób podłączenie do portów we/wy mikro_kontrolera diod LED, przycisków i buzzera.

obrazek
Schemat przedstawia sposób przyłączenia do atmega8 zasilania, resetu oraz programatora ISP. Kliknij w obrazek, żeby powiększyć.
obrazek
Schemat przedstawia sposób przyłączenia diod LED, przycisków i buzzera do portów we/wy uC Kliknij w obrazek, żeby powiększyć.

Ja zestawiłem wszystkie części na małej płytce stykowej.

obrazek
Gotowy układ zestawiony na płytce stykowej.Kliknij w obrazek, żeby powiększyć.

Szkielet prostego programu dla avr-gcc

Wszystkie przykładowe programy z tej części kursy będą wyglądać podobnie, poniżej znajduje się szkielet prostego programu dla AVR-GCC.

/* Szkielet prostego programu dla avr-gcc */

#define F_CPU 1000000L
#include <avr/io.h>
#include <util/delay.h>               

int main(void)
{
  /* Tutaj wpisujemy instrukcje naszego  programu */
  for(;;)
  {   
  /* Instrukcje można umieścić w nieskończonej pętli */
  }
}
Szkielet prostego programu dla avr-gcc

Pierwsza linia to komentarz.

/* Szkielet prostego programu dla avr-gcc */

Komentarze są pomijanie przez kompilator, zwykle objaśniają mniej oczywiste fragmenty kodu. GCC pozwala wstawiać komentarze na dwa sposoby. Pierwszy sposób to objęcie treści komentarza parą ograniczników: '/*' , '*/'; w ten sposób utworzony komentarz może zawierać wiele linii tekstu.

/* Komentarz blokowy, może zawierać wiele linii tekstu */

Drugi sposób to umieszczenie przed treścią komentarza dwóch znaków slash '//' , tak utworzony komentarz rozciąga tylko do końca linii.

// Komentarz liniowy

A czy GCC pozwala zakomentowywać inne komentarze ? Proszę to sprawdzić samemu :)

Kolejne trzy linijki to polecenia preprocesora.

#define F_CPU 1000000L #include <avr/io.h> #include <util/delay.h>

Polecenia preprocesora zaczynają się znakiem hash "#". Preprocesor języka C przeprowadza rozmaite operacje na tekście programu jeszcze przed rozpoczęciem "właściwej" kompilacji programu. Na przykład pierwsze z tych trzech poleceń zmienia w tekście programu wszystkie wystąpienia ciągu znaków "F_CPU" na "1000000L", jak opcja "replace" w edytorze teksu. Liczba ta jest częstotliwością taktowania mikrokontrolera podaną w Hz. Nowe układy atmega skonfigurowane są do pracy z wewnętrznym oscylatorem RC 1Mz, dla przykładowych programików z tej części kursu nie ma potrzeby tego zmieniać. Inne częstotliwości taktowania mikrokontrolera atmaga można wybrać programując odpowiednie fuse-bity, napiszę o tym w dalszej części kursu. Drugie polecenie dołącza (wkleja) do tekstu programu, w miejscu jego wystąpienia, zawartość pliku "include/avr/io.h"; podobnie trzecie polecenie dołącza zawartość pliku "include/util/delay.h" A co takiego zawierają te pliki? Są to pliki tekstowe, więc ich zawartość można przejrzeć w dowolnym edytorze tekstu. Plik "include/avr/io.h" zawiera definicje rejestrów, bitów i przerwań; zaś plik "include/util/delay.h" zawiera funkcje wstrzymujących działanie programu na zadany okres czasu. Temat preprocesora zostanie dalej w kursie szczegółowo omówiony.

Następny fragment listingu to początek "głównej" funkcji programu.

int main(void) { /* Tutaj wpisujemy instrukcje naszego programu */ }

Funkcja w języku C to najprościej mówiąc wydzielony z programu fragment kodu, wykonujący jakieś konkretne zadanie. Odpowiednikiem funkcji z C w innych językach programowania są procedura i podprogram. Każda funkcja posada własną nazwę, nadaną jej przy tworzeniu, posługując się nazwą funkcji można wielokrotnie, dowolnym miejscu programu, uruchamiać blok instrukcji zawarty w funkcji, tak jak by to była pojedyncza instrukcja. Programy podzielone są zwykle na wiele mniejszych funkcji, dzięki temu są bardziej czytelne i oszczędza się pamięć. Funkcje można tworzyć (definiować) samemu, a także korzysta się z gotowych funkcji z bibliotek dostarczonych wraz z kompilatorem. Każdy program w C musi zawierać funkcję o nazwie "main" (funkcja główna), ponieważ pierwsza instrukcja funkcji "main" jest jednocześnie pierwszą instrukcją całego programu. Przykładowe programy w tej części kursu będą zawierać jedynie funkcję "main", cały nasz kod będzie umieszczany w głównej funkcji, między nawiasami klamrowymi "{","}".

W naszych prostych, przykładowych programach będzie można wyróżnić dwie sekcje, pierwsza to instrukcje wykonywane raz jeden, natychmiast po starcie programu, a druga sekcja to blok instrukcji wykonywany wielokrotnie w nieskończonej pętli. Nieskończoną pętle w programie można zbudować używając instrukcji "for" lub "while", w taki sposób, jak w przykładzie poniżej. W obu przypadkach instrukcje we wnętrzu pętli objęte są parą nawiasów klamrowych "{","}", podobnie jak zawartość całej funkcji głównej "main". Instrukcje tworzące pętle: "for" i "while" omówię szczegółowo w dalszej części kursu, ale już teraz będziemy je wykorzystywać w naszych przykładowych programach.

int main(void) { /* Instrukcje wykonywane raz jeden po starcie programu */ /* Pętla nieskończona utworzona instrukcją "for" */ for(;;) { /* Instrukcje w nieskończonej pętli */ } }
/* Pętla nieskończona utworzona instrukcją "while" */ while(1) { /* Instrukcje w nieskończonej pętli */ }

Programujemy porty we/wy

Jak pisałem, zaczniemy od naprawdę prostych przykładów. Pierwszy program będzie powodował miganie ośmiu diod LED przyłączonych do wyprowadzeń skojarzonych z portem D. Diody mają świecić się na przemian, raz parzyste, raz nieparzyste. Tak, jak pokazuje to animacja poniżej.

/* przykład 2.1 "leds.c" */
/* 8 diod LED przłączonych do portu D */
/* ATmega 1MHz */

#define F_CPU 1000000L
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{   
   /* Wszystkie linie portu D będą wyjściami */
   DDRD = 0xFF;  /* 0xFF binarnie 1111 1111 */

   /* Początek nieskończonej pętli */
   while(1)
   {
      PORTD = 0xaa;    /* 0xaa binarnie 1010 1010 */
      /* opóźnienie 0.33 sek. */
      _delay_ms(330); 
       PORTD = 0x55;    /* 0x55 binarnie 0101 0101 */
      /* opóźnienie 0.33 sek. */
      _delay_ms(330);
   }
}
Listing 2.1
obrazek
Efekt działania programu z listingu 2.1

Pierwszą instrukcją (będę tłumaczył zaczynając od wnętrza funkcji głównej "main") ładujemy do rejestru DDRD wartość 0xff (postać szesnastkowa liczby), w ten sposób konfigurujemy wszystkie linie portu D jako wyjścia.

/* Wszystkie linie portu D będą wyjściami */ DDRD = 0xFF; /* 0xFF binarnie 1111 1111 */

Używając nazwy rejestru i operatora przypisania - znaku "=", można zapisać(odczytać) całą 8-bitową zawartość rejestru I/O, instrukcję przypisania należy zakończyć znakiem średnika, inaczej kompilacja zakończy się z błędem. Należy też pamiętać o dołączeniu do kodu plików z definicjami rejestrów I/O, wstawiając gdzieś na początku programu linię:

#include <avr/io.h>

Inaczej kompilator nie rozpozna nazw rejestrów I/0 i przerwie kompilację wysyłając komunikat o wielu błędach.

W tekście programu można umieszczać stałe liczby (tzw. literały) w postaci dziesiętnej, szesnastkowej oraz ósemkowej, natomiast standard języka C nie przewiduje możliwości zapisywania stałych w postaci dwójkowej. Postać szesnastkową liczby stałej tworzymy wstawiając przed liczbą parę znaków '0x' lub '0X' (np. 0xFF), stałe ósemkowe rozpoczynają się od cyfry "0" (np. 077), liczby w systemie dziesiątkowym wpisujemy zwyczajnie (np. 123).

Kolejne dwie linie to początek nieskończonej pętli utowrzonej instrukcją "while". Wykonanie bloku instrukcji po "while(1)", objętych parą nawiasów klamrowych "{","}", będzie powtarzane, aż do momentu odłączenia zasilania lub resetu mikroprocesora

/* Początek nieskończonej pętli */ while(1) {

Pierwsza instrukcja w pętli zapisuje do rejestru PORTD wartość 0xAA ( binarnie 1010 1010), zaświecą się diody LED przyłączone do wyprowadzeń: PD1,PD3,PD5 i PD7; pozostałe diody będą wygaszone.

PORTD = 0xaa; /* 0xaa binarnie 1010 1010 */

Kolejna linijka wprowadza w tym miejscu programu opóźnienie ok 0.33 sek. Na razie nie będę szczegółowo objaśniał tej instrukcji, bo nie jest dobrze tłumaczyć zbyt wielu rzeczach na raz. Będziemy wstawiać tę linię do naszych przykładów tam, gdzie potrzebne będzie opóźnienie, w kolejnej części kursu dokładnie wyjaśnię działanie tej instrukcji. Długość opóźnienia wpisujemy tam gdzie jest liczba 330, w tysięcznych częściach sekundy.

/* opóźnienie 0.33 sek. */ _delay_ms(330);

W następnej linii do rejestru PORTD ładowana jest wartość 0x55( dwójkowo 0101 0101), tym razem zaświecą się diody LED przyłączone do wyprowadzeń PD0,PD2,PD4 i PD6. I ponownie działanie programu zostanie wstrzymane na okres ok 0.33 sek.

PORTD = 0x55; /* 0x55 binarnie 0101 0101 */ /* opóźnienie 0.33 sek. */ _delay_ms(330);

Dalej, pierwszy nawias klamrowy kończy blok instrukcji wykonywanych w pętli, kolejny nawias oznacza koniec funkcji głównej "main".

} }

W pierwszym przykładzie zapisywana była cała zawartość rejestru PORTD, w kolejnym programie pokażę jak ustawiać i kasować poszczególne bity rejestrów.

Zanim zacznę objaśniać program, to omówię operacje bitowe. Operacje bitowe działają na wartościach całkowitych i służą do manipulowania bitami. W języku C jest sześć operatorów bitowych:|,&,^,<<,>>,~. Operatory te są szczególnie użyteczne przy zabawie z bitami rejestrów, więc już teraz wyjaśnię ich działanie na przykładach. Oczywiście w przykładach liczby przedstawione są w postaci dwójkowej.

operator "|" - bitowa alternatywa (OR) 0 1 0 1 0 1 0 1 | 0 0 1 1 0 0 1 1 = 0 1 1 1 0 1 1 1
operator "&" - bitowa koniunkcja (AND) 0 1 0 1 0 1 0 1 & 0 0 1 1 0 0 1 1 = 0 0 0 1 0 0 0 1
operator "^" - bitowa alternatywa wykluczająca (XOR) 0 1 0 1 0 1 0 1 ^ 0 0 1 1 0 0 1 1 = 0 1 1 0 0 1 1 0
operator "<<" - przesunięcie w lewo 1 0 0 1 1 0 0 1 << 3 = 1 1 0 0 1 0 0 0
operator ">>" - przesunięcie w prawo 1 0 0 1 1 0 0 1 >> 5 = 0 0 0 0 0 1 0 0
operator "~" - dopełnienie jedynkowe ~1 0 0 1 1 0 0 1 = 0 1 1 0 0 1 1 0

Drugi programik różni się niewiele od pierwszego, więc omówię tylko te linie gdzie, gdzie można znaleźć coś nowego.

/* przykład 2.2 "leds2.c" */
/* 8 diod LED przłączonych do portu D */
/* ATmega 1MHz */

#define F_CPU 1000000L
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
    /* Wszystkie linie portu D będą wyjściami */
    DDRD  = 0xFF;

    /* Początek nieskończonej pętli */
    for(;;)
    {
        PORTD = 0x0f;  /* Ładuje do PORTD wartość 0x0f*/
        /* opóźnienie 1 sek. */
         _delay_ms(1000);
        PORTD |= 0xf0;  /* ustawia bity nr. 4..7 */
         _delay_ms(1000);
        PORTD &= 0xaa;  /* zeruje bity nr. 0,2,4,6 */
         _delay_ms(1000);
        PORTD ^= 0x0f;  /* "odwraca" bity nr. 0..3 */
         _delay_ms(1000);    
        PORTD = 0x00;
        /* opóźnienie 2 sek. */
         _delay_ms(2000); 
    }
}
Listing 2.2
obrazek
Efekt działania programu z listingu 2.2

Wybrane bity rejestru można ustawić na wartość "1", bez zmiany wartości pozostałych bitów rejestru, używając operatora przypisania "|=", instrukcja przypisania kończy się średnikem.

PORTD |= 0xf0; /* ustawia bity nr. 4..7 */

Na zawartości rejestru PORTD wykonywana jest operacja bitowa OR z wartością stałej znajdującej się po prawej stronie operatora "|=", a następnie wynik operacji zapisywany jest do rejestru PORTD.

PORTD 0 0 0 0 1 1 1 1 bitowe OR 0xF0 1 1 1 1 0 0 0 0 = 1 1 1 1 1 1 1 1 -> PORTD

W kodach źródłówych programów spotyka się następujący sposób ustawiania wybranych bitów rejestru.

PORTC |= (1<<3)|(1<<5)|(1<<7);

W tym przykładzie, zostaną ustawione bity numer: 3,5,7 rejestru PORTC (bity w rejestrze numerowane są zaczynając od zera), pozostałe bity pozostaną niezmienione. Użyto operatorów bitowych: "|"- bitowe OR, "<<" - przesunięcie w lewo.

(1<<3) = 0000 1000 bitowe OR (1<<5) = 0010 0000 bitowe OR (1<<7) = 1000 0000 ------------- 1010 1000

Wracamy do naszego programu. Wybrane bity rejestru można ustawiać na wartość "0", bez zmiany pozostałych bitów rejestru, używając instrukcji przypisania "&="

PORTD &= 0xaa; /* zeruje bity nr. 0,2,4,6 */

Na zawartości rejestru PORTD wykonywana jest operacja bitowa AND z wartością stałej znajdującej się po prawej stronie operatora "&=", a następnie wynik operacji zapisywany jest do rejestru PORTD.

PORTD 1 1 1 1 1 1 1 1 bitowe AND 0xAA 1 0 1 0 1 0 1 0 = 1 0 1 0 1 0 1 0 -> PORTD

Wybrane bity rejestru można "odwrócić", tzn. zmieniać wartość bitu "1" na "0", a "0" na "1", bez zmiany pozostałych bitów rejestru, używając instrukcji przypisania "^="

PORTD ^= 0x0f; /* "odwraca" bity nr. 0..3 */

Na zawartości rejestru PORTD wykonywana jest operacja bitowa XOR z wartością stałej znajdującej się po prawej stronie operatora "^=", a następnie wynik operacji zapisywany jest do rejestru PORTD.

PORTD 1 0 1 0 1 0 1 0 bitowe XOR 0x0f 0 0 0 0 1 1 1 1 = 1 0 1 0 0 1 0 1 -> PORTD

Trzeci przykładowy program pokazuje jak odczytać całą zawrtość rejestru

/* przykład 2.3 "leds3.c" */
/* 8 diod LED przłączonych do portu D */
/* 4 przyciski przyłączone do PC0..PC3 */
/* ATmega 1MHz */

#define F_CPU 1000000L
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
    /* Wszystkie linie portu D będą wyjściami */

    DDRD  = 0xff;
    
    /* Linie portu C będą wejściami z podciągnięciem do VCC */
    DDRC  = 0x00;

    PORTC = 0xff;    
    
    /* Początek nieskończonej pętli */
    for(;;)
    {
        /* Przepisanie zawartości PINC do PORTD */
        PORTD = PINC;
        //PORTD = ~PINC & 0x0f;
    }
}
Listing 2.3
obrazek
Efekt działania programu z listingu 2.3

Wpierw linie we/wy portu C zostają skonfigurowane jako wejścia podciągnięte do VCC, a linie portu D wyjścia. Dalej, w nieskończonej pętli, z użyciem operatora przypisania "=", zawartość rejestru PINC jest bezpośrednio przepisywana do rejestru PORTD.

/* Przepisanie zawartości PINC do PORTD */ PORTD = PINC;

Normalnie cztery pierwsze diody LED przyłączone do linii PD0..PD3 będą się świecić, wciśnięcie któregoś z przycisków powoduje wygaszenie odpowiedniej diody LED.

W kolejnych przykładach potrzebna będzie instrukcja "if-else" wykorzystywana do podejmowania decyzji.

if( wartość_logiczna PRAWDA/FAŁSZ ) /* Instrukcja wykonywana jeśli PRAWDA */ else /* Instrukcja wykonywana jeśli FAŁSZ */

Część "else" , czyli instrukcje wykonywaną gdy FAŁSZ można pominąć.

if( wartość_logiczna PRAWDA/FAŁSZ ) /* Instrukcja wykonywana jeśli PRAWDA */

Obejmując fragment kodu parą klamrowych nawiasów "{","}" tworzymy tzw. blok instrukcji, blok w "if-else" jest traktowany jako pojedyncza instrukcja.

if( wartość_logiczna PRAWDA/FAŁSZ ) { /* Blok instrukcji wykonywany jeśli PRAWDA */ } else { /* Blok instrukcji wykonywany jeśli FAŁSZ */ }

Chcąc sprawdzić czy jeden lub grupa bitów jednocześnie w rejestrze I/0 ma wartość "1" można to zrobić z użyciem instrukcji "if" w następujący sposób:

if(REJESTR_I0 & MASKA) { /* Blok instrukcji wykonywany jeśli warunek spełniony */ }

Gdzie "REJESTR_IO" to nazwa rejestru, a "MASKA" to stała wartość z ustawionymi tymi bitami, które potrzeba testować
Przykłady:

/* Jeśli bit nr. 3 rejestru PINC ma wartość "1" */ if(PINC & 0x08){} /* Jeśli bity 0 lub 1 w PIND mają wartość "1" */ if(PIND & 0x03){}

Na zawartości rejestru wykonywana jest operacja bitowa AND z wartością stałej stojącej po prawej stronie operatora "&". I jeśli wynik tej operacji będzie różnił się od zera, to całe wyrażenie w nawiasach okrągłych będzie uznane jako wartość logiczną "PRAWDA" i wykonane zostaną instrukcje objęte nawiasami klamrowymi po "if"; w przeciwnym przypadku instrukcje te zostaną pominięte. W języku C, jeżeli jakieś wyrażenie po obliczeniu jest różne od zera, to ma wartość logiczną "PRAWDA", a jeżeli wyrażenie jest równe zero, to ma wartość logiczną "FAŁSZ".

A po co na wartości odczytanej z rejestru wykonywana jest bitową operację AND? Żeby przysłonić te bity rejestru, których wartości nas nie interesują. Przykład:

Interesuje na stan bitu nr 3 rejestru REJESTR_I0 0 1 0 1 1 1 1 1 (0x5f) bitowe AND 0 0 0 0 1 0 0 0 (0x08) ----------------------------- = 0 0 0 0 1 0 0 0 (0x08) REJESTR_I0 0 1 0 0 0 1 0 1 (0x45) bitowe AND 0 0 0 0 1 0 0 0 (0x08) ----------------------------- = 0 0 0 0 0 0 0 0 (0x00)

Jednak na schemacie przyciski przyłączono do portów we/wy uC w taki sposób, że przy wciśniętym przycisku odczytujemy z rejestru wartość bitu "0", a nie "1".Tak można sprawdzić czy jeden lub grupa bitów w rejestrze I/0 ma wartość "0":

if(!(REJESTR_IO & MASKA)) { /* Blok instrukcji wykonywany jeśli warunek spełniony */ }

Przykłady:

/* Jeśli bit nr. 0 rejestru PINC ma wartość "0" */ if(!(PINC &0x01)){} /* Jeśli bit nr. 1 rejestru PINC ma wartość "0" */ if(!(PINC & 0x02)){} /* Jeśli bit nr. 2 rejestru PINC ma wartość "0" */ if(!(PINC & 0x04)){} /* Jeśli bit nr. 3 rejestru PINC ma wartość "0" */ if(!(PINC & 0x08)){}

Tutaj bitowy iloczyn zawartości rejestru i stałej został dodatkowo wzięty w okrągłe nawiasy i wartość logiczna całości została zanegowana z użyciem operatora wykrzyknik "!". Znak wykrzyknik "!" jest w języku C logicznym operatorem negacji, zmienia wartość logiczną PRAWDA na FAŁSZ, A wartość FAŁSZ na PRAWDA. A jak pisałem przed chwilą, jeżeli jakieś wyrażenie po obliczeniu jest większe od zera to ma wartość logiczną "PRAWDA", a jeżeli równe zero to ma wartość logiczną "FAŁSZ".

A jeśli potrzeba, aby blok instrukcji wykonywał się wielokrotnie w pętli, dopóki jeden lub grupa bitów jednocześnie w rejestrze I/0 ma wartość "1", to można to zrobić z użyciem instrukcji "while":

while(REJESTR_I0 & MASKA) { /* Blok instrukcji wykonywany jeśli warunek spełniony */ }

A jeśli potrzeba, aby blok instrukcji wykonywał się wielokrotnie w pętli, dopóki jeden lub grupa bitów jednocześnie w rejestrze ma wartość "0", na przykład gdy wciśnięty jest przycisk:

while(!(REJESTR_IO & MASKA)) { /* Blok instrukcji wykonywany jeśli warunek spełniony */ }

Gdzie, jak poprzednio, "REJESTR_IO" to nazwa rejestru, a "MASKA" to stała wartość z ustawionymi tymi bitami, które potrzeba testować

Instrukcje sterujące programem w języku C będą głównym tematem następnej, trzeciej części kursu.

A to kolejny przykładowy program, działa w następujący sposób: Jeśli jest wciśnięty pierwszy przycisk (przyłączony do PC0), to święcą się diody LED przyłączone do PD4..PD7, pozostałe LED są zgaszone. Jeśli wciśnięty jest drugi przycisk ( przyłączony PC1), to świecą się cztery diody podłączone do PD0..PD3, pozostałe LED gasną.

/* przykład 2.4 "leds4.c" */
/* 8 diod LED przłączonych do portu D */
/* 2 przyciski przyłączone do PC0,PC1 */
/* ATmega 1MHz */


#include <avr/io.h>

int main(void)
{
  /* Wszystkie linie portu D będą wyjściami */
  DDRD  = 0xff;

  /* linie PC0,PC1 będą wejściami z podciągnięciem do VCC */
  DDRC  = 0x00;
  PORTC = 0x03;

  /* Początek nieskończonej pętli */
  while(1)
  {
    /* Jeśli pierwszy przycisk wciśnięty */
    if(!(PINC & 0x01)) PORTD = 0xf0;
  
    /* Jeśli drugi przycisk wciśnięty */
    if(!(PINC & 0x02)) PORTD = 0x0f;
  }
}
Listing 2.4
obrazek
Efekt działania programu z listingu 2.4

Omówię tylko te fragmenty listingu, w których jest coś nowego.

Linia programu poniżej testuje czy został wciśnięty przycisk przyłączony do PC0. Sprawdzane jest czy odpowiadający przyciskowi bit w rejestrze PINC ma wartość "0", jeśli tak to wykonuje się instrukcję wpisującą do rejestru PORTD wartość 0xf0.

/* Jeśli pierwszy przycisk wciśnięty */ if(!(PINC & 0x01)) PORTD = 0xf0;

Podobnie w kolejnej linii programu sprawdzany jest stan drugiego przycisku, podpietego do PC1; jeżeli jest wciśnięty, to do rejestru PORTD ładowana jest wartość 0x0f;

/* Jeśli drugi przycisk wciśnięty */ if(!(PINC & 0x02)) PORTD = 0x0f;

Odczytując stan przycisków podłączonych do portów uC napotyka się kłopotliwy efekt drgających styków przycisku. W momentach wciśnięcia i zwolnienia przycisku dostajemy na wejściu uC serie impulsów, co "źle" napisany program może błędnie zinterpretować jako wielokrotne wciśnięcie i zwolnienie przycisku.

obrazek
Drgania na stykach przycisku

Prostym i skutecznym sposobem ominięcia problemu drgających styków przycisku jest przeczekanie drgań. Po wykryciu wciśnięcia lub zwolnienia przycisku program może wstrzymać dalsze działanie na okres nieco dłuższy, niż spodziewany czas zaniku drgań styków. Pokaże to na kolejnym przykładzie, listing poniżej.

Kolejny program będzie zliczał każde wciśnięcie przycisku przyłączonego do PC0, a aktualny stan tego licznika będzie wyświetlany na ośmiu diodach LEd przyłączonych do portu D.

/* przykład 2.5 "leds5.c" */
/* 8 diod LED przłączonych do portu D */
/* przycisk przyłączony do PC0 */





/* ATmega 1MHz */

#define F_CPU 1000000L
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
  /* Wszystkie linie portu D będą wyjściami */
  DDRD  = 0xff;
  /* Linia PC0 będzie wejściem z podciągnięciem do VCC */
  DDRC  = 0x00;
  PORTC = 0x01;
  /* Początek nieskończonej pętli */
  while(1)
  {
    /* Jeśli pierwszy przycisk wciśnięty */
    if(!(PINC & 0x01))
    {
     /* Zwiększenie stanu licznika o 1 */
      PORTD +=1;
      /* opóżnienie aż drgania na stykach ustaną */
       _delay_ms(80);
      /* oczekiwanie na zwolnienie przycisku */
      while(!(PINC & 0x01)) {}
      /* opóżnienie aż drgania na stykach ustaną */
       _delay_ms(80);
    }
  }
}
Listing 2.5
obrazek
Efekt działania programu z listingu 2.5

Tutaj, w pętli sprawdzany jest stan przycisku, jeśli jest wciśnięty, to wykonywany jest blok instrukcji po "if" objęty parą nawiasów klamrowych, w przeciwnym przypadku stan przycisku testowany jest ponownie.

/* Jeśli pierwszy przycisk wciśnięty */ if(!(PINC & 0x01)) {

To kolejna postać operatora przypisania "+=", jak można się domyśleć, do rejestru PORTD zapisywana jest aktualna jego zawartość powiększona o wartość stałej stojącej po prawej stronie operatora "+=", w tym przypadku o 1.

/* Zwiększenie stanu licznika o 1 */ PORTD +=1;

Wstrzymanie działania programu na spodziewany czas wygaśnięcia drgań styków przycisku, czas wstrzymania programu dobrałem doświadczalnie.

/* Opóżnienie aż drgania na stykach ustaną */ _delay_ms(80);

Po ustaniu drgań styków, w następnej instrukcji, program testuje czy przycisk został zwolniony. W tym miejscu program zostanie uwięziony w wewnętrznej (zagnieżdżonej) pętli, wykonanej też z pomocą "while", do momentu zwolnienia przycisku. Po "while()", między nawiasami klamrowymi, jest pusto, program w pętli będzi "robił nic", zatrzma się w tym miejscu do chwili zwolnienia przycisku.

/* oczekiwanie na zwolnienie przycisku */ while(!(PINC & 0x01)) {}

Ponowne wstrzymanie działania programu, aby wygasły drgania styków przycisku.

/* Opóżnienie aż drgania na stykach ustaną */ _delay_ms(80);

Nawias klamrowy zamyka nieskończoną pętlę

}

I to już wszystko w tej części kursu. Na zadanie domowe proponuje uruchomić program z listingu poniżej i samodzielnie przanalizować jego działanie. Jeśli znajdzie się coś w tym kodzie, o czym nie było jeszcze mowy, to porszę poszukać odpowiedzi swojej książce do języka C bądź w Internecie.

/* przykład 2.6 "leds6.c */
/* 8 diod LED przłączonych do portu D */
/* 2 przycisk przyłączone do PC0,PC1 */
/* Buzzer z generatorem przyłączony do PB1*/
/* ATmega 1MHz */

#define F_CPU 1000000L
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
  /* Wszystkie linie portu D będą wyjściami */
  DDRD = 0xff;
  /* PB1 wyjście - buzzer z generatorem */
  DDRB = 0x02;
  /* PC0,PC1 będą wejściami z podciągnięciem do VCC */
  DDRC  = 0x00;
  PORTC = 0x03;
  
  /* Początek nieskończonej pętli */
  while(1)
  {
    /* Jeśli pierwszy przycisk wciśnięty */
    if(!(PINC & 0x01))
    {
      if(!PORTD)
      {
      /* Krótki sygnał dźwiękowy */
        PORTB |= 0x02;
        _delay_ms(100);
        PORTB &= ~0x02;
      }
      else
       /* Wygasza jedną diodę LED */
        PORTD >>= 1;

      /* Opóżnienie, aż drgania na stykach przycisku ustaną */
       _delay_ms(80);
      /* Oczekiwanie na zwolnienie przycisku */
      while(!(PINC & 0x01)) {}
      /* Opóżnienie, aż drgania na stykach przycisku ustaną */
       _delay_ms(80);
    }
    /* Jeśli drugi przycisk wciśnięty */
    if(!(PINC & 0x02))
    {
      if(PORTD & 0X80)
      {
      /* Krótki sygnał dźwiękowy */
        PORTB |= 0x02;
        _delay_ms(100);
        PORTB &= ~0x02;
      }
      else
      {
       /* Zapala jedną diodę LED */
        PORTD <<= 1;
        PORTD |= 1;
      }
      /* Opóźnienie, aż drgania na stykach przycisku ustaną */
      _delay_ms(80);
      /* Oczekiwanie na zwolnienie przycisku */
      while(!(PINC & 0x02)) {}
      /* Opóżnienie, aż drgania na stykach przycisku ustaną */
      _delay_ms(80);
    }
  }
}
obrazek
Efekt działania programu z listingu 2.6

W następnej części kursu...

Tematem kolejnej części kursu będą: zmienne i stałe liczbowe, operatory oraz instrukcje sterujące programem. Dalej będziemy się bawić diodami LED, brzęczykiem i przyciskami.



Kurs AVR-GCC cz.1 | Kurs AVR-GCC cz.3

Inne artykuły na podobny temat:

  1. Gamepad od Sony PlayStation
legenda

Komentarze (126)

kalaksaw
17.11.2023 (11:48)
gość
elo co tam
Maniek
07.02.2019 (09:16)
gość
"O co chodzi z tą linijką zadania domowego PORTD |= 1; ???"
Też nad tym rozmyślałem i już wiem: podczas gdy masz wszystkie diody wygaszone to port D wygląda tak 0000 0000, gdy przesuniesz o jeden bit w lewo to nic Ci nie da bo dalej masz same zera. Dlatego PORTD |= 1 ustawia na końcu zawsze jedynkę do przesunięcia w lewo.
mark
06.02.2016 (21:25)
gość
O co chodzi z tą linijką zadania domowego PORTD |= 1; ???
Marcin
17.01.2016 (20:17)
gość
Dlaczego ? Działanie sygnału dzwiekowego jest zapisane
/* Krótki sygnał dźwiękowy */
PORTB |= 0x02;
_delay_ms(100);
PORTB &= ~0x02;

skoro zapis

/* Krótki sygnał dźwiękowy */
PORTB = 0x02;
_delay_ms(100);
PORTB = 0x00;

działa dokładnie tak samo/ nie rozumiem co zmienia uzywanie operatorów bitowych a ustawianie bitów na sztywno
dart_001
21.10.2015 (21:36)
użytkownik
Witam. To moje 1_sze starcie z językiem C. Niestety nie rozumie ostatniego przykładu 2.6 z 2_giej części kursu...
Procesor po załadowaniu programu na Porcie D ma stan niski (świecą diody LED/ zestaw ZL...), oraz brak reakcji na zwarcie do masy pinów z Portu C. Wyciąłem połowę programu/ ta postać ułatwia "analizę"... i dalej mam to samo,
Ponadto mam jeszcze pytania:
* co oznacza i jak działa wyrażenie if(!PORTD) ?
* co oznacza i jak działa wyrażenie PORTD >>= 1; ?

Pozdrawiam i Dzięki za Kurs!!!
abxyz
07.07.2015 (22:05)
autor strony
Mikroprocesor używa systemu dwójkowego, tak można obrazowo powiedzieć.
Dla programisty system dwójkowy jest nieporęczny: liczny ciąg zer i jedynek - łatwo o pomyłkę. Wygodniej byłoby korzystać z systemu dziesiętnego, ale zamiana liczb w zapisie dziesiętnym na dwójkowy(i na odwrót) jest uciążliwa, zwłaszcza dla większych liczb. Natomiast zamiana liczby w zapisie szesnastkowym na dwójkowy (i odwrotnie) jest zwyczajnie łatwa, niezależnie od wielkości liczby. Nawet początkujący programista, po krótkim treningu, może nauczyć się zamieniać liczby w zapisie HEX na BIN (i BIN na HEX), błyskawicznie w pamięci, bez pomocy kartki i ołówka czy kalkulatora.
gość
05.07.2015 (17:13)
gość
wyjaśni mi ktoś,czemu zamiast systemu dziesiętnego stosuje sie szesnastkowy do programowania? wpisując na przykład 255 zamiast 0xff jest ten sam efekt,a liczy się dużo prościej z biarnego na dziesiętny.
abxyz
09.12.2014 (18:40)
autor strony
E.. tam, system szesnastkowy to podstawa. We wszystkich programach w rodzaju: debugger , monitor, edytor binarny itp. dane przedstawiane są w zapisie szesnastkowym.

Żaden programista, nawet zupełny amator, nie powinien mieć trudności ze zmianą BIN<->HEX, bez kalkulatora - wystarczy chwilę potrenować.

Właśnie dlatego, z premedytacją, wszędzie w kursie wstawiałem liczby w systemie HEX, by czytelnik miał okazję poćwiczyć.
Horhe
04.12.2014 (04:15)
gość
Zapis dwójkowy bezpośrednio i w prosty sposób prezentuje stan na wejściach/wyjściach, z kolei zapis szesnastkowy jest krótszy i to jest Twój argument za jego stosowaniem. Ok, nie zamierzam z tym polemizować, ale czy używasz kalkulatora programisty żeby przeliczać dwójkowy na szesnastkowy i odwrotnie czy robisz to w pamięci?
Pytam, bo przypomniał mi się Matrix i facet, który patrząc na ciąg zer i jedynek widział blondynki i brunetki :D.
abxyz
14.10.2014 (02:10)
autor strony
Programista powinien biegle posługiwać się systemem szesnastkowym, bo zapis dwójkowy liczb jest niepraktyczny. Wyobraź sobie, że masz mikrokontroler 32-bitowy, np ARM , wtedy co?

PORT = 0b101001100110011001100111 ;

MrQubo
13.10.2014 (23:06)
gość
Dlaczego przypisując wartości używasz hexa? O wiele łatwiej przypisuje się po prostu binarnie np. PORTD = 0b00110101
warsztat
04.05.2014 (12:10)
gość
do ostatniego wpisowicza: nic nie trzeba kasować. u mnie wgrywa się bardzo ładnie.
ciężko mi idzie to c ale ten kurs bardzo pomaga więc dzięki.
pozdrawiam.
Camo
31.01.2014 (17:54)
gość
Po zaprogramowaniu Atmegi8, trzeba program "led" usunąć jakoś z AVR-ka? Ponieważ próbuję wgrać nowy z listingu 2.1 i jest problem :/
congrim
03.01.2014 (21:19)
gość
Karolen dzięki wielkie! Też się męczyłem z tym ostatnio, a jeszcze nie doszedłem do części 3.
Rozwiązanie tymczasowe dla tych, którzy nie chcą się bawić z FuseBitem JTAGEN: zmieńcie po prostu port na A :) Czyli odpowiednio przepiąć przewody i drobne korekcje w programie.
karolen
29.12.2013 (16:21)
użytkownik
DO KAMILA odnośnie posta z 20.07
Kamil miałem dokładnie tak samo, rozwiązanie problemu jest nieco zawoalowany sposób pokazane w części numer 3.
A mianowicie chodzi o to że na porcie C w Atmedze 16 oraz 32 na pinach PC2 - PC5 fabrycznie jest załączony PORT JTAG.
Można go wyłączyć i wykorzystywać te piny jako zwykłe porty we/wy - służy do tego FuseBit JTAGEN.
WW
19.08.2013 (22:28)
gość
Czesc Lukasz,
Ja tez uzywam atmega8, przy programowaniu zasilanie biore z programatora (Usbasp) i programuje ok. natomiast przy wlaczaniu ukladu( podlaczajac diode led itp) korzystam juz z zewnetrznego zasilacza.
Pozdrawiam,
WW.
lukasz
09.08.2013 (12:39)
gość
witam
mam problem używam atmega 8 wpisuje kod jak na kursie a mimo to nie dziala mi zasilanie pobieram z programatora a nie zewnątrz czy może to być przyczyną ?
pozdrawiam
kamil
20.07.2013 (20:34)
gość
Listing 2.3 nie działa mi. Nie wiem czemu, ale świecą się tylko dwie pierwsze diody i dwie ostatnie (11000011), a po podaniu napięcia na pinyc nic się nie dzieje. Bawię się ATmega 16. Wcześniejszy program działał jak u ciebie.
Mareczek
15.03.2013 (20:52)
gość
Gratuluje kursu!
Po długich próbach przejścia "piekła początkujących" związanego z innym kursem i korzystaniem z Atmel studio 6 przez przypadek trafiłem tutaj i doznałem olśnienia.
Jesteś hojnym człowiekiem! Wiedza to skarb a ty obdarowujesz nim wszystkich spragnionych tego bogactwa.
Dziękuję serdecznie!
Spoko
10.01.2013 (08:41)
gość
Bardzo fajny kurs, tylko znalazłem błąd który może mylić bardzo początkujących na obrazku konfiguracji Portu B powinno być ustawienie PORTB 10010101 a jest 1001001, gdyż w PINB jest 10010101
xyz
20.09.2012 (22:26)
gość
Bardzo dobry kurs dla początkujących. Gratuluję. Znalazłem drobny błąd: PORTD |= 0xf0; /* ustawia bity nr. 0..3 */
Powinno być: 4..7
shofer
27.02.2012 (11:51)
gość
Witam
Kurs jest po prostu genialny, lepszy od książki na którą wydałem 80 zł
Znalazłem jednak mały błąd literowy "17(PB3), 18(PB4) i 19(PB4)"
a powinno być "17(PB3), 18(PB4) i 19(PB5)"
atek000
28.05.2011 (17:15)
gość
Faktycznie, mój błąd, gdyż ja użyłem zanegowanego porównania. wówczas przyciski podłączone do masy muszą być wciśnięte oby dwa.
while(1)
{
if (!(PINC & 0X01))
if (PINC & 0X02) PORTB = 0x01;
if (!(PINC & 0X02))
if (PINC & 0X01) PORTB = 0X02;
if (!(PINC & 0X03)) PORTB = 0X04;
if (PINC & 0XFF) PORTB =0X00;
}
Przy wciśniętym:
PC0 świeci się dioda dołączona do PB0,
PC1 - PB1
PC0 i PC1 - PB2
Zwolnione PC0 i PC1 - diody wyłączone.
abxyz
27.05.2011 (20:35)
autor strony
Nie masz racji. Wyrażenie (PIND & 0x03) ma wartość logiczną 1, gdy w PIND jest 0x01 lub 0x02 lub 0x03

atek000
27.05.2011 (15:43)
gość
Bardzo ciekawy kurs, szkoda, że nie będzie więcej. Po wielu latach z Bascom-em ten kurs otworzył mi oczy na normalny język. Szkoda tylko że na części 5-tej się kończy.
Ale do rzeczy. Kursant nov3l dnia 20.07.2009 zwrócił uwagę na "błąd" i został on poprawiony. Błąd w cudzysłowie, bo chyba go jednak nie było. Obecnie jest:
/* Jeśli bity 0 lub 1 w PIND mają wartość "1" */
if(PIND & 0x03){}
Moim zdaniem powinno być /* Jeśli bity 0 [b]i[/b] 1 w PIND mają wartość "1" */ , gdyż funkcja if sprawdza wartość na porcie czy jest 0x03 a nie czy jest 0x01 lub 0x02. Specjalnie zbudowałem na szybko układ i to sprawdziłem.
Gość
19.05.2011 (20:38)
gość
Świetny kurs, ale czy będzie coś o USB?
abxyz
21.03.2011 (11:36)
autor strony
Nie ma błędu. W tym przykładzie na wyprowadzenia PB3..PB0 podano napięcia L H L H ( zaznaczyłem to na rysunku strzałkami, pewnie powinienem był wspomnieć o tym w opisie), dlatego w rejestrze PINB bity 3..0 przyjmują wartość 0101.
Adam
21.03.2011 (08:58)
gość
Czy na drugim rysunku z przyprowadzkładem konfiguracji pinów nie błędu ???
Chodzi mi o oznaczenie PINB ???
Na DDRB wprowadzono 0b11110000=0xF0 natomiast na PORTB 0b10010011=0x95.
Zaś na PINB jest 0b10010101=0x95.
I czy nie ma błędu w ostatnich trzech bitach czyli: 101
Bo zgodnie z tabelką powyżej na PINx pojawi się 1 tylko tam gdzie na PORTx jest 1 (czyli podciągnięcie do Vcc)
A zatem czy nie powinno na PINB być 0b10010011=0x95 ????????


A tak po za tym artykuł jest świetny! i chwała Autorowi za kawał dobrej roboty !

pozdro
Adam
abxyz
28.02.2011 (09:08)
autor strony
Specjalnie w kursie nie używam zapisu dwójkowego. Biegłe posługiwanie się systemem szesnastkowym to przy programowaniu mikrokontrolerów podstawowa umiejętność. Dwójkowych zapis liczb jest niepraktyczny i właściwie zbędny, korzystają z tego rozszerzenia wyłącznie lamerzy :) No spójrz tylko na to:

0b10101010 == 0xAA
0b1010101010101010 == 0xAAAA
0b10101010101010101010101010101010 == 0xAAAAAAAA


dz_
28.02.2011 (01:25)
gość
Nie wiem czy dobrze myśle, ale czy czasem pisząc 0b10101010 nie osiągamy tego samego co 0xaa? Widzę, że artykuł z 2008 więc nie wiem jak było wtedy, ale napisałeś, że C nie przyjmuje wartości binarnych. Sprawdziłem 0b... i działa, więc chyba nie do końca jest to prawdą, a czasem wygodniej wpisać od razu wartości binarnie.

P.S. Ten kurs to kawał dobrej roboty.
Woj
20.01.2011 (16:32)
gość
Świetny kurs. Jestem programistą w C i nie mam pojęcia o elektronice. Zastanawia mnie jedna rzecz. Na schemacie art002_schemat2.png podłączonych jest 8 diód led. Czy można podłączyć w ten sam sposób zamiast jednej zestaw 4 diód led ? Daje to w sumie 8x4 - 32 diody led podłączone do układu. Zdaje sobię sprawę że będzie wiekszy pobór prądu, czy mikrokontroler to wytrzyma ? Jakie wtedy dobrać oporniki ?
abxyz
19.01.2011 (23:19)
autor strony
Patrz III część kursu :)
r2r
19.01.2011 (12:10)
gość
Bardzo dobry artykuł. Pytanie mam w sprawie zwiększenia PORTD w jednym z przykładów w którym jest zastosowane "+=" i wartość. Czy ta wartość podawana jest jako wartość dziesiętna czy może jako HEX'a?
Radosław Grymin
25.12.2010 (21:40)
gość
Popraw proszę "nr." na "nr";) Przy drganiach na stykach możesz napisać coś o dawaniu kondensatorów filtrujących piki napięcia. jakies 100n i wtedy drgania są mniejszym problemem(układ gasikowy)
abxyz
09.09.2010 (21:35)
autor strony
Niewykorzystane wejścia AVRa można pozostawić niepodłączone


X
08.09.2010 (22:20)
gość
Czy jeśli linie np. portu C konfiguruje jako wejścia z podciągnięciem do VCC, a wykorzystuje tylko linie PC0 i podłączam do niej przycisk to:

czy linie PC1...PC7 mogą wisieć w powietrzu? bo ATmega to przeciez technologia CMOS (nie wykorzystane piny do GND),

tym bardziej jeśli chce do portu A (wyjścia) podłączyć 8 ledów i dokonac przypisania PORTA=PORTC
????
losrabinos
23.07.2010 (17:29)
gość
Kawał naprawdę solidnej roboty!
abxyz
17.07.2010 (20:22)
autor strony
Mało prawdopodobne, że kupiłeś uszkodzonego AVRa. Jeśli AVR-ek się tak nagrzewa, trzeba natychmiast wyłączyć zasilanie.
Nie jestem pewien czy dobrze zrozumiałem, podłączyłeś, równolegle z programatorem, wiązkę przewodów z zasilacza komputera do płytki z AVRem? Zły pomysł. Wymień AVRa na drugi egzemplarz :) i użyj innego zasilacza.
nonew
17.07.2010 (17:14)
użytkownik
Witam.
Podłączyłem wszystko tak jak w instrukcji (atmega8 + stk200) z ta różnicą że wszystko zasilam bezpośrednio z zasilacza komputerowego.
Problem polega na tym że zawsze na porcie PD4 jest stan wysoki, nawet gdy jest wciśnięty reset. Gdy daje PORTD = 11111111 to jest na porcie PD3 i PD5 stan niski (~0V). Gdy chce załączać co drugi port na przemian (tak jak w przykładzie nr 1) wszystko jest ok. poza tym portem nr 4.
Sprawdzałem wiele razy czy się nigdzie nie pomyliłem i nie ma żadnego zwarcia. Napięcia sprawdzałem na wyjściach z uC. Układ bardzo się grzeje, można się oparzyć.
Czy to możliwe żeby nowo zakupiony uC miał jakaś wadę?
ABXYZ
27.05.2010 (21:36)
autor strony
Wydawałoby się, że jeśli do wejścia AVRa nic nie jest podłączone , to odczytamy z wejścia 0, jednak tak nie jest. Z luźnego wejścia odczyt może być przypadkowy (nie koniecznie 0), taka jest własność wejść układów CMOS.


grayfox
27.05.2010 (01:24)
gość
Ja mam z kolej następujące pytanie:
O co chodzi z tym podciąganiem do vcc ?
Moje rozumowanie jest takie:
Zakładając, że nie podciągnę do vcc, czyli PORTx=0x00 to na pinach Px0-Px7 będzie stan niski, a wysoki dopiero po przyłożeniu napięcia. Jeżeli podciągnę to ze względu na podciągnięcie do Vcc stan będzie wysoki, a po zwarciu z masą niski.
Jednak pierwszy przypadek nie do końca działa tak jak sobie wyobrażam.
Gdzie popełniam błąd ?
ABXYZ
07.05.2010 (23:18)
autor strony
Użyta w przykładach funkcja _delay_ms z biblioteki avrlibc, aby właściwie działała, potrzebuje znać częstotliwość pracy AVRa. Podajemy tę informację tworząc na początku programu makrodefinicję:
#define F_CPU 1000000UL
Nowe( ze sklepu) AVRy atmega8 skonfigurowane są do pracy z wewnętrznym oscylatorem RC 1MHz.

Można też częstotliwość zegara wpisać do zmiennej F_CPU w pliku Makefile, wtedy program zostanie skompilowany dodatkowo z parametrem
-DF_CPU=1000000UL
co też spowoduje zdefiniowane makra F_CPU

shade
07.05.2010 (12:35)
gość
qatric
Zmienna TARGET ktora sie znajduje w pliku Makefile musi byc zgodna z nazwa pliku twojego programu.

# Target file name (without extension).
TARGET = prog
dla pliku prog.c

shade
07.05.2010 (12:24)
gość
Witam, Mam pytanie odnosnie
#define F_CPU 1000000L
Jest to definiowe w kodzie programu, ale kompilator tego nie uzywa, wiec po co to jest? Ta zmienna jest zdefiniowana w makefile i tam nie jest domyslnie (wg kurusu) 1000 000, ale 8000 000. Potwierdzeniem tego ze przy kompilacji kompilator bierze 8M jest ten log.

avr-gcc -c -mmcu=atmega16 -I. -gdwarf-2 -DF_CPU=8000000UL -O2 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=./led.lst -std=gnu99 -MMD -MP -MF .dep/led.o.d led.c -o led.o

Poprosze o wyjasnienie tej sprawy. Pozdrawiam
qatrick
21.04.2010 (21:36)
gość
Witam, mam taki mały problemik mianowicie podczas kompilacji wywala błąd make.exe: *** No rule to make target `prog.elf, needed by `elf. Stop.
program testowy działa normalnie ale każdy inny już nie nie wiem czemu składnia na pewno jest dobrze bo już wcześniej trochę programowałem, ale nawet samą funkcję main nie chce skompilować. pomocy!!!
Gordon
15.04.2010 (21:31)
gość
Też się zastanawiałem nad tą linijką w ostatnim kodzie. Dobrze, że są komentarze to można doczytać:)

Super kurs! Teraz nawet taki &#039;lejek&#039; jak ja może się wziąć za uC.
ABXYZ
31.03.2010 (22:48)
autor strony
Brzęczyk powinien się odezwać, jeśli najstarszy bit w rejestrze PORTD jest jedynką

if(PORTD & 0X80)
{
/* Krótki sygnał dźwiękowy */

A taka sytuacja, w tym programiku, może wystąpić tylko, jeżeli w PORTD wszystkie bity są jedynkami. Mógłbym ten fragment napisać tak:

if(PORTD == 0xff)
{
/* Krótki sygnał dźwiękowy */

Ale w tej części kursu chciałem szczególną uwagę poświęcić operacjom na bitach.

gość
31.03.2010 (22:21)
gość
Lol - już wiem.
Wybaczcie - późno już :-P
Gdybym zastosował moją (niżej wymieniona) myś to tylko 1 dioda by się paliła :-/

Super kurs, a nie jak większość książek - gdzie pomijają wiele spraw i tylko tłumaczą manuala ze strony Atmel-a!
Może, ten kto pisze taką książę jest tylko tłumaczem i nie ma pojęcia o uC :-P
gość
31.03.2010 (21:57)
gość
Witam
Chodzi o ostatni kod:
if(PORTD & 0X80) równe 1111 0000; a wg mojego rozumowania napisał był tak if(PORTD & 0XFF) równe 1111 1111, bo przecież buzzer ma działać po zaświeceniu się wszystkich diod.
Wyjaśnijcie mi tą linijkę, będę wdzięczny.


ABXYZ
14.03.2010 (17:08)
autor strony
Ee.. tam! Zawracanie głowy. Nośnikiem informacji jest poziom napięcia na wyprowadzeniu portu we/wy, a nie prąd
Jeśli przycisk nie jest wciśnięty, to na wyprowadzeniu portu jest wysoki poziom napięcia, gdyż port jest podciągnięty wewnętrznie poprzez rezystor do linii zasilania. Gdy przycisk jest wciśnięty, to wyprowadzenie portu jest zwarte do masy i jest tam niski poziom napięcia,

Pozdrawiam !
michail
14.03.2010 (14:15)
gość
Witam, zastanawia mnie pewna sprawa, chodzi o tekst na początku części drugiej, w podtytule SCHEMATY POŁĄCZEŃ, paragraf 2. Otóż jest tam napisane że gdy przycisk nie jest wciśnięty, czyli nie płynie prąd, na wejściu PINC jest ustawiony stan 1. Logicznie patrząc powinno być chyba tak, że po wciśnięciu przycisku obwód jest zwarty, prąd płynie i na wejściu PINC ustawiany jest wtedy stan 1. gdzie jest błąd w moim rozumowaniu i czy w ogole? :)

pozdrawiam
jaTy
25.02.2010 (14:56)
gość
Zgadza się. Człowiek jak sie zapatrzy to nawet symulacja mu tak wyjdzie. Mój błąd przy symulacji polegał na tym iż bity ustawiałem myszką a nie programowo.
ABXYZ
24.02.2010 (18:38)
autor strony
No co ty jaTy :)

Po wykonaniu instrukcji
PORTC |= (1<<3) | (1<<5) | (1<<7);

w rejestrze PORTC zostaną ustawione bity numer 3,5,7, a pozostałe bity zostaną niezmienione, ponieważ tu został użyty operator |= a nie operator =

Instrukcja powyżej jest równoznaczna z tą:
PORTC = PORTC | ((1<<3) | (1<<5) | (1<<7));
jaTy
24.02.2010 (18:07)
gość
ŚWIETNY KURS.
Jestem początkujący ale z tego co Pan pisze o przesuwaniu bitów, przy zapisie PORTC |= (1<<3)|(1<<5)|(1<<7); wartość pozostałych zostanie zmieniona. Na symulacji też wyszła mi zmiana.
Gruby
23.01.2010 (19:12)
gość
Super kurs!

BTW: Jakby się ktoś zastanawiał jak zrobić zwiększenie licznika z blokadą drgań styków oraz zliczaniem w przypadku przytrzymania przycisku:

if (!(PINC & 0x01)) {
PORTD++;
_delay_ms(50);

int first = 1;
while (!(PINC & 0x01)) {
_delay_ms(200);

if (!first) {
PORTD++;
}

first = 0;
}
_delay_ms(50);
}
Darek111
14.01.2010 (14:26)
gość
Gratulacje dla autora za BARDZO DOBRĄ robotę, SUPER kurs.
P@WEŁ
06.01.2010 (23:20)
gość
Ja szukałem mobilizacji do programowania od dłuższego czasu.
Jest szansa, że w końcu się za to wezmę, bo o wiele łatwiej jest wstawić procka i tylko zmieniać program niż przebudowywać dość rozbudowaną elektronikę ;)
Pozdrowienia dla autora i wielkie dzięki za materiały.
ABXYZ
07.12.2009 (22:53)
autor strony
Schematy robione są w XCircuit, a pozostałe ilustracje wykonuję z pomocą programów Inkscape I Gimp
R
07.12.2009 (20:51)
gość
W jakim programie rysujesz schematy?
IronMike
27.11.2009 (23:50)
gość
Pozdro dla Autora. Megakozacki kurs, najlepsy z jakim sie spotkałem.
H3nry
26.11.2009 (22:05)
gość
Dziękuję ..nic więcej nie powiem na tym etapie :)
władysław
24.11.2009 (23:02)
gość
Bardzo dziękuje za ten kurs to jest naprawdę dobra robota .
l3cho
21.11.2009 (23:31)
gość
Witam
Czy dopisze Pan brakujący komentarz do ostatniego programu?
Pozdrawiam.
Gość
04.10.2009 (11:55)
gość
Wielka pomoc nie tylko dla początkujących amatorów ale i dla studentów :D dzięki wielkie, pozdro
Damian
10.09.2009 (08:07)
gość
czytam kolejną część i jestem coraz bardziej zadowolony że taki kurs powstał. wielkie dzięki i pozdrowienia dla autora:)
Modzel
05.09.2009 (22:12)
gość
Aż trudno mi wyrazić wdzięczność:) Jest to chyba pierwszy kurs któy opisuje temat w sposób który rozumie się od razu, aż człowiek nie może się doczekać żeby następny program wgrać do procesora i zacząć rozumieć:)
Pozdrawiam i dziękuję za swietny kurs
ABXYZ
23.07.2009 (21:31)
autor strony
Oczywiście, że będą następne części niniejszego kurs, właśnie obmyślam przykładowe programy.
Tom
23.07.2009 (16:03)
gość
Witam. Moje pytanie to czy będą następne części tego kursu?

Bardzo mi się spodobał i dzięki niemu zdecydowałem się na programowanie ATmegi.

Pozdrowienia dala autora :)
nov3l
20.07.2009 (13:19)
gość
/* Jeśli bity 0 i 1 w PIND mają wartość 1 */
if(PIND & 0x03){}

a dalej mamy: "W języku C, jeżeli jakieś wyrażenie po obliczeniu jest różne od zera, to ma wartość logiczną PRAWDA, a jeżeli wyrażenie jest równe zero, to ma wartość logiczną FAŁSZ. ";

Tak wiec, czy w komentarzu nie powinno byc raczej "(..) bity 0 lub 1 (...)" ??
ABXYZ
29.06.2009 (23:39)
autor strony
Wcześniej wszystko działało, a teraz atmega nie chce się zaprogramować, co można poradzić ...
Można sprawdzić czy się coś nie rozłączyło, spróbować z innym egzemplarzem mikrokontrolera.
jerraz
29.06.2009 (22:58)
gość
witam mam problem. Programowalem sobie plytke dokladnie jak w kursie. Z czasem próbowalem pozaprogramowac diode pod port C i od tego czasu wyswietla mi sie blad: "Address: 0x0000, Expected: 0xc012, Received: 0xffff" i nie chce sie zaden program wgrac na mikroprocesor. posiadam atmege 8 i do tego programator dokladnei taki: http://www.vacon.pl/InstrukcjaAVRProg-USB.pdf . Z gory dzieki za pomoc. Kurs jest swietny.
kamil
25.06.2009 (11:36)
gość
Ale extra kurs! Do tej pory jakoś omijałem język C dla AVR ze względu na niezrozumiało prowadzone kursy dla początkujących i programowałem sobie w Bascomie. Ale teraz po przestudiowaniu tego extra kursu wydaje mi się, że C wcale nie jest taki trudny! Podziękowania i Pozdrowienia dla autora i prosimy o dalsze części :)
admiral
16.05.2009 (12:03)
gość
mam takie pytanie co do generowania opoznien przez _delay_ms()

The maximal possible delay is 262.14 ms / F_CPU in MHz.

Chodzi mi o to ze niewazne jaki kwarc zastosujemy to przy uzyciu funkcji np. _delay_ms(250) uzyskamy zawsze opoznienie takie same np. przy kwarcu 1Mhz, 8MHz czy tez np. 16MHz ?
pozdrawiam
ABXYZ
20.04.2009 (17:58)
autor strony
Spotyka się różne typy i wielkości brzęczyków, jedne do zadziałania potrzebują zaledwie kilka miliamperów, można by je bezpośrednio przyłączać do porów AVRa, zaś inne mogą pobierać znacznie więcej prądu niż może przepłynąć przez porty AVRa.

Ja zwykle wykorzystuje brzęczyk, który przy zasilaniu 5V zużywa ponad 20mA, dlatego przyłączam go poprzez tranzystor. Brzęczyk ten wymontowałem ze starej igłowej drukarki; jest dość głośny, generuje taki miękki, niedrażniący dźwięk. Buzzer na fotografii pobiera zaledwie 3mA, tranzystor wstawiłem tam po prostu z nawyku.
Piotr
19.04.2009 (11:51)
gość
Witam, kurs jest naprawde swietny.
Mam takie pytanie, dlaczego buzzer jest podlaczany przez tranzystor? Nie da sie go podlaczyc tak jak leda?
Kangurek
11.04.2009 (12:00)
gość
Czytając komentarze trochę się zaniepokoiłem... Czy do portów PC0...PC5 Mogę podłączyć fototranzystor? Z tego co się orientuję to uC sam ustala kiedy będzie stan 0 a kiedy stan 1. Kolejne pytanie: gdy podłączam fototranzystor do ATmega8 to muszę dawać wejście z podpięciem do Vcc? I jeszcze dla pewności czy dobrze zrozumiałem: kiedy jest ustawione podłączenie do Vcc i jest podłączony switch (tak jak ja schemacie do GND) to wartość 0 wyniesie wtedy, gdy zrobi się zwarcie (GND z Vcc)?
leon
28.02.2009 (21:23)
gość
Świetny kurs na początek bo też nie mogłem wystartować z uC jak zresztą wielu:) dzięki! i czekam na kolejne części;)
shadow_man
20.02.2009 (20:57)
gość
A ja mam pytanie do autora. Czy w przyszłości tego kursu planujesz napisać coś o wyświetlaczu z noki 3310 ? Słyszałem że da się to opanować ;)
miszczu
17.02.2009 (22:59)
gość
Witam.Tak jak kolega wcześniej chciałem zapytać kiedy będzie kolejna część kursu???
adaszek
15.02.2009 (20:29)
gość
świetna robota ! wszędzie szukałem tak łopatologicznego wytłumaczenia jak zabrać się za avr ... czy już nie czas na trzecią część :] ?
shadow_man
12.02.2009 (18:51)
gość
No muszę przyznać że kurs się udał :) Szczególnie podoba mi się wyjaśnienie operacji bitowych. Pisałem dotąd w Bascom'ie ale jego możliwości były marne. Nie mogę się doczekać 3 części. Podobno to już nie długo
Andrzej
11.02.2009 (08:17)
gość
OK. Zwracam honor:) Po prostu nie miałem tej dokumentacji przed oczami tylko pisałem z pamięci.
ABXYZ
10.02.2009 (21:00)
autor strony
Fragment z dokumentacji avr-libc, proszę czytać ten fragment w całości :)

%<-------------------------------------------------
void _delay_ms(double __ms)

Perform a delay of __ms milliseconds, using _delay_loop_2().

The macro F_CPU is supposed to be defined to a constant defining the CPU clock frequency (in Hertz).

The maximal possible delay is 262.14 ms / F_CPU in MHz.

When the user request delay which exceed the maximum possible one, _delay_ms() provides a decreased resolution functionality. In this mode _delay_ms() will work with a resolution of 1/10 ms, providing delays up to 6.5535 seconds (independent from CPU frequency). The user will not be informed about decreased resolution.
%<-------------------------------------------------
Andrzej
10.02.2009 (20:12)
gość
Kurs bardzo ciekawy, ale mam uwagę odnośnie realizacji dłuższego opóźnienia:
_delay_ms(330);
Może mamy inne dokumentacje, ale z mojej wynika, że funkcja _delay_ms(double __ms) maksymalnie może wstrzymać działanie układu na 262.14 ms / (F_CPU w MHz), czyli przy tym zegarze na 262.14ms. W napisanym programie opóźnienie występuje, ale na pewno nie wynosi ono dokładnie 330ms. Przy świeceniu diodami jest to mało ważne, lecz gdy sterujemy np. transmisją danych taka pomyłka wysypie cały program.
Życzę dużo wytrwałości do opracowywania dalszych części kursu.
Pozdrawiam.
Modzel
08.02.2009 (02:05)
gość
Aż postanowiłem napisać komentarz tak mi się to podoba co tutaj znalazłem:)
Już kilka podejść robiłem do tematu mikrokontrolerów i dopiero pański kurs pomógł mi wystartować, wprawdzie nie zrobiłem żadnego programu jeszcze, ale mam złożony zasilacz, przyszedł dzis programator i właśnie skończyłem budować płytkę na atmegę (postanowiłem zbudować jeden moduł unierwsalny, który zawiera przyłacze zasilania, reset i wyprowadzenie wszystkich portów procesorka, do których podłączać będę moduły z LED, włącznikami, czy co tam trzeba będzie:P).

Mam nadzieje, że kurs nie umrze, bo naprawdę super:)

Pozdrawiam.
Modzel.
AVRfan
07.02.2009 (06:03)
gość
Dobra robota. Jesli kurs nie umrze i beda pojawiac sie kolejne czesci to jestem pewien, ze bedzie cieszyl sie niemalym zainteresowaniem. Wrecz jestem przekonany, ze bedzie najlepszym kursem dla poczatkujacych stawiajacych swoje pierwsze kroki. Wiekszosc kursow dla poczatkujacych pisana jest niestety z zalozeniem spraw oczywistych, ktore dla poczatkujacego oczywiste nie sa, przez co w wiekszosci wypadkow staja sie nieprzydatne. Tutaj kolega wyklada kawe na lawe i o to wlasnie chodzi !!! Powodzenia w pisaniu i wytrwalosci.
ABXYZ
24.01.2009 (14:08)
autor strony
Tak, wystarczy użyć operatora "~" (dopełnienie jedynkowe)

Przykład:
PORTD = ~0xaa; /* Do PORTD trafi wartość 0101 0101 */
puntigamer
24.01.2009 (11:12)
gość
Już wszystko jasne. mam inaczej podłączone diody niż tutaj opisane:) GND ("0") oczekuje z uC. Czy da się jakoś to odwrócić? :)
puntigamer
24.01.2009 (11:05)
gość
hej. dzieki za odp. przykłady robię na płytce zl2avr v.2. z tego co widzę na schemacie to z jednej strony diody podłączone są pod 5v, później są R i diody. Czyli wystarczy, że daną diodę podłącze do GND i będzie świecić. Zamiast prosto pod GND sygnał wychodzi z uC i właśnie nie świeci przy "1" tylko przy "0". W sumie wydaje mi się, że diody są podłączone wg tego schematu pxx > r > led > gnd.
Daję DDRD = 0xFF; później tylko PORTD = 0x12 i świecą się tak : XXX-XX-X, gdzie pierwszy z prawej podłączony do PD0 :( masakra
ABXYZ
24.01.2009 (02:52)
autor strony
Nie ma tu błędu. Jeśli dioda LED podłączona jest do uC AVR w taki sposób, jak na schemacie (PXx->R->LED->GND), to będzie świecić, gdy wartość odpowiedniego bitu w rejestrze PORTX jest "1";, wcześniej należy ustawić daną linię jako wyjście - zapisać wartość "1" na odpowiednim bicie rejestru DDRX.

Hmm... ,być może uruchamiasz przykłady na jakieś płytce startowej z AVR-em, gdzie diody LED mogą być przyłączone w taki sposób: VCC->R->LED->PXx, wtedy faktycznie diody będą się świecić się "na odwrót"- dla wartości "0" odpowiedniego bitu w rejestrze PORTX.

puntiga
24.01.2009 (01:14)
gość
zeby nie było pomyłek kolejności dodam, że gdy wpiszę 0x33 czyli binarnie "0011 0011" układ świecenia diod jest następujący: XX--XX-- czyli wychodziłoby na to, że "1" gasi diodę (bo DDRD = 0xFF podnosi do Vcc). Nie czepiam się szczegółów tylko miałem problem z operacjami bitowymi przez to :)
puntiga
24.01.2009 (01:09)
gość
"Pierwsza instrukcja w pętli zapisuje do rejestru PORTD wartość 0xAA ( binarnie 1010 1010), zaświecą się diody LED przyłączone do wyprowadzeń: PD1,PD3,PD5 i PD7; pozostałe diody będą wygaszone.
PORTD = 0xaa; /* 0xaa binarnie 1010 1010 */ "

Witam na początku dałem cytat. Pod PD0 podłączyłem diodę, która jest pierwsza z prawej, PD1 druga od prawej itd zgodnie z obrazkiem oraz gifem z wynikiem świecenia diod. Pytanie brzmi, czy binarna "1" gasi diodę czy ją zapala, bo u mnie gasi, a w cytacie jest odwrotnie. Czyli u mnie 0xAA świeci tak -X-X-X-X przy czym X to paląca się dioda. Wg mnie zdanie "zaświecą się diody LED przyłączone do wyprowadzeń: PD1,PD3,PD5 i PD7" jest błędne. Proszę o pomoc. THX
paweł
21.01.2009 (09:08)
gość
Witam, kiedy można liczyć na następną część kursu bo te już przerobiłem, są naprawdę super, nie żebym kogoś popędzał ale spodobało mi się programowanie avr a ten kurs jest najlepszy pośród tych które znalazłem w sieci, mam również książkę dr Witkoskiego, ale tamto to jeszcze trochę wyższa szkoła jazdy
piotr
16.01.2009 (21:09)
gość
Próbowałem z różnych źródeł korzystać i nie mogłem zrozumieć dopiero ten kurs ustawił porządek i sukcesywność w toku całościowej analizy każdego projektu .
ABXYZ
15.01.2009 (16:39)
autor strony
2miszczu A którego z AVR-ów używasz? Na przykład w fabrycznie nowym ATMega16 domyślnie jest włączony interfejs JTAG i w tej konfiguracji nie można wykorzystywać pinów PC2-PC5 jako cyfrowych wejść/wyjść.
nobile
11.01.2009 (23:17)
gość
Sam nie czytasz tego co pisze wczesniej bo sie poprawilem z 2 na 3 :]
anze
11.01.2009 (18:37)
gość
nobile: użyj mózgu i przeczytaj komentarze poprzednie.
Poza tym facet robi pro publico bono, i za free, więc nie poganiaj i nie strasz. no a DRUGĄ część, na którą niby czekasz, właśnie skomentowałeś
nobile
10.01.2009 (22:51)
gość
edit: Kiedy 3 czesc kursu (pomylka przez pospiech) ;)
nobile
10.01.2009 (22:49)
gość
kiedy 2 część tego kursu bo mogę powiedzieć ze jesteś jednym z niewielu autorów którzy używają mózgu pisząc kurs dla początkujących. Jest tu tak wszystko przejrzyście napisane ze preaktycznie nie trzeba znać C żeby zaprogramować AVR. Sprężaj się z tym kursem bo już się doczekać nie mogę... ew. podaj datę dodania następnego.
miszczu
09.01.2009 (08:18)
gość
Witam.Mam pytanie następujące:
-zaprogramowanie portu C z podciągnięciem do napięcia zasilającego(tak jak w podanych przykładach) bez wciśniętego przycisku jest odczytywane przez atmege jako logiczne "1"?
Ja
08.01.2009 (23:20)
gość
Witam.

Mam pytanie, czy byłaby możliwość aby autor przedrukował (do .pdf lub .doc) owe części kursu i zamieścił na WWW?

Ewentualnie mogę zrobić to ja i przesłać na e-mail, albo jakoś inaczej...
ABXYZ
06.01.2009 (13:20)
autor strony
>Początkujący
Zaproponowany przez Ciebie kawałek kodu nie testuje czy przycisk został zwolniony. Jeśli ma działać w pętli, tak jak jest w przykładach, wtedy instrukcje, które powinny się wykonać raz przy każdym wciśnięciu przycisku, mogłyby się wykonać kilka razy - zależnie od tego, jak długo przycisk pozostawałby wciśnięty.

2anze Planuję ukończyć trzecią część kursu w połowie stycznia, ale pewnie będzie to luty :)

Dzięki za wszystkie komentarze.

Pozdrawiam.
Początkujacy
05.01.2009 (16:37)
gość
Witam,

Na wstępie gratuluję autorowi kursu i życzę wytrwałości w jego dalszej realizacji. Mam też pytanie, czy aby likwidacja drgań styków nie powinna wyglądać w ten sposób ???

if (!(PINC & 0x02))
{
_delay_ms(20);
if (!(PINC & 0x02))
.
tu właściwa część tego co chcemy osiągnąć
.
}

Bo wydaje mi się że to zastosowane w przykładowym programie kursu nie czeka na ustabilizowanie się styków, tylko na wykonanie instrukcji w miejscu gdzie nie musi... Poprawcie mnie jeśli się mylę. Dziękuję i pozdrawiam.
anze
04.01.2009 (00:08)
gość
miesiąc minął, będzie następna część? czy dopiero w lutym?
pozdrawiam
ABXYZ
30.12.2008 (18:46)
autor strony
2 dawid512 Tak, racja! W tych przykładach nie ma specjalnie potrzeby umieszczać funkcji _delay_ms() w pętli. Już przerobiłem kod przykładów. Dzięki za tę uwagę.

Szczegóły działania funkcji _delay_ms() można znaleźć w pliku "C:\WinAVR\avr\include\util\delay.h"
Ja
30.12.2008 (14:47)
gość
Jadę po części na programator i płytkę uruchomieniową ;]
Panie Autorze, jesteś WIELKI :) Najlepszy kurs C jaki widziałem
Samezrp
30.12.2008 (12:28)
gość
"Po za tym liczymy tylko do 33 więc po co aż int? Wystarczy unsigned char."

1. unsigned int
2. w [C] OIDP zmienna char czy int to w zasadzie dokładnie ten sam typ, często stosowany wymiennie, oba typy zajmują 8 bitów, niezależnie od znaku, więc na jedno wychodzi.

Co do meritum to też się zastanawiałem czy delay() nie przyjmie 330, ale w tym momencie chyba trzeba by się przyjrzeć dokładniej funkcji delay(), a tego nie robiłem. Może kwestia zapanowania nad czasem opóźnienia przy różnych wartościach kwarcu?
mufi
28.12.2008 (07:21)
gość
Kiedy kolejna część kursu? ;D Może coś o ADC albo o PWM :D?
dawid512
27.12.2008 (20:05)
gość
Kurs w porządku ale zastanawia mnie kilka rzeczy:

/* opóźnienie 0.33 sek. */
for(unsigned int i=0; i<33; i++) _delay_ms(10);

Nie prościej _delay_ms(330); ?

Po za tym liczymy tylko do 33 więc po co aż int? Wystarczy unsigned char.

Pozdrawiam.
geth
22.12.2008 (18:20)
gość
Gratuluję kursu! Wielkie brawa dla autora, za poświęcony czas i kawał dobrej roboty ;) W dziedzinie programowania mikrokontrolerów jestem pewien że ta strona przejdzie do historii polskiego internetu ;)
Adam Sz.
14.12.2008 (23:13)
gość
Gratuluję świetnego kursu! Szukałem czegoś takiego od prawie roku :)
Roman
14.12.2008 (17:30)
gość
Jasne, że nie!
Zpieprzyłem konwersje hex->bin
Roman
14.12.2008 (17:19)
gość
2BartS:
Nie ma być tak:
DDRB = 0x00 => PB0 wyjściem
DDRB = 0x01 => PB1 wyjściem
DDRB = 0x02 => PB2 wyjściem
itd ?
Szwagier90
14.12.2008 (16:38)
gość
Kurs jest genialny. Właśnie takiego kursu o C na procki szukałem od długiego czasu. A na dodatek ta prostota i przejrzystość.
Dzięki wielkie.
Wielkie pozdro dla autora!
Raff
14.12.2008 (16:01)
gość
Gratuluję autorowi wytrwałości i chęci przygotowania tak przejrzystego i łatwego w interpretacji kursu programowania w jakże ciekawym języku jaki jest C. Mama nadzieję że właśnie dzięki temu kursowi mnóstwo ludzi doceni wartość mikrokontrolerów jak i języka i przkonają się że to wcale nie takie trudne :) Jeszcze raz gratuluję autorowi i zachęcam do dalszego poszerzania kursu :)
BartS
14.12.2008 (12:38)
gość
Dzieki wielkie za kurs! :) W ostatnim przykladzie zauwazylem blad. Mianowicie do adresowania DDRB = 0x02 w komentarzu jest podany, ze wyjsciem jest port PB2 a nie PB1. Pozdrawiam i czekam na czesc nr 3. :)
Karol
13.12.2008 (18:08)
gość
Świetna sprawa, ogromna pomoc dla początkujących.
piotr
13.12.2008 (17:12)
gość
Takiego kursu mi właśnie brakowało. Wytłumaczone jest prosto, łatwo, zrozumiale. Czesta przyjemność! Czekam na następne części tego kursu.
Mam prośbe do autora kursu - dobrze by było zamieszczac poszczególne odcinki również w formie spekowaniej np. kursC_nr**.zip
Michlis
12.12.2008 (17:58)
gość
Bardzo przystępny i ciekawy kurs, dziękuję!
pasta20
11.12.2008 (22:21)
gość
Wspaniałe, jutro muszę się doczytać, właśnie o to chodziło :D Obyś miał dużo czasu i poświęcił go nam czytelnikom :D w pisaniu kolejnych kursów.

Dzięki odwalasz kawał dobrej roboty :D
Maciej
09.12.2008 (21:00)
gość
Świetny kurs! Pisałem dużo w BASCOM`IE, przyszła pora na C, dlatego uprzejmie proszę polećcie mi jakąś książkę opisującą krok po kroku programowanie w C z uwzględnieniem mikroprocesorów z rodziny AVR.

Pozdrawiam i gratuluję autorowi tak dobrego kursu.
Samezrp
08.12.2008 (12:54)
gość
Cieszę się, że kiedy w końcu zabrałem się za procki, to znalazł się kurs, który porządkuje moją wiedzę :) Czekam na ciąg dalszy i dziękuje :)
waad
07.12.2008 (23:26)
gość
Bardzo przydatny kurs. Mnie pomógł rozwiązać problem, z którym borykałem się od jakiegoś czasu. Jako uzupełnienie dla początkujących warto zajrzeć na stronę p.Borkowskiego z Akademii Długosza w Częstochowie: http://www.imi.ajd.czest.pl
anze
07.12.2008 (00:12)
gość
Błąd w listingu /* przykład 2.1 "leds.c;" */
zbędny znak ">" w linii #define F_CPU 1000000L>
pozostałe programy ruszyły

pozdrawiam AM
anze
04.12.2008 (14:23)
gość
podoba mi się Pański kurs. mam nadzieję, że teraz będzie częściej, niż co 2 miesiące ;-)
powodzenia
Piotrek
03.12.2008 (12:06)
gość
Jejuu - Panie autor, jesteś człowiek Wielki :) wielkie pozdro i wielkiej motywacji !!!
Kursy>Kurs AVR-GCC>Kurs AVR-GCC, cz.2
Ostatnie artykuły