Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

ATTiny2313 / C - Timer0 Początki

maximus22_kr 13 Oct 2015 11:20 2721 47
Testo
  • #1
    maximus22_kr
    Level 18  
    Witam
    Próbuję zapoznać się z językiem C. Mam gotową płytkę z ATTiny2313.
    Chciałem na początek pomęczyć diodę LED. Jako, że Delay nie jest dobrym rozwiązaniem próbuję z Timerem0

    Code: c
    Log in, to see the code


    Chciałem włączyć go w trybie Normal z preskalerem 64 i załadować wartość 6 do rejestru, jeśli dobrze obliczyłem, gdy Timer0 "przekręci" się 500 razy będzie sekunda.
    Mam błąd przy konfiguracji Timera0. Błąd "Symbol 'TCCR0B' could not be resolved".

    W PDF Attiny2313 jest:
    TCCR0B
    TCCR1B

    Jako "Bascomowiec" jestem przyzwyczajony do oznaczeń Timer0, Timer1, Timer2. Jeśli dobrze odczytuję PDF to Timer0 ( 8Bit ) ma rejestr TCCR1B i jest konfigurowany przez bity CS12 CS11 CS10.

    Czy mógłby ktoś to potwierdzić lub wyprowadzić z błędu ?
  • Testo
  • #2
    szczywronek
    Level 27  
    Timer0 to bity i rejestry z "0" w nazwie, np: TCCR0A, TCCR0B, COM0A1, CS00, CS01, ... Analogicznie licznik 1 będzie miał w nazwie "1".

    Przy okazji: zdecydowanie musisz poczytać o obsłudze przerwań w C. To co masz w pętli nieskończonej jest zdecydowanie dziwaczne :) ISR (procedura obsługi przerwania) powinna być osobną funkcją. U Ciebie, w pętli while, jest deklaracja (?) procedury przerwania i pusty blok {}.

    EDIT:
    Jeszcze kilka spraw się nie zgadza:
    1. Zjadło Ci się przesunięcie bitowe przy CS00
    2. Przy ustawianiu rejestrów TCCR0B i TIMSK niepotrzebnie korzystasz z sumy bitowej zamiast przypisania.
    3. Przypuszczam, że z tą wartością początkową to nie do końca o to Ci chodziło. Tzn. to zadziała jednokrotnie. Licznik odliczy od tych 6 do przekręcenia, ale potem będzie już liczył od 0 a nie od 6.
  • #3
    maximus22_kr
    Level 18  
    Pusty blok jest dlatego, że utknąłem na konfiguracji Timer0.
    Jeśli chodzi o rejestry, to podejrzewałem, że jest tak, jak Kolega pisze.

    Wartość TCNT0 = 6; trzeba będzie wpisać do przerwania Timera

    Przy ustawieniach:
    Code: c
    Log in, to see the code


    jest błąd, w ustawieniach projektu mam wybrany ATTiny2313 i 8000000 Hz.

    Ale jeśli włączę Timer1
    Code: c
    Log in, to see the code


    to błędów nie ma
  • #4
    szczywronek
    Level 27  
    Teraz to popsułeś. Zobacz opis rejestru TCCRxA w dokumentacji (strona 73 w pdfie ze strony atmela). Tam nie ma bitów CSx0 i CSx1.
    Punkt (1) z mojego poprzedniego postu też bym poprawił.

    Jeżeli kompilator nie rozpoznaje rejestru TCCR0B to jest to problem ze środowiskiem a nie kodem programu. Napisz z jakiego środowiska korzystasz i wklej cały log z kompilacji.
  • #5
    maximus22_kr
    Level 18  
    Dla TCCR0A jest WGM01 i WGM00
    Dla TCCR0B w trybie Compare jest CS02, CS01 i CS00

    Środowisko to Eclipse Mars, zainstalowane najnowsze Atmel Toolchain i AVR Dude ( AVR Dude wziąłem z programu MK AVR Kalkulator Pana Mirka )

    Ta sama płytka i kontroler, ale na próbę odpaliłem tylko Delay i LED działa bez problemu, wygląda, jakby był problem z nazwą rejestru.
  • #6
    yokoon
    Level 29  
    Witam.
    Jeżeli kompiluje się bez błędów to nie się nie przejmuj tym.
    Miałem to samo, po kilku uruchomieniach samo zniknęło.

    Pisałem o tym na forum Atnela - poszukaj.
    Temat: 28-09-2015
    Rejestry typu TCCRxx podkreślone na czerwono.
  • Testo
  • #7
    maximus22_kr
    Level 18  
    Jedynym błędem, który pokazuje Eclipse jest ta nazwa rejestru.

    Czy poniższy kod jest poprawny i będzie migał diodą co 1 sekundę ?

    Code: c
    Log in, to see the code


    albo raczej, czy powinien działać, bo u mnie dioda cały czas świeci.
  • #8
    szczywronek
    Level 27  
    Nie powinien działać tak jak zakładasz. Nie włączyłeś licznika - rejestr TCCR0B był ok, czemu uparcie zmieniasz na TCCR0A? No i sam zauważyłeś, że sekunda to będzie 500 przekręceń licznika.

    Ten Twój "błąd" to nie błąd kompilatora tylko analizatora z Eclipse. Program pewnie kompilował się bez błędów - nie pokazałeś logu z kompilacji więc tylko gdybam.
    Spróbuj wyczyścić projekt (Project -> Clean) i przebudować Index (Projekt -> C/C++ Index -> Rebuild).

    Dodane po chwili:
    No i w definicjach na początku coś się nie zgadza. Np. przy LED1... raz masz port D a za chwilę B. Ponadto operacja:
    Code: c
    Log in, to see the code
    Robi chyba coś innego niż byś chciał.
  • #9
    maximus22_kr
    Level 18  
    Początki trudne.
    Posiłkowałem się teraz tym, Link
    Faktycznie, trochę zamieszania narobiłem.

    Teraz wygląda to tak:
    Code: c
    Log in, to see the code


    Jeśli chodzi o włączenie przerwań to jest sei();

    Mam natomiast inne pytanie.
    Dlaczego inicjując wyjścia w taki sposób:
    Code: c
    Log in, to see the code


    Zapala się LED2 i LED3 ( a powinno tylko LED3 )

    a gdy zmienię kolejność - nie zmieniając kodu
    Code: c
    Log in, to see the code

    świeci tylko LED3
  • #10
    szczywronek
    Level 27  
    Wersja zapalająca oba LEDy:
    Code: c
    Log in, to see the code
    Dla poprawy czytelności wyrzućmy definicje i linijki związane z rejestrem DDR bo to nie one są problemem:
    Code: c
    Log in, to see the code
    I jeszcze zamieńmy definicje PB0 i PB1 na odpowiadające im wartości:
    Code: c
    Log in, to see the code
    Obliczmy przesunięcia:
    Code: c
    Log in, to see the code
    No i teraz wszystko widać:
    - w pierwszej linijce masz sumę bitową rejestru PORTB i wartości binarnej 0b1, po tej operacji rejestr PORTB ma wartość 0b1
    - w drugiej linijce masz iloczyn bitowy wartości rejestru PORTB (0b1) i wartości 0b10 -> w efekcie otrzymujesz 0. Jeśli diody podłączone są od VCC do mikrokontrolera - to się zapalają.

    Teraz druga wersja kodu - ta która zapala tylko LED3:
    Code: c
    Log in, to see the code
    Postępowanie analogiczne jak poprzednio:
    Code: c
    Log in, to see the code
    - pierwsza linijka to iloczyn wartości rejestru PORTB (0) i 0b10 -> w wyniku otrzymujesz zero
    - druga linijka to suma wartości rejestru PORTB (0) i 0b1 -> w wyniku masz 0b1. Wszystko się zgadza.

    Błąd wynika z tego, że nie masz dobrze opanowanych operacji bitowych. Jeżeli chcesz skasować jakiś bit rejestru to musisz wykonać operację:
    Code: c
    Log in, to see the code
    U Ciebie brakuje negacji (tyldy). Osobna kwestia jest taka, że po resecie mikrokontrolera te rejestry mają wartość 0. Kasowanie (nie ustawionych wcześniej) bitów nie ma sensu.
  • #11
    maximus22_kr
    Level 18  
    Quote:
    Błąd wynika z tego, że nie masz dobrze opanowanych operacji bitowych.

    Niestety smutna prawda.

    Do tego dochodzą przyzwyczajenia z Bascom, tam prościej operowało się poszczególnych bitach portu.

    A jak w kwestii Timera0 ?
    jeśli dobrze wyczytałem w PDF Attiny2313 to:
    Dla TCCR0A jest WGM01 i WGM00
    Dla TCCR0B w trybie Compare jest CS02, CS01 i CS00
    [/quote]Nie włączyłeś licznika - rejestr TCCR0B był ok, czemu uparcie zmieniasz na TCCR0A? No i sam zauważyłeś, że sekunda to będzie 500 przekręceń licznika.

    To jest OK ?
    Code: c
    Log in, to see the code
    [/quote]
  • #12
    BlueDraco
    MCUs specialist
    To nie jest ok:

    TCCR0B |= (1 << CS01)|(CS00);

    A w ogóle operacje |= na rejestrach sterujących są bez sensu.
  • #13
    szczywronek
    Level 27  
    Wszystko już było - zobacz punkty 1 i 2 z drugiego postu w tym wątku ;) Z tym "nie włączaniem licznika" chodziło mi o to, że w którejś wersji programu nie ustawiałeś bitów CS w rejestrze TCCR0B. A bez tego licznik nie mógł działać.
  • #14
    maximus22_kr
    Level 18  
    BlueDraco wrote:
    To nie jest ok:

    TCCR0B |= (1 << CS01)|(CS00);

    A w ogóle operacje |= na rejestrach sterujących są bez sensu.


    Jako początkujący na razie raczej "klepie" gotowe kody, jak działa to eksperymentuje, żeby skumać jak to działa.

    W większości przykładów, np. tutaj jest
    Code: c
    Log in, to see the code
  • #15
    szczywronek
    Level 27  
    Najtrudniej analizuje się własny kod, bo zawsze patrzy się przez pryzmat wiedzy o tym co on powinien robić i nie dostrzega się drobnych błędów :)

    Porównaj linijkę z Twojego kodu i z przykładu:
    Code: c
    Log in, to see the code
    Teraz widzisz różnicę? Od drugiego postu w tym temacie zwracam Ci na to uwagę...
  • #16
    maximus22_kr
    Level 18  
    Quote:
    Najtrudniej analizuje się własny kod, bo zawsze patrzy się przez pryzmat wiedzy o tym co on powinien robić i nie dostrzega się drobnych błędów :)


    Zgadzam się z tym w 100%.
    Przy Bascomie rzadko sięgałem do PDF'ów kontrolerów, przy C nie da się bez tego wszystkiego zrobić.

    Bez tych 500 "przekręceń" licznika nawet w Bascom by nie poszło, jak zwykle zbyt dużo chęci i za szybko działam, nie wczuwając się w niektóre tematy.

    Udało się odpalić, więc teraz walczę z moim ulubionym DS18B20, w założeniu oprócz pomiaru temperatury, wynik chcę przesłać na UART - korzystałem z kodu Pana Mirka ( zarówno main.c jak biblioteki do obsługi 1Wire ), zmieniając tylko tryb Timera na przepełnienie ( do CTC jeszcze się nie przyzwyczaiłem ), no i oczywiście w pliku onewire.h ustawiłem odpowiednią końcówkę ( PORTD.5, nóżka nr 9 ATTiny2313 )

    onewire.h
    Code: c
    Log in, to see the code


    main.c
    Code: c
    Log in, to see the code


    UART działa ( zajrzałem do PDF i ustawiłem rejestry ), ale cały czas wysyła Brak DS.

    Zastanawiam się, czy coś pominąłem, połączenia elektryczne sprawdziłem miernikiem, rezystor 4K7 oczywiście jest.
  • #18
    maximus22_kr
    Level 18  
    Może źle to ująłem, nic nie robi poza wysyłaniem na UART Brak DS co około sekundę.
  • #19
    szczywronek
    Level 27  
    Ok. Zauważ, że kod odpowiedzialny za wysyłanie tego komunikatu (" Brak DS ") znajduje się przed pętlą główną w funkcji main. Czyli ten kod nie powinien się wykonać więcej niż jeden raz w trakcie działania programu. U Ciebie tak nie jest. Procesor cyklicznie wykonuje kod z początku funkcji main, stąd wniosek -> procesor się resetuje. To opóźnienie (około 1s) wynika najpewniej z delaya (750ms) na początku programu.

    Mikrokontroler może się resetować przez problemy sprzętowe z zasilaniem - np. program tak steruje wyjściami że wywołuje zwarcie lub źródło zasilania ma zbyt małą wydajność aby uciągnąć jakieś wyświetlacze/ledy i inne wodotryski.
    Inna prawdopodobna opcja (i ta jest moim faworytem) to przepełnienie stosu. Piszesz o UARTcie p. Mirka - chodzi o tą "bibliotekę" z buforami kołowymi? Ile pamięci SRAM zajmuje Twój program?

    W ramach poszukiwania winowajcy skróć na razie program. Np. wstaw pętlę nieskończoną (pustą) tuż po rozkazie sei. Jeśli program nadal będzie wariował to eliminując kolejne instrukcje dojdziesz do tego, która powoduje problem.

    Przy okazji: ta linijka po ifie na pewno jest zakomentowana u Ciebie? Bo jej odkomentowanie "rozsypie" wyrażenie warunkowe z if
    Code: c
    Log in, to see the code
  • #20
    maximus22_kr
    Level 18  
    Żadnych dodatków nie ma, jest tylko ATTiny2313 z kwarcem, wyprowadzone kilka portów oraz złącze 3 pinowe terminal block dla DS18B20 oczywiście podciągnięte rezystorem.

    Jeśli chodzi o rozmiar to
    Program: 1830 bytes (89.4% Full)
    (.text + .data + .bootloader)

    Data: 116 bytes (90.6% Full)
    (.data + .bss + .noinit)

    mkAVR Kalkulator pokazuje 89% - 1830 b

    Jeśli chodzi o bibliotekę, to użyłem tej z płytki dołączonej do książki Pana Mirka, są dwa pliki MKUART.H i MKUART.C
  • #21
    szczywronek
    Level 27  
    No to najprawdopodobniej masz już jeden błąd namierzony - zajętość pamięci SRAM 90% to zdecydowanie za dużo. Nie mam pod ręką tej płyty, ale z tego co pamiętam to w pliku nagłówkowym (mkuart.h) powinny być definicje rozmiarów buforów. Coś w stylu "UART_RX_BUFF_SIZE" i "UART_TX_BUFF_SIZE". Strzelam, że mają po 32B. Zmniejsz je do 16B i daj znać czy coś się zmieniło.
  • #22
    maximus22_kr
    Level 18  
    w mkuart.h mam tak:
    Code: c
    Log in, to see the code


    zmieniłem wartości na 12 i 16, bo były większe

    Teraz jest
    Device: attiny2313

    Program: 1830 bytes (89.4% Full)
    (.text + .data + .bootloader)

    Data: 96 bytes (75.0% Full)
    (.data + .bss + .noinit)
  • #24
    maximus22_kr
    Level 18  
    Musiałem dać 16. Przy 8 nic nie wysyłał.

    Program: 1820 bytes (88.9% Full)
    (.text + .data + .bootloader)

    Data: 100 bytes (78.1% Full)
    (.data + .bss + .noinit)

    Wyrzucę na razie obsługę RS485.
    Efekt taki, że tylko raz wysyła Brak DS oraz to że dioda LED miga cyklicznie co mniej więcej sekundę.

    Zastanawiam się, czy problemem nie jest to, że mam podpięty jeden czujnik, a wywołuję procedure dla kilku
  • #25
    User removed account
    User removed account  
  • #26
    szczywronek
    Level 27  
    Piotrus_999 wrote:
    Nie za bardzo kumam co robi definicja procedury obsługi przerwania w pętli
    Odnosisz się do omawianego aktualnie kodu, czy też nie chciało Ci się czytać całego tematu i tylko siejesz zamęt komentując omówione już błędy :> ?
    Swoją drogą: w żadnym z prezentowanych tu kodów nie ma definicji procedury obsługi przerwania umieszczonej w pętli. Poczytaj o różnicy między definicją a deklaracją ;)
  • #27
    User removed account
    User removed account  
  • #28
    maximus22_kr
    Level 18  
    Quote:
    Raczej najpierw musisz sie nauczyć C

    No właśnie próbuję. Przez ostatnie kilka dni przewertowałem więcej PDF od kontrolerów, niż przez ostatnie 3 lata :D
    Na razie największy problem dla mnie to operacje bitowe - wiadomo w Bascom łatwiej.

    Kupiłem nawet Attiny4313, coby nie brakło pamięci.
    Problem był jednak w momencie polecenia włączenia przerwań, były włączone dopiero po pierwszym odczycie czujników, przesunąłem wyżej zaraz po konfiguracji rejestrów Timer'a ( tak, jak w Bascom ). Trochę to dziwne, cały kod wziąłem z płyty Pana Mirka, dodając tylko obsługę UART a wyrzucając obsługę LCD.

    Teraz działa, ale chciałem dodać "mignięcie" LED w momencie odczytu i tutaj mam problem. Zrobiłem funkcję, która ma to obsłużyć.
    Dioda ma mignąć na 0,5 sekundy, dlatego dodałem drugą zmienną dla licznika. Niestety dioda "milczy" uparcie, czyli się nie świeci.


    Code: c
    Log in, to see the code
  • #29
    hugeone.co.uk
    Level 10  
    po pierwsze nie licznik_led nie jest volatile a dalej nie sprawszalem
  • #30
    maximus22_kr
    Level 18  
    hugeone.co.uk wrote:
    po pierwsze nie licznik_led nie jest volatile a dalej nie sprawszalem


    I z tego powodu się nie zapala LED ? Raczej nie powinna się zgasić.