Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Jaki język wybrać w moim przypadku?

piotrekhbn 21 Kwi 2008 00:59 2682 24
  • #1 21 Kwi 2008 00:59
    piotrekhbn
    Poziom 11  

    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?

    0 24
  • #2 21 Kwi 2008 01:59
    qrdel
    Poziom 28  

    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.

    0
  • #3 21 Kwi 2008 03:03
    JmL(TM)
    Poziom 24  

    C++ RULEZ! ;)

    Pozostaje jeszcze asm ale... no wlasnie ALE!

    0
  • #4 21 Kwi 2008 07:10
    lord_dagoth
    Poziom 25  

    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.

    0
  • #5 21 Kwi 2008 16:17
    piotrekhbn
    Poziom 11  

    Od dawna mi się marzyło programowanie uC , więc C czy C++?

    0
  • #6 21 Kwi 2008 16:26
    bbxb
    Poziom 31  

    Zaawansowani programiści uP piszą w C.
    Ale w Twoim przypadku dużo lepszym wyborem będzie C++.

    0
  • #7 21 Kwi 2008 16:43
    piotrekhbn
    Poziom 11  

    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:)

    0
  • #8 21 Kwi 2008 17:56
    Stepel
    Poziom 20  

    Najprostszy dla Ciebie byłby BASCOM... ale ten język często spotyka się z krytyką "zaawansowanych" programistów uC.

    0
  • #9 21 Kwi 2008 19:27
    lord_dagoth
    Poziom 25  

    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".

    0
  • #10 21 Kwi 2008 19:30
    JmL(TM)
    Poziom 24  

    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... ;)

    0
  • #11 21 Kwi 2008 20:23
    piotrekhbn
    Poziom 11  

    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?

    0
  • #12 21 Kwi 2008 20:41
    lord_dagoth
    Poziom 25  

    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++

    0
  • #13 22 Kwi 2008 00:56
    piotrekhbn
    Poziom 11  

    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:)

    0
  • #14 22 Kwi 2008 01:45
    JmL(TM)
    Poziom 24  

    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 ;)

    0
  • #15 22 Kwi 2008 04:20
    shg
    Specjalista techniki cyfrowej

    Ż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:
    Code:
    #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.
    Code:
    #include <avr/io.h>

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


    Główna procedura:
    Code:
    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).





    Code:
    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.

    Code:
    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.

    Code:
    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:

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


    Albo nawet tak:

    Code:
    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

    Code:
    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).

    Code:
    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:

    Code:
    sei();


    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.

    Code:
    while(1) {
    
    }


    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:

    Code:
    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.

    Code:
    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:
    Code:
    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 ;].

    0
  • #16 22 Kwi 2008 08:14
    lord_dagoth
    Poziom 25  

    Dzięki wypowiedzi shg ja bym proponował przykleić ten temat i nieco zmienić jego nazwę:)

    0
  • #17 22 Kwi 2008 19:17
    piotrekhbn
    Poziom 11  

    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:)

    0
  • #18 22 Kwi 2008 19:34
    lord_dagoth
    Poziom 25  

    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;)

    0
  • #19 22 Kwi 2008 22:54
    JmL(TM)
    Poziom 24  

    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!

    0
  • #20 23 Kwi 2008 20:39
    piotrekhbn
    Poziom 11  

    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++?

    0
  • #21 23 Kwi 2008 21:08
    tarpiote
    Poziom 12  

    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) ).

    0
  • #23 23 Kwi 2008 23:48
    piotrekhbn
    Poziom 11  

    No właśnie chodzi mi głównie o różnice "graficzne" od weekendu biorę się za czytanie tutoriali :)

    0
  • #24 24 Kwi 2008 00:44
    JmL(TM)
    Poziom 24  

    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!

    0
  • #25 24 Kwi 2008 18:03
    piotrekhbn
    Poziom 11  

    :) 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:)

    0