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] - Obsługa wyświetlaczy 7 LED - pierwsze starcie, krytyka programu

Logan 21 Lip 2012 08:10 2432 18
  • #1 21 Lip 2012 08:10
    Logan
    Poziom 30  

    Witam serdecznie

    Od jakiegoś czasu postanowiłem zakończyć moja przygodę z Bascomem i skupić się na języku C. Okazało się to bardziej czasochłonne niż myślałem, ale powoli idę do przodu. Napisałem program, który w przyszłości będzie zegarkiem, może nawet z termometrem i magistralą RS232, ale to odległa przyszłość.

    Na razie udało mi się opanować Timer0 (bułka z masłem) i obsługę wyświetlaczy 7 segmentowych. Cały myk polega na tym, że segmenty są podłączone do portów B i C. W związku z powyższym proszę i rady, jak napisać ten program lepiej/optymalnie/prościej.

    main.c:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    7led.h:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    7led.c:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    0 18
  • #2 21 Lip 2012 09:58
    excray
    Poziom 39  

    Kod? A gdzie tam jest kod? Przepraszam ale pogubiłem się w tym gąszczu definicji i re-definicji. W zasadzie przemyślane definicje są po to aby ułatwić ewentualne przerobienie programu bądź skrócić jego pisane ale u Ciebie chyba było dokładnie odwrotne zamierzenie.

    0
  • #3 21 Lip 2012 10:32
    Logan
    Poziom 30  

    A tak konkretniej?

    0
  • #4 21 Lip 2012 10:32
    tmf
    Moderator Mikrokontrolery Projektowanie

    Logan napisał:
    Witam serdecznie

    Od jakiegoś czasu postanowiłem zakończyć moja przygodę z Bascomem i skupić się na języku C. Okazało się to bardziej czasochłonne niż myślałem, ale powoli idę do przodu. Napisałem program, który w przyszłości będzie zegarkiem, może nawet z termometrem i magistralą RS232, ale to odległa przyszłość.

    Na razie udało mi się opanować Timer0 (bułka z masłem) i obsługę wyświetlaczy 7 segmentowych. Cały myk polega na tym, że segmenty są podłączone do portów B i C. W związku z powyższym proszę i rady, jak napisać ten program lepiej/optymalnie/prościej.


    Skoro opanowałeś obsługę timera, to zrób jeszcze całą obsługę LED w przerwaniu timera. W pętli głównej się multipleksowania LED nie robi, bo ciężko w to wpleść jakikolwiek inny kod.

    0
  • #5 21 Lip 2012 10:38
    Logan
    Poziom 30  

    tmf napisał:
    Skoro opanowałeś obsługę timera, to zrób jeszcze całą obsługę LED w przerwaniu timera. W pętli głównej się multipleksowania LED nie robi, bo ciężko w to wpleść jakikolwiek inny kod.


    Jaki wtedy jest sens podziały projektu na pliki *.h i *.c skoro część pliku "7led.c" będę miał w pliku związanym z Timer0 ? Chyba, że coś źle zrozumiałem.

    0
  • Pomocny post
    #6 21 Lip 2012 11:15
    mungo
    Poziom 18  

    To jest właśnie cały sens podziału na pliki ;) w pliku z timerem tylko inkludujesz hedery z 7led a wszystkie definicje 7led masz w innym pliku.

    0
  • #7 21 Lip 2012 12:46
    Logan
    Poziom 30  

    Czyli teraz jest źle? Flagi od Timer0 będę używać jeszcze do innych rzeczy, np. obsługi klawiatury. Czy wszystkie te procedury mam umieszczać w obsłudze przerwania? Czy flaga to złe rozwiązanie ? Wszędzie czytałem, że obsługa przerwań powinna być jak najkrótsza.

    0
  • Pomocny post
    #8 21 Lip 2012 14:13
    tmf
    Moderator Mikrokontrolery Projektowanie

    Logan napisał:
    tmf napisał:
    Skoro opanowałeś obsługę timera, to zrób jeszcze całą obsługę LED w przerwaniu timera. W pętli głównej się multipleksowania LED nie robi, bo ciężko w to wpleść jakikolwiek inny kod.


    Jaki wtedy jest sens podziały projektu na pliki *.h i *.c skoro część pliku "7led.c" będę miał w pliku związanym z Timer0 ? Chyba, że coś źle zrozumiałem.


    Źle do tego podchodzisz. Podział na pliki nie robi się dla samego podziału - to ma czemuś służyć, np. poprawie czytelności kodu, czy wprowadzeniu niezależnych modułów. Więc jeśli 7led.c korzysta z timera to można to połączyć razem i nic w tym złego nie ma.

    Dodano po 4 [minuty]:

    Logan napisał:
    Czyli teraz jest źle? Flagi od Timer0 będę używać jeszcze do innych rzeczy, np. obsługi klawiatury. Czy wszystkie te procedury mam umieszczać w obsłudze przerwania? Czy flaga to złe rozwiązanie ? Wszędzie czytałem, że obsługa przerwań powinna być jak najkrótsza.


    Funkcje obsługi przerwań mają być krótkie, ale mają też jakieś zadanie do wykonania. Po co przez pooling w kodzie main sprawdzać stan flagi, jeśli bez sprawdzania daną funkcję można zrealizować w przerwaniu? Dla multipleksowania LED istotne są czasy, tylko pisząc to jako handler przerwania jesteś w stanie je kontrolować. Tak nawiasem mówiąc obsługa multipleksowania jest tak krótka, że CPU nawet jej nie zauważy. Tak samo klawisze - można zrealizować obsługę w przerwaniu, dzięki temu wygodnie też realizuje się debouncing. Dzięki czemu w kodzie programu po prostu sprawdzasz jakąś zmienną odzwierciedlającą stan klawiszy i nie musisz sprawdzać czy to drgania, szum czy inne zło.
    Także zachęcam cię do wywalenia tego kodu i zaczęcia od nowa, tym razem z przerwaniami. Będziesz zaskoczony jak elegancki kod można napisać.
    BTW, te wszystkie ify w multipleksowaniu są zupełnie zbędne, zastanów się jak je wywalić.

    0
  • #9 21 Lip 2012 15:26
    zumek
    Poziom 39  

    Ja natomiast stwierdzam, że załapałeś "zarazę wskaźnikową".

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Po co Ci te wskaźniki :?:

    0
  • #10 21 Lip 2012 18:54
    Logan
    Poziom 30  

    :arrow: zumek Myślałem, że to najlepsza metoda na przekazywanie zmiennych do funkcji, tak, żeby funkcja mogła je modyfikować.

    :arrow: tmf Rozumiem, mam nadzieję, że nie przesadziłem teraz w "drugą stronę" ;)
    Czy teraz jest lepiej?
    main.c:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    timer0.c:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    timer0.h:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    led7.h:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • Pomocny post
    #11 21 Lip 2012 20:09
    tmf
    Moderator Mikrokontrolery Projektowanie

    Moim zdaniem zdecydowanie lepiej, niesądzisz? Przede wszystkim zysk jest taki, że multipleksowanie robi się "samo" i w main sobie piszesz co chcesz.
    Popracuj jeszcze nad jedną kwestią, która zmniejsza czytelność kodu - zasięg zmiennych. Zastanów się, które zmienne naprawdę muszą być globalne, a które nie. Te, które nie muszą zrób jako zmienne lokalne. Kolejna rzecz - czas czasami prościej trzymać w spakowanym BCD, zaoszczędza to każdorazowej konwersji. Podobnie, tablice ze stałymi, np. konwersji cyfra-segmenty można umieścić we FLASH (makro PROGMEM), po co niepotrzebnie zajmować pamięć. No i też zasięg zmiennej - skoro tablica jest wykorzystywana wyłącznie w ISR, to czemu jej tam nie zdefiniować?
    Pamiętaj też, że tablice można jednocześnie deklarować i definiować, co powoduje, że kod jest czytelniejszy - nie ma potrzeby definicji tablicy w kodzie, co tylko prowadzi do wygenerowania dłuższego kodu.

    0
  • #12 22 Lip 2012 13:22
    Logan
    Poziom 30  

    Faktycznie, kod jest teraz dużo czytelniejszy i mniej porozrzucany. Zmienne już uporządkowałem. Z BCD masz rację, będzie mi potrzebny przy DS1307 oraz przy transmisji przez UART. Wymyśliłem coś takiego:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Podobne rozwiązanie chcę zastosować dla godzin, czy to dobra droga?

    FLASHem się jeszcze "nie bawiłem", jak wrzucę tam co potrzeba to się "pochwalę" kodem.
    Przeniosłem też definicję tablicy zaraz przy jej deklaracji.

    0
  • #13 22 Lip 2012 14:11
    tmf
    Moderator Mikrokontrolery Projektowanie

    Trochę sobie zaoszczędzisz kodowania jak popatrzysz jak wygląda korekcja BCD przy dodawaniu binarnym. Te wszystkie ify nie są potrzebne - poczytaj o BCD.

    0
  • #14 22 Lip 2012 18:19
    Logan
    Poziom 30  

    tmf napisał:
    Trochę sobie zaoszczędzisz kodowania jak popatrzysz jak wygląda korekcja BCD przy dodawaniu binarnym. Te wszystkie ify nie są potrzebne - poczytaj o BCD.


    Code:
    Po wykonaniu standardowej operacji nad liczbami w kodzie BCD należy sprawdzić i w razie potrzeby skorygować wynik. Dla dodawania i odejmowania korekcja będzie potrzebna wtedy, gdy dana grupa bitów reprezentujących cyfrę dziesiętną ma wartość większą od 9 (binarnie 1001). W takiej sytuacji do grupy tej należy dodać (dla odejmowania odjąć) wartość binarną 0110 (dziesiętnie 6).


    Wnioskuję z tego, że dalej muszę stosować ify.

    Dodano po 3 [godziny] 9 [minuty]:

    main.c:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    timer0.h:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    timer0.c:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Coś jeszcze można zmienić ?

    0
  • #15 22 Lip 2012 18:51
    tmf
    Moderator Mikrokontrolery Projektowanie

    Tak, ify ciągle są niezbędne w C, miałem na myśli wstawkę w assemblerze i wykorzystanie flagi half-carry, co prawda ciągle potrzebujesz instrukcje skoku warunkowego, a już nie trzeba robić CP/CPI. To oczywiście niewiele zmienia i chyba nie ma sensu się w to babrać. Tak przy okazji masz błąd w sekwencji:
    if(((godziny_bcd & 0xF0) == 2) & ((godziny_bcd & 0x0F) > 3))
    Nie bardzo też kojarzę czemu ma służyć to:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Licznik sam się przeładuje.[/quote]

    0
  • #16 22 Lip 2012 19:39
    Logan
    Poziom 30  

    Faktycznie bez problemu udało mi się ustawić godzinę "dwudziestą piątą" :D
    Zmieniłem na

    Kod: c
    Zaloguj się, aby zobaczyć kod
    i teraz działa poprawnie.

    Zmienna licznik jest używana podczas multipleksowania (4 wyświetlacze) w funkcji switch(licznik).

    Do T0 wpisuje wartość początkową, żeby zliczał mi 255 - WART_POCZ impulsów.

    0
  • #17 22 Lip 2012 20:10
    tmf
    Moderator Mikrokontrolery Projektowanie

    No tak, taka operacja na liczniku może być wykonana z użyciem operatora modulo (%) lub maskowania - zauważ, że ciebie interesują tylko dwa najmłodsze bity, reszta ma mieć zero. To oczywiście bez znaczenia, ale warto zacząć myśleć binarnie :)
    Co do T0 - jeśli potrzebujesz określoną liczbę impulsów, to prościej zmienić tryb pracy T0 i zmienić wartość top do której zlicza licznik. To też szczegół, ale jeśli coś się da zrobić hardwarowo...

    0
  • #18 22 Lip 2012 22:51
    LordBlick
    VIP Zasłużony dla elektroda

    tmf napisał:
    Co do T0 - jeśli potrzebujesz określoną liczbę impulsów, to prościej zmienić tryb pracy T0 i zmienić wartość top do której zlicza licznik. To też szczegół, ale jeśli coś się da zrobić hardwarowo...
    W ATmega8 nie ma takiej możliwości, Timer0 nie ma trybu CTC. Można użyć Timer2, jeśli nie jest zajęty... :P

    0
  • #19 23 Lip 2012 12:45
    Logan
    Poziom 30  

    Myślę, że temat został wyczerpany. Dziekuję za pomoc. Zamykam.

    0