Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania

p.kaczmarek2 02 Apr 2020 01:54 1413 4
  • Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Witajcie moi drodzy
    Zapraszam na kolejną część mojego tutoriala PIC18F2550 i kompilatora SDCC.
    W tej części zademonstruję jak używać wyświetlacza 7-segmentowego z PIC18F2550. Kod obsługi wyświetlacza będzie oczywiście napisany w oparciu o przerwania i timery.
    Cały proces powstawania układu na płytce stykowej oraz programu na PICa przedstawię krok po kroku, w każdym kroku będę wprowadzać dodawać dodatkową funkcjonalność i opisywać co zmieniłem.
    Zacznę od prostych rzeczy, a potem będą bardziej zaawansowane.

    Spis części (osobnych tematów) tutoriala
    Tutorial podzielony jest na osobne tematy i tutaj znajdują się do nich linki.
    Część 1 - Konfiguracja środowiska pracy
    https://www.elektroda.pl/rtvforum/viewtopic.php?p=18304424#18304424
    Część 2 - Hello world, piny IO, cyfrowe wejścia i wyjścia
    https://www.elektroda.pl/rtvforum/viewtopic.php?t=3647884&highlight=
    Część 3 - Ustawienia oscylatora. Oscylator wewnętrzny, zewnętrzny, rezonator kwarcowy, PLL
    https://www.elektroda.pl/rtvforum/viewtopic.php?t=3657704&highlight=
    Część 4 - Timery, przerwania
    https://www.elektroda.pl/rtvforum/viewtopic.php?p=18580858#18580858
    Część 5 - Obsługa wyświetlacza siedmiosegmentowego
    https://www.elektroda.pl/rtvforum/viewtopic.php?p=18580877#18580877
    Spis treści będzie uzupełniany wraz z pisaniem przeze mnie kolejnych części.


    Krok 1 - podstawy o wyświetlaczach 7-segmentowych
    Na początek wypada napisać kilka słów o wyświetlaczach, który są bohaterem tego tematu.
    Wyświetlacz 7-segmentowy to tak naprawdę najzwyklejsze diody LED w jednej obudowie i każda dioda odpowiada innemu fragmentowi cyfry:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Cała kontrola wyświetlacza sprowadza się do sprytnego zapalania poszczególnych fragmentów tak by powstały znaki.
    Każdy fragment wyświetlacza ma swoją ogólnoprzyjętą nazwę, kolejno 'fragment a', 'fragment b', itp, co pokazano na obrazku:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    (Źródło obrazka: Wikipedia, licencja CC0)
    Z natury wyświetlaczy 7-segmentowych łatwo jest wywnioskować, że nie są w stanie one wyświetlić naprawdę dużej ilości różnych znaków. Grafika poniżej pokazuje wszystkie możliwe kombinacje symboli na takim wyświetlaczu:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    (Źródło obrazka: Wikipedia, licencja CC0)
    W celu zmniejszenia ilości pinów wyświetlacza i uproszczenia sterowania z reguły łączy się tworzące jego LEDy razem anodami lub katodami.
    Czyli dostępne są dwa rodzaje wyświetlaczy 7-segmentowych:
    - wyświetlacze o wspólnej katodzie (ang. 'common cathode') - są to wyświetlacze, których diody LED po prostu są połączone katodami
    - wyświetlacze o wspólnej anodzie (ang. 'common anode') - są to wyświetlacze, których diody LED po prostu są połączone anodami
    Poniżej pokażę konkretny przykład takiego wyświetlacza.

    Krok 2 - wybieramy i poznajemy nasz wyświetlacz
    Wyświetlacze są różne i różnią się rozmieszczeniem pinów oraz rozmiarem, dlatego postarałem się wybrać coś, co jest w miarę popularne i łatwodostępne.
    Wybór padł na 3461AS - wyświetlacz 7-segmentowy o wspólnej katodzie z kropkami.
    3461AS jest łatwo dostępny w sklepach online i można kupić go np. na Aliexpress:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Wyświetlacz ten jest też dostępny na eBayu:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Wyświetlacz ten jest rozmiaru 0.36 cala, posiada 4 cyfry i właściwie 8 segmentów (ósmym jest kropka).
    Jest to wyświetlacz z wspólną katodą, ale też dostępna jest jego siostrzana wersja 3461BS z wspólną anodą.
    Schemat poniżej pokazuje rozpiskę pinów tego wyświetlacza:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Dla porównanie poniżej umieszczam rozpiskę jego siostrzanej wersji z wspólną anodą:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Cały ten temat będzie bazować właśnie na nim, ale oczywiście bez problemu można do niego dopasować inny wyświetlacz.

    Krok 3 - podłączamy wyświetlacz (na razie wszystkie cyfry razem)
    Na początek podłączymy wyświetlacz tylko razem z rezystorami na osobnej płytce stykowej.
    Starczy nam mniejsza płytka stykowa oferująca 400 pól:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    I oczywiście rezystory - tak jak dla każdej diody LED:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Ja wybrałem 220Ω. Wartość ta nie jest krytyczna, ale bardzo ważne jest byśmy pamiętali o tym ile wybrany przez nas mikrokontroler jest w stanie zapewnić prądu ze swoich pinów.
    PIC18F2550 jest w stanie zapewnić 25mA z każdego pinu:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Należy też pamiętać o tym ile w sumie prądu jest zapewnić ten PIC, dla PIC18F2550 to jest 200mA:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Sam rezystor dla fragmentu wyświetlacza (czyli diody LED) liczymy oczywiście tak jak dla diody LED.
    Warto jest znać w tym celu spadek napięcia na fragmencie wyświetlacza, ale można też założyć standardowy po kolorze LEDa (dla czerwonej 2V).
    Do liczenia można skorzystać z gotowego kalkulatora:
    http://ledcalc.com/
    Przykład obliczeń dla 15mA na diodę LED (a i tak starczyłaby pewnie połowa z tego lub mniej):
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Mamy 8 segmentów, w najgorszym wypadku jest zatem 8*15mA = 120mA, czyli i tak poniżej 200mA limitu.


    Ale starczy tyle teorii, teraz można przejść do składania układu.
    Na początek umieściłem wyświetlacz na płytce stykowej:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Następnie zworki od katod do masy (na początek; potem użyjemy tu tranzystorów):
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Dalej rezystory dla każdego segmentu (8 segmentów, 7 segmentów cyfry i kropka):
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    (jeden z rezystorów na zdjęciu jest niewidoczny, zasłania go wyświetlacz)
    Po tym podłączyłem płytkę z wyświetlaczem do reszty układu:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    W tym momencie można się już pobawić i potestować czy poszczególne fragmenty się świecą.
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Następnie zdecydowałem się już podłączyć wyświetlacz do portu PICa.
    Wyświetlacz najlepiej jest podłączyć do jednego portu, gdyż każdy port ma osobny rejestr, a gdy wszystkie diody wyświetlacza są na jednym porcie to łatwiej można go obsługiwać w kodzie. Wtedy ustawienie wszystkich segmentów wyświetlacza można zrealizować jedną linijką, np:
    Code: c
    Log in, to see the code

    Porty w PIC18F2550 są ośmiobitowe a my mamy 8 segmentów, więc aż prosi się wybrać port B którego wszystkie piny mamy dostępne:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Co prawda na port B jest też złącze do programowania (ICSP), ale nasze diody nie będą zakłócać jego działania.
    Na tym etapie możemy już z poziomu PICa pomigać wyświetlaczem, kod jest banalny, to po prostu klasyczny blink LED:
    Code: c
    Log in, to see the code

    Rezultat działania kodu:

    Działa, w następnym akapicie pójdziemy o krok dalej.
    Pełna paczka p18f2550_blinkPortB_intOsc1MHz.zip z przykładem do pobrania (kod w C, skompilowany .hex, .bat do kompilacji w SDCC):
    p18f2550_b...sc1MHz.zip Download (9.2 kB)Points: 0.5 for user

    Krok 4 - obsługa wyświetlacza bez podziału na cyfry
    Mamy już wyświetlacz podłączony do portu B. Teraz trzeba zaprogramować PICa tak, by potrafił wyświetlać cyfry.
    W tym celu najpierw określimy które bity portu B odpowiadają którym fragmentom wyświetlacza.
    Dla przypomnienia, nazwy fragmentów wyświetlacza są na rysunku:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    (Źródło obrazka: Wikipedia, licencja CC0)
    Parowanie segment<->bit portu zapiszemy z pomocą preprocesora w kodzie:
    Code: c
    Log in, to see the code

    W powyższym fragmencie kodu mamy makro FLAG_BIT które zamienia numer bitu (0, 1, 2, ... 7) na jego flagę/wartość (1, 2, 4, 8, ... 128). Przyda się to nam nieco dalej, ale najpierw musimy uzupełnić makra SEGMENT_A, SEGMENT_B itp. by były zgodne z tym jakie mamy podłączenia do portu B.
    Można to zrobić na dwa sposoby:
    - po prostu prześledzić nasze połączenia (na schemacie i/lub płytce)
    - albo zapalać kolejne bity portu B i patrzeć które fragmenty wyświetlacza się świecą
    Po uzupełnieniu wyszło mi:
    Code: c
    Log in, to see the code

    Teraz mamy już pełne mapowanie pin<->fragment i możemy utworzyć z niego cyfry. Do tego też użyjemy preprocesora i oczywiście obrazka poglądowego z Wikipedii. Cyfry powstaną jako wynik operacji OR na poszczególnych bitach odpowiedzialne za fragmenty.
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    (Źródło tabelki: Wikipedia)
    W moim kodzie wygląda to tak:
    Code: c
    Log in, to see the code

    Opracowałem w sposób widoczny powyżej wszystkie cyfry, ewentualne litery zostawiam do opracowania czytelnikom.
    Teraz można sprawdzić czy cyfry wyświetlane są poprawnie, na razie w prosty sposób:
    Code: c
    Log in, to see the code

    Rezultat powyższego kodu uwieczniłem na filmie:

    Jak widać, wszystko działa.
    W tym momencie jeszcze przyda się jakiś wygodny sposób wyświetlenia danej liczby od 0 do 9 na wyświetlaczu bez pomocy wpisywania na sztywno wartości makra do LATB. Użyjemy w tym celu tablicy:
    Code: c
    Log in, to see the code

    Od teraz wartość liczby będzie indeksem tablicy i sama tablica zwróci nam odpowiednią wartość dla portu B.
    Program testowy:
    Code: c
    Log in, to see the code

    Filmik z działania:

    Obsługa segmentów gotowa. W następnym akapicie zajmiemy się podziałem na cyfry.
    Pełna paczka p18f2550_7seg_simple_intOsc1MHz.zip z przykładem do pobrania (kod w C, skompilowany .hex, .bat do kompilacji w SDCC):
    p18f2550_7...sc1MHz.zip Download (12.57 kB)Points: 0.5 for user

    Krok 5 - dodajemy tranzystory i podział na cyfry
    Teraz musimy w jakiś sposób podłączyć wspólne katody każdej cyfry tak, by móc nimi sterować. W tej chwili są podłączone bezpośrednio do masy, nie może tak dalej być.
    Kuszące mogłoby być podłączenie katod wyświetlaczy bezpośrednio do pinów PICa, ale niestety to nie sprawdzi się względu na to jakie prądy tam płyną. Jeśli zapalimy jednocześnie wszystkie 8 segmentów, to przy wybranych teraz rezystorach popłynie tam jakieś 120mA!
    Musimy zatem użyć tranzystorów NPN. Ja wybrałem popularnego BC547:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Jego wyprowadzenia pokazują zrzuty ekranu z noty katalogowej:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Pełna nota katalogowa do pobrania:
    BC547.pdf Download (43.91 kB)
    Do tego potrzebne będą cztery rezystory o oporze rzędu 1kΩ do ograniczenia prądu bazy tranzystorów:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Zaczniemy od umieszczenia tranzystorów na płytce stykowej (ich emitery razem, do masy):
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Następnie podłączymy ich kolektory do wspólnych katod cyfr i damy po rezystorze na ich bazy:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Na tym etapie można podpiąć bazę każdego tranzystora (przez rezystor) do zasilania by sprawdzić czy jest ok (w sumie to nawet dotknięcie tej bazy może sprawdzić lekkie zaświecenie się wyświetlacza):
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Ale my oczywiście chcemy sterować bazami z poziomu PICa, więc musimy wybrać na jakie piny je podłączymy.
    Ja wybrałem pierwsze cztery piny portu A:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Zdjęcie przedstawia już wykonane połączenie:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    W tym momencie musimy w kodzie odpowiedni skojarzyć piny portu A z tranzystorami.
    Całość będzie działać tak, że w danym momencie:
    - jeden pin będzie mieć stan wysoki (tranzystor będzie włączony, jedna cyfra będzie świecić)
    - pozostałe trzy piny będą mieć stan niski (tranzystory będą wyłączone, cyfry zgaszone)
    W celu sprawdzenia tego przygotowałem prosty przykładowy kod:
    Code: c
    Log in, to see the code

    Tu warto zwrócić uwagę, że powiązanie danego pinu portu A z daną cyfrą mogłoby być inne, i możemy sobie to do woli zmieniać np. jeśli np. projektujemy płytkę i chcemy wygodniej pociągnąć ścieżki.
    Rezultat kodu powyżej uwieczniłem na filmiku:

    Cyfry kolejno się zapalają, wszystko działa. W następnym akapicie będziemy zapalać je nieco szybciej.


    Krok 6 - przyśpieszamy, czyli multiplexing bez przerwań
    Teraz spróbujemy wyświetlić liczbę czterocyfrową, tzn. zapalić cztery cyfry jednocześnie (choć w praktyce, nie będzie to dosłownie jednocześnie).
    W tym celu wprowadzimy multiplexing.
    Multiplexing polega na tym, że kolejno zapalamy tylko po jednej cyfrze, ale wykonujemy to tak szybko, że ludzkie oko nie jest w stanie dostrzec tego przełączania i sami odnosimy wrażenie, że świecą się po prostu ciągle wszystkie cyfry.
    W tym celu zmodyfikujemy poprzedni kod tak by delaye wynosiły nie 1000ms, lecz na przykład 4 ms:
    Code: c
    Log in, to see the code

    Czemu 4ms? Jeśli przyjmiemy, że chcemy mieć częstotliwość odświeżania całego wyświetlacza 50Hz (a 50Hz to jest z reguły częstotliwość odświeżania ekranów) to na jedno odświeżenie całości przypada 1000/50=20ms, czyli na jedną cyfrę 5ms, ja dałem z zapasem 4ms.
    Dodatkowo w kodzie przed przełączeniem cyfry gaszę wszystkie segmenty by uniknąć tzw. efektu ghosting, czyli 'prześwitywania' fragmentów poprzednich cyfr na skutek wolnej szybkości przełączania.
    Rezultat działania:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    W ten sposób zrobiliśmy prosty multiplexing 4 cyfr, ale jeszcze zostało go ulepszyć.
    Pełna paczka p18f2550_7seg_simple2_intOsc1MHz.zip z przykładem do pobrania (kod w C, skompilowany .hex, .bat do kompilacji w SDCC):
    p18f2550_7...sc1MHz.zip Download (10.89 kB)Points: 0.5 for user

    Krok 7 - multiplexing z pomocą timera i przerwania
    Teraz musimy tylko przepisać powyższy kod tak by korzystał z timera i przerwania PICa.
    Do tego celu użyję Timera 0 oraz kalkulatora 'Timer Calculator' od Mikro C:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Na bazie tego zmodyfikowałem swój kod tak by przerwanie wykonywało się co 4 ms i przeniosłem do niego to co wcześniej działo się w pętli while:
    Code: c
    Log in, to see the code

    W kodzie zmieniłem też wyświetlanie cyfr tak by było "1234" a nie "0123", tylko w celu pokazania zmiany.
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Multiplexing na przerwaniu działa, choć uważam, że powyższy kod można by nieco ulepszyć.
    Pełna paczka p18f2550_7seg_tmr_intOsc1MHz.zip z przykładem do pobrania (kod w C, skompilowany .hex, .bat do kompilacji w SDCC):
    p18f2550_7...sc1MHz.zip Download (15.87 kB)Points: 0.5 for user

    Krok 8 - dodajemy jakieś odliczanie
    Multiplexing już działa, ale warto byłoby jeszcze cokolwiek sensownego pokazywać na naszym wyświetlaczu.
    W ramach przykładu po prostu będziemy odliczać kolejne liczby (z tym, że nie jest to dokładny sposób na odliczanie i nie można powiedzieć, że to jest sekundnik) w funkcji main.
    Zrealizujemy tak, że dodamy zmienną globalną g_counter którą będziemy inkrementować o 1 oraz dodamy tablicę g_digits[4] w której zapamiętamy jakie cyfry chcemy wyświetlać na danej pozycji.
    W funkcji main ważną operacją będzie rozbicie liczby całkowitej g_counter na poszczególne cyfry, użyjemy do tego operacji modulo % i dzielenia całkowitego.
    Nowy kod:
    Code: c
    Log in, to see the code

    Rezultat działania na filmie:

    Pełna paczka p18f2550_7seg_tmr_counter_intOsc1MHz.zip z przykładem do pobrania (kod w C, skompilowany .hex, .bat do kompilacji w SDCC):
    p18f2550_7...sc1MHz.zip Download (20.28 kB)Points: 0.5 for user

    Krok 9 - dodatek - programowa regulacja jasności wyświetlacza
    Na tym układzie co mamy można łatwo zrealizować regulację jasności wyświetlacza - bez modyfikacji hardware.
    Po prostu tak jak z pomocą PWM reguluje się np. jasnością diody LED, tak my z pomocą Timera zrobimy regulacje jasności całego wyświetlacza.
    Tutaj jednak pomocne będzie zwiększenie częstotliwości taktowania PICa. W poprzednich przykładach używałem domyślnego 1MHz wewnętrznego oscylatora, ale teraz wybrałem 8MHz:
    Code: c
    Log in, to see the code

    Musimy pamiętać o tym, że przy 1MHz jeden cykl instrukcji wynosi 0.25MHz czyli 4us. Jakbyśmy chcieli mieć np. przerwanie co 50us i mielibyśmy w nim z 12 instrukcji (12*4 = 48us) to byłoby już źle. Należy też pamiętać, że jedna linijka kodu to często wiele instrukcji...
    Ja chciałem mieć przerwanie co 50us, więc wybrałem częstotliwość 8MHz, co daje 2MHz cykl instrukcji - 0.5us trwać będzie jedna instrukcja.
    Uznałem, że będzie 50 różnych poziomów jasności i czas wyświetlania jednej cyfry będzie się wynosić:
    - przy największej jasności 50*50us = 2500us czyli 2.5ms
    - przy najmniejszej jasności 50us (przez pozostałe 2450us będzie zgaszona)
    Cały cykl wyświetlania 4 cyfr będzie trwać około 2.5ms*4 = 10ms, czyli 100Hz częstotliwość odświeżania.
    (Uwaga: te obliczenia powyżej są obarczone małym błędem względem tego co jest w kodzie, m. in. dlatego że ustawiam rejestry TMR0H i TMR0L dopiero po wykonaniu operacji z przerwania, ale to pomijalne).
    Timer 0 więc ustawiłem wedle parametrów z kalkulatora:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Dodałem stałą określającą ile cyklów przypada na jedną cyfrę oraz zmienne step (krok bieżącego wyświetlania cyfry) i bright (bieżąca jasność):
    Code: c
    Log in, to see the code

    I w przerwaniu dodałem warunek który włącza cyfrę dopiero gdy zmienna step osiągnie wartość brig (czyli brig=0 oznacza największą jasność) oraz zwiększanie licznika kroków:
    Code: c
    Log in, to see the code

    Działa to tak:
    - na wyświetlanie jednej cyfry przypada BRIGHTNESS_CYCLES przerwań
    - co każde przerwanie inkrementuje step
    - gdy licznik step osiągnie wartość bright (bieżąca jasność) to zapalamy bieżącą cyfrę
    - gdy licznik step osiągnie wartość BRIGHTNESS_CYCLES to jest zerowany i przełączamy na następną cyfrę
    Kod można zoptymalizować poprzez zwiększenie okresu przerwań i zmniejszenie ilości BRIGHTNESS_CYCLES, tylko wtedy stracimy 'rozdzielczość' kontroli jasności.
    Pełny kod:
    Code: c
    Log in, to see the code

    Filmik z działania - test zmiany jasności:

    Filmik z działania - wersja odliczająca i zmieniająca jasność:


    Niestety filmiki nie oddają w pełni tego jak efekt wygląda na żywo - video nagrane telefonem nieco przekłamuje i pokazuje miganie które nie jest odczuwalne na żywo, to pewnie wynika z tego ile klatek ma film.

    Taka regulacja jasności jest bardzo fajna, ale trzeba uważać, by nie przesadzić z częstotliwością timera. Jeśli będziecie mieć jakieś kłopoty z powyższym kodem, polecam zwiększyć okres timera i zmniejszyć wartość BRIGHTNESS_CYCLES.

    Pełna paczka p18f2550_7seg_tmr_counter_brightness_intOsc8MHz.zip z przykładem do pobrania (kod w C, skompilowany .hex, .bat do kompilacji w SDCC):
    p18f2550_7...sc8MHz.zip Download (20.21 kB)Points: 0.5 for user


    Krok 10 - Prosty sekundnik w oparciu o drugi Timer
    Bieżący kod możemy łatwo zmodyfikować tak, by w miarę dokładnie odmierzać sekundy.
    Wystarczy użyć do tego któregoś z wolnych Timerów, np. Timera 1.
    Nie będzie to oczywiście odmierzanie czasu na poziomie RTCC (czyli Real Time Clock Calendar), zwłaszcza, że korzystamy z niedokładnego wewnętrznego oscylatora PICa a nie z kwarcu zegarkowego 32.768kHz, ale do prostego minutnika jak bardziej się nada.
    Najwygodniej byłoby tu mieć przerwanie wywoływane co sekundę, ale przy zegarze PICa 8MHz niestety Timer 1 nie jest w stanie pokryć tak dużego czasu:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Więc ustawimy timer tak, by wyzwalał zdarzenie co 100ms:
    Tutorial PIC18F2550 + SDCC - Część 5 - Wyświetlacz 7-segmentowy i przerwania
    Ilość okresów 100ms będzie zliczana w zmiennej cnt_100ms, dla wygody wyświetlacz będziemy odświeżać w głównej pętli.
    Pełny kod:
    Code: c
    Log in, to see the code

    Rezultat działania na filmie o długości 60 sekund:

    Pełna paczka p18f2550_7seg_tmr_counter_brightness_1s_intOsc8MHz.zip z przykładem do pobrania (kod w C, skompilowany .hex, .bat do kompilacji w SDCC):
    p18f2550_7...sc8MHz.zip Download (24.29 kB)Points: 0.5 for user


    Krok 11 - Dodajemy obsługę kropki
    Opisałem już 10 kroków rozwijania obsługi wyświetlacza 7-segmentowego a nie wspomniałem nic o kropce.
    Pora to zmienić.
    Od strony sprzętowej kropka nie różni się niczym od pozostałych fragmentów cyfry. Mamy już ją podłączoną.
    Musimy tylko jakoś przekazać do przerwania informację o tym kiedy trzeba będzie wyświetlać kropkę, będzie to osobno niż same cyfry.
    Do tego celu użyłem dodatkowej zmiennej:
    Code: c
    Log in, to see the code

    Kolejne bity tej zmiennej będą mówić nam czy na danym miejscu (danej cyfrze) należy wyświetlić kropkę.
    Uwzględniłem to też w funkcji przerwania:
    Code: c
    Log in, to see the code

    Teraz funkcja przerwania sprawdza czy odpowiadający bieżącej cyfrze bit zmiennej g_dot jest zapalony i jeśli tak to dodatkowo zapala kropkę na wyświetlaczu.
    Jeszcze trzeba to ustawić od strony zewnętrznej, spoza przerwania, w funkcji wyświetlającej wybrana zmienną.
    Dlatego zrobiłem wersję dla napisu (tablica charów, tzw. string):
    Code: c
    Log in, to see the code

    Funkcja powyżej obsługuje wyświetlanie tablicy znaków, gdzie znaki to oczywiście muszą być cyfry, ale uwzględnia też kropki. Pozwala wyświetlić np:
    Code: c
    Log in, to see the code

    Dodatkowo wydzieliłem wersję dla typu int (liczba całkowita - bez kropki). Nazwałem ją analogicznie, displayInt:
    Code: c
    Log in, to see the code

    Oto pełny kod (dla prostoty i odciążenia PICa zrezygnowałem z regulacji jasności):
    Code: c
    Log in, to see the code

    I rezultat działania na filmie:

    Dużo tu można by usprawnić, dodać np. wsparcie wyświetlania 'pustego' znaku (brak zapalonych segmentów), dodać wyświetlanie znaków A, B, C, D, E, F (by móc wyświetlać szesnastkowo), ale myślę, że na początek starczy tyle ile zaprezentowałem.
    Pełna paczka p18f2550_7seg_tmr_counter_floatingPoint_intOsc8MHz.zip z przykładem do pobrania (kod w C, skompilowany .hex, .bat do kompilacji w SDCC):
    p18f2550_7...sc8MHz.zip Download (30.7 kB)Points: 0.5 for user

    Ostrzeżenie - niezdefiniowane działanie PICa i dziwne problemy z przerwaniami
    Tutaj chciałbym tylko przestrzec początkujących przed pewnym dość popularnym i ciężkim do zdiagnozowania błędem.
    Sam się z nim nie raz spotykałem, więc uznałem, że warto poświęcić na to cały akapit.
    A mianowicie PIC może zachowywać się w dziwny sposób jeśli będziemy wywoływać przerwanie szybciej niż jest on w stanie je obsługiwać. To znaczy, jeśli w przerwaniu damy dłuższy fragment kodu który przekłada się na dużą ilość instrukcji to możliwe jest, że timer będzie chciał ponownie wywołać przerwanie nim się wykonywanie tego kodu skończy. Może to prowadzić do trudnych do zdiagnozowania błędów i niezdefiniowanego zachowania PICa.
    Więc przede wszystkim proszę pamiętać o tym, by nie przesadzać z częstotliwością przerwań i z ilością kodu w funkcji obsługującej przerwania...
    Jeśli nie mamy pewności co się dzieje, to warto np. zmniejszyć częstotliwość przerwania albo po prostu policzyć sobie z wartości zegara i ilości instrukcji w przerwaniu czy wszystko zdąży się wykonać (w pliku .asm generowanym przez SDCC można podejrzeć instrukcje). Można też oczywiście włączać ponownie Timer dopiero po wykonaniu tego całego kodu - ale wtedy z kolei tracimy dokładność i okres timera jest dłuższy niż sobie wyliczymy.

    Co można by zrobić lepiej?
    Przedstawiony tu kod i rozwiązania można by zoptymalizować, ulepszyć i przyśpieszyć jego działanie. Niestety byłoby to m. in. kosztem czytelności kodu. Mimo to wymienię tutaj kilka zmian, które możecie zrobić sami w ramach ćwiczenia:
    - można spróbować się pozbyć wolnych operacji dostępu do tablicy z pomocą [ ]
    - przełączanie kolejnych cyfr można by zrealizować z pomocą prostego przesunięcia bitowego (całkiem wyrzucić tablicę), tzn. operatora >> lub <<, jedynie trzeba by zamienić odpowiednio kolejność kabelków do poszczególnych segmentów bo << i >> przesuwają tylko o jeden bit.
    - można by nieco zwiększyć jasność świecenia cyfr, teraz pomiędzy gaszeniem poprzedniej cyfry a ustawianiem nowej mija dość dużo cyklów instrukcji ze względu na użycie [] (dostępu do tablic), można by chociażby odczytywać z tablic do tymczasowych zmiennych a potem dopiero gasić poprzednią cyfrę i ustawiać następną na zawartość zmiennej tymczasowej
    - w skrajnym przypadku można by po prostu przepisać to do assemblera; przy dobrej znajomości assemblera napisany kod może być wydajniejszy niż ten z kompilatora języka C

    Podsumowanie
    Pokazałem tutaj krok po kroku jak można zaprogramować obsługę wyświetlacza 7-segmentowego dla PIC18F2550 w kompilatorze SDCC. Zacząłem od prostego wyświetlenia jednej cyfry, bez przerwań i tranzystorów, a potem stopniowo też i je wprowadziłem. Każdy zaprezentowany tu przykładowy kod jest działający i został sprawdzony przeze mnie. W razie pytań/uwag zapraszam na PW, temat będzie jeszcze redagowany.

    Cool! Ranking DIY
    Can you write similar article? Send message to me and you will get SD card 64GB.
    About Author
  • IGE-XAOIGE-XAO
  • IGE-XAOIGE-XAO
  • #3
    p.kaczmarek2
    Level 25  
    Seba_smd wrote:
    Jak zawsze kawał dobrej roboty i poświęconego czasu.


    Dzięki, materiału jest do przerobienia bardzo dużo, a ja jeszcze ciągle ulepszam poprzednie części i wprowadzam poprawki.

    Zastanawiałem się też czy na pewnym etapie tutorialu nie zrobić jakiegoś "mini projektu" na normalnej PCB, na przykład wziąć ten 7-segmentowy wyświetlacz i zrealizować na nim prosty sekundnik do kuchni (dwa przyciski, buzzer?).
    Oparł bym to na darmowej wersji Eagle (z limitacją rozmiaru płytki; bo ten program znam).
    Czyli opis mini-projektu by zawierał:
    - najpierw na bazie tego tematu o wyświetlaczu informacje jak przygotować kod w C, prototyp na płytce stykowej
    - potem opis jak przerysować to do Eagle schematu
    - potem opis jak zrobić PCB w Eagle
    - potem opis jak wyeksportować PCB do Gerberów
    - potem opis jak zamówić PCB w płytkarni z której ja korzystam (niestety korzystam z tych z Chin ze względu na cene)
    - potem opis jak to zlutować i uruchomić...

    A następna, szósta część tutorialu chyba będzie o ADC
  • #5
    yogi009
    Level 43  
    Bardzo dobry wykład, gratuluję, brakuje mi czegoś takiego pod AVR. Prosto, logicznie, krok po kroku. Jedna uwaga, u mnie film niby leci (suwak na dole), ale obraz cały czas stoi w postaci początkowej.