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.

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

afterparty 24 Lut 2013 21:28 1938 17
  • #1 24 Lut 2013 21:28
    afterparty
    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?

    0 17
  • Pomocny post
    #3 24 Lut 2013 22:39
    BlueDraco
    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.

    0
  • #4 25 Lut 2013 14:29
    afterparty
    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ą.

    0
  • Pomocny post
    #5 25 Lut 2013 15:32
    piotrva
    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.

    0
  • Pomocny post
    #6 25 Lut 2013 15:40
    BlueDraco
    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.

    0
  • #7 25 Lut 2013 20:34
    afterparty
    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ć?

    0
  • #9 26 Lut 2013 16:43
    afterparty
    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?

    0
  • Pomocny post
    #10 26 Lut 2013 17:13
    piotrva
    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).

    0
  • Pomocny post
    #11 26 Lut 2013 17:15
    BlueDraco
    Specjalista - Mikrokontrolery

    Przerwania powinny mieć częstotliwość (300 * liczba_cyfr) Hz, ew. nieco mniejszą. Przy czterech cyfrach idealnie 1200 Hz.

    0
  • #12 26 Lut 2013 19:19
    afterparty
    Poziom 12  

    OK, udało się, wszystko działa, i ładnie świeci. Może tak być?

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    0
  • #13 26 Lut 2013 19:41
    BlueDraco
    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.

    0
  • #14 26 Lut 2013 21:10
    afterparty
    Poziom 12  

    Czy tak będzie lepiej?

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    0
  • #15 26 Lut 2013 21:35
    BlueDraco
    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.

    0
  • #16 28 Lut 2013 15:47
    afterparty
    Poziom 12  

    Dzięki BlueDraco, jesteś niesamowity. Czy coś takiego się sprawdzi?

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    0
  • #17 28 Lut 2013 16:49
    BlueDraco
    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.

    0
  • #18 28 Lut 2013 18:58
    afterparty
    Poziom 12  

    Timer2 pracuje w trybie CTC - po zrównaniu z OCR2 zeruje się.

    0