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

[Atmega8][C] - Wyświetlacz 7-seg, nie działa

24 Lut 2013 21:28 2079 17
  • Poziom 12  
    Cześć, chciałem zapoznać się z multipleksowaniem wyświetlaczy 7-seg (wspólna katoda). Na początek pomyślałem, że trzeba zrobić jakąś funkcję, która przekształci cyfrę na wartość heksadecymalną jej odpowiadającą. Żeby to sprawdzić napisałem program który liczy do 10:
    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    Problem w tym, że po włączeniu nic się nie dzieje, nic nie świeci. Po prostu nie wiem o co chodzi, co tu jest źle?
  • Pomocny post
    Specjalista - Mikrokontrolery
    Pokaż schemat połączeń, to po pierwsze. Po drugie nie potrzebujesz żadnej funkcji, ani instrukcji switch, tylko zwykłej tablicy :

    const uint8_t obraz_cyfry[10] = {0x7E, 0x30, 0x6d, itd...};

    PORTD = obraz_cyfry[czas];

    Na AVR short int ma taką samą długość jak int, a tutaj wyraźne chodzi o bajt - użyj uint8_t z stdint.h.

    Samo wyświetlanie multipleksowane musi być zrobione w obsłudze przerwania timera, ale to wtedy, kiedy uporasz się z problemem podstawowym, jakim póki co jest brak sterowania segmentów.
  • Poziom 12  
    Dobra, już wiem co było źle. Po pierwsze:
    Cytat:
    Magiczne słowo volatile

    Po drugie:
    Cytat:
    while(1);
    -średnik
    Po trzecie odwrotnie wpisałem bity oznaczające segmenty wyświetlacza.

    Teraz mam program który liczy od 0-9. Działa ta moja funkcja, i tablica.
    Cytat:
    Samo wyświetlanie multipleksowane musi być zrobione w obsłudze przerwania timera

    A dlaczego? Czytałem, że przerwania mają być jak najkrótsze. Poza tym wyświetlacz odświeży się tylko raz na sekundę?

    Teraz mam inny problem. Wyświetlacze pokazują jakieś śmieci, na dodatek oba to samo. Tutaj kod:
    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Aha, a schemat połączeń tutaj:
    [Atmega8][C] - Wyświetlacz 7-seg, nie działa
    Filtrowanie zasilania, rezystor na resecie itp. są.
  • Pomocny post
    Moderator na urlopie...
    Bo wszystko działa Ci za szybko.
    Zamiast:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    daj na razie do testów:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    A potem tak czy siak zapakuj całe odświeżanie do przerwania timera, a nie tylko zwiększanie liczby, bo to co przedstawiłeś jest... ekhm... śmieszne ;)
    ---
    Poza tym schemat nie pokazuje najważniejszego - jak masz podłączone zasilanie i czy AVCC oraz drugie GND są podłączone.
  • Pomocny post
    Specjalista - Mikrokontrolery
    Obsługa przerwania nie ma być "jak najkrótsza", tylko "nie za długa". Odświeżanie wyświetlacza zawsze robi się w przerwaniu, gdyż zajmuje to czasu tyle co nic, a nie zrobienie tego w przerwaniu powodowałoby złe działanie wyświetlacza - nierówną jasność cyfr, zmiany jasności, migotanie, przygasanie itp. To ma być działać ze stałą częstotliwością, a do tego właśnie służy timer.
  • Poziom 12  
    Oto pełny schemat:
    [Atmega8][C] - Wyświetlacz 7-seg, nie działa

    No dobra, przeniosłem to do procedury przerwania:
    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    I dzieje się to co myślałem - pierwsza cyfra tylko miga, druga normalnie się wyświetla. Jak sobie z tym poradzić?
  • Poziom 12  
    No tak, ale przerwanie mam co jedną sekundę, więc świeciła by tylko jedna cyfra na przemian co sekundę.
    Dlatego włączyłem drugi timer:
    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    Teraz działa, ale nie wolno używać funkcji delay w przerwaniu :/ Jest na to jakiś sposób?
  • Pomocny post
    Moderator na urlopie...
    To przerwanie w którym wykonujesz odświeżanie musi działać z dużą częstotliwością, a co do używania delay w przerwaniu napisałem Ci już wcześniej - w każdym wywołaniu przerwania zapalasz kolejną cyfrę, która świeci się do momentu kolejnego wystąpienia przerwania. W kolejnym przerwaniu zwiększasz sobie jakiś licznik, który teraz wskaże na drugą cyfrę, ją zapalasz i znowu do kolejnego przerwania się ona świeci (a program główny i inne przerwania robią swoje).
  • Pomocny post
    Specjalista - Mikrokontrolery
    Przerwania powinny mieć częstotliwość (300 * liczba_cyfr) Hz, ew. nieco mniejszą. Przy czterech cyfrach idealnie 1200 Hz.
  • Poziom 12  
    OK, udało się, wszystko działa, i ładnie świeci. Może tak być?
    Kod: cpp
    Zaloguj się, aby zobaczyć kod
  • Specjalista - Mikrokontrolery
    Bardzo dobry przykład do pokazywania, do czego nie powinno się stosować instrukcji switch oraz jak nie należy programować timera, jeśli chce się, żeby precyzyjne odmierzał czas.
  • Poziom 12  
    Czy tak będzie lepiej?
    Kod: cpp
    Zaloguj się, aby zobaczyć kod
  • Specjalista - Mikrokontrolery
    Zamiast źle użytej konstrukcji switch mamy jescze gorzej użyte if. Jak już sprawdziliśmy, że licznik jest równy 1, to jeszcze na wszelki wypadek sprawdzamy, czy jest równy 2, a może jeszcze przypadkiem jest równy i 1, i 2, i 3 równocześnie.

    switch (if zresztą też) służy do rozejścia na różne akcje, w zależności od wartości danych. U Ciebie akcje są zawsze takie same, a tylko niektóre z nich różnią się wartością danych, ale NIE tym, co się robi.

    Masz np. coś takiego: jeśli licznik równy, to podstaw 0 pod PORTD, a jeśli licznik równy 2, to też podstaw 0 pod PORTD. No ale jeśli licznik jest równy 3, to z kolei... podstaw 0 pod PORTD.

    Zapisz cyfry w tablicy cyfry[3]. Zapisz stałe wyswietlacz w tablicy wyswietlacz[3]. Wtedy w przerwaniu możesz napisać:

    PORTC =0;
    PORTD = cyfra[cyfry[licznik]];
    PORTC = wyswietlacz[licznik];
    if (++ licznik == 3)
    licznik = 0;

    ... i żaden switch ani if nie będzie potrzebny.

    Tablicę cyfra zadeklaruj na zewnątrz obsługi przerwania, a jeśli koniecznie chcesz wewnątrz - to ze słowem static (na zewnątrz static też nie zaszkodzi). Tak, jak jest teraz, ryzykujesz inicjowanie tablicy stałych w każdym przerwaniu, chyba, że kompilator będzie baaaardzo mądry.

    Nie nazywaj stałych ani innych symboli preprocesora małymi literami, bo tak się przyjęło nazywać zmienne.

    Przerzuć inkrementację całego licznika do procedury przerwania. Użyj jednego przerwania timera w trybie CTC, a nie dwóch. W tym jedynym (załóżmy że 1200 Hz) po wyświetleniu cyfry odliczaj co ile masz zinkrementować licznik i zinkrementuj go.

    W pętli głównej zostaw tylko usypianie procesora.
  • Poziom 12  
    Dzięki BlueDraco, jesteś niesamowity. Czy coś takiego się sprawdzi?
    Kod: cpp
    Zaloguj się, aby zobaczyć kod
  • Specjalista - Mikrokontrolery
    Nie wiem, nie mam AVR. Sprawdź, to zobaczysz. Na oko nieźle, tylko nie wiem, czy dobrze zaprogramowałeś sam timer. Powinien być w trybie CT, z automatycznym przeładowaniem okresu.
  • Poziom 12  
    Timer2 pracuje w trybie CTC - po zrównaniu z OCR2 zeruje się.