LinkedIn YouTube Facebook
Szukaj

Newsletter

Proszę czekać.

Dziękujemy za zgłoszenie!

Wstecz
Artykuły

Konfigurator MPLAB Code Configurator (cz. 2)

Po skonfigurowaniu modułu TMRO klikamy na przycisk Generate w oknie Project Resources. MCC wygeneruje kod na podstawie ustawień i zapisze go do właściwych katalogów.

Dla modułu peryferyjnego TMRO generowany jest plik tmr0.c zawierający funkcje inicjalizacji modułu Timer0, uruchomienia i zatrzymania zliczania, a także zapisania i odczytania zawartości licznika.

Na listingu 1 pokazano funkcję TMR0_Intialize realizującą inicjalizację modułu Timer0 zgodnie z ustawieniami wykonanymi w MCC.

Listing 1. Inicjalizacja licznika Timer0

void TMR0_Initialize(void)
{
    // Set TMR0 to the options selected in the User Interface
    // T0CS T0CKI_PIN; T0CKPS 1:1; T0ASYNC synchronised;
    T0CON1 = 0x00;
    // TMR0H = 99D
    TMR0H = 0x63;
    // TMR0L 0;
    TMR0L = 0x00;
    // Clear Interrupt flag before enabling the interrupt
    PIR0bits.TMR0IF = 0;
    // Enabling TMR0 interrupt.
    PIE0bits.TMR0IE = 1;
    // Set Default Interrupt Handler
    TMR0_SetInterruptHandler(TMR0_DefaultInterruptHandler);
    // T0OUTPS 1:1; T0EN enabled; T016BIT 8-bit;
    T0CON0 = 0x80;
}

Ponieważ przyjęliśmy, że przepełnienie Timer0 będzie zgłaszało przerwanie, to w funkcji obsługi przerwań umieszczonej w pliku interrupt_manager.c zdefiniowano wywołanie funkcji obsługi przerwania TMR0_ISR() zgłaszanego przez moduł TMR0 – listing 2.

Listing 2. Wywołanie funkcji obsługi przerwania od TMR0

void __interrupt() INTERRUPT_InterruptManager (void)
{
    // przerwanie zgłoszone przez TMR0
    if(PIE0bits.TMR0IE == 1 && PIR0bits.TMR0IF == 1)
    {
       TMR0_ISR(); //funkcja obsługi przerwania
    }
    else
    {
         ;
   }
}

Obsluga przerwań

Funkcję obsługi przerwania od TMR0 pokazano na listingu 3. Jak pamiętamy, w ustawieniach przerwania określiliśmy, że funkcja callback będzie wywoływana co 1 sekundę, przy przerwaniach zgłaszanych co 1 milisekundę. W funkcji TMR0_ISR zdefiniowano zmienną CountCallBack, która jest inkrementowana przy każdym wywołaniu przerwania. Jeżeli ta zmienna osiągnie wartość równą TMR0_INTERRUPT_TICKER_FACTOR (czyli 1000), to zostanie wywołana funkcja TMR0_CallBack(), a zmienna CountCallBack jest zerowana.

Listing 3. Obsługa przerwania od TMR0 wygenerowana przez MCC

void TMR0_ISR(void)
{
    static volatile uint16_t CountCallBack = 0;
    // clear the TMR0 interrupt flag
    PIR0bits.TMR0IF = 0;
    // callback function - called every 1000th pass
    if (++CountCallBack >= TMR0_INTERRUPT_TICKER_FACTOR)
    {
        // ticker function call
        TMR0_CallBack();
        // reset ticker counter
        CountCallBack = 0;
    }
    // add your TMR0 interrupt custom code
}

Funkcja TMR0_Callback() jest również generowana przez konfigurator, ale jej definicja sprowadza się głównie do umieszczenia w niej własnego kodu i dlatego nie będę jej tu pokazywał. Wywoływanie funkcji TMR0_Callback() co 1 sekundę służy tylko do demonstracji możliwości konfiguratora. Można ją wywoływać w różnych interwałach czasowych, lub też w ogóle z niej zrezygnować. Co ważne, MCC generuje wszystkie pliki obsługi przerwania i po uzupełnieniu o własny kod i wspomnianym już odblokowaniu przerwań globalnych, a także przerwań od układów peryferyjnych, można używać mechanizmów przerwań. Do odblokowania przerwań można użyć gotowych makr – listing 4.

Listing 4. Odblokowanie systemu przerwań

//Enable the Global Interrupts
INTERRUPT_GlobalInterruptEnable();
//Enable the Peripheral Interrupts
INTERRUPT_PeripheralInterruptEnable();

Konfiguracja wyprowadzeń układu

Pozostała jeszcze konfiguracja wyprowadzeń mikrokontrolera. Standardowo określa się kierunek przepływu danych przez linie portów (wejście, wyjście) i definiowanie wejść/wyjść analogowych. W przypadku funkcji alternatywnych związanych z działaniem układów peryferyjnych, mogą być potrzebne dodatkowe definicje. W naszym przypadku dochodzi też przypisanie funkcji alternatywnej (wejścia impulsów zliczanych przez Timer0) do linii portów. Realizuje to specjalny moduł peryferyjny PPS (Peripherial Pin Select). Programowanie tego modułu “na piechotę” jest żmudne i łatwo o pomyłkę. Jak pokazano to wyżej, użycie Pin Manager we wtyczce MMC bardzo ułatwia to zadanie. Na listingu 5 pokazano funkcję programującą wszystkie konieczne ustawienia dotyczące pracy linii portów: kierunek przepływu danych (rejestry LATx i TRISx), podciągania wejść cyfrowych do plusa zasilania (rejestry WPUx), wejść analogowych (rejestry ANSELx), a także modułu PPS.

Listing 5. Konfiguracja wyprowadzeń mikrokontrolera

void PIN_MANAGER_Initialize(void)
{
    /**
    LATx registers
    */
    LATA = 0x00;
    LATB = 0x00;
    LATC = 0x00;
    
    /**
    TRISx registers
    */
    TRISA = 0x3F;
    TRISB = 0xF0;
    TRISC = 0xFF;
    
    /**
    ANSELx registers
    */
    ANSELC = 0xFB;
    ANSELB = 0xF0;
    ANSELA = 0x37;

    /**
    WPUx registers
    */
    WPUB = 0x00;
    WPUA = 0x00;
    WPUC = 0x00;

    /**
    ODx registers
    */
    ODCONA = 0x00;
    ODCONB = 0x00; 
    ODCONC = 0x00;
    
    /**
    SLRCONx registers
    */
    SLRCONA = 0x37;
    SLRCONB = 0xF0;
    SLRCONC = 0xFF;
  
  /**
    INLVLx registers
    */
    INLVLA = 0x3F;
    INLVLB = 0xF0;
    INLVLC = 0xFF;
    T0CKIPPS = 0x12;   //RC2->TMR0:T0CKI;
}

Postępując podobnie jesteśmy w stanie skonfigurować dowolny moduł peryferyjny mikrokontrolera. Oczywiście niezbędna jest przy tym pewna wiedza na temat budowy i działania peryferii, ale MCC zwalania nas z wielu żmudnych czynności konfiguracyjnych.

Generacja funkcji bibliotecznych dla peryferii

Konfigurator może też zrobić trochę więcej niż tylko konfigurować moduły peryferyjne. Jedną z takich możliwości jest wygenerowanie funkcji bibliotecznych dla wybranych układów peryferyjnych, głównie dla układów komunikacyjnych. W naszym przypadku MCC dla wybranego mikrokontrolera automatycznie dołączył opcje dostępne w oknie Device Resources:

  • Listę z elementami IoT zawierającą biblioteki, a także przykłady dla Internetu rzeczy – rysunek 18,
  • Biblioteki, w tym Bootloader generator, biblioteki Foundation Services, LIN, Mtouch i UCS211x – rysunek 19,
  • Listę Mikro-E Clicks z bibliotekami wsparcia dla minimodułów modułów serbskiej firmy Mikroelektronika podłączanych do gniazda mikrobus, umieszczonego w płycie ewaluacyjnej MPLABXpress.

Rysunek 18. Lista z bibliotekami i przykładami IoT

Rysunek 19. Lista bibliotek

Popatrzmy teraz jak można użyć biblioteki przeznaczonej do obsługi transmisji w standardzie I2C. Jest to biblioteka I2CSIMPLE dostępna z menu Library->Foundation Services (lista bibliotek – rysunek 20).

Rysunek 20. Dodawanie biblioteki I2CSIMPLE

Biblioteka I2CSIMPLE

MCC automatycznie dodaje do listy Project Resources dwa elementy. Pierwszy z nich to sprzętowy moduł komunikacyjny MSSP mogący pracować jako moduł komunikacyjny SPI lub moduł I2C. Drugi element to biblioteka Foundations Services I2CSIMPLE. Po jego zaznaczeniu pojawia się okno I2CSIMPLE, w którym można zamienić moduł MSSP1 na MSSP2. Zostało to pokazane na rysunku 20.

Rysunek 21. Konfiguracja MSSP1

Moduł MSSP1 automatycznie dodany do projektu jest domyślnie skonfigurowany. MCC automatycznie ustawia go w tryb pracy I2C Master bez zgłaszania przerwań – rysunek 21. Umieszczenie w oknie Project Resources MSSP1 spowoduje, że MCC wygeneruje plik i2c1_master.c zawierający driver obsługujący transmisję I2C. Ten driver jest dość rozbudowany, gdyż moduł MSSP1 I2C może pracować z ograniczeniami w trybie multi master, jako master lub slave. Zawiera także obsługę różnych zdarzeń, między innymi kolizji, czy nieprawidłowych stanów na magistrali. Pełny opis działania drivera wykracza poza ramy tego artykułu i dociekliwy czytelnik, jeżeli chce może spróbować przeanalizować go samodzielnie.

Dodatkowe pliki

Oprócz drivera obsługującego transmisje I2C dodawane są dwa pliki: i2c_simple_master.c i i2c_simple_master_example.c. Ten ostatni zawiera funkcje, które mogą być użyte do standardowych sekwencji przesyłania danych po magistrali I2C. Pokazana na listingu 6 przykładowa funkcja I2C1_Write1ByteRegister ma trzy argumenty: adres slave address, adres rejestru reg i daną data. Funkcja realizuje zapisanie przez moduł Master do układu Slave o podanym adresie danej do rejestru reg.

Listing 6. Zapisanie danej do rejestru

void I2C1_Write1ByteRegister(i2c1_address_t address, uint8_t reg, uint8_t data)
{
    while(!I2C1_Open(address)); // sit here until we get the bus..
    I2C1_SetDataCompleteCallback(wr1RegCompleteHandler,&data);
    I2C1_SetBuffer(&reg,1);
    I2C1_SetAddressNackCallback(NULL,NULL); //NACK polling?
    I2C1_MasterWrite();
    while(I2C1_BUSY == I2C1_Close()); // sit here until finished.
}

Pierwsza funkcja I2C_Open sprawdza, czy interfejs może być otwarty i czy nie powoduje to błędów lub kolizji. Program czeka w nieskończoność, aż funkcja I2C_Open otworzy interfejs. Potem wysyłana jest sekwencja START oraz bajt adresu slave z bitem R/W = 0. Kolejne bajty to bajt adresu i bajt zapisywanej danej. Wszystko kończy się sekwencją STOP.

Na pierwszy rzut oka widać, że jest to funkcja blokująca i do poważnych zastosowań nie bardzo się nadaje. Czekanie w pętli niekończonej na zakończenie jakiegoś działania prędzej czy późnej zablokuje cały program. Ale z drugiej strony dość łatwo jest ją zmodernizować, na przykład wprowadzając kryterium czasowe oczekiwania na zdarzenie i obsługę błędu przekroczenia czasu.

Oprócz opisanej powyżej funkcji dostępne są funkcje odczytu jednego, dwóch lub całego bloku danych oraz podobne funkcje zapisu. Pewnym problemem jest brak jakiejkolwiek dokumentacji generowanych funkcji. Być może istnieje, ale ja nie mogłem jej znaleźć mimo usilnych starań. Wystarczyłby krótki komentarz na początku funkcji lub w plikach nagłówkowych.

Lista bibliotek dostępnych dla MCC jest dużo szersza. Obejmuje system plików FAT, obsługę USB, mini stos TCP/IP itd. Dla naszego mikrokontrolera lista bibliotek została okrojona. Być może uznano, że tylko te, które są dostępne w oknie Device Resources będą działały poprawnie z wybranym mikrokontrolerem.

Dodawanie bibliotek do MCC

Jeżeli interesuje nas biblioteka, której nie ma w standardzie, to można ją pobrać ze strony Microchipa i zainstalować ręcznie. Na rysunku 22 pokazano przykład instalowania biblioteki stosu TCP/IP w wersji lite. Na stronie Microchipa https://www.microchip.com/mplab/mplab-code-configurator otwieramy zakładkę Current Download i odszukujemy bibliotekę TCP/IP Lite Stack. Pobrany spakowany plik biblioteki zapisujemy w dowolnym miejscu. Z menu Tools otwieramy kartę opcji, zaznaczamy Plugins i klikamy na Install Library. Następnie wyszukujemy spakowany plik biblioteki i to już wszystko. Po zrestartowaniu wtyczki MCC w oknie Device Resources pojawią się dwa elementy: Ethernet i TCP/IP Lite. To czy będzie można użyć tej biblioteki z wybranym mikrokontrolerem musi ocenić programista na podstawie zasobów mikrokontrolera.

Rysunek 22. Instalowanie biblioteki dla wtyczki MCC

Podsumowanie

Wtyczka MPLAB Code Configurator to jedno z podstawowych narzędzi środowiska MPLAB X IDE przeznaczonego dla mikrokontrolerów PIC wszystkich rodzin, od PIC16 do PIC32. Początkowo przeznaczona głównie do konfigurowania peryferii w mikrokontrolerach PIC16F sukcesywnie obejmowała coraz bardziej zaawansowane rodziny mikrokontrolerów. Ponieważ stopniowo Microchip wchłania w swój system projektowy MPLAB mikrokontrolery Atmel, to MCC obsługuje również część z nich.

Konfigurator przeznaczono do dwóch zadań. Pierwsze to konfigurowanie układów peryferyjnych, systemu przerwań i bitów konfiguracyjnych (fuse). Drugie zadanie to generowanie plików bibliotecznych dla szeregu zastosowań od obsługi transmisji protokołów SPI, I2C, UART przez generator bootloadera, biblioteki związane z IoT, mTouch, aż po bardziej zaawansowane biblioteki obsługi systemu plików (FAT), stosu TCP/IP czy interfejsu USB.

Układy peryferyjne i biblioteki można dodawać i usuwać, a MCC powinna poradzić sobie z zarządzeniam potrzebnymi i niepotrzebnymi plikami. Ręczna ingerencja nie jest więc konieczna, ale istnieje możliwość modyfikacji wygenerowanych plików źródłowych. Jeżeli MCC w trakcie generowania plików na nowo wykryje, że taki plik został wcześniej zmieniony, to otwierane jest okno merge umożliwiające programiście zachowanie swoich zamian.

Osobiście w każdym z projektów wykorzystujących mikrokontrolery PIC korzystam z MCC. Diametralnie to skraca czas potrzebny na konfigurację układów peryferyjnych. Korzystam też z bibliotek do szybkiego testu działania na przykład transmisji oraz jako część kodu przeznaczonego do pracy. W tym drugim przypadku przerabiam funkcje blokujące na warunek związany z timout’em.

Wtyczka jest ciągle rozwijana i jest coraz bardziej niezawodna.

Absolwent Wydziału Elektroniki Politechniki Wrocławskiej, współpracownik miesięcznika Elektronika Praktyczna, autor książek o mikrokontrolerach Microchip i wyświetlaczach graficznych, wydanych nakładem Wydawnictwa BTC. Zawodowo zajmuje się projektowaniem zaawansowanych systemów mikroprocesorowych.