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

Wybór języka do programowania AVR dla początkującego z TurboPascalem

piotrekhbn 21 Kwi 2008 00:59 3033 24
REKLAMA
  • #1 5059589
    piotrekhbn
    Poziom 11  
    Posty: 73
    Ocena: 2
    Witam, uczę się w 1 klasie technikum informatycznym. Uczymy się tam TurboPascala. Chciałbym zacząć uczyć się programować Avr. Np. napisać program który po złączeniu danych pinów w układzie oddtworzy dźwięk Wave albo podobny. Głównie chodzi mi właśnie o takie rzeczy z avr. Jaki język polecilibyście mi, żeby był w miarę podobny do tp a który podołałby moim oczekiwaniom?
  • REKLAMA
  • #2 5059627
    qrdel
    Poziom 28  
    Posty: 1074
    Pomógł: 100
    Ocena: 71
    Najmodniejszy jest C++ i zwykle środowiska do procków dopuszczają przełączanie między C i C++.
    C jest wpowiedzmy podstawowej warstwie podobny do pascala, zmieniają się głównie słowa kluczowe.
    Pod pascala trudno znaleźć środowisko dla procków.
    Trenuj C i C++ i spróbuj nie zwariować. A TP też się przydaje ze względów dydaktycznych.
  • REKLAMA
  • #3 5059645
    JmL(TM)
    Poziom 24  
    Posty: 804
    Pomógł: 44
    Ocena: 12
    C++ RULEZ! ;)

    Pozostaje jeszcze asm ale... no wlasnie ALE!
  • #4 5059722
    lord_dagoth
    Poziom 25  
    Posty: 860
    Pomógł: 68
    Ocena: 6
    Również polecam Ci C++, sam w nim programuje od dawna (na PC'ta) i od niedawna na AVR (przynajmniej próbuje stawiać pierwsze kroki:P).

    TP może dobry będzie na sam początek (ja również od niego zaczynałem), ale potem to raczej szybko go porzucisz na rzecz bardziej "uniwersalnych" języków, jak właśnie C++. Tylko teraz pozostaje pytanie, czy chcesz bawić się tylko i wyłącznie w programowanie uC czy również w pisanie aplikacji na PC? Bo jeżeli to i to, to C++ będzie dla Ciebie najlepszy.
  • #5 5060951
    piotrekhbn
    Poziom 11  
    Posty: 73
    Ocena: 2
    Od dawna mi się marzyło programowanie uC , więc C czy C++?
  • #6 5060997
    bbxb
    Poziom 31  
    Posty: 2271
    Pomógł: 147
    Ocena: 94
    Zaawansowani programiści uP piszą w C.
    Ale w Twoim przypadku dużo lepszym wyborem będzie C++.
  • #7 5061048
    piotrekhbn
    Poziom 11  
    Posty: 73
    Ocena: 2
    A który jak na początek po TP jest prostrzy w obsłudze, a można już się nim pobawić w avr?

    A mógłby ktoś napisać w C++ i w C program który np. powoduje naprzemienne miganie Ledów. Wtedy byłoby porównanie:)
  • #8 5061327
    Stepel
    Poziom 20  
    Posty: 490
    Pomógł: 26
    Ocena: 28
    Najprostszy dla Ciebie byłby BASCOM... ale ten język często spotyka się z krytyką "zaawansowanych" programistów uC.
  • REKLAMA
  • #9 5061720
    lord_dagoth
    Poziom 25  
    Posty: 860
    Pomógł: 68
    Ocena: 6
    Mi również się wydaje, że tak na pierwszy kontakt z programowaniem uC (nie znając wcześniej C) lepszy byłby bascom, łagodniej wprowadzi w zmianę hmmm... "architektury".
  • #10 5061741
    JmL(TM)
    Poziom 24  
    Posty: 804
    Pomógł: 44
    Ocena: 12
    Stepel napisał:
    Najprostszy dla Ciebie byłby BASCOM... ale ten język często spotyka się z krytyką "zaawansowanych" programistów uC.


    Wszyscy krytykuja ten jezyk a nasze rodzime gazety elektroniczne "Elektronika Praktyczna" i "Elektronika Dla Wszystkich" lubuja sie wlasnie w tym jezyku... ;)
  • #11 5061976
    piotrekhbn
    Poziom 11  
    Posty: 73
    Ocena: 2
    Czyli już sam nie wiem, jak wyglądałaby przesiadka z tp na bascom albo C++. Co do możliwości to który z tych języków ma większe zachowując łatwość pisania?
  • #12 5062081
    lord_dagoth
    Poziom 25  
    Posty: 860
    Pomógł: 68
    Ocena: 6
    Największe możliwości (bo nie tylko programowanie uC wchodzi w potęgę tego języka, ae również programowanie aplikacji na pc'ta) i największą wydajność (nie licząc ASM) ma C++
  • #13 5063191
    piotrekhbn
    Poziom 11  
    Posty: 73
    Ocena: 2
    A jak to jest z poziomem trudności? Wiecie ja dopiero się uczę tp, ciężko będzie zacząć 2 język ale chcę avr się nauczyć programować już tak odkąd miałem z 10 lat:)
  • #14 5063256
    JmL(TM)
    Poziom 24  
    Posty: 804
    Pomógł: 44
    Ocena: 12
    piotrekhbn napisał:
    A jak to jest z poziomem trudności? Wiecie ja dopiero się uczę tp, ciężko będzie zacząć 2 język ale chcę avr się nauczyć programować już tak odkąd miałem z 10 lat:)


    To ile masz teraz lat? ;)
    Nie bedzie tak ciezko z drugim jezykiem bo juz poznasz jeden jezyk to kazdy nastepny przychodzi latwiej i latwiej az w koncu wychodzi ze znasz ich szesc albo nawet siedem w sumie ;)
  • #15 5063300
    shg
    Poziom 35  
    Posty: 2289
    Pomógł: 339
    Ocena: 135
    Żeby pisać na mikrokontrolery w C++ trzeba znać ten język bardzo dobrze. Niestety mikrokontroler to nie PC i nie "wybacza" nieprzemyślanych konstrukcji, które kończą się alokacją ogromnych ilości pamięci. Tak konkretniej to chodzi mi o nieprzemyślane używanie klas.

    C na mikrokontrolery jest znacznie łatwiejszy.

    piotrekhbn napisał:
    A mógłby ktoś napisać w C++ i w C program który np. powoduje naprzemienne miganie Ledów. Wtedy byłoby porównanie:)

    Kod wygląda mniej więcej tak samo i raczej jest w języku C. Nie ma sensu na siłę pchać mechanizmów z C++ tam gdzie nie są potrzebne, więc jeżeli chodzi o porównanie języków jest to kiepski przykład.

    W skrócie:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    /* procedura obsługi przerwania przy przepełnieniu timera 0 */
    ISR(TIMER0_OVF_vect) {
    	PORTB ^= _BV(PB4);
    }
    
    int main(void) {
    
    /* ustawienie kierunku i początkowych wartości na portach I/O dla ATmega8 */
    	PORTB = 0xff & ~_BV(PB4);
    	PORTC = 0xff;
    	PORTD = 0xff;
    	DDRB |= _BV(PB4);
    
    /* konfiguracja timera */
    	TIMSK |= _BV(TOIE0); /* przerwanie */
    	TCCR0 = _BV(CS02) | _BV(CS00); /* preskaler i uruchomienie */
    
    /* globalne włączenie przerwań */
    	sei();
    
    	while(1) {
    		/* główna pętla programu */
    	}
    	
    }


    Bardziej rozwlekle:

    Definicje rejestrów itp. dla danego procesora. Typ procesora podaje się przy kompilacji jako jeden z argumentów gcc, innym sposobem jest skorzystanie z gotowego szablonu makefile dostarczanego razem a WinAVR, gdzie wpisuje sie typ w odpowiednią linijkę, w AVR Studio po zainstalowaniu WinAVR też można pisać w C i tam typ procesora i inne "bajery" wklepuje sięw odpowiednie okna dialogowe.
    #include <avr/io.h>

    Makra do definiowania wektorów przerwań:
    #include <avr/interrupt.h>


    Główna procedura:
    int main(void) {

    Na początek wypadało by ustawić kierunek portu, a konkretniej pinu
    do pracy jako wyjście. Służą do tego rejestry DDRx, gdzie x to litera portu (A, B, C itd.) Każdy bit w tym ośmiobitowym rejestrze odpowiada jednej linii danego portu. Makro _BV(x), to po prostu (1 << (x)), BV jak Bit Value, czyli wartość bitu. w <avr/io.h> bity pełniące w rejestrach różne funkcje zdefiniowane są w postaci ich numeru, a nie wartości, stąd konieczność "konwersji" numeru bitu na jego wartość (wagę). Na przykład bity odnoszące się do poszczególnych pinów portów I/O zdefiniowane są jako Px0, Px1, Px2, Px3 itd., ich wartości to odpowiednio 0, 1, 2, 3, a po podaniu ich jako argumentów do makra _BV() dostaniemy odpowiednio 1, 2, 4, 8 itd. Na rejestrze DDRB wykonujemy sumę logiczną, rezultat będzie taki, że bit 4 zostanie ustawiony (ale to już nie programowanie, a algebra Boole'a).

    DDRB |= _BV(PB4);


    Na początek zgasimy LEDa, przy założeniu, że anoda połączona jest z pinem PB4, a katoda z masą i oczywiście gdzieś tam szeregowy rezystor żeby ograniczyć wartość prądu. Rejestr PORTx to rejestr wyjściowy, za jego pomocą ustala się stan na porcie pracującym jako wyjście. Do odczytywania z portu służy rejestr PINx, o czym należy pamiętać. Dla portów pracujących jako wejście zapis do rejestru PORTx służy do włączenia / wyłączenia podciągania odpowiednich linii portu do plusa zasilania (przez "rezystory" o wartości rzędu chyba 30kohm). Tutaj liczymy wartość bitu: 1 << 4 = 16 (binarnie 00010000), wykonujemy negację (binarnie: 11101111), wykonujemy operację iloczynu logicznego (AND) na porcie B, czyli wszystko zostaje bez zmian, oprócz bitu 4, który zostanie wyzerowany. O ile włączona będzie optymalizacja kodu, to procesor w tym wypadku nie wykona operacji AND, tylko zoptymalizuje to do pojedynczej (szybszej) instrukcji CBI służącej właśnie do zerowania pojedynczych bitów.

    PORTB &= ~_BV(PB4);


    Powyższe operacje można i nawet czasem powinno się wykonać w odwrotnej kolejności. Nieużywane piny należy ponadto skonfigurować tak, żeby nie pojawiały się na nich nieprzewidziane stany, czy napięcia pośrednie między stanem 0 a 1. Przyczynia się to przede wszystkim do zmniejszenia poboru prądu. Założenie jest takie, że po włączeniu zasilania wszystkie porty skonfigurowane są do pracy jako wejście, najprościej i najbezpieczniej będzie włączyć na tych portach "rezystory" podciągające (tak na prawdę są to tranzystory polowe). Żeby było jeszcze prościej, to włączymy pull-upy na całym porcie na raz. Załóżmy, że to ATmega8, która ma porty B, C i D. Nieważne, że części z tych pinów fizycznie nie ma, albo są im przypisane inne funkcje (/RESET, generator kwarcowy), nic się nie stanie.

    PORTB = 0xff;
    PORTC = 0xff;
    PORTD = 0xff;


    Oczywiście ustawianie zera na pinie PB4 w poprzedniej operacji traci sens. Ale chciałem takie łagodniejsze wprowadzenie zrobić, kolejność wszystkich dotychczasowych operacji powinna zatem wyglądać tak:

    PORTB = 0xff;
    PORTC = 0xff;
    PORTD = 0xff;
    DDRB |= _BV(PB4);
    PORTB &= ~_BV(PB4);


    Albo nawet tak:

    PORTB = 0xff & ~_BV(PB4);
    PORTC = 0xff;
    PORTD = 0xff;
    DDRB |= _BV(PB4);



    Teraz pora na konfigurację timera.
    Timery pracują niezależnie od rdzenia uC, więc doskonale nadają się do odmierzania czasu, albo wykonywania jakiejś operacji w ściśle ustalonych odstępach czasu. Ta ostatnia opcja najbardziej nas interesuje.

    Krótko o timerach w AVR.
    Timery taktowane są przez preskaler (dzielnik częstotliwości), który z kolei taktowany jest przez główny zegar (niektóre AVRy mają dodatkowy zegar do timerów). Uruchomienie i zatrzymanie timera sprowadza się do zapisu odpowiedniej wartości do preskalera 0 - zatrzymany, inne wartości - pracuje z wybranym stopniem podziału. Timer zlicza od zera w górę do wartości TOP. W najprostszym przypadku TOP = 255 dla timerów ośmiobitowych i 65535 dla szesnastobitowych. Są też inne możliwości, ale odsyłam do noty katalogowej. Po osiągnięciu wartości ustawiana jest flaga przerwania i timer rozpoczyna znowu zaczyna zliczać od zera. (również w tym wypadku są inne możliwości).

    Wybieramy sobie timer 0, żadne cuda oferowane przez inne timery nie są potrzebne. Timery i wszystkie inne peryferia konfiguruje się przez zapis odpowiednich wartości do odpowiednich rejestrów, jakie to wartości i jakie rejestry - patrz nota katalogowa. Nazwy rejestrów i bitów w WinAVR są takie same jak w nowych(!) notach katalogowych. W razie problemów z językiem angielskim na elektrodzie jest gdzieś nota ATmegi32 po polsku. Wszystkie AVRy są podobne, więc nie powinno być problemów.
    Timer 0 w ATmega8 nie ma praktycznie żadnych bajerów. Jedyne co trzeba skonfigurować, to włączyć przerwanie i ustawić preskaler. Rejestr TIMSK jest wspólny dla trzech timerów i służy do włączania przerwań generowanych przez różne zdarzenia związane z timerami (nie tylko przepełnienie, jak tutaj)

    Albo robimy tak jak poniżej, nie ruszając ustawień innych przerwań (po resecie są wyłączone), albo po prostu przypisujemy tą wartość do TIMSK

    TIMSK |= _BV(TOIE0);


    Przerwanie już włączone, teraz trzeba tylko wybrać wartość preskalera jednocześnie uruchamiając timer. Dla zegara 1MHz sam timer (preskaler = 1) podzieli tą częstotliwość przez 256, bo co 256 kroków będzie się przepełniał i generował przerwanie. 1MHz / 1 / 256 = 3.9kHz, zdecydowanie za dużo jak na migającą diodę. Największa dostępna wartość preskalera to 1024. Więc: 1MHz / 1024 / 256 = 3.815Hz, lepiej, czyli średnio mniej więcej 3.815 raza na sekundę będzie wywoływane przerwanie. Miganie z taką częstotliwością da się już bez problemów zobaczyć, a będzie wolniej, ale o tym zaraz.

    Za ustawienia preskalera odpowiedzialne są bity CS0x w rejestrze kontrolnym timera (TCCR0) wartości preskalera 1024 odpowiadają ustawione bity CS02 i CS00 (w nocie katalogowej jest tabelka).

    TCCR0 = _BV(CS02) | _BV(CS00);


    Od tego momentu timer zaczyna pracować, no ale co z tego, skoro jeszcze nie ma kodu, który będzie przerwania obsługiwał? Mało tego, żadne przerwanie nie będą obsługiwane dopóki nie ustawi się globalnej flagi uaktywniającej tą funkcjonalność. Flaga ta to bit I w rejestrze stanu (SREG) procesora. Jest do tego odpowiednia instrukcja (SEI), z poziomu C wywoływana jako makro:



    Przy okazji, do globalnego wyłączenia przerwań służy cli();.

    I to by było na tyle konfiguracji. Teraz główna pętla programu może się "kręcić" w nieskończoność wykonując jakiś kod, a od czasu do czasu zostanie przerwana i wywołana zostanie procedura obsługi przerwania.



    Do definicji procedury obsługi przerwania służy makro ISR() z <avr/interrupt.h> Jako argument podaje się nazwę wektora przerwania, wszystkie dostępne dla danego procesora wymienione są między innymi w dokumentacji avr-libc (instaluje się razem z WinAVR). Do wyboru jest kilka wariantów. Najważniejsze, bo najczęściej stosowane to przerwania bez zagnieżdżenia (tzn. takie, które nie mogą być przerwane przez inne przerwania).
    Definiuje się je w ten sposób:

    ISR(TIMER0_OVF_vect) {
    /* Kod tutaj umieszczony będzie wykonywany przy każdym przepełnieniu licznika timera 0,
    ** o ile oczywiście odpowiednie flagi przerwań zostały ustawione.
    */
    }

    Najprostszym sposobem na zrobienie migającego LEDa będzie zmiana stanu pinu na przeciwny. Można to zrobić za pomocą operatora różnicy symetrycznej (Exclusive-OR). Pobrany zostanie stan rejestru PORTB i na nim wykonana operacja EOR (czy XOR, jak kto woli) z wartością odpowiadającą wybranemu pinowi.
    Do odczytu stanu linii portu, jak już wcześniej pisałem służy rejestr PINx, ale tu odczytamy wartość z rejestru PORTx, bo można i tak. Różnica jest taka, że jak zewrze się drutem pin procesora do masy i ustawi na tym pinie stan wysoki (zapisując odpowiednią wartość do rejestru PORTx), to z rejestru PIN odczyta się wartość logiczną jaka fizycznie na pinie jest, czyli zero, natomiast z rejestru PORT odczyta się wartość, jaka została tam zapisana, czyli 1. Oczywiście taka operacja spowoduje uszkodzenie procesora (uszkodzenie drivera wyjściowego portu), więc nie polecam testowania w praktyce.

    PORTB ^= _BV(PB4);


    W wypadku takiego rozwiązania w każdym przerwaniu stan pinu zmieniany będzie na przeciwny, więc pełny okres będzie obejmował dwa przerwania (włączenie i wyłączenie), stąd częstotliwość migania wyniesie około 3.815Hz / 2 = 1.907Hz. Po wykonaniu kodu w tej procedurze procesor powróci do wykonywania kodu w pętli głównej, do momentu, w którym została ona przerwana.

    Przerwanie dla powyższego przykładu z możliwością zagnieżdżenia definiuje się tak:
    ISR(TIMER0_OVF_vect, ISR_NOBLOCK)

    Ale używanie takich przerwań w sposób nieprzemyślany może skończyć się zawieszaniem się programu (przepełnienie stosu).

    Obsługę drugiego LEDa to już sobie sam dopisz w ramach ćwiczeń praktycznych ;].
  • #16 5063446
    lord_dagoth
    Poziom 25  
    Posty: 860
    Pomógł: 68
    Ocena: 6
    Dzięki wypowiedzi shg ja bym proponował przykleić ten temat i nieco zmienić jego nazwę:)
  • #17 5065780
    piotrekhbn
    Poziom 11  
    Posty: 73
    Ocena: 2
    Po wypowiedzi shg doszedłem do wniosku, że lepiej będzie dla mnie jak i dla całej elektroniki jak poczekam z c++ aż będzie w szkole. Ja pisałem już, że chodzę do 1 klasy technikum informatycznego:) mam 17lat:)
  • #18 5065869
    lord_dagoth
    Poziom 25  
    Posty: 860
    Pomógł: 68
    Ocena: 6
    No ale co w związku z tym? ja mam 18, a zacząłem programować w tp jak byłem w 6 klasie podstawówki, na C++ przesiadłem się w 2 gim... wiek tu nie ma znaczenia tylko odrobina samozaparcia;)
  • #19 5066950
    JmL(TM)
    Poziom 24  
    Posty: 804
    Pomógł: 44
    Ocena: 12
    lord_dagoth napisał:
    No ale co w związku z tym? ja mam 18, a zacząłem programować w tp jak byłem w 6 klasie podstawówki, na C++ przesiadłem się w 2 gim... wiek tu nie ma znaczenia tylko odrobina samozaparcia;)


    Zgadzam sie z Toba! Pamietam jak dawno temu pisalem pierwsze programy na Commodore 64 ;) Wiek nie ma zadnego znaczenia!
  • #20 5070221
    piotrekhbn
    Poziom 11  
    Posty: 73
    Ocena: 2
    No ale wiecie, jeszcze jakbym rozumiał te polecenia, w tp jak się umie angielski a umiem, to jest łatwo się połapać nawet po samych nazwach typu "write" "readln" itp a w C++ to już wyższa półka. A może polecilibyście mi jakąś książkę o C++?
  • #21 5070391
    tarpiote
    Poziom 12  
    Posty: 27
    Pomógł: 2
    piotrekhbn napisał:
    No ale wiecie, jeszcze jakbym rozumiał te polecenia, w tp jak się umie angielski a umiem, to jest łatwo się połapać nawet po samych nazwach typu "write" "readln" itp a w C++ to już wyższa półka
    moim zdaniem C dosc blisko do pascala, różnią się 'graficznie', ale konstrukcja instrukcji warunkowych czy pętli jest bardzo podobna, tak samo jak idea funkcji (w C nie ma procedur ale są funkcje które nic nie zwracają ;) (void) ).
  • #22 5070632
    lord_dagoth
    Poziom 25  
    Posty: 860
    Pomógł: 68
    Ocena: 6
    tam też jest łatwo się połapać... np. cin (Si in... Console INput) itp, wystarczy tylko poczytać.
    A do nauki C++ standardowo polecam: http://www.gamedev.pl/tutorials.php
  • REKLAMA
  • #23 5071191
    piotrekhbn
    Poziom 11  
    Posty: 73
    Ocena: 2
    No właśnie chodzi mi głównie o różnice "graficzne" od weekendu biorę się za czytanie tutoriali :)
  • #24 5071298
    JmL(TM)
    Poziom 24  
    Posty: 804
    Pomógł: 44
    Ocena: 12
    piotrekhbn napisał:
    No właśnie chodzi mi głównie o różnice "graficzne" od weekendu biorę się za czytanie tutoriali :)


    Chlopie wiecej gadasz niz robisz! Jeszcze nigdy nie widzialem zeby ktos sie tak rozwodzil nad tym czy ma sie brac za cos czy moze jednak nie. Po prostu zacznij czytac i cwicz a na pewno szybko sie nauczysz i nie bedziesz zalowal... ;)

    Milej nauki!
  • #25 5072955
    piotrekhbn
    Poziom 11  
    Posty: 73
    Ocena: 2
    :) No bo wiecie, jestem leniwy z natury :) ale teraz na serio w tyg mam za mało czasu żeby usiąść i tak pare godzin poświęcić na to:) Dzięki wszystkim za udział w dyskusji:)

Podsumowanie tematu

LABEL_AI_GENERATED
Rozpoczynając naukę programowania mikrokontrolerów AVR, początkujący z doświadczeniem w TurboPascalu powinien rozważyć języki C lub C++. C jest bliższy Pascalowi pod względem struktury i prostszy do opanowania na początku, natomiast C++ oferuje większe możliwości, zwłaszcza jeśli planuje się również programowanie aplikacji na PC. Programowanie w C++ na mikrokontrolery wymaga jednak dobrej znajomości języka i ostrożności w stosowaniu zaawansowanych konstrukcji, aby uniknąć nadmiernego zużycia pamięci. Alternatywnie, dla łatwiejszego startu polecany jest język BASCOM, który jest prostszy, choć krytykowany przez zaawansowanych programistów. Przykładowy kod w C pokazuje obsługę przerwań i manipulację portami I/O na mikrokontrolerze ATmega8. Nauka C++ wymaga czasu i cierpliwości, ale dostępne są liczne tutoriale i materiały edukacyjne. Wiek i wcześniejsze doświadczenie nie są przeszkodą w nauce nowych języków programowania mikrokontrolerów.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA