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.

Attiny13 - 3-bitowy licznik - nie działa zgodnie z oczekiwaniami

yogi009 12 Wrz 2013 17:25 1881 8
  • #1 12 Wrz 2013 17:25
    yogi009
    Poziom 42  

    Niestety nie siedzę w mikrokontrolerach, tym bardziej w języku C, ale mam tu do zrealizowania prościutkie sterowanie 8 kanałami. Pomyślałem, że wygeneruję z małego kontrolera kod (trzy bity, czyli osiem możliwości), potem takie trzy sygnały polecą np. na CD4051. No i się zabrałem za doświadczenie z AVR. Na potrzeby doświadczenia zrobiłem dwa mini-moduły: płytkę z Attiny, złączem ISP6 i wyjściami PB0-PB4 (PB5 jako niepotrzebne celowo zostawiłem w spokoju). Druga mini-łytka to 3 diody LED (PB0-PB2) i dwa przełączniki (PB3 i na razie nieużywany PB4). Oba mini-moduły wpinam w płytkę stykową, do której podaję stabilizowane 5V. Pewnie fotki to lepiej wyjaśnią, niż słowa.

    Attiny13 - 3-bitowy licznik - nie działa zgodnie z oczekiwaniami Attiny13 - 3-bitowy licznik - nie działa zgodnie z oczekiwaniami Attiny13 - 3-bitowy licznik - nie działa zgodnie z oczekiwaniami

    Do tego "ukleiłem" taki kodzik (proszę się nie nabijać, na razie próbuję nieco po omacku robić pierwsze kroki):

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Objawy są interesujące. Po włączeniu zasilania mogę - naciskając switch - zwiększać liczbę trzybitową 000-001-010-....111- i tu następuje wygaszenie LED-ów. Początkowo sądziłem, że to jakiś błąd kodu (do tej pory brzydko go podejrzewam), ale zauważyłem jeszcze coś ciekawego. Po wyjęciu z płytki stykowej tego mini-modułu z diodami i switchami i ponownym jego włożeniu układ jest jakby w momencie startu, znowu mogę taki jeden cykl odliczania wykonać. Jeśli dodam do tego fakt, że podczas programowania nie mogę zapisać pliku .hex (za pomocą avrdude), dopóki nie wyjmę tej małej płytki z diodami i switchami, to chyba mam powody, że i tą małą płytkę oglądać ze szczególną uwagą. Zrobiłem jeszcze drugi moduł wyjściowy, z 5 diodami LED (wiadomo, najpierw zabawa z zapalaniem lampek), ten zachowuje się książkowo, mogę wpisać plik .hex nie wyjmując go z płytki stykowej.

    To chyba tyle faktów, które zdołałem powiązać. Proszę Kolegów o wsparcie w tej nowej dla mnie dziedzinie. Chciałbym uzyskać licznik 0-7 (po uzyskaniu 7 przechodzi na początek cyklu), nie bardzo jeszcze wiem, jak zachowa się ten tutaj, skoro wydzieliłem trzy bity na wyjścia, a czwarty jako wejście switch'a. No, ale Attiny13 ma tylko jeden port i do wymienionego celu na pewno wystarczy z nadmiarem.

    0 8
  • Pomocny post
    #2 12 Wrz 2013 17:40
    piotrva
    Moderator na urlopie...

    Zastanów się co się stanie, gdy zwiększasz wartość zapisaną w rejestrze PORTB
    na początku pętli nieskończonej:

    Code:

    PORTB = 0b00001000 - mamy włączone podciąganie

    W czasie przyciskania:
    Code:

    PORTB = 0b00001000
    PORTB = 0b00001001
    PORTB = 0b00001010
    PORTB = 0b00001011
    PORTB = 0b00001100
    PORTB = 0b00001101
    PORTB = 0b00001110
    PORTB = 0b00001111
    PORTB = 0b00010000 - i tu problem - podciąganie zostaje wyłączone!!

    Ogólnie w programie należy poprawić:
    1. F_CPU definiujemy w opcjach projektu - nie w kodzie
    2. Nie zapisuj wartości zapisanych do rejestrów jako liczby - używaj do tego nazw bitów i przesunięć bitowych. Np. dla ustawienia kierunków i podciągania:
    Code:

    DDRB |= (1<<PB0)|(1<<PB1)|(1<<PB2);//ustawiam PB0,PB1 i PB2 jako wyjścia, pozostałe piny są domyślnie wejściami.
    PORTB |= (1<<PB3);//włączam podciąganie dla PB3

    3. Poczytaj co-nieco o eliminacji drgań styków - można to zrobić lepiej niż zaprezentowałeś.
    4. Puste pętle możesz zapiać jako while(warunek);, nie musisz dawać {}
    5. Sam problem rozwiążesz stosując maskę bitową - na zadanie (w podziękowaniu za gotowca) przeanalizuj i dokładnie opisz na forum jak działa taki fragment kodu:
    Code:

    PORTB = (PORTB&0b11111000)|((PORTB+1)&0b00000111);

    0
  • #3 12 Wrz 2013 18:36
    yogi009
    Poziom 42  

    Dziękuję za cenny materiał. Jak widać, na razie dopiero wchodzę na tę oślą łączkę, mam świadomość "stylu" :-) Teraz do rzeczy:

    -. F_CPU zdefiniowałem w kodzie, ponieważ korzystam z konsoli linuksowej i avrdude, kompiluję i wgrywam komendą w linii poleceń, póki co nie potrzebuję obciążać sprzętu "środowiskiem",

    -. odnośnie utraty stanu podciągnięcia do plusa, bardzo cenna uwaga, tu błędnie oceniałem sytuację, sądziłem, że odliczam od zera, tymczasem odliczam de facto od 1000 do 1111, potem rzeczywiście jest stan 0001 0000 i switch traci dostęp do wejścia. Zastanawiałem się (przy moim braku wiedzy), czy nie zastosować 8-elementowej tablicy w mapą bitową i nie użyć pętelki for(), oczywiście w globalnej, nigdy nie kończącej się pętli while(). Wtedy licznikiem byłaby wartość zmiennej sterującej pętlą for().

    -. bardzo ciekawy styl zapisu do rejestrów, jeszcze nie dotarłem w lekturce do tego miejsca,

    -. drgania styków eliminuję sprzętowo, co widać na schemacie. Wiem, że Atmel zaleca ostatnio w szeregu z włącznikiem włożyć rezystor 330R, w następnym projekcie tak to zrobię, póki co przerwania jeszcze są dla mnie za bardzo magiczne,

    -. nawiasy klamrowe przy pustych instrukcjach to oczywiście brak dbałości o wygląd kodu, przegapiłem to.

    Pytanie jakie nadal mam, to zachowanie układu po wyjęciu i ponownym włożeniu małej płytki z diodami LED i włącznikami. Główny moduł cały czas pracuje, czyli zakładając, że mamy stan sprzed wyjęcia płytki LED: 0001 0000 (wszystkie diody gasną i optycznie system się jakby "wiesza"). Potem wkładamy w pracujący układ tą samą płytkę LED i okazuje się, że widzę coś takiego: 0000 1001 (czyli w zasadzie trzybitową jedynkę - 001). I to jest zastanawiające.

    Z Twojego postu zrozumiałem, że mimo wydzielenia PB0-PB2 na wyjścia i PB3-PB5 na wejścia, zastosowana inkrementacja dotyczy całego portu, czyli PB0..PB5. Kombinowałem trochę w tym kierunku, że jeśli mam zdefiniowane tyko 3 wyjścia, być może jest jakiś mechanizm odliczający w "zakresie" tych trzech bitów. To oczywiście była nieco optymistyczna hipoteza, którą udało się zweryfikować negatywnie :-)

    0
  • #5 12 Wrz 2013 18:54
    yogi009
    Poziom 42  

    A zachowanie podczas programowania plikiem .hex?

    Swoją drogą bardzo ciekawy jest ten zapis:

    Code:
    PORTB = (PORTB&0b11111000)|((PORTB+1)&0b00000111); 


    coś czuję, że mnie czeka wieczór przed ekranem :-)

    0
  • #7 12 Wrz 2013 19:31
    yogi009
    Poziom 42  

    Twój kod daje mi wartości od 0000 1001 do 0000 1111 - bardzo ciekawy patent, jednak chyba nie obejmuje początkowej wartości 0000 1000 (lub jeszcze jej nie widzę). Przy dotarciu do wartości 0000 1111 następna inkrementacja nie zmienia wartości 0000 1111. Prawdopodobnie należało by tu jakiś warunek zapisać i ustalić wartość startową 0000 1000.

    Odnośnie momentu wpisywania pliku .hex do kontrolera pytałem o możliwą przyczynę niepowodzenia akcji zapisu dopóki nie wyjąłem małej płytki z diodami i switch'ami.

    0
  • Pomocny post
    #8 12 Wrz 2013 19:48
    piotrva
    Moderator na urlopie...

    A to diody lub kondensatory mogą zbytnio obciążać linie programatora - stąd operacja jest niemożliwa.
    A mój kod obejmuje przecież wszystko.
    Rozpisz sobie to wszystko powoli i po kolei - operacja po operacji - zrozumiesz zasadę MASKOWANIA BITÓW.

    0
  • #9 12 Wrz 2013 21:00
    yogi009
    Poziom 42  

    Serdeczne dzięki, poniżej cały, działający kod:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Co do obciążania portów kontrolera, następną płytkę doświadczalną zrobię z funkcją rozłączania ścieżki do switch'a - LED'ów na razie nie podejrzewam, wszak druga płytka, z samymi diodami, nie daje takiego efektu.

    Jeszcze raz serdeczne dzięki za gotowca. Muszę do niego jeszcze raz usiąść, w sumie kombinacji osiem :-) Obecnie układ startuje z wartością 0000 1001, naciśnięcie switch'a przy stanie 0000 1111 powoduje zmianę na 0000 1000 (jeszcze nie wiem dlaczego :) ).

    W trakcie wklejania kodu zrobiłem początkowo małą pomyłkę i wyszło mi coś takiego:

    PORTB |= PORTB = (PORTB&0b11111000)|((PORTB+1)&0b00000111);

    a piszę o tym dlatego, że układ też się zachowywał ciekawie, miał trzy stany:

    0000 0001 - 0000 0011 - 0000 0111

    taka jakby graficzna prezentacja poziomu sygnału w audio. No ale z tych dwóch wolę pierwszy.

    Dziękuję bardzo za profesjonalną pomoc, jak rozkoduję linijkę, odezwę się jeszcze.

    ====== PRACA DOMOWA =======

    Maski bitowe do moje dzisiejsze hasło dnia. Oto obrazkowe wytłumaczenie zjawiska z tego kodu:

    Code:
    PORTB = (PORTB-1&0b11111000)|((PORTB)&0b00000111); 


    Attiny13 - 3-bitowy licznik - nie działa zgodnie z oczekiwaniami

    Niech zostanie dla następnych :-)

    0