
Witajcie moi drodzy
Oto trzecia część mojego praktycznego tutoriala dla ośmiobitowego mikrokontrolera PIC18F2550 od Microchipa i programatora SDCC. W tym temacie najpierw krótko omówię różne konfiguracje oscylatora PIC18F2550 - oscylator wewnętrzny (internal oscillator), zewnętrzny (zegarowy i kwarcowy), funkcjonalność PLL (Phase Locked Loop), itp., a potem przedstawię je na wielu przykładach wraz z kodami do pobrania.
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/topic3647884.html
Część 3 - Ustawienia oscylatora. Oscylator wewnętrzny, zewnętrzny, rezonator kwarcowy, PLL
https://www.elektroda.pl/rtvforum/topic3657704.html
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.
Ten temat to jest część 3, czyli Ustawienia oscylatora. Oscylator wewnętrzny, zewnętrzny, rezonator kwarcowy, PLL. Zaczynamy.
Wstęp
W tej części najpierw opiszę jakie ustawienia oscylatora oferuje PIC18F2550, a potem część z nich przetestuję w praktyce. Do sprawdzenia częstotliwości z jaką chodzi zegar PIC użyję oscyloskopu. Na koniec też zmierzę pobór prądu przez mikrokontroler w różnych ustawieniach zegara.
Uwaga - podstawowa wiedza przydatna
W temacie zakładam, że czytelnik ma jakąś podstawową wiedzę, wie czym jest np. mikrokontroler, czym jest cykl instrukcji, taktowanie mikrokontrolera, UART itp. Oczywiście, takie rzeczy można też na bieżąco sprawdzać w wyszukiwarce, ale tylko ostrzegam, że całkowitych podstaw nie będę tu wyjaśniać.
Znajomość podstaw języka C też jest tutaj zalecana.
Dodatek - wydruk danych UART
Wysyłanie danych poprzez UART umieszczam tutaj ponieważ uważam je za dobry i prosty sposób na sprawdzenie konfiguracji zegara. Jeśli źle ustawimy zegar to baud rate z PICa i naszego urządzenia nie będzie zgodny i odbierzemy same krzaczki. Dzięki temu za pomocą UART można wygodnie weryfikować czy dobrze ustawiliśmy oscylator.
Użyty przez nas kompilator SDCC sam nie oferuje gotowych bibliotek pod UART, ale takie dostępne są w sieci. Chociażby w kodzie Pinguino:
https://github.com/PinguinoIDE/pinguino-libra...8ff5cd2fac50673cc183e7bf849f/p8/pinguino/core
Powyższy kod (jak i jego pochodne) znajdują się na licencji GPL, szczegóły tutaj:
https://github.com/PinguinoIDE/pinguino-libra...dd2816a178ff5cd2fac50673cc183e7bf849f/LICENSE
Na bazie kodu z poprzedniego linku przygotowałem minimalne demo komunikacji (a właściwie wysyłania) UART dla PIC18F2550 i SDCC:
Code: c
Najważniejsze uwagi co do powyższego kodu:
- UART musi wiedzieć jak ustawiony jest zegar PICa. Ja w tym celu użyłem #define CPU_CLOCK 1000000U. Jeśli zmienimy taktowanie, to musimy zaktualizować tą wartość. Jest ona oczywiście w Hz.
- UART inicjalizujemy za pomocą UART_Init(9600). Wartość 9600 to wybrany baud rate. Oczywiście można wybrać inny, ale ogranicza nas tu taktowanie mikrokontrolera.
- dane na UART drukujemy za pomocą UART_PrintStr("Hello UARTrn"). Ta funkcja przyjmuje ciąg znaków zakończony zerem jako argument, czyli typowy string w stylu C.
Kod jest o wiele bardziej złożony, ale cała "magia" dzieje się w przygotowanych przeze mnie dla was funkcjach i nie trzeba ich teraz całych rozumieć by z nich korzystać.
W ramach ćwiczenia polecam przenieść funkcje związane z UART do osobnego pliku z kodem .c i zrobić mu osobny nagłówek.
Do odebrania tego co jest wysyłane przez UART użyłem taniej przejściówki USB-UART HW-597:


Funkcje UART w PIC18F2550 są na dwóch określonych pinach - nie można ich przypisać na inne piny. Taka możliwość jest tylko w nowych PICach z PPS (Peripheral Pin Select).
W PIC18F2550 mamy:
- pin RX (odbieranie UART) - jest to pin 18
- pin TX (wysyłanie UART) - jest to pin 17
Oba piny zaznaczyłem na obrazku:

I do pinu TX (wysyłanie) od PICa podłączyłem pin RX (odbieranie) przejściówki:

Całość po podłączeniu do komputera:

UWAGA: Cały układ powinien mieć wspólną masę! W moim przypadku wszystko podłączone jest do jednego USB komputera więc nie ma w tym problemu (też biorę stamtąd zasilanie całego układu), ale jeśli wy np. zasilacie PICa z bateryjki lub zasilacza 5V to musicie połączyć masy PICa i przejściówki USB-UART.
Rezultat działania na komputerze w programie RealTerm:

WSKAZÓWKA: Warto wiedzieć, że użyta przez nas przejściówka USB-UART ma diody LED na pinach RX/TX i pokazuje nam, czy coś odbiera. Jest to przydatne gdy uruchamiamy UART, coś nie działa i chcemy określić czy jakieś dane są wysyłane.
Filmik pokazuje, jak wygląda te miganie LED dla kodu zaprezentowanego powyżej:
Załącznik do pobrania: p18f2550_uart_intOsc1MHz (kod, skompilowany hex, plik .bat do kompilacji na Windowsie):
Przegląd dostępnych ustawień oscylatora PIC18F2550
PIC18F2550 oferuje szeroką gamę ustawień oscylatora. Wspiera zewnętrzne oscylatory, jak i oferuje wewnętrzny oscylator (do 8MHz).
Ustawienie oscylatora określa z jaką częstotliwością pracuje PIC.
Częstotliwość cyklu instrukcji PICa stanowi 1/4 częstotliwości pracy jego oscylatora.
Większa częstotliwość zegara oznacza szybsze dokonywanie obliczeń i operacji przez mikroprocesor, ale też większe zużycie energii.
Oprócz częstotliwości rezonatora ważna jest też jego dokładność - np. wewnętrzny oscylator PIC18F2550 nie jest zbyt dokładny i nie nadaje się do zastosowań USB, ale do UART jeszcze tak.
Bezbłędne skonfigurowanie oscylatora jest niezwykle ważne, gdyż bez tego będziemy mieć problem z poprawnym odliczaniem czasu i co za tym idzie też z komunikacją z peryferiami (np. baud rate od UART będzie błędne).
Tabelka przedstawia dostępne konfiguracje oscylatora PIC18F2550:

Część z nich dokładnie w tym temacie omówię i przedstawię na szczegółowo opisanych przykładach.
PLL, preskaler i postskaler
Układ PLL (na którego składa się preskaler i postskaler) pozwala uzyskać nam różne częstotliwości zegara PIC z tej samej częstotliwości wejściowej.
Całość działania PLL dobrze schemat:

Prześledzimy teraz co się na nim dzieje.
- blok "Primary Oscillator" - to jest wejście zewnętrznych źródeł zegara (nie jest dostępne dla wewnętrznego rezonatora). Tu podajemy nieprzetworzony sygnał
- blok "PLL Prescaler" - to pierwszy blok, który konfigurujemy w ustawieniach PICa. Jego zadaniem jest podzielenie sygnału tak by uzyskać 4MHz.
- blok "96MHz PLL" - to blok który zamienia uzyskane wcześniej 4MHz na 96MHz za pomocą PLL
- blok "PLL Postscaler" - to ostatni blok, który dzieli 96MHz na ustawioną przez nas w konfiguracji PICa liczbę, np. na 2, 3, 4 lub 6. W ten sposób uzyskujemy kolejno: 96MHz/2=48MHz, 96MHz/3=32MHz, 96MHz/4=24MHz, 96MHz=12MHz.
Po prześledzeniu schematu przebieg sygnału w PICu powinien być jasny, lecz może pojawić się jedno pytanie - czemu na wejściu PLL musi być akurat 4MHz?
Odpowiedź na to pytanie jest też na schemacie - blok "USB Clock Source" podłączony jest bezpośrednio do bloku "96MHz PLL", więc na jego działanie nie wpływa już "PLL Postscaler". Z tego powodu jeśli chcemy używać USB to musimy respektować zasadę, że do PLL ma iść 4MHz.
W celu dokładniejszego zapoznania się z wewnętrznym działaniem PIC odsyłam do jego noty katalogowej. Nie ma sensu bym tutaj o tym szczegółowo pisał, jak wszystko jest w nocie - tutaj skupię się na przykładach.
Podłączenie oscylatora dla PIC18F2550
Cała przygoda z oscylatorami, zegarami, itp. odbywać się będzie na pinach OSC1/OSC2 zaznaczonych na obrazku:

W przypadku rezonatora kwarcowego oba te piny są podłączone.
W przypadku zewnętrznego zegara sygnał podajemy na OSC1/CLKI a OSC2 może być pinem IO lub wyjściem zegara instrukcji (czterokrotnie mniejsza częstotliwość niż podana na CLKI).
W przypadku wewnętrznego oscylatora pin OSC1/CLKI jest nieużywany a OSC2 przyjmuje funkcje albo IO albo CLKO (wyjście zegara instrukcji).
Ustawienie oscylatora - wewnętrzny oscylator (INTOSCIO_EC/INTOSC_EC)
Na początek przeanalizujemy działanie wewnętrznego oscylatora PIC18F2550.
Jest on najłatwiejszy do uruchomienia i nie wymaga żadnych zewnętrznych elementów, ale jego zasadniczą wadą jest mała dokładność.
Wewnętrzny oscylator PIC18F2550 nie nadaje się do zastosowań USB. Jeśli chcemy używać sprzętowego USB od PIC18F2550, to musimy albo użyć dobrego, zewnętrznego oscylatora, albo przerzucić się na PIC18F25K50 (z literką ''K''), który posiada dokładniejszy wewnętrzny oscylator.
Wewnętrzny oscylator PIC18F2550 dostępny jest w dwóch konfiguracjach:
- INTOSCIO_EC - wewnętrzny oscylator, funkcje IO na pinie RA6
- INTOSC_EC - wewnętrzny oscylator, funkcja CLKOUT na pinie RA6
Aby skonfigurować wewnętrzny oscylator PIC18F2550 musimy:
1. Wybrać w konfiguracji opcję INTOSCIO_EC lub INTOSC_EC
2. Ustawić odpowiednio rejestr OSCCON
Dostępne wartości/częstotliwości wewnętrznego zegara opisane są w nocie katalogowej mikrokontrolera:

Dodatkowo dostępny jest rejestr OSCTUNE, który pozwala dokładnie dostroić wewnętrzny oscylator, ale nim nie będziemy się zajmować.
Zaraz pokażę na konkretnych przykładach jak to działa.
Ustawienie oscylatora - wewnętrzny oscylator (INTOSCIO_EC) - przykład 8MHz
Teraz przedstawię prosty, praktyczny przykład ustawienia wewnętrznego oscylatora PIC18F2550 wraz z badaniem częstotliwości zegara oscyloskopem (funkcja CLKOUT) oraz prędkości przełączania stanu pinu IO.
Do całości użyjemy minimalnego układu z PIC18F2550 z poprzedniej części tutoriala (podprowadzone zasilanie, rezystor 10k na MCLR, kondensator na VCAP):

Schemat połączeń ze zdjęcia powyżej:

Zaczniemy od kodu blink led z poprzedniej części. Dla przypomnienia wygląda on tak:
Code: c
Na początek lekko go zmodyfikujemy.
- zmienimy ustawienie oscylatora z INTOSCIO_EC na INTOSC_EC (gdyż na pinie RA6 chcemy mieć funkcję CLKOUT, czyli wyjście sygnału zegara)
- usuniemy funkcję delay by PIC najszybciej jak jest w stanie przełączał stan na pinie RC0
- zainicjujemy wewnętrzny oscylator 8MHz zgodnie z dokumentacją
Kod po zmianach:
Code: c
Załącznik do pobrania: p18f2550_pinSwitch_intOsc8MHz (kod, skompilowany hex, plik .bat do kompilacji na Windowsie):
Tak zmodyfikowany kod wgrałem na PICa w celu dokonania pomiarów oscyloskopem.
Pomiary dokonałem na zaznaczonych tu pinach:

Ustawienie testowe na płytce stykowej, wszystko tak jak wcześniej, tylko dodatkowo podłączyłem sondy oscyloskopu do CLKOUT (RA6, wyjście zegara) oraz RC0 (pin, którego przełączamy):

I oto wyniki pomiarów:

Dolny sygnał to CLKOUT, czyli zegar instrukcji PICa. Ma częstotliwość 2MHz.
Jest to zgodne z tym co pisałem wcześniej, gdyż 8MHz/4 = 2MHz. Czyli wykonanie jednej instrukcji trwa 500ns.
Górny sygnał został zmierzony na pinie RC0. Ma on parametry:
Częstotliwość: 500kHz
Czas wysoki: 500ns
Czas niski: 1500ns
Wiemy, że czas jednej instrukcji wynosi 500ns.
Można stąd wywnioskować, że w pętli wykonują się 4 instrukcje.
Zaraz zastanowimy się, skąd się to bierze.
W celu dokładniejszego zbadania czemu sygnał na RC0 jest taki jaki jest zajrzymy do kodu assembler wygenerowanego przez SDCC. Znajduje się w on pliku .asm o nazwie takiej samej jak nazwa naszego pliku z kodem:

W moim przypadku ma on zawartość:
Code: x86asm
Interesująca nas pętla tutaj zaczyna się od etykiety _00106_DS_ i zawiera w sobie dwie instrukcje (BSF i BCF) oraz skok BRA. Po dokonaniu skoku zaczyna się na nowo.
Tylko czemu całość trwa 4 cykle, skoro mamy tylko trzy instrukcje?
Odpowiedź na to pytanie znajdziemy w dokumentacji instrukcji PIC18F.
Instrukcje BSF (set, ustawienie, zapalenie jednego bitu) trwa standardowo jeden cykl:

BCF (clear, zgaszenie jednego bitu) tak samo - trwa jeden cykl:

Z kolei instrukcja BRA (skok) trwa aż dwa cykle:

Sumując cykle: 1+1+2 = 4
Cztery cykle, każdy 500ns, stąd czas wysoki 500ns, niski 1500ns oraz częstotliwość przełączania pinu RC0 500kHz.
Ustawienie oscylatora - wewnętrzny oscylator (INTOSCIO_EC) - przykład 4MHz
Analogicznie jak w poprzednim przykładzie. Zmieniona zostaje tylko wartość OSCCON. Pokażę nowy kod i oscylogram, ale zostawię to bez komentarza.
Nowy kod:
Code: c
Oscylogram:

CLKOUT 1MHz (4MHz / 4 = 1MHz), częstotliwość przełączania pinu IO: 250kHz. Wszystko zgodnie z oczekiwaniami.
Załącznik do pobrania: p18f2550_pinSwitch_intOsc4MHz (kod, skompilowany hex, plik .bat do kompilacji na Windowsie):
Ustawienie oscylatora - wewnętrzny oscylator (INTOSCIO_EC) - przykład 31kHz
Jeszcze sprawdzimy jakąś niższą częstotliwość zegara wewnętrznego. Analogicznie jak w poprzednim przykładzie. Zmieniona zostaje tylko wartość OSCCON. Pokażę nowy kod i oscylogram, ale zostawię to bez komentarza.
Nowy kod:
Code: c
Oscylogramy z pomiarami:


CLKOUT 7.75kHz (31kHz / 4 = 7.75kHz), częstotliwość przełączania pinu IO: 1.93kHz. Wszystko zgodnie z oczekiwaniami.
Analogicznie całość zachowuje się dla pozostałych ustawień wewnętrznego oscylatora (OSCCON).
Załącznik do pobrania: p18f2550_pinSwitch_intOsc31KHz (kod, skompilowany hex, plik .bat do kompilacji na Windowsie):
Ustawienie oscylatora - oscylator kwarcowy bez PLL (HS) - przykład 20MHz
Teraz przetestujemy używanie oscylatora kwarcowego, zewnętrznego wraz z PIC18F2550. Wykorzystanie go pozbawia nas dwóch pinów IO (bo do nich podłączamy kwarc; a właściwie to jednego, bo OSC1/CLKI i tak nie ma funkcji portu), ale otwiera nam nowe możliwości, takie jak:
- użycie sprzętowego USB z tego PICa (wewnętrzny oscylator 2550''tki nie jest na to dość dokładny)
- wyższe częstotliwości zegara PICa
Oscylatory kwarcowe są tanie i mają różne wartości, te przewlekane z reguły występują w obudowie HC-49. Z takiego też skorzystam (20MHz):


Zgodnie z notą katalogową PIC zewnętrzny oscylator kwarcowy powinien być podłączony wraz z ceramicznymi kondensatorami o odpowiedniej pojemności:

Nota katalogowa pokazuje jakie standardowo stosuje się ich pojemności, ale ich ostateczny wybór zależy od użytego rezonatora:

Ich dobry wybór jest niezbędny gdy przygotowujemy końcowy produkt, lecz dla szybkiego testu na płytce stykowej można je pominąć. Rezonator kwarcowy zadziała też bez nich.
Zatem podłączamy rezonator na pinach OSC1/OSC2:

I uruchamiamy (odpowiednio zmodyfikowany - zmiana ustawienia zegara na HS) wcześniejszy kod:
Code: c
W tym przypadku oba piny oscylatora są zajęte, bo jest na nich kwarc, więc nie mamy jak zmierzyć CLKOUT. Możemy tylko sprawdzić co się dzieje na RC0.

Wynik pomiaru sygnału na pinie RC0:

Oscyloskop pokazuje 1.25MHz.
Teraz zweryfikujemy pomiary obliczeniowo.
Wejściowy sygnał zegara to 20MHz.
Zegar instrukcji to 20MHz/4 = 5MHz.
Nasz kod (jak omawiane wcześniej) ma 4 instrukcje. Więc powinien przełączać pin z częstotliwością 1.25MHz - i to właśnie widzimy na oscyloskopie.
Załącznik do pobrania: p18f2550_pinSwitch_crystal20MHz (kod, skompilowany hex, plik .bat do kompilacji na Windowsie):
Ustawienie oscylatora - oscylator kwarcowy 20MHz z PLL (HSPLL_HS) - przykład 16MHz
Jak już mamy podłączony rezonator kwarcowy do PICa to nic nie stoi na przeszkodzie by włączyć funkcję PLL. Pozwala ona uzyskać różne częstotliwości zegara z tego samego rezonatora kwarcowego.
Konfiguracja PLL ma zasadniczo dwa etapy.
Etap 1: Wybieramy PLLDIV taki by z wejściowego sygnału uzyskać 4MHz
Etap 2: Wybieramy CPUDIV taki by z 96MHz od PLL uzyskać pożądany przez nas zegar
Teraz na tym przykładzie przejdę oba te etapy.
Powiedzmy, że z rezonatora kwarcowego 20MHz chcemy uzyskać 16MHz.
W bieżącej konfiguracji mamy zegar wejściowy 20MHz.
Musimy wybrać takie PLLDIV by uzyskać z niego 4MHz.
Ustawiamy zatem PLLDIV na 5, ponieważ 20MHz / 4MHz = 5.
W ten sposób uzyskujemy 4MHz na wejście PLL. Na wyjściu PLL mamy 96MHz i teraz musimy zdecydować co z tym 96MHz zrobimy, czyli musimy wybrać konfiguracje CPUDIV.
Mamy następujące możliwości:
- OSC1_PLL2, co da nam 96MHz / 2 = 48MHz
- OSC2_PLL3, co da nam 96MHz / 3 = 32MHz
- OSC3_PLL4, co da nam 96MHz / 4 = 24MHz
- OSC4_PLL6, co da nam 96MHz / 6 = 16MHz
W SDCC najwygodniej wpisać je za pomocą preprocesora:
Code: c
I tak też zrobimy.
Dla przykładu wybraliśmy, że chcemy uzyskać 16MHz. Wpisujemy w kodzie konfigurację OSC4_PLL6:
Możemy w ten sposób opracować taki kod:
Code: c
W tym przypadku oba piny oscylatora są zajęte, bo jest na nich kwarc, więc nie mamy jak zmierzyć CLKOUT. Możemy tylko sprawdzić co się dzieje na RC0.
Wynik pomiaru sygnału na pinie RC0:

Oscyloskop pokazuje 1MHz. Stan wysoki trwa mniej więcej 250us, czas niski 750us.
Teraz zweryfikujemy pomiary obliczeniowo.
Zegar po PLL to 16MHz.
Zegar instrukcji to 16MHz/4 = 4MHz.
Nasz kod (jak omawiane wcześniej) ma 4 instrukcje. Więc powinien przełączać pin z częstotliwością 1MHz - i to właśnie widzimy na oscyloskopie.
Załącznik do pobrania: p18f2550_pinSwitch_crystal20MHz_PLL_16MHz (kod, skompilowany hex, plik .bat do kompilacji na Windowsie):
Rezonator kwarcowy 20MHz z PLL do 16MHz - UART
W poprzednim przykładzie pokazałem jak za pomocą rezonatora kwarcowego 20MHz uzyskać zegar 16MHz przy użyciu PLL.
Teraz w ramach uzupełnienia pokażę jak przy tym ustawieniu uruchomić UART.
Pamiętać należy zasadniczo o jednym - w kodzie na UART podajemy jako CPU_CLOCK rzeczywiste taktowanie PICa, nie wartość z kwarcu, nie podzieloną przez 4, itp.
Czyli:
Code: c
Oto kompletny kod:
Code: c
I standardowo - rezulat jego działania:

Nie potrzeba tutaj raczej dodatkowego komentarza.
Załącznik do pobrania: p18f2550_uart_crystal20MHz_PLL_16MHz (kod, skompilowany hex, plik .bat do kompilacji na Windowsie):
Ustawienie oscylatora - zewnętrzny zegar (EC_EC)
Kolejnym dostępnym ustawieniem oscylatora jest EC_EC, External Clock, czyli sterowanie zewnętrznym sygnałem prostokątnym zegara.
W tej konfiguracji:
- pin OSC1 (CLKI) jest wejściem sygnału zegara
- pin OSC2 (CLKO, RA6) może być wyjściem zegara instrukcji (FOsc/4) lub pinem IO
Do tej konfiguracji można użyć dowolnego źródła zegara, może być nawet nim inny układ scalony.
Przykładowo, jak robimy projekt z komunikacją Ethernet na bazie układu ENC28J60:

To możemy wykorzystać jego zegar do taktowania naszego PICa. Po prostu podłączamy CLKO z ENC28J60 do CLKI z PIC18F2550.
Tutaj załączam akapit na temat CLKO z noty katalogowej ENC28J60:

Wtedy ENC28J60 korzysta z rezonatora 25MHz, a PIC korzysta z sygnału zegara z ENC.
Oczywiście, ja tu przedstawię mniej skomplikowane przykłady.
Ustawienie oscylatora - zewnętrzny zegar bez PICa
Na początek pokażę jak w ogóle uruchomić zewnętrzny zegar. Użyję do tego NSK XTAL OSC 48.000MHz 0106BC3 którego dostałem na wagę od chińczyka:


Nie byłem w stanie znaleźć jego noty katalogowej, ale założyłem że ma standardowe wyprowadzenia.
Czyli kolejno (na pierwszym zdjęciu, tym co widać napisy na obudowie):
- dolny lewy róg - pin ENABLE (lub niepodłączony)
- dolny prawy róg - masa
- górny prawy róg - wyjście sygnału
- górny lewy róg - Vcc
Podłączyłem go na płytce w stykowej w następujący sposób:

I zbadałem wyjście oscyloskopem. Pin przy kropce (numer 1) został niepodłączony. Od razu pojawił się sygnał 48MHz:

Oczywiście, gdy projektuje się płytkę z takim zegarem to trzeba pamiętać o dobrej filtracji jego zasilania itp., ja go podłączyłem na szybko tylko by sprawdzić czy działa.
Ustawienie oscylatora - zewnętrzny zegar (EC_EC) - przykład 48MHz
Mamy już uruchomiony zewnętrzny zegar i teraz chcemy podłączyć go do PICa. Wystarczy podać jego wyjście na pin CLKI mikrokontrolera. Mi się udało go zmieścić na stykówce w następujący sposób:

Następnie przerobiłem znany nam już kod by korzystał z konfiguracji EC_EC:
Code: c
Następnie zmierzyłem kolejno przebiegi.
Pin CLKI (wejście zegara), 48MHz:

Pin CLKO (wyjście zegara instrukcji, 4-krotnie mniejszy), 12MHz:

Pin RC0 (przełączany w kodzie), 3MHz:

Wszystko zgodnie z oczekiwaniami i obliczeniami przedstawionymi wcześniej.
Załącznik do pobrania: p18f2550_pinSwitch_externalOSC_48MHz (kod, skompilowany hex, plik .bat do kompilacji na Windowsie):
Ustawienie oscylatora - zewnętrzny zegar (EC_EC) - przykład 48MHz - UART
Powyżej przedstawioną konfigurację oscylatora można też użyć do przykładu wysyłania danych przez UART.
W kodzie zmodyfikowana została konfiguracja FOSC (dyrektywa preprocesora #pragma config) oraz ustawiona poprawne częstotliwość CPU_CLOCK:
Code: c
Całość oczywiście działa poprawnie i przesyła dane przez UART:

Załącznik do pobrania: p18f2550_uart_ec48MHz_48MHz (kod, skompilowany hex, plik .bat do kompilacji na Windowsie):
Ustawienie oscylatora - zewnętrzny zegar z PLL (ECPLL_EC) - 32MHz z zegara 48MHz
Analogicznie tak jak w przypadku oscylatora kwarcowego mamy tutaj możliwość użycia PLL do uzyskania innych częstotliwości taktowania PICa. Wszystkie przykłady tutaj uruchamiałem na układzie tym co wcześniej, czyli:

W bieżącej konfiguracji mamy zegar wejściowy 48MHz.
Musimy wybrać takie PLLDIV by uzyskać z niego 4MHz.
Ustawiamy zatem PLLDIV na 12, ponieważ 48MHz / 4MHz = 12.
W ten sposób uzyskujemy 4MHz na wejście PLL. Na wyjściu PLL mamy 96MHz i teraz musimy zdecydować co z tym 96MHz zrobimy, czyli musimy wybrać konfiguracje CPUDIV.
Mamy następujące możliwości:
- OSC1_PLL2, co da nam 96MHz / 2 = 48MHz
- OSC2_PLL3, co da nam 96MHz / 3 = 32MHz
- OSC3_PLL4, co da nam 96MHz / 4 = 24MHz
- OSC4_PLL6, co da nam 96MHz / 6 = 16MHz
W SDCC najwygodniej wpisać je za pomocą preprocesora:
Code: c
I tak też zrobimy.
Dla przykładu wybierzmy, że chcemy uzyskać 32MHz. Wpisujemy w kodzie konfigurację OSC2_PLL3:
Code: c
I wykonujemy pomiary.
Pin CLKI (wejście zegara) pominąłem, gdyż na nim nic nie miało się prawa zmienić - oscylator jest ten sam, 48MHz.
Piny CLKO oraz RC0 przedstawiam na jednym oscylogramie:

Jak widać, na CLKO jest 8MHz (4-krotnie mniejszy, 32MHz/4 = 8MHz), a RC0 2MHz.
Wszystko zgodnie z oczekiwaniami - PLL działa poprawnie i pozwala uzyskać nam różne częstotliwości taktowania z tego samego źródła zegara.
Załącznik do pobrania: p18f2550_pinSwitch_externalOSC_48MHz_PLL_32MHz (kod, skompilowany hex, plik .bat do kompilacji na Windowsie):
Pobór prądu dla powyższych przykładów
Dodatkowo zmierzyłem jeszcze pobór prądu dla powyższych przykładów. Użyłem do tego DT-9208A. Taki pomiar pozwala pokazać, że rzeczywiście taktowanie mikroprocesora wpływa na pobór mocy przez układ.
UWAGA: Do pomiaru prądu należy odłączyć oczywiście wszystko zbędne od układu, diody LED itp. Odłączyć też należy programator - sam fakt, że jest podłączony zawyża pomiar o jakieś 5mA (nic dziwnego, na schemacie PICKIT3 aż rzuca się w oczy np. ten rezystor 1k).
UWAGA: Niniejsze pomiary nie mają na celu zobrazować jak bardzo energooszczędny jest PIC. Pobór prądu przez PICa można zredukować na wiele sposobów, których tutaj nie opisuję. Proszę nie sądzić, że PIC zawsze musi tyle pobierać. W wielu projektach można np. wprowadzić mikrokontroler w tryb snu i tylko budzić go co jakiś czas (np. jak robimy logger temperatury), tutaj tego nie wprowadziłem. Zapewne omówię to w innej części kursu.
Pomiary będą poukładane wedle pomiaru prądu.
Pomiar 1 - pobór prądu przy wewnętrznym oscylatorze 31 kHz:
Program: p18f2550_pinSwitch_intOsc31kHz.c
Pomiar:

Pomiar 2 - pobór prądu przy wewnętrznym oscylatorze 1MHz:
Program: p18f2550_pinSwitch_intOsc1MHz.c
Pomiar:

Pomiar 3 - pobór prądu przy wewnętrznym oscylatorze 8MHz:
Program: p18f2550_pinSwitch_intOsc8MHz.c
Pomiar:

Pomiar 4 - pobór prądu przy zewnętrznym rezonatorze kwarcowym 20MHz bez PLL:
Program: p18f2550_pinSwitch_crystal20MHz.c
Pomiar:

Pomiar 5 - pobór prądu przy zewnętrznym rezonatorze kwarcowym 20MHz z PLL do 24MHz:
Program: p18f2550_pinSwitch_crystal20MHz_PLL_24MHz.c
Pomiar:

Pomiar 6 - pobór prądu przy zewnętrznym rezonatorze kwarcowym 20MHz z PLL do 48MHz:
Program: p18f2550_pinSwitch_crystal20MHz_PLL_48MHz.c
Pomiar:

Pomiar 7 - pobór prądu przy zewnętrznym zegarze 48MHz bez PLL:
Program: p18f2550_pinSwitch_externalOSC_48MHz.c
Pomiar poboru prądu przez sam zegar:


Pomiar poboru prądu przez całość:

Wyniki pomiarów przedstawiłem w tabeli:
Pomiar | Tryb | Taktowanie | Pobór prądu | Pobór prądu PICa | Pobór prądu zegara |
1 | INTOSC | 31kHz | 0.27mA | 0.27mA | brak |
2 | INTOSC | 1MHz | 1.33mA | 1.33mA | brak |
3 | INTOSC | 8MHz | 5.29mA | 5.29mA | brak |
4 | CRYSTAL 20MHz | 20MHz | 11.75mA | 11.75mA | brak |
5 | CRYSTAL 20MHz + PLL | 24MHz | 15.7mA | 15.7mA | brak |
6 | CRYSTAL 20MHz + PLL | 48MHz | 27mA | 27mA | brak |
7 | EC 48MHz | 48MHz | 37mA | 25mA | 12mA |
Obserwacje:
- oczywiście im większe taktowanie tym większy pobór energii
- zewnętrzny zegar 48MHz (patrz. pomiar nr 7) jest w stanie lekko odciążyć PIC (gdyż PIC sam nie musi tworzyć oscylacji i ma wyłączony PLL)
- zewnętrzny zegar (patrz. pomiar nr 7) pobiera aż 12mA, ale to jest raczej w normie. Nie mam jego noty katalogowej, ale wystarczy popatrzeć na inne podobne zegary i widać, że to jest w normie:

Podsumowując, widać jak bardzo taktowanie zegara wpływa na zużycie energii. Chciałbym na koniec podkreślić, że pobór prądu można by jeszcze znacznie zmniejszyć, chociażby poprzez obniżenie napięcie zasilania PICa, itp. Uzyskanie jak najmniejszego poboru prądu nie było tutaj celem, chciałem tylko zobrazować jak zmienia się pobór prądu wraz z ustawieniem zegara.
[Ciekawostka] Ustawienie oscylatora - oscylator RC
PIC18F2550 który jest tematem tego tutorialu nie posiada możliwości użycia układu RC do oscylatora, ale i tak chciałbym o tym wspomnieć, bo warto wiedzieć że inne PICe posiadają taką możliwość.
Można o tym poczytać w nocie katalogowej PIC16F628A:

Oto akapit dotyczący tego oscylatora RC:

Ale tak jak napisałem - to jest np. w PIC16F628A, nie jest dostępne w omawianym tu PIC18F2550. Niestety Microchip usunął tę funkcjonalność.
Podsumowanie
Tutaj streściłem najpierw informacje na temat działania oscylatora PICa, a potem pokazałem praktyczne przykłady jak skonfigurować PIC18F2550 do użycia w trybie wewnętrznego oscylatora, rezonatora kwarcowego, zewnętrznego źródła zegara.
Przykłady starałem się dobrać tak, by zaprezentować działania ważniejszych konceptów i dać Wam gotowe bazy do modyfikacji.
Kody wszystkich przykładów oraz skompilowane pliki hex są załączone do pobrania w temacie.
Oczywiście mój temat nie ma stanowić zamiennika dla noty katalogowej PICa - to właśnie tam wszystko jest bardziej szczegółowo opisane i mimo wszystko polecam się z nią zapoznać:
PS: Temat będzie redagowany/poprawiany na bieżąco, w razie uwag proszę na PW
Cool? Ranking DIY