i w przypadku wciśnięcia odpowiedniego klawisza przejść do ponownego wczytywania czasu. Nasz program przez zdecydowa-
|
|
- Urszula Malinowska
- 6 lat temu
- Przeglądów:
Transkrypt
1 Kurs AVR lekcja 8 Rozwiązania zadań i w przypadku wciśnięcia odpowiedniego z ostatniego odcinka klawisza przejść do ponownego wczytywania czasu. Nasz program przez zdecydowa- Tematem pierwszego zadania było dodanie walidacji wpisywanego czasu. Można to ną większość czasu czeka na pojawienie się zrobić na kilka sposobów. Np. w samej flagi OCF1A oznaczającej upłynięcie kolejnej sekundy. Najlepiej więc sprawdzanie funkcji readtime() można dodać kod, który nie pozwoli przesunąć kursora dalej, jeśli stanu klawiatury umieścić w pętli while() wpisane dotychczas cyfry tworzą nieprawidłową liczbę godzin, minut lub sekund. nie oprócz czekania na flagę nic nie robi czekającej na tę właśnie flagę. Pętla ta obec- Drugi sposób to zmienić kod wykrywający i ma postać pojedynczej linijki. Możemy ją przekręcenie się liczników poszczególnych składowych czasu. W naszym kodzie Teraz pętla nie tylko sprawdza flagę, ale rozbudować np. jak w listingu 2. sprawdzaliśmy, czy liczniki sekund i minut też odczytuje stan klawiatury. Jeśli jakiś osiągnęły wartość 60 oraz czy licznik przycisk został wciśnięty, sprawdzany jest godzin osiągnął 24. Ponieważ nieprawidłowe wartości będą się w praktyce sprowacisk S14, wykonywana jest opisana już jego numer. Jeśli był to przykładowo przydzały do liczb zbyt dużych dla poprawnego wyżej pętla do-while. czasu, można zmienić operator równości na Zadanie trzecie polegało na dodaniu większe bądź równe : funkcji budzika. Tutaj można postąpić if (seconds >= 60) analogicznie i w pętli sprawdzającej flagę seconds = 0; minutes++; OCF1A dodać sprawdzenie, czy nie został if (minutes >= 60) minutes = 0; hours++; wciśnięty klawisz np. S13. Poniżej szkielet if (hours >= 24) kodu, bez wczytywania czasu: hours = 0; while(!(tifr & _BV(OCF1A))) W ten sposób wpisanie godziny 33:33:33 if (readkeyboard()) spowoduje ustawienie godziny 00:33:33, if (key == 14) a wpisanie godziny 55:66:77 da godzinę // wczytanie nowego czasu 00:00:00. Inna opcja to zażądanie od użytkownika wprowadzenia godziny jeszcze raz if (key == 13) // wczytanie czasu alarmu (listing 1). Wykorzystujemy tu pętlę do-while. Gdy klawisz ten zostanie wciśnięty, trzeba wczytać czas, ale nie umieszczać go Charakteryzuje się ona tym, że zawsze wykonuje się przynajmniej raz, ponieważ w zmiennych zegara, tylko w dodatkowych warunek jej wykonywania sprawdzany jest zmiennych przechowujących czas budzika. dopiero po pierwszej iteracji. Jeśli któraś ze Następnie, np. obok kodu sprawdzającego zmiennych sekund, minut lub godzin będzie przepełnienie zmiennych czasu, konieczne miała wpisaną przez użytkownika zbyt dużą jest dodane porównania zmiennych czasu wartość, pętla nie zakończy się, tylko rozpocznie kolejną iterację i użytkownik zostanie Gdy będą równe, trzeba jakoś zasygnali- alarmu ze zmiennymi bieżącego czasu. poproszony o wpisanie czasu jeszcze raz. zować alarm. Może to być migający LED, W zadaniu drugim trzeba było dać możliwość przestawiania zegara. Musi więc coś innego. W przypadku piezo bez gene- piezo z generatorem, bez generatora lub istnieć możliwość poinformowania programu o chęci zmiany czasu. W tym celu pro- Output Compare do sterowania pinem. Opis ratora można wykorzystać Timer0 i funkcję gram może np. sprawdzać stan klawiatury był w lekcji 4, przy omówieniu rozwiązania zadania 1 z lekcji 3. Nic nie stoi na przeszkodzie, aby samodzielnie dodać różne inne funkcje, np. kalendarz oraz pomyśleć nad różnymi dodatkami umilającymi pracę z programem, np. ikonką while(!(tifr & _BV(OCF1A))) if (readkeyboard()) if (getkey() == 14) do printf(" : : "); readtime(&hours, &minutes, &seconds); while (seconds > 59 minutes > 59 hours > 23); Listing 2 dla alarmu czy komunikatem w przypadku wpisania nieprawidłowego czasu. lcdwritecommand(lcd_command_on_off LCD_PARAM_ON_OFF_DISPLAY LCD_PARAM_ON_OFF_CURSOR); uint8_t hours, minutes, seconds; do Listing 1 printf(" : : "); readtime(&hours, &minutes, &seconds); while (seconds > 59 minutes > 59 hours > 23); lcdwritecommand(lcd_command_on_off LCD_PARAM_ON_OFF_DISPLAY); Przerwania W tej lekcji omówimy przerwania, jedną z najważniejszych funkcji, jakie mają mikrokontrolery. Zanim jednak powiemy sobie czym są, podsumujmy sposób, w jaki dotychczas obsługiwaliśmy zdarzenia, takie jak naciśnięcie przycisku albo przepełnienie się licznika timera. Wystąpienie zdarzenia stwierdzaliśmy, odczytując stan odpowiednich bitów w rejestrach takich jak PINA czy TIFR. Odczyt ten był wykonywany przez ciągłe odczytywanie tych rejestrów w oczekiwaniu na zmianę określonych bitów. Taka obsługa zdarzeń nie jest wygodna. Sprawdzenie wystąpienia zdarzenia musi być wykonywane pomiędzy innymi zadaniami realizowanymi przez program. Jeśli jakieś zadanie trwa dłuższy czas, zdarzenie zostanie odnotowane z opóźnieniem lub całkiem przegapione. Przykładem może być proste miganie diodą z pierwszej lekcji. Jeśli chcielibyśmy podczas migania sprawdzać stan przycisku, to w przypadku, gdy przycisk został wciśnięty i puszczony w trakcie wykonywania się funkcji _delay_ms(), nie zostanie to w ogóle zauważone przez program. Możemy to rozwiązać w różny sposób. Np. zmniejszyć okres opóźnienia, a samo opóźnienie wywoływać wielokrotnie dla danego półokresu. W ten sposób dioda będzie migać z tą samą częstotliwością, ale stan przycisku będzie sprawdzany częściej. Można też zrezygnować z _delay_ms() i zastosować timer. Wówczas sprawdzając flagę w rejestrze TIFR, można też sprawdzać stan przycisku. Tak zrobiliśmy, rozwiązując zadanie 1 z lekcji 6 (rozwiązanie opublikowane w lekcji 7). W ten sposób rozwiązaliśmy problem z przegapianiem zdarzeń, ale kod stał się bardziej zagmatwany. Ponadto czym więcej zdarzeń, które program monitoruje, tym trudniej oddzielić obsługę jednych zdarzeń od drugich. Przydałoby się, żeby zdarzenia można było obsługiwać niezależnie. Tutaj z pomocą przychodzą przerwania. W momencie wystąpienia określonego zdarzenia mikrokontroler przerywa wykonywanie programu i zaczyna wykonywać specjalną funkcję obsługującą to zdarzenie. Gdy ta funkcja się wykona, mikrokontroler wznawia wykonywanie głównego programu od miejsca, w którym przerwał. Dzieje się to asynchronicznie funkcja obsługująca zdarzenie/przerwanie może się wykonać w każdej chwili. Trzeba o tym pamiętać, bo ma to swoje plusy i minusy. Z jednej strony zaletą przerwań jest możliwość natychmiastowej reakcji na zdarzenie. Z drugiej jednak programista musi zadbać o to, aby główny program nie był wrażliwy na wystąpienie przerwania w nieoczekiwanym momencie. Elektronika dla Wszystkich 29
2 30 Programowanie Obsługa przerwań Jak wspomnieliśmy, przerwania obsługiwane są za pomocą specjalnych funkcji. Aby stworzyć funkcję obsługującą przerwanie, musimy ją odpowiednio nazwać. Nazwy funkcji dla poszczególnych przerwań zostały zebrane w tabeli 1. Dodatkowo funkcja ta musi mieć odpowiednie atrybuty, aby kompilator mógł ją wykorzystać do obsługi przerwań. Atrybuty te nadaje się za pomocą makra ISR(), które wymaga pliku nagłówkowego interrupt.h. Przykładowo funkcja dla przerwania pochodzącego z funkcji Output Compare z kanału A w Timer1 będzie wyglądała następująco: ISR(TIMER1_COMPA_vect) //ciało funkcji Funkcja ta będzie się wykonywała za każdym razem, gdy w Timer1 włączy się mechanizm Output Compare, czyli gdy licznik timera osiągnie wartość zapisaną w rejestrze OCR1A. Jeśli skonfigurujemy timer tak, aby Output Compare następowało co sekundę, nasza funkcja obsługi przerwania będzie uruchamiana właśnie co sekundę. W ten sposób będziemy mogli wykonywać określoną czynność w odstępach sekundowych niezależnie od tego, co będzie robił główny program. Stworzenie samej funkcji obsługującej dane przerwanie to jednak za mało, abyśmy mogli z niego korzystać. Generowanie przerwań przez mikrokontroler trzeba najpierw włączyć, i to na dwóch poziomach. Po pierwsze trzeba przerwania włączyć globalnie funkcją sei(). Inaczej przerwania nie będą się w ogóle wykonywać. Po drugie trzeba włączyć przerwanie dla danego peryferium, które jest źródłem zdarzeń. W przypadku timerów konfiguruje się to rejestrem TIMSK (tabela 2). Popatrzmy na przykład migania diodą za pomocą przerwania listing 3: Na początku zaczynamy od globalnego włączenia przerwań za pomocą sei(). Ponieważ będziemy migać diodą podłączoną do pinu 0 portu B, konfigurujemy go jako wyjście, ustawiając pin DDB0 w rejestrze DDRB. Tak jak w zegarze z lekcji 7, źródłem odmierzającym czas jest Timer1 i jego funkcja Output Compare. Tak samo też konfigurujemy jego rejestr OCR1A, aby uzyskać przerwanie co sekundę. Liczba wynika z przyjętego wtedy taktowa- nia kwarcem 16 MHz. Oczywiście dla innego źródła taktowania lub innego okresu musimy obliczyć inną wartość dla OCR1A, zgodnie z konfiguracją taktowania opi- saną w lekcji 4. Na koniec ustawiamy bit OCIE1A w rejestrze TIMSK, aby Timer1 Tabela 1 generował przerwania dla funkcji Output Compare w kanale A. Główna pętla programu jest pusta. Zadanie realizowane przez nasz program, czyli miganie diodą, realizowane jest w funkcji TIMER1_COMPA_vect(). Przełączanie LED-a wykonywane jest w tym przykładzie w najprostszy sposób, przez logiczną negację stanu rejestru portu. Jeśli w rejestrze jest liczba 0, to wpisana zostanie do niego 1, a jeśli wpisane jest 1, zostanie wpisane 0. W ten sposób zmienia się stan tylko jednego, najmłodszego bitu (pinu), reszta jest zerowana. Gdybyśmy użyli nie operatora negacji logicznej (!), a operatora negacji bitowej (~), przestawiane byłyby wszystkie bity. W każdym razie sterowane są wszystkie piny portu B i gdyby główny program zmienił stan jednego z pinów tego portu, to w przerwaniu byłoby to nadpisane. W naszym prostym przykładzie jednak to nie przeszkadza, bo główny program nie przestawia żadnego pinu. Przekazywanie danych do funkcji obsługi przerwania Uważni Czytelnicy zauważą, że definicja funkcji wygląda nietypowo, bo po jej nazwie brakuje nawiasów z ewentualnymi parametrami, a te nawiasy są przecież wymagane przez język C. Otóż są one dodawane przez makro ISR, nie ma więc odstępstwa od standardu. Ważne jest to, że są one dodawane w postaci (void), czyli funkcja obsługi przerwania nie przyjmuje żadnych parametrów. Jest ona wywołana asynchronicznie, gdy wykonanie głównego programu odbywa się w bliżej nieokreślonym miejscu. Trudno więc, aby jakieś parametry były przekazane. W jaki więc sposób funkcja obsługi przerwania może uzależnić swoje działanie od stanu głównego programu? Skoro nie można przekazać parametrów, funkcja musi skorzystać ze zmiennych globalnych lub, jak nasza DDRB = _BV(DDB0); //pin PORTB0 jako wyjście OCR1A = 15624; while (1) ISR(TIMER1_COMPA_vect) PORTB =!PORTB; Listing 3 funkcja migająca, odczytywać stan rejestrów. Jak wiemy, zmiennych globalnych należy unikać, ale tutaj będą właśnie potrzebne. Załóżmy, że chcemy migać linijką 8 LED-ów, ale niekoniecznie wszystkimi w danej chwili, tylko wybierać z klawiatury, które diody mają migać. Do przechowywania informacji o tym, który LED ma aktualnie włączone miganie, wystarczy zmienna typu uint8_t. Zadeklarujemy ją jako globalną, czyli jej deklarację umieścimy przed deklaracjami funkcji. W naszym kodzie będziemy potrzebować jeszcze jednej zmiennej związanej z obsługą migania. Gdy migaliśmy jedną diodą, mogliśmy w danej iteracji sprawdzać obecny stan pinu, do którego podłączony jest LED i ustawiać jego stan na przeciwny. Teraz już nie jest to możliwe, bo sterować będziemy diodami niezależnie i miganie będzie mogło być np. w danej chwili wyłączone dla wszystkich z nich. Potrzebna będzie więc zmienna (ledon), która będzie mówiła, czy w danej iteracji jesteśmy w fazie wyłączenia wszystkich diod, czy też włączenia wybranych z nich. Ponieważ zmienna ta musi zachowywać swój stan pomiędzy wywołaniami funkcji obsługi przerwania, nie możemy zadeklarować tej zmiennej wewnątrz tejże funkcji jako zwykłej zmiennej automatycznej. Pamięć dla nich jest bowiem rezerwowana tylko na czas wykonywania się funkcji, w których są zadeklarowane i może być później nadpisana innymi danymi. Pasowałaby nam tutaj więc zmienna globalna, która będzie żyła przez cały czas działania programu. Byłoby to jednak nieeleganckie, gdyż ideą zmiennych globalnych jest ich dostępność z różnych miejsc kodu, a nie zapewnienie nieograniczonego czasu życia. Na szczęcie mamy do dyspozycji zmienne statyczne. Są one deklarowane wewnątrz funkcji, w której są używane i nie ma problemu z ich niepotrzebną widocznością poza tą funkcją. Jednocześnie umieszczane są nie na stosie, ale w obszarze pamięci zwanym stertą, tak jak zmienne global- Tabela 2 Elektronika dla Wszystkich
3 ne. Aby zmienna była statyczna, używamy modyfikatora static. Nasza funkcja obsługi przerwania będzie wyglądała następująco: uint8_t ledconf = 0; ISR(TIMER1_COMPA_vect) static uint8_t ledon = 0; ledon =!ledon; if (ledon) PORTB = ledconf; else PORTB = 0; Zmienną ledon przestawiamy za każdym wywołaniem w przeciwny stan logiczny. Zależnie od bieżącego stanu włączamy wybrane diody według bitów w zmiennej ledconf lub wyłączamy wszystkie diody. Zmienna statyczna lenon jest inicjalizowana zerem tylko za pierwszym wywołaniem funkcji obsługi przerwania. Mając gotową obsługę przerwania, przejdźmy do funkcji main(), aby dopisać w niej obsługę klawiatury i wpisywanie odpowiednich wartości do zmiennej globalnej ledconf. Dla klawiatury mamy naszą bibliotekę, możemy więc skopiować pliki keyb.h i keyb.c do katalogu z naszym nowym projektem, obok pliku main.c. Następnie trzeba je dodać do projektu, klikając na nim prawym przyciskiem w okienku Solution Explorer i wybierając z menu Add-> Existing Item Aby sprawdzić, czy wszystko jest w porządku, wciśnijmy F7, aby skompilować projekt. Niestety pojawi się błąd: Error lcd.h: No such file or directory. Jak widać, przyczyną jest brak pliku lcd.h w naszym projekcie. Wynika to z tego, że biblioteka klawiatury odwołuje się do biblioteki LCD, bo w poprzedniej lekcji dopisaliśmy obsługę klawisza Backspace i konieczne było kasowanie znaków na wyświetlaczu oraz przesuwanie kursora z poziomu funkcji wczytującej czas z klawiatury. W ten sposób biblioteka klawiatury została powiązana z biblioteką alfanumerycznego wyświetlacza ciekłokrystalicznego. Dodając obsługę Backspace, sprawiliśmy, że biblioteka stała się mniej uniwersalna. Można powiedzieć, że nie jest to duży problem, bo w każdym projekcie mamy oddzielne pliki keyb.h oraz keyb.c i w związku z tym nic nie stoi na przeszkodzie, aby dostosować je do potrzeb danego projektu. Możemy np. w pliku keyb.c wykasować dyrektywę #include dołączającą plik lcd.h oraz wykasować funkcje readtime() i readnumber(). Wykonajmy więc teraz tę operację, a później zastanowimy się, jak możemy przepisać bibliotekę klawiatury, aby pasowała do różnych projektów. Po skasowaniu wymienionych fragmentów kod powinien się już skompilować. Może ewentualnie pojawić się ostrzeżenie odnośnie do braku definicji makra F_CPU. Zdefiniujmy je, jeśli jeszcze tego nie zrobiliśmy w naszym projekcie. Ponieważ pozostajemy przy taktowaniu częstotliwością 16 MHz, definicja będzie miała postać F_ CPU= Aby korzystać z biblioteki klawiatury, na początku funkcji main() dodajemy wywołanie funkcji keybinit(). Następnie w głównej pętli będziemy odczytywać klawisz funkcją getkey(). Jak pamiętamy, funkcja ta oczekuje na wciśnięcie klawisza i zwraca jego numer. Ponieważ mamy 8 LED-ów, załóżmy, że będziemy nimi sterować za pomocą klawiszy S1 S8. Naszym celem jest, aby wciśnięcie klawisza włączało lub wyłączało miganie odpowiedniego LED-a. Włączanie/wyłączanie migania ustawiamy przez odpowiedni bit w zmiennej ledconf. Przykładowo aby migały nam diody LED3 i LED5, do zmiennej ledconf musi być wpisana wartość b, czyli muszą być ustawione bity 2 i 4. Aby te diody przestały migać, te bity muszą zostać wyzerowane. Skoro naciśnięcie klawisza ma włączać/ wyłączać miganie danej diody, to na podstawie numeru wciśniętego klawisza musimy przestawić odpowiedni bit na przeciwny. Omawialiśmy już ustawianie i zerowanie wybranych bitów, ale nie zajmowaliśmy się jeszcze przestawianiem na stan przeciwny. Oczywiście możemy to zrobić na piechotę: sprawdzić stan bitu a następnie go wyzerować lub ustawić. Okazuje się, że można to zrobić znacznie prościej: operacją XOR. Czytelnicy, którzy mieli styczność z podstawami elektroniki cyfrowej, na pewno pamiętają bramki XOR. Działają one w ten sposób, że zwracają 1, jeśli na wejściach mają różne stany, a 0 jeśli takie same. Wynika też z tego, że jeśli na jednym z wejść będzie 1, to na wyjściu będzie stan przeciwny niż na drugim wejściu (tabelka obok). Operacje logiczne w C działają na zmiennych tak, jakby było wiele bramek logicznych, a każda obsługiwała po jednym bicie z obu zmiennych. A więc XOR dwóch zmiennych 1-bajtowych to tak jakby 8 XOR-ów: jeden na bitach 0 jednej i drugiej zmiennej, drugi na bitach 1, trzeci na bitach 2 itd. Załóżmy teraz, #include "keyb.h" uint8_t ledconf = 0xff; że mamy dwie zmienne. W jednej przechowujemy jakąś daną wejściową, a w drugiej wszystkie bity są wyzerowane oprócz jednego. W wyniku operacji XOR na tych zmiennych otrzymamy wartość wyglądającą jak pierwsza zmienna, z wyjątkiem bitu, który był na tej pozycji, co bit ustawiony na 1 w drugiej zmiennej. Innymi słowy, jedynka w drugiej zmiennej przestawi bit w wartości pochodzącej z pierwszej zmiennej na przeciwny (tabela poniżej). Dzięki operacji XOR możemy w głównej pętli przestawiać bity w zmiennej, znajdujące się na pozycji wskazanej przez numer klawisza: ledconf ^= _BV(key - 1); Wykorzystujemy tutaj znane nam makro wykonujące przesunięcie bitowe i zwracające bajt, który ma jedną jedynkę na wybranym miejscu. Parametrem jest tutaj numer klawisza pomniejszony o jeden, ponieważ bity są numerowane od 0, a klawisze od 1. W języku C operatorem XOR jest symbol ^ (daszek). Ponieważ wynik zapisujemy do tej samej zmiennej (ledconf), wykorzystana jest notacja ^=. W ten sposób w głównym programie czekamy na wciśnięcie klawisza, a gdy ono nastąpi, aktualizujemy odpowiednio bity w zmiennej ledconf. Uruchamiające się cyklicznie przerwanie odczytuje tą zmienną i odpowiednio zaświeca lub gasi LED-y. Na listingu 4 pokazany jest kompletny program główny, bez funkcji obsługi klawiatury z naszej biblioteki. keybinit(); OCR1A = 15625; while (1) ledconf ^= _BV(key - 1); ISR(TIMER1_COMPA_vect) static uint8_t blinkon = 0; blinkon =!blinkon; if (blinkon) PORTB = ledconf; else PORTB = 0; Niespodzianka ulotna Jak wspomnieliśmy, Listing 4 przerwania są bardzo pożyteczną rzeczą, ale ze względu na swoje asynchroniczne działanie wymagają większej uwagi od programisty. Bez przerwań kod wykonuje się linijka po linijce i generalnie nie ma tutaj niespodzianek. Jeśli jakaś funkcja się wykonuje, to dlatego, że w kodzie umieściliśmy jej wywołanie. Funkcja obsługi przerwania Elektronika dla Wszystkich 31
4 wykonuje się jednak, mimo że nigdzie jej bezpośrednio nie wywoływaliśmy. Wywołanie wykonywane jest sprzętowo, gdy zaszło pewne zdarzenie, jest dla niego włączone przerwanie i zdefiniowana funkcja obsługi przerwania. Na tym jednak nie koniec trudności związanych z przerwaniami. Rozważmy prosty przypadek: oczekiwanie na wystąpienie przerwania. Ilustruje to listing 5. Tak jak w poprzednim przykładzie, włączamy przerwania, ustawiamy piny portu B jako wyjścia i konfigurujemy timer. W głównej pętli czekamy, aż zmienna counter będzie różna od zera. Gdy to nastąpi, wpisujemy 1 do rejestru portu B, aby włączyć LED-a. Zmienna counter jest ustawiana na 1 w funkcji obsługującej przerwanie z timera. W ten sposób LED ma się włączyć po sekundzie od uruchomienia programu. Kompilujemy nasz program, programujemy procesor i nic. Dioda nie świeci. Czyżby przerwanie się nie wyzwoliło? Sprawdźmy. W obsłudze przerwania wpiszmy PORTB = 1; zamiast counter = 1;. Po zmianie faktycznie dioda się włącza po upływie sekundy. Czyżby było coś nie tak ze zmienną counter? Ustawiamy ją na 1, a pętla while() zachowuje się, jakby zmienna ta była ciągle wyzerowana. I tak właśnie jest, problem tkwi w tej zmiennej. Żeby zobaczyć, co się tak właściwie dzieje, w okienku Solution Explorer rozwińmy katalog Output Files i otwórzmy plik z rozszerzeniem.lss. W pliku tym mamy pokazane, w jaki sposób kompilator przetłumaczył kod C na asembler. Popatrzmy, jak wygląda nasza pętla while() (rysunek 1). Instrukcją lds procesor wczytuje wartość zmiennej counter przechowywanej w pamięci RAM pod adresem 0x0060 do rejestru R24. Robi tak, ponieważ nie potrafi wykonywać operacji arytmetycznych na komórkach pamięci, tylko właśnie na rejestrach. Stąd też konieczne jest skopiowanie wartości z RAM-u do rejestru. Gdy już wartość zmiennej jest w rejestrze, wykonuje na niej operację and, jako drugi argument biorąc tę samą wartość. W ten sposób sprawdza, czy wartość ta jest różna od zera. Następnie uint8_t counter = 0; OCR1A = 15624; mamy instrukcję breq, która jest skokiem warunkowym. Skok wykonywany jest wtedy, gdy w procesorze ustawiona jest flaga Z (zero). Flaga ta jest ustawiana przez różne instrukcje arytmetyczne, m.in. and, gdy ich wynikiem jest zero. Jeśli więc wczytana do rejestru wartość była zerem, to flaga Z zostaje ustawiona i następuje skok. Jak widzimy, argumentem jest tu liczba 4, czyli procesor skacze o 4 bajty do tyłu w kodzie programu. Ponieważ wczytana już była instrukcja breq (licznik rozkazów jest już ustawiony na kolejną instrukcję), skok o 4 bajty będzie skokiem do instrukcji and. I tu jest właśnie przyczyna naszych kłopotów. Procesor ciągle sprawdza instrukcją and stan rejestru R24, nie uwzględnia w ogóle zmiennej w RAM. Wczytuje ją tylko raz. Dlaczego tak się dzieje? Czy to błąd kompilatora? Otóż efekt ten jest wynikiem procesu optymalizacji wykonywanej przez kompilator. Wewnątrz pętli while() kompilator nie napotyka nic, co sugerowałoby konieczność wczytywania zmiennej z pamięci i uniemożliwiałoby posługiwanie się jej kopią przechowywaną w rejestrze R24. Nie uwzględnia faktu, że może nastąpić przerwanie, w którego obsłudze oryginalna zmienna zostanie zmodyfikowana. W tym miejscu wnikliwi Czytelnicy oglądający asemblerowy kod obsługujący przerwanie zapewne zaprotestują, bo widać że tam również modyfikowany jest rejestr R24. To prawda. Jednak najpierw wartość rejestru R24 jest zachowywana na stosie (instrukcja push), następnie jest on używany do modyfikacji zmiennej (instrukcje ldi i sts), a na koniec jest on odtwarzany ze stosu (instrukcja pop). W ten sposób różne funkcje używające tych samych rejestrów nie przeszkadzają sobie. Kończąc dygresję, zostajemy z pytaniem, jak poradzić sobie ze skutkami optymalizacji. Otóż rozwiązanie jest bardzo proste: słowo kluczowe volatile. Zmieńmy deklarację zmiennej counter na poniższą: volatile uint8_t counter = 0; Kompilujemy program, programujemy mikrokontroler i okazuje się, że nasz program działa w pełni poprawnie. Za while (!counter) PORTB = 1; ISR(TIMER1_COMPA_vect) counter = 1; Listing 5 pomocą słowa kluczowego volatile poinformowaliśmy kompilator, że zmienna counter może zmienić swoją wartość w nieprzewidywalnym momencie i w związku z tym musi on w generowanym Rys. 1 Rys. 2 kodzie zawsze umieszczać bezpośrednie odwołania do niej. Warto w tym momencie ponownie zajrzeć do pliku.lss. Okazuje się, że zmiana jest niewielka: skok wykonywany jest nie o 4, ale o 8 bajtów do tyłu, do instrukcji ładującej zmienną do rejestru (rysunek 2). W ten sposób instrukcja and otrzymuje w rejestrze R24 zawsze aktualną wartość zmiennej. Korzystając z przerwań, musimy więc pamiętać o stosowaniu słowa kluczowego volatile do zmiennych, które są używane i w przerwaniach, i w zwykłym kodzie. Jednak optymalizacja może nam przeszkadzać nie tylko w przypadku przerwań. Załóżmy, że chcemy wstawić w kodzie opóźnienie za pomocą pętli: for(uint32_t i = 0; i < ; i++); Niby wszystko jest w porządku. Procesor będzie zwiększał zmienną aż jej wartość osiągnie milion i wykona kolejne instrukcje. Załóżmy jednak, że zależy nam, aby nasz program zajmował jak najmniej pamięci Flash w mikrokontrolerze i we właściwościach projektu ustawimy optymalizację na -Os. Okaże się, że kompilator usuwa tę pętlę, nie umieszcza jej w kodzie wynikowym. Jest to bowiem pusta pętla, zajmująca się jedynie modyfikacją zmiennej nieużywanej nigdzie indziej. Z logicznego punktu widzenia pętla ta jest więc zbędna. Nam jednak zależy na opóźnieniu i tutaj również z pomocą przychodzi volatile: for(volatile uint32_t i = 0; i < ; i++); Taka pętla już nie zostanie usunięta w procesie optymalizacji jako niepotrzebna. Niespodzianka atomowa Przy pracy z przerwaniami czeka na nas jeszcze jedna niespodzianka. Załóżmy, że chcemy migać diodą z częstotliwością ok. 0,5Hz, korzystając z Timer0 z preskalerem wynoszącym Przy podziale częstotliwości 16MHz przez 1024 licznik timera będzie się zwiększał razy na sekundę. Ponieważ chcemy migać dużo wolniej, korzystamy z funkcji CTC, aby uzyskać przerwania z częstotliwością np. 32-krotnie mniejszą, czyli ok. 488Hz. Do rejestru OCR0 wpisujemy liczbę 31, ponieważ po osiągnięciu przez licznik wartości z rejestru OCR0 nie resetuje się on od razu, tylko dopiero w następnym cyklu swojego zegara. Wpisanie liczby 32 spowodowałoby odliczenie 33 cykli. 32 Elektronika dla Wszystkich
5 W funkcji obsługującej przerwanie dekrementujemy zmienną zainicjowaną liczbą wynoszącą tyle, ile wynosi częstotliwość taktowania licznika wyrażona w hercach, czyli 488. W ten sposób wartość zmiennej spadnie do zera w ciągu 1 sekundy. Dwa takie półokresy, dla diody włączonej i zgaszonej, dadzą 2 sekundy całkowitego okresu, czyli miganie z częstotliwością 0,5 Hz. Nasz kod będzie wyglądał jak na listingu 6. Dioda miga, ale jakoś dziwnie. Co 2 3 okresy zdarza się szybsze mignięcie. Widać to dobrze na oscyloskopie (rysunek 3). Dlaczego tak się dzieje? Czyżby timer zmieniał swoje taktowanie? Odpowiedź znów kryje się w kodzie asemblerowym. Zaglądając do pliku.lss, widzimy, że nasza pętla while(counter) została skompilowana jako dwie instrukcje lds, instrukcja or, oraz instrukcja brne. Nasza zmienna licznikowa jest typu uint16_t, czyli zajmuje 2 bajty. Inaczej nie zmieściłaby się w niej wartość 488. Mikrokontroler, aby sprawdzić jej wartość, ładuje najpierw jej młodszy bajt spod adresu 0x0060 do rejestru R24, a następnie starszy, z adresu 0x0061, do rejestru R25. Dzięki temu może potem instrukcją or sprawdzić, czy oba bajty (połówki zmiennej 16-bitowej) są wyzerowane. Nasz mikrokontroler volatile uint16_t counter = 0; void delay(); sei(); TCCR0 = _BV(WGM01) _BV(CS02) _BV(CS00); OCR0 = 9; TIMSK = _BV(OCIE0); while(1) delay(); PORTB = 1; delay(); PORTB = 0; ISR(TIMER0_COMP_vect) counter--; void delay() while(counter); Rys. 3 Listing 6 jest 8-bitowy i nie może wczytać zmiennej 16-bitowej w jednej instrukcji. I tutaj właśnie daje o sobie znać asynchroniczność przerwań. Może się przecież zdarzyć, że przerwanie nastąpi między jedną a drugą instrukcją lds. Nasza zmienna inicjowana jest liczbą 488 i ciągle zmniejszana w przerwaniu. W którymś momencie otrzymuje wartość 256, czyli b. Popatrzmy, co się teraz dzieje. Mikrokontroler ładuje młodszy bajt do rejestru R24. Jest w nim więc zero. I nagle, jeśli mamy (nie)szczęście, następuje przerwanie. Zmienna counter zostaje zdekrementowana i otrzymuje wartość 255, czyli b. Przerwanie się kończy, a kod sprawdzający wartość zmiennej wykonuje się dalej. Mikrokontroler ładuje starszy bajt do rejestru R25. W tym starszym bajcie nie ma już jednak wartości 1, tylko 0. Oba rejestry R24 i R25 otrzymują wartość 0, mimo że zmienna counter wcale nie miała wartości 0. Instrukcja or stwierdza, że w obu rejestrach są zera, nie ma skoku instrukcją brne, funkcja delay() kończy się. Zakończenie tej funkcji następuje przedwcześnie, zmienna counter nie osiągnęła wartości 0 i obserwujemy krótsze mignięcie. Patrząc na oscyloskop, widzimy, że zamiast 1 sekundy zostało odmierzonych ok. 480 milisekund. Jeśli zmienna licznikowa nie odlicza do 0, tylko do 256, to zamiast 488 dekrementacji wykonywanych jest tylko 232, co daje ok 48% zakładanego czasu. Obserwacja potwierdza więc, że przyczyną nieprawidłowego działania jest wystąpienie przerwania, gdy sprawdzana zmienna ma wartość zmniejszaną z 256 na 255. Jak sobie z tym poradzić? Nasz mikrokontroler jest 8-bitowy i musi do zmiennych zajmujących więcej niż 1 bajt odwoływać się na raty. Pozostaje więc wyłączenie przerwań na czas sprawdzania wartości zmiennej: void delay() volatile uint16_t tmp; do cli(); tmp = counter; sei(); while (tmp); Funkcją cli() wyłączamy przerwania, a funkcją sei() włączamy. Konieczne przy tym było użycie dodatkowej zmiennej, by w ten sposób oddzielić pobranie wartości zmiennej counter od sprawdzenia tejże wartości. Zmienną tę dobrze zadeklarować jako volatile, aby podczas optymalizacji nie została usunięta jako zbędna. Zamiast bezpośrednio wywoływać funkcje cli() oraz sei(), możemy skorzystać z makra ATOMIC_BLOCK: void delay() volatile uint16_t tmp; do ATOMIC_BLOCK(ATOMIC_FORCEON) tmp = counter; while (tmp); Aby z niego skorzystać, trzeba dołączyć plik util/atomic.h za pomocą dyrektywy #include. Makro ATOMIC_BLOCK może przyjmować następujące parametry, które określają jego zachowanie po wykonaniu się bloku kodu, którego dotyczy: ATOMIC_RESTORESTATE pozostaw przerwania w takim stanie w jakim były ATOMIC_FORCEON włącz przerwania ATOMIC_FORCEOFF wyłącz przerwania Generalnie działanie tego parametru sprowadza się do tego, czy na koniec ma być wykonana funkcja sei(), czy nie. Wyłączając przerwania na czas wykonania jakiegoś fragmentu kodu, tworzymy w tym miejscu tzw. sekcję krytyczną, czyli kod, którego wykonanie nie zostanie przerwane. Jeśli wystąpi jakieś przerwanie, to jego funkcja obsługująca zostanie wykonana dopiero po wykonaniu funkcji sei(). Innymi słowy, funkcja obsługi przerwania nie zaingeruje w nasz kod oznaczony jako sekcja krytyczna. Zostanie on wykonany w jednym kawałku, atomowo. Kiedy powinniśmy korzystać z sekcji krytycznych (bloków atomowych)? Wszędzie tam, gdzie funkcja obsługi przerwania mogłaby w niepożądany sposób zaingerować w wykonywanie się głównego programu i trudno byłoby znaleźć lepsze rozwiązanie. Zadania Do przerwań będziemy jeszcze wracać wielokrotnie. Tymczasem zachęcam do samodzielnych eksperymentów z przerwaniami pochodzącymi z timerów. Jako ćwiczenia można wykonać np.: 1. Dzielnik częstotliwości: częstotliwość na jednej nóżce mikrokontrolera ma być n-krotnie niższa niż na innej nóżce. 2. Generowanie dwóch różnych częstotliwości jednocześnie. Zadania powinny być wykonane przy użyciu przerwań, bez angażowania głównej pętli programu. Jak zwykle ko dy źródłowe do lekcji są dostępne w materiałach dodatkowych do tego numeru EdW w Elportalu. W przypadku jakichkolwiek problemów z realizacją kursu AVR, niejasności lub wątpliwości proszę o kontakt mailowy lub zadanie pytania na forum Elportalu. Grzegorz Niemirowski grzegorz@grzegorz.net Elektronika dla Wszystkich 33
Cwiczenie nr 1 Pierwszy program w języku C na mikrokontroler AVR
Cwiczenie nr 1 Pierwszy program w języku C na mikrokontroler AVR Zadanie polega na napisaniu pierwszego programu w języku C, jego poprawnej kompilacji i wgraniu na mikrokontroler. W tym celu należy zapoznać
znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.
Część XVI C++ Funkcje Jeśli nasz program rozrósł się już do kilkudziesięciu linijek, warto pomyśleć o jego podziale na mniejsze części. Poznajmy więc funkcje. Szybko się przekonamy, że funkcja to bardzo
Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.
Część XXII C++ w Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie. Ćwiczenie 1 1. Utwórz nowy projekt w Dev C++ i zapisz go na
Podstawowe urządzenia peryferyjne mikrokontrolera ATmega8 Spis treści
Podstawowe urządzenia peryferyjne mikrokontrolera ATmega8 Spis treści 1. Konfiguracja pinów2 2. ISP..2 3. I/O Ports..3 4. External Interrupts..4 5. Analog Comparator5 6. Analog-to-Digital Converter.6 7.
Wprowadzenie do podstaw programowania AVR (na przykładzie mikrokontrolera ATmega 16 / 32)
Wprowadzenie do podstaw programowania AVR (na przykładzie mikrokontrolera ATmega 16 / 32) wersja 0.4 (20 kwietnia 2015) Filip A. Sala W niniejszym, bardzo krótkim opracowaniu, postaram się przedstawić
Systemy wbudowane. Uniwersytet Łódzki Wydział Fizyki i Informatyki Stosowanej. Witold Kozłowski
Uniwersytet Łódzki Wydział Fizyki i Informatyki Stosowanej Systemy wbudowane Witold Kozłowski Zakład Fizyki i Technologii Struktur Nanometrowych 90-236 Łódź, Pomorska 149/153 https://std2.phys.uni.lodz.pl/mikroprocesory/
1 Podstawy c++ w pigułce.
1 Podstawy c++ w pigułce. 1.1 Struktura dokumentu. Kod programu c++ jest zwykłym tekstem napisanym w dowolnym edytorze. Plikowi takiemu nadaje się zwykle rozszerzenie.cpp i kompiluje za pomocą kompilatora,
Poradnik programowania procesorów AVR na przykładzie ATMEGA8
Poradnik programowania procesorów AVR na przykładzie ATMEGA8 Wersja 1.0 Tomasz Pachołek 2017-13-03 Opracowanie zawiera opis podstawowych procedur, funkcji, operatorów w języku C dla mikrokontrolerów AVR
Programowanie mikrokontrolerów AVR
Programowanie mikrokontrolerów AVR Czym jest mikrokontroler? Mikrokontroler jest małym komputerem podłączanym do układów elektronicznych. Pamięć RAM/ROM CPU wykonuje program Układy I/O Komunikacje ze światem
Technika Mikroprocesorowa Laboratorium 5 Obsługa klawiatury
Technika Mikroprocesorowa Laboratorium 5 Obsługa klawiatury Cel ćwiczenia: Głównym celem ćwiczenia jest nauczenie się obsługi klawiatury. Klawiatura jest jednym z urządzeń wejściowych i prawie zawsze występuje
Instrukcja do ćwiczeń nr 4 typy i rodzaje zmiennych w języku C dla AVR, oraz ich deklarowanie, oraz podstawowe operatory
Instrukcja do ćwiczeń nr 4 typy i rodzaje zmiennych w języku C dla AVR, oraz ich deklarowanie, oraz podstawowe operatory Poniżej pozwoliłem sobie za cytować za wikipedią definicję zmiennej w informatyce.
Inż. Kamil Kujawski Inż. Krzysztof Krefta. Wykład w ramach zajęć Akademia ETI
Inż. Kamil Kujawski Inż. Krzysztof Krefta Wykład w ramach zajęć Akademia ETI Metody programowania Assembler Język C BASCOM Assembler kod maszynowy Zalety: Najbardziej efektywny Intencje programisty są
Niektóre piny mogą pełnić różne role, zależnie od aktualnej wartości sygnałów sterujących.
Podłączenie mikrokontrolera ATmega8: zasilanie 8 i 22
długo. W tym celu w czasie przeczesywania if (key) {
Kurs AVR lekcja 3 Rozwiązania zadań z ostatniego odcinka Tradycyjnie odcinek zaczynamy od analizy zadania z poprzedniego numeru. Celem było wygenerowanie dźwięku o wysokości zależnej od wciśniętego przycisku.
Instytut Teleinformatyki
Instytut Teleinformatyki Wydział Fizyki, Matematyki i Informatyki Politechnika Krakowska Mikroprocesory i Mikrokontrolery Dostęp do portów mikrokontrolera ATmega32 język C laboratorium: 10 autorzy: dr
Podstawowe urządzenia peryferyjne mikrokontrolera ATmega8 Spis treści
Podstawowe urządzenia peryferyjne mikrokontrolera ATmega8 Spis treści 1. Konfiguracja pinów...2 2. ISP...2 3. I/O Ports...3 4. External Interrupts...4 5. Analog Comparator...5 6. Analog-to-Digital Converter...6
Programowanie mikrokontrolerów. 5 grudnia 2007
Programowanie mikrokontrolerów Marcin Engel Marcin Peczarski 5 grudnia 2007 Przerwania Umożliwiają asynchroniczną obsługę różnych zdarzeń, np.: zmiana stanu wejścia, zakończenie przetwarzania analogowo-cyfrowego,
Architektura systemów komputerowych Laboratorium 14 Symulator SMS32 Implementacja algorytmów
Marcin Stępniak Architektura systemów komputerowych Laboratorium 14 Symulator SMS32 Implementacja algorytmów 1. Informacje Poniższe laboratoria zawierają podsumowanie najważniejszych informacji na temat
Jak zawsze wyjdziemy od terminologii. While oznacza dopóki, podczas gdy. Pętla while jest
Pętle Pętla to pewien fragment kodu, który jest wykonywany wielokrotnie. Wyobraź sobie taką sytuację. Piszesz program do szyfrowania danych. Dane są szyfrowane kolejno bajt po bajcie. Załóżmy, że plik
Warsztaty AVR. Instalacja i konfiguracja środowiska Eclipse dla mikrokontrolerów AVR. Dariusz Wika
Warsztaty AVR Instalacja i konfiguracja środowiska Eclipse dla mikrokontrolerów AVR Dariusz Wika 1.Krótki wstęp: Eclipse to rozbudowane środowisko programistyczne, które dzięki możliwości instalowania
Programowanie mikrokontrolerów AVR z rodziny ATmega.
Programowanie mikrokontrolerów AVR z rodziny ATmega. Materiały pomocnicze Jakub Malewicz jakub.malewicz@pwr.wroc.pl Wszelkie prawa zastrzeżone. Kopiowanie w całości lub w częściach bez zgody i wiedzy autora
/* dołączenie pliku nagłówkowego zawierającego deklaracje symboli dla wykorzystywanego mikrokontrolera */ #include <aduc834.h>
Szablon programu: /* dołączenie pliku nagłówkowego zawierającego deklaracje symboli dla wykorzystywanego mikrokontrolera */ #include /* opcjonalne: deklaracja typów o rozmiarze jednego i dwóch
Po uruchomieniu programu nasza litera zostanie wyświetlona na ekranie
Część X C++ Typ znakowy służy do reprezentacji pojedynczych znaków ASCII, czyli liter, cyfr, znaków przestankowych i innych specjalnych znaków widocznych na naszej klawiaturze (oraz wielu innych, których
Przedrostkowa i przyrostkowa inkrementacja i dekrementacja
Część VIII C++ Przedrostkowa i przyrostkowa inkrementacja i dekrementacja W poprzednim ćwiczeniu operatory inkrementacji i dekrementacji występowały w wersji przyrostkowej. Istnieje inny sposób zapisu
Programowanie w języku C++ Grażyna Koba
Programowanie w języku C++ Grażyna Koba Kilka definicji: Program komputerowy to ciąg instrukcji języka programowania, realizujący dany algorytm. Język programowania to zbiór określonych instrukcji i zasad
Laboratorium 1: Wprowadzenie do środowiska programowego. oraz podstawowe operacje na rejestrach i komórkach pamięci
Laboratorium 1: Wprowadzenie do środowiska programowego oraz podstawowe operacje na rejestrach i komórkach pamięci Zapoznanie się ze środowiskiem programowym: poznanie funkcji asemblera, poznanie funkcji
przedmiot kilka razy, wystarczy kliknąć przycisk Wyczaruj ostatni,
Baltie Zadanie 1. Budowanie W trybie Budowanie wybuduj domek jak na rysunku. Przedmioty do wybudowania domku weź z banku 0. Zadanie 2. Czarowanie sterowanie i powtarzanie W trybie Czarowanie z pomocą czarodzieja
Laboratorium Systemów wbudowanych Wyższa Szkoła Zarządzania i Bankowości, Informatyka studia inżynierskie
Laboratorium Systemów wbudowanych Wyższa Szkoła Zarządzania i Bankowości, Informatyka studia inżynierskie Ćwiczenie nr l Podstawy programowania mikrokontrolerów rodziny AVR8 opracował dr inż. Wojciech
Hardware mikrokontrolera X51
Hardware mikrokontrolera X51 Ryszard J. Barczyński, 2016 Politechnika Gdańska, Wydział FTiMS, Katedra Fizyki Ciała Stałego Materiały dydaktyczne do użytku wewnętrznego Hardware mikrokontrolera X51 (zegar)
Spis treœci. Co to jest mikrokontroler? Kody i liczby stosowane w systemach komputerowych. Podstawowe elementy logiczne
Spis treści 5 Spis treœci Co to jest mikrokontroler? Wprowadzenie... 11 Budowa systemu komputerowego... 12 Wejścia systemu komputerowego... 12 Wyjścia systemu komputerowego... 13 Jednostka centralna (CPU)...
Podstawy programowania skrót z wykładów:
Podstawy programowania skrót z wykładów: // komentarz jednowierszowy. /* */ komentarz wielowierszowy. # include dyrektywa preprocesora, załączająca biblioteki (pliki nagłówkowe). using namespace
Architektura systemów komputerowych Laboratorium 13 Symulator SMS32 Operacje na bitach
Marcin Stępniak Architektura systemów komputerowych Laboratorium 13 Symulator SMS32 Operacje na bitach 1. Informacje Matematyk o nazwisku Bool wymyślił gałąź matematyki do przetwarzania wartości prawda
Programowanie mikrokontrolerów. 3 stycznia 2008
Programowanie mikrokontrolerów Marcin Engel Marcin Peczarski 3 stycznia 2008 Liczniki, cd. Przypomnienie wiadomości o liczniku 0 Przykładowy program korzystający z licznika Ćwiczenia praktyczne Licznik
Podstawy techniki mikroprocesorowej
Podstawy techniki mikroprocesorowej Temat 2 Obsługa wyświetlaczy v.1.0 Uniwersytet Pedagogiczny, Instytut Techniki Dominik Rzepka, dominik.rzepka@agh.edu.pl, 2014 1. Obsługa pinów mikroprocesora i wyświetlacze
Tablice (jedno i wielowymiarowe), łańcuchy znaków
Tablice (jedno i wielowymiarowe), łańcuchy znaków wer. 8 z drobnymi modyfikacjami! Wojciech Myszka Katedra Mechaniki i Inżynierii Materiałowej 2017-04-07 09:35:32 +0200 Zmienne Przypomnienie/podsumowanie
Widoczność zmiennych Czy wartości każdej zmiennej można zmieniać w dowolnym miejscu kodu? Czy można zadeklarować dwie zmienne o takich samych nazwach?
Część XVIII C++ Funkcje Widoczność zmiennych Czy wartości każdej zmiennej można zmieniać w dowolnym miejscu kodu? Czy można zadeklarować dwie zmienne o takich samych nazwach? Umiemy już podzielić nasz
Programowanie i techniki algorytmiczne
Temat 2. Programowanie i techniki algorytmiczne Realizacja podstawy programowej 1) wyjaśnia pojęcie algorytmu, podaje odpowiednie przykłady algorytmów rozwiązywania różnych 2) formułuje ścisły opis prostej
Instytut Teleinformatyki
Instytut Teleinformatyki Wydział Fizyki, Matematyki i Informatyki Politechnika Krakowska Mikroprocesory i mikrokontrolery Przerwania laboratorium: 04 autor: mgr inż. Michał Lankosz dr hab. Zbisław Tabor,
W przeciwnym wypadku wykonaj instrukcję z bloku drugiego. Ćwiczenie 1 utworzyć program dzielący przez siebie dwie liczby
Część XI C++ W folderze nazwisko36 program za każdym razem sprawdza oba warunki co niepotrzebnie obciąża procesor. Ten problem można rozwiązać stosując instrukcje if...else Instrukcja if wykonuje polecenie
Podstawy Programowania C++
Wykład 3 - podstawowe konstrukcje Instytut Automatyki i Robotyki Warszawa, 2014 Wstęp Plan wykładu Struktura programu, instrukcja przypisania, podstawowe typy danych, zapis i odczyt danych, wyrażenia:
7. Pętle for. Przykłady
. Pętle for Przykłady.1. Bez użycia pętli while ani rekurencji, napisz program, który wypisze na ekran kolejne liczby naturalne od 0 do pewnego danego n. 5 int n; 6 cin >> n; 8 for (int i = 0; i
Pętle. Dodał Administrator niedziela, 14 marzec :27
Pętlami nazywamy konstrukcje języka, które pozwalają na wielokrotne wykonywanie powtarzających się instrukcji. Przykładowo, jeśli trzeba 10 razy wyświetlić na ekranie pewien napis, to można wykorzystać
1 Podstawy c++ w pigułce.
1 Podstawy c++ w pigułce. 1.1 Struktura dokumentu. Kod programu c++ jest zwykłym tekstem napisanym w dowolnym edytorze. Plikowi takiemu nadaje się zwykle rozszerzenie.cpp i kompiluje za pomocą kompilatora,
Zestaw Edukacyjny Atmega-8 (AJAWe-0711) Porty wejścia-wyjścia.
Zestaw Edukacyjny Atmega-8 (AJAWe-0711) LEKCJA 4 Porty wejścia-wyjścia W poprzedniej lekcji napisaliśmy pierwszy program, który zapalił nam jedną diodę led Teraz omówimy szczegółowo działanie niniejszego
Programowanie mikrokontrolerów AVR z rodziny ATmega.
Programowanie mikrokontrolerów AVR z rodziny ATmega. Materiały pomocnicze Jakub Malewicz jakub.malewicz@pwr.wroc.pl Wszelkie prawa zastrzeżone. Kopiowanie w całości lub w częściach bez zgody i wiedzy autora
Nazwa implementacji: Nauka języka Python wyrażenia warunkowe. Autor: Piotr Fiorek. Opis implementacji: Poznanie wyrażeń warunkowych if elif - else.
Nazwa implementacji: Nauka języka Python wyrażenia warunkowe Autor: Piotr Fiorek Opis implementacji: Poznanie wyrażeń warunkowych if elif - else. Nasz kalkulator umie już liczyć, ale potrafi przeprowadzać
Mikrokontroler ATmega32. Język symboliczny
Mikrokontroler ATmega32 Język symboliczny 1 Język symboliczny (asembler) jest językiem niskiego poziomu - pozwala pisać programy złożone z instrukcji procesora. Kody instrukcji są reprezentowane nazwami
SYSTEM PRZERWAŃ ATmega 32
Zachodniopomorski Uniwersytet Technologiczny WYDZIAŁ ELEKTRYCZNY Katedra Inżynierii Systemów, Sygnałów i Elektroniki LABORATORIUM TECHNIKA MIKROPROCESOROWA SYSTEM PRZERWAŃ ATmega 32 Opracował: mgr inż.
1. Operacje logiczne A B A OR B
1. Operacje logiczne OR Operacje logiczne są operacjami działającymi na poszczególnych bitach, dzięki czemu można je całkowicie opisać przedstawiając jak oddziałują ze sobą dwa bity. Takie operacje logiczne
Warto też w tym miejscu powiedzieć, że w C zero jest rozpoznawane jako fałsz, a wszystkie pozostałe wartości jako prawda.
Nazwa implementacji: Nauka języka C wyrażenia warunkowe if- Autor: Piotr Fiorek Opis implementacji: Poznanie struktury oraz zastosowania wyrażeń warunkowych if- w języku C. W programie realizującym jakiś
PMiK Programowanie Mikrokontrolera 8051
PMiK Programowanie Mikrokontrolera 8051 Wykład 3 Mikrokontroler 8051 PMiK Programowanie mikrokontrolera 8051 - wykład S. Szostak (2006) Zmienna typu bit #define YES 1 // definicja stałych #define NO 0
LABORATORIUM. TIMERY w mikrokontrolerach Atmega16-32
Zachodniopomorski Uniwersytet Technologiczny WYDZIAŁ ELEKTRYCZNY Katedra Inżynierii Systemów, Sygnałów i Elektroniki LABORATORIUM TECHNIKA MIKROPROCESOROWA TIMERY w mikrokontrolerach Atmega16-32 Opracował:
Zmienne, stałe i operatory
Zmienne, stałe i operatory Przemysław Gawroński D-10, p. 234 Wykład 2 4 marca 2019 (Wykład 2) Zmienne, stałe i operatory 4 marca 2019 1 / 21 Outline 1 Zmienne 2 Stałe 3 Operatory (Wykład 2) Zmienne, stałe
Komunikacja w mikrokontrolerach Laboratorium
Laboratorium Ćwiczenie 1 Podstawy programowania, stany uśpienia Program ćwiczenia: zapoznanie z regulaminem laboratorium i zasadami zaliczenia, zapoznanie ze sprzętem laboratoryjnym i oprogramowaniem,
XMEGA. Warsztaty CHIP Rok akademicki 2014/2015
XMEGA Warsztaty CHIP Rok akademicki 2014/2015 Plan warsztatów: Wprowadzenie do Atmel Studio (20/11/2014) Porty I/O (20/11/2014) Przerwania (27/11/2014) Wykorzystana literatura: [1] Dokumentacja ATMEL(www.atmel.com):
Programowanie mikrokontrolerów 2.0
13.1 Programowanie mikrokontrolerów 2.0 Sterowanie fazowe Marcin Engel Marcin Peczarski Instytut Informatyki Uniwersytetu Warszawskiego 19 grudnia 2016 Triak Triak jest półprzewodnikowym elementem przełączającym
LICZNIKI LABORATORIUM. Elektronika AKADEMIA GÓRNICZO-HUTNICZA IM. STANISŁAWA STASZICA W KRAKOWIE. Wydział Informatyki, Elektroniki i Telekomunikacji
AKADEMIA GÓRNICZO-HUTNICZA IM. STANISŁAWA STASZICA W KRAKOWIE Wydział Informatyki, Elektroniki i Telekomunikacji Katedra Elektroniki LABORATORIUM Elektronika LICZNIKI Rev.1.0 1. Wprowadzenie Celem ćwiczenia
JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6
JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM Wykład 6 1 SPECYFIKATOR static Specyfikator static: Specyfikator ten powoduje, że zmienna lokalna definiowana w obrębie danej funkcji nie jest niszczona
Informatyka I: Instrukcja 4.2
Informatyka I: Instrukcja 4.2 1 Wskaźniki i referencje - bezboleśnie Nauczyliśmy się do tej pory, że funkcje w języku C mogą zwracać wartość. Co jednak, gdybyśmy chcieli napisać funkcję, która rozwiąże
LABORATORIUM. TIMERY w mikrokontrolerach Atmega16-32
Zachodniopomorski Uniwersytet Technologiczny WYDZIAŁ ELEKTRYCZNY Katedra Inżynierii Systemów, Sygnałów i Elektroniki LABORATORIUM TECHNIKA MIKROPROCESOROWA TIMERY w mikrokontrolerach Atmega16-32 Opracował:
Część XV C++ Ćwiczenie 1
Część XV C++ Instrukcja break przerywa działanie tylko tej pętli, w ciele której została wywołana. Jeśli więc wywołamy break w pętli zagnieżdżonej w innej pętli, zostanie przerwane działanie tylko tej
Architektura Systemów Komputerowych, Wydział Informatyki, ZUT
Laboratorium: Wprowadzenie Pojęcia. Wprowadzone zostaną podstawowe pojęcia i mechanizmy związane z programowaniem w asemblerze. Dowiemy się co to są rejestry i jak z nich korzystać. Rejestry to są wewnętrzne
Informatyka II. Laboratorium Aplikacja okienkowa
Informatyka II Laboratorium Aplikacja okienkowa Założenia Program będzie obliczał obwód oraz pole trójkąta na podstawie podanych zmiennych. Użytkownik będzie poproszony o podanie długości boków trójkąta.
Wyświetlacz alfanumeryczny LCD zbudowany na sterowniku HD44780
Dane techniczne : Wyświetlacz alfanumeryczny LCD zbudowany na sterowniku HD44780 a) wielkość bufora znaków (DD RAM): 80 znaków (80 bajtów) b) możliwość sterowania (czyli podawania kodów znaków) za pomocą
Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Ćwiczenie 3 stos Laboratorium Metod i Języków Programowania
Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych Ćwiczenie 3 stos Laboratorium Metod i Języków Programowania Celem ćwiczenia jest zapoznanie studentów z najprostszą dynamiczną strukturą
Instrukcja do ćwiczenia P4 Analiza semantyczna i generowanie kodu Język: Ada
Instrukcja do ćwiczenia P4 Analiza semantyczna i generowanie kodu Język: Ada Spis treści 1 Wprowadzenie 1 2 Dane i kod 2 3 Wyrażenia 2 3.1 Operacje arytmetyczne i logiczne.................. 2 3.2 Podstawowe
Praktycznie całe zamieszanie dotyczące konwencji wywoływania funkcji kręci się w okół wskaźnika stosu.
Krótki artykuł opisujący trzy podstawowe konwencje wywoływania funkcji C++ (a jest ich więcej). Konwencje wywoływania funkcji nie są tematem, na który można się szeroko rozpisać, jednak należy znać i odróżniać
Programowanie w języku Python. Grażyna Koba
Programowanie w języku Python Grażyna Koba Kilka definicji Program komputerowy to ciąg instrukcji języka programowania, realizujący dany algorytm. Język programowania to zbiór określonych instrukcji i
3. Instrukcje warunkowe
. Instrukcje warunkowe Przykłady.1. Napisz program, który pobierze od użytkownika liczbę i wypisze na ekran słowo ujemna lub nieujemna, w zależności od tego czy dana liczba jest ujemna czy nie. 1 #include
Adresowanie obiektów. Adresowanie bitów. Adresowanie bajtów i słów. Adresowanie bajtów i słów. Adresowanie timerów i liczników. Adresowanie timerów
Adresowanie obiektów Bit - stan pojedynczego sygnału - wejście lub wyjście dyskretne, bit pamięci Bajt - 8 bitów - wartość od -128 do +127 Słowo - 16 bitów - wartość od -32768 do 32767 -wejście lub wyjście
W dowolnym momencie można zmienić typ wskaźnika.
c++ Wskaźniki mają jeszcze jedną przydatną cechę. W dowolnym momencie można zmienić typ wskaźnika. Robi się to za pomocą operatora rzutowania. Najpierw zdefiniujemy sobie wsk_uniwersalny mogący pokazywać
Organizacja pamięci VRAM monitora znakowego. 1. Tryb pracy automatycznej
Struktura stanowiska laboratoryjnego Na rysunku 1.1 pokazano strukturę stanowiska laboratoryjnego Z80 z interfejsem częstościomierza- czasomierz PFL 21/22. Rys.1.1. Struktura stanowiska. Interfejs częstościomierza
MIERNIK T-SCALE BWS 1
MIERNIK T-SCALE BWS 1 2 Spis treści 1. WSTĘP... 4 2. OPIS KLAWIATURY... 4 3. PODSTAWOWE OPERACJE... 5 Zerowanie... 5 Tarowanie... 5 Ważenie przedmiotu... 5 4. WAŻENIE KONTROLNE... 6 Ustawianie limitów...
2. Architektura mikrokontrolerów PIC16F8x... 13
Spis treści 3 Spis treœci 1. Informacje wstępne... 9 2. Architektura mikrokontrolerów PIC16F8x... 13 2.1. Budowa wewnętrzna mikrokontrolerów PIC16F8x... 14 2.2. Napięcie zasilania... 17 2.3. Generator
1 Moduł Neuronu Cyfrowego
1 Moduł Neuronu Cyfrowego Moduł Neuronu Cyfrowego daje użytkownikowi Systemu Vision możliwość obsługi fizycznych Neuronów Cyfrowych. Dzięki temu możliwe jest sterowanie zewnętrznymi urządzeniami wykonawczymi
SYSTEMY OPERACYJNE I SIECI KOMPUTEROWE
SYSTEMY OPERACYJNE I SIECI KOMPUTEROWE WINDOWS 1 SO i SK/WIN 006 Wydajność systemu 2 SO i SK/WIN Najprostszym sposobem na poprawienie wydajności systemu, jeżeli dysponujemy zbyt małą ilością pamięci RAM
Instytut Teleinformatyki
Instytut Teleinformatyki Wydział Fizyki, Matematyki i Informatyki Politechnika Krakowska Mikroprocesory i Mikrokontrolery System przerwań laboratorium: 11 autorzy: dr hab. Zbisław Tabor, prof. PK mgr inż.
Ustawienia ogólne. Ustawienia okólne są dostępne w panelu głównym programu System Sensor, po kliknięciu ikony
Ustawienia ogólne Ustawienia okólne są dostępne w panelu głównym programu System Sensor, po kliknięciu ikony Panel główny programu System Sensor (tylko dla wersja V2, V3, V4) Panel główny programu System
INSTRUKCJA OBSŁUGI. Przekaźnik czasowy ETM ELEKTROTECH Dzierżoniów. 1. Zastosowanie
INSTRUKCJA OBSŁUGI 1. Zastosowanie Przekaźnik czasowy ETM jest zadajnikiem czasowym przystosowanym jest do współpracy z prostownikami galwanizerskimi. Pozwala on załączyć prostownik w stan pracy na zadany
Uproszczony schemat blokowy zespołu 8-bitowego timera przedstawiono na rys.1
Dodatek C 1. Timer 8-bitowy (Timer0) 1.1. Opis układu Uproszczony schemat blokowy zespołu 8-bitowego timera przedstawiono na rys.1 Rys. 1. Schemat blokowy timera Źródłem sygnału taktującego może być zegar
Niezwykłe tablice Poznane typy danych pozwalają przechowywać pojedyncze liczby. Dzięki tablicom zgromadzimy wiele wartości w jednym miejscu.
Część XIX C++ w Każda poznana do tej pory zmienna może przechowywać jedną liczbę. Jeśli zaczniemy pisać bardziej rozbudowane programy, okaże się to niewystarczające. Warto więc poznać zmienne, które mogą
Struktura i działanie jednostki centralnej
Struktura i działanie jednostki centralnej ALU Jednostka sterująca Rejestry Zadania procesora: Pobieranie rozkazów; Interpretowanie rozkazów; Pobieranie danych Przetwarzanie danych Zapisywanie danych magistrala
PODSTAWY INFORMATYKI 1 PRACOWNIA NR 6
PODSTAWY INFORMATYKI 1 PRACOWNIA NR 6 TEMAT: Programowanie w języku C/C++: instrukcje iteracyjne for, while, do while Ogólna postać instrukcji for for (wyr1; wyr2; wyr3) Instrukcja for twory pętlę działającą
Liczby losowe i pętla while w języku Python
Liczby losowe i pętla while w języku Python Mateusz Miotk 17 stycznia 2017 Instytut Informatyki UG 1 Generowanie liczb losowych Na ogół programy są spójne i prowadzą do przewidywanych wyników. Czasem jednak
Wykład 8: klasy cz. 4
Programowanie obiektowe Wykład 8: klasy cz. 4 Dynamiczne tworzenie obiektów klas Składniki statyczne klas Konstruktor i destruktory c.d. 1 dr Artur Bartoszewski - Programowanie obiektowe, sem. 1I- WYKŁAD
Uwagi dotyczące notacji kodu! Moduły. Struktura modułu. Procedury. Opcje modułu (niektóre)
Uwagi dotyczące notacji kodu! Wyrazy drukiem prostym -- słowami języka VBA. Wyrazy drukiem pochyłym -- inne fragmenty kodu. Wyrazy w [nawiasach kwadratowych] opcjonalne fragmenty kodu (mogą być, ale nie
Podstawy programowania, Poniedziałek , 8-10 Projekt, część 1
Podstawy programowania, Poniedziałek 30.05.2016, 8-10 Projekt, część 1 1. Zadanie Projekt polega na stworzeniu logicznej gry komputerowej działającej w trybie tekstowym o nazwie Minefield. 2. Cele Celem
Systemy wbudowane. Uniwersytet Łódzki Wydział Fizyki i Informatyki Stosowanej. Witold Kozłowski
Uniwersytet Łódzki Wydział Fizyki i Informatyki Stosowanej Systemy wbudowane Witold Kozłowski Zakład Fizyki i Technologii Struktur Nanometrowych 90-236 Łódź, Pomorska 149/153 https://std2.phys.uni.lodz.pl/mikroprocesory/
ZASOBY ZMIENNYCH W STEROWNIKACH SAIA-BURGESS
ZASOBY ZMIENNYCH W STEROWNIKACH SAIA-BURGESS Autorzy Wydanie Data : : : Zespół SABUR Sp. z o.o. 3.00 Sierpień 2013 2013 SABUR Sp. z o. o. Wszelkie prawa zastrzeżone Bez pisemnej zgody firmy SABUR Sp. z
3. Sieć PLAN. 3.1 Adresowanie płyt głównych regulatora pco
3. Sieć PLAN Wszystkie urządzenia podłączone do sieci plan są identyfikowane za pomocą swoich adresów. Ponieważ terminale użytkownika i płyty główne pco wykorzystują ten sam rodzaj adresów, nie mogą posiadać
ĆWICZENIE 5. TEMAT: OBSŁUGA PORTU SZEREGOWEGO W PAKIECIE KEILuVISON WYSYŁANIE PORTEM SZEREGOWYM
ĆWICZENIE 5 TEMAT: OBSŁUGA PORTU SZEREGOWEGO W PAKIECIE KEILuVISON WYSYŁANIE PORTEM SZEREGOWYM Wiadomości wstępne: Port szeregowy może pracować w czterech trybach. Tryby różnią się między sobą liczbą bitów
Wstęp do Programowania, laboratorium 02
Wstęp do Programowania, laboratorium 02 Zadanie 1. Napisać program pobierający dwie liczby całkowite i wypisujący na ekran największą z nich. Zadanie 2. Napisać program pobierający trzy liczby całkowite
1. Cel ćwiczenia. 2. Podłączenia urządzeń zewnętrznych w sterowniku VersaMax Micro
1. Cel ćwiczenia Celem ćwiczenia jest zaprojektowanie sterowania układem pozycjonowania z wykorzystaniem sterownika VersaMax Micro oraz silnika krokowego. Do algorytmu pozycjonowania wykorzystać licznik
Wskaźniki w C. Anna Gogolińska
Wskaźniki w C Anna Gogolińska Zmienne Zmienną w C można traktować jako obszar w pamięci etykietowany nazwą zmiennej i zawierający jej wartość. Przykład: kod graficznie int a; a a = 3; a 3 Wskaźniki Wskaźnik
Notatka lekcja_#3_1; na podstawie W.Kapica 2017 Strona 1
Na poprzednich zajęciach zajmowaliśmy się odczytywaniem sygnałów cyfrowych. Dzięki temu mogliśmy np.: sprawdzić, czy przycisk został wciśnięty. Świat, który nas otacza nie jest jednak cyfrowy, czasami
Część XVII C++ Funkcje. Funkcja bezargumentowa Najprostszym przypadkiem funkcji jest jej wersja bezargumentowa. Spójrzmy na przykład.
Część XVII C++ Funkcje Funkcja bezargumentowa Najprostszym przypadkiem funkcji jest jej wersja bezargumentowa. Spójrzmy na przykład. 2 3 Tworzymy deklarację i definicję funkcji o nazwie pobierzln() Funkcja
Podstawy programowania w języku C i C++
Podstawy programowania w języku C i C++ Część czwarta Operatory i wyrażenia Autor Roman Simiński Kontakt roman.siminski@us.edu.pl www.us.edu.pl/~siminski Niniejsze opracowanie zawiera skrót treści wykładu,
Java pierwszy program w Eclipse «Grzegorz Góralski strona własna
Strona 1 z 9 «Przykładowe zadania do cz. III ćwiczeń z genetyki Java pierwsze kroki w programowaniu (01)» Kategoria: java, Tagi: eclipse - java - programowanie. Autor: Grzegorz, napisał dnia: February
Lista instrukcji mikroprocesora 8086. Programowanie w assemblerze
Lista instrukcji mikroprocesora 8086 Programowanie w assemblerze Lista instrukcji mikroprocesora 8086 Lista instrukcji mikroprocesora 8086 Lista instrukcji mikroprocesora 8086 Lista instrukcji mikroprocesora
Parametryzacja przetworników analogowocyfrowych
Parametryzacja przetworników analogowocyfrowych wersja: 05.2015 1. Cel ćwiczenia Celem ćwiczenia jest zaprezentowanie istoty działania przetworników analogowo-cyfrowych (ADC analog-to-digital converter),