sobota, 6 kwietnia 2019

PIC32MM - Tutorial part 5 - UART

Operacje na pinach mam nadzieję są przyswojone z poprzednich tutoriali. Czas zatem na najbardziej pożądane przez hobbystów peryferium mikrokontrolera czyli UART. W PIC32MM mamy do dyspozycji trzy UART-y , które mogą pracować jako RS232, RS485, LIN, IrDA. No trochę tego dobrodziejstwa jest.
W tutorialu pokażę jak w najprostszy sposób skonfigurować UART i w bardzo prosty sposób wykorzystać . Do zabawy przydadzą się dodatkowe narzędzia takie jak analizator stanów logicznych . Tak na marginesie PIC32MM ma na pokładzie USB ale na razie tego tematu nie poruszam.


Uruchamiamy MPLABX-IDE  i tworzymy nowy projekt dla PIC32MM0256GPM064 nazwę sobie wymyślcie sami u mnie jest ona pic32mm_tutorial_part5 . Po utworzeniu projektu uruchamiamy MCC (ikonka odznaki policyjnej z napisem MCC). Konfigurujemy zegar jak na obrazku poniżej :




Zegar systemowy FRC 8 MHz . Pamiętać aby z automatu ustawiać opcję Clock Output Configuration na OSCO pin operates as normal I/O. Opcja ta umożliwia normalne działanie pinu RA3.
Zegar mamy z głowy teraz bierzemy na widelec UART. W tym celu patrzymy na lewo na okienko Device Recources. Znajdujemy tam UART i rozwijamy menu dla tej opcji :



Widzimy , że w każdym z trzech UART1...UART3 mamy dwie opcje do wybrania. My wybieramy zawsze tę opcję gdzie w nawiasie wymienione są modele PIC24/dsPIC33/PIC32MM . Do zabawy wybieram UART1. Klikam w zaznaczoną na zdjęciu powyżej opcję i wyskakuje mi okienko konfiguracyjne dla UART1i jednocześnie moduł UART1 pojawia się w okienku Project Resources
Jeśli chcemy ten moduł usunąć z projektu to w tym okienku odznaczamy ptaszka.


W okienku konfiguracyjnym UART1 zaznaczamy  opcję Enable UART Interrupts i Redirect Printf to UART oraz bardzo ważne zmieniamy  Clock Source na FRC ,resztę zostawiamy tak jak jest domyślnie.

Teraz czas aby przyporządkować piny do naszego UART1. W tym celu przełączamy sobie widoki potrzebne do konfiguracji pinów. Od góry zakładka PIN MODULE od dołu zakładka PIN Manager Grid View efekt poniżej :


Widzimy, że MCC był uprzejmy za nas zapiąć odpowiednie kłódeczki. Piny na których mamy naszego UART1 to :

RA6 --> U1RX
RC12 --> U1TX

W przypadku użycia UART2 lub UART3 mamy znacznie większe możliwości przyporządkowania do prawie dowolnych pinów. UART1 jest  akurat przyporządkowany do jednego zestawu pinów.

Zapomniałem , że przyda nam się jedna dioda LED. Wracamy do okienka z kłódeczkami i zapinamy kłódeczkę w wierszu Output dla RD3 bo tam mamy podłączoną jedną z diod LED na naszej płytce PIC32MM Curiosity. RD3 pojawia nam się w okienku Pin Module Gdyby w kolumnie Analog dla pinu który chcemy użyć jako wyjście/wejście cyfrowe byłby  "zaptaszkowany" kwadracik to trzeba by było go koniecznie odznaczyć


Cała konfiguracja jest już za nami.  MCC jest bardzo dobrym narzędziem i to Microchipowi się naprawdę udało. Szczególnie początkujący mogą za pomocą tego narzędzia nabrać szybko wiatru w żagle. Klikamy zakładkę Generate w okienku Project Recources. Jak w okienku Output, które otworzy się na dole automatycznie zobaczymy napis Generation complete, możemy zamknąć MCC klikając raz w ikonkę policyjną z napisem MCC. Po wyjściu z MCC klikamy zakładkę Projects aby otworzyć widok z projektami. Efektem działania MCC są katalogi MCC Generated Files i plik main.c


W wygenerowanych plikach znajdziemy pliki uart1.h i uart1.c ,znajduje się w nich API do wygodnej obsługi naszego UART-a. Wszystkie funkcje są czytelnie opisane i nawet są przykłady ich użycia. Zaimplementowane są bufory TX i RX oraz obsługa FIFO . Po prostu mamy gotowy skonfigurowany soft do korzystania komfortowego z UART-a. Warto nad tym softem Microchipa się pochylić bo jest to m.in bardzo dobry materiał do nauki języka C. Aby jednak zrozumieć przepływ danych w buforze FIFO i wykorzystanie głowy i ogona "węża", polecę wam książkę gdzie jest do genialnie wytłumaczone . Książka jest dostępna w języku polskim i angielskim : Mikrokontrolery AVR Język C - podstawy programowania

UART jest inicjalizowany automatycznie w funkcji SYSTEM_Initialize() ,więc nic kompletnie nie musimy robić oprócz korzystania z API. Sprawdźmy zatem czy UART działa.  Dobrym do tego narzędziem jest analizator stanów logicznych. Nie musimy wcale mieć tutaj profesjonalnego narzędzia mnie wystarcza całkowicie takie za mniej 50 zł :)



Modyfikujemy program tak aby np.wysłać cyklicznie literkę 'A' (0x41). Przyda nam się w tym przypadku obsługa delay-i. Dołączam zatem do programu plik delay.h i delay.c. Prawym klawiszem myszki na Header Files w naszym projekcie (w przypadku dołączania pliku delay.h) i opcja Add Existing Item wybieramy lokalizacje pliku delay.h i zaznaczamy opcję Copy. U mnie wygląda to jak poniżej :



Analogicznie robimy dla pliku delay.c ale w tym przypadku prawy klawisz myszki na katalogu Sources Files. Wiem , że wy nie macie tych plików, więc trzeba je utworzyć i wypełnić treścią jak poniżej :  

plik delay.h


plik delay.c




Teraz w pliku main.c piszemy najprostszy możliwy  program, który wyśle nam cyklicznie literkę 'A' w eter po UART1. Umożliwi nam to sprawdzenie, czy UART1 w ogóle działa i ma chęci współpracować  z nami. Korzystam z funkcji  UART1_Write() wysyłającej jeden bajt po UART1 . Ciało funkcji znajdziemy w pliku uart1.c wygenerowanym automatycznie przez MCC


Kompilujemy program i wgrywamy wsad do PIC32MM Curiosity. Podłączamy pin RC12 (TX) do analizatora stanów logicznych. W analizatorze otrzymujemy przepiękny obrazek :) udowadniający, że UART1 działa.


Życie z PIC-ami jest piękne. W sumie to jest nawet perpetum-mobile bo program się wgrał pomimo, że zapomniałem przyporządkować właściwe piny do programatora. A przypomniał mi o tym komunikat podczas próby użycia debuggera :

Programming/Verify complete
The target device is not ready for debugging. Please check your configuration bit settings and program the device before proceeding. The most common causes for this failure are oscillator and/or PGC/PGD settings.


Chodzi o to ,że standardowo w MCC wybrane są piny dla PGC1/PGD1 a płytka PIC32MM Curiosity potrzebuje do szczęścia PGC2/PGD2. Korygujemy to zatem. W tym celu uruchamiamy MCC klikając plik MyConfig.mc3, który znajdziemy w katalogu Important Files w naszym projekcie.
Po uruchomieniu MCC zastana sytuacja wygląda jak poniżej :


Naszym celem jest przepięcie kłódeczek RB0 i RB1 przyporządkowanych do PGC1/PGD1 na RA0 i RA1 , które są przyporządkowane do PGC2/PGD2. robimy to w wierszu ICD. Efekt po zmianie powinien wyglądać jak poniżej :



Od tej chwili programator będzie rozmawiał z MCU po pinach RA0 i RA1.
Klikamy Generate aby zmiany zostały dodane do plików naszego projektu. Zamykamy MCC jednym kliknięciem w ikonkę MCC i zapominamy o temacie no pewnie do następnego tutoriala :) .Wracamy do naszych rozważań o UART.

Zmodyfikujmy teraz program tak aby wysyłać stringa w tym celu użyjemy funkcji UART1_WriteBuffer(). Ciało funkcji znajdziemy oczywiście w pliku uart1.c wygenerowanym automatycznie przez MCC. Argumenty jakie musimy podać to wskaźnik na bufor z naszym stringiem lub po prostu stringa i jego długość. Zmienimy program jak poniżej , kompilujemy i wgrywamy :


Efekt działania programu na analizatorze stanów logicznych :


Wiemy zatem jak wysłać znak i stringa. Tera przetestujemy odbiór . Ponieważ nie mamy wyświetlacza aby wyświetlić odebrane dane. Zrobimy sobie potwierdzenie w postaci zapalenia lub zgaszenia diody LED, którą mamy na pinie RD3. Przyjmijmy sobie , że np odebrany string "ON" zapali nam diodę LED a odebrany string "OFF" zgasi. Tu już wchodzimy na wyższy stopień skomplikowania ale to nic , jak pokażę prostą drogę do uzyskania tej funkcjonalności z wykorzystaniem dostępnych funkcji wygenerowanych przez MCC dla UART1. Będzie fajna zabawa. Do przeprowadzenia ćwiczenia z odbiorem łączymy jednym przewodem TX i RX na płytce czyli piny RA6 i RC12 muszą być jednym kabelkiem połączone. Co nam to da ? Nie będzie nam potrzebny w tym przypadku , żaden terminal na PC typu Putty etc. Dane wyślemy z programu naszego i odbierzemy w tym samym czasie również w programie. Robimy takie jak gdyby "echo". Zakładam ,że mamy już połączone piny RA6 i RC12, kabelkiem. Wracamy do części programowej.

Nanosimy zmianę do pliku main.c, dodajemy dwa includy dla uart1.h i string.h oraz definiujemy LedON i LedOFF . Zmiany ,które trzeba nanieść pokazane na obrazku poniżej :


Teraz "core" naszego programu. Rozbudowujemy plik main.c o kod pokazany poniżej :



Teraz objaśnię o co biega . Naszą intencją jest wykrycie w buforze odbiorczym stringa "ON" lub "OFF"  i ustawienie odpowiednie diody LED. Stringa wysyłamy jeden raz przed pętlą while(1) za pomocą funkcji UART1_WriteBuffer().  
String , który wyślemy będzie miał postać "ON%".
Analizę bufora użytkownika w poszukiwaniu naszego stringa rozpoczniemy dopiero jeśli zostanie odebrany znak '%' . Do analizy bufora i wyszukania stringa wykorzystam funkcję strstr() znajdującą się w pliku bibliotecznym string.h.
Analizować będziemy dane w buforze użytkownika myBuffer[], do tego bufora przepisujemy każdy bajt jaki zostanie odebrany przez UART1.  To czy bajt został odebrany informuje nas o tym ustawiona przez API Microchipa flaga UART1_TRANSFER_STATUS_RX_DATA_PRESENT. Dziwić może sprawdzenie warunku czy odebrany bajt nie jest zerem, zrobiłem to dlatego , że pierwszym odebranym bajtem u mnie jest zero , szczególnie nie wnikałem skąd się wziął w transmisji ten zbędny bajt . A to przeszkadza w poprawnym działaniu funkcji strstr(), która wykrywa nam wzór naszego stringa np. "ON" lub "OFF". Funkcja patternSearch(), zostanie wywołana jeśli odebrany bajt jest znakiem '%' i wtedy przystępujemy do analizy bufora użytkownika. Jeśli w buforze użytkownika zostanie znaleziony string "ON" zostanie zapalona dioda LED. Jeśli chcemy reagować na stringa "OFF" trzeba najpierw zapalić diodę prze wejściem w pętle while(1).

Podsumowując, zabawa z UART w wykonaniu Microchipa i jego zabawek w postaci MCC i wygenerowanego API jest bardzo przyjemna i prosta. Więcej miałem problemów zaczynając z AVR kiedyś niż z PIC-ami. W zasadzie odkąd przesiadłem się na PIC-e wszystko zaczęło mi się udawać a to spowodowało rozwój chęci do dalszej nauki i zabawy. Dzięki PIC32MM byłem w stanie bardzo szybko migrować na rdzenie ARM-a bez żadnej pomocy, bez żadnych tutoriali etc. Dlatego uważam , że ekosystem PIC dał mi bardzo dużo a przede wszystkim dał mi kopa do szybkiego samorozwoju i za to będę go gloryfikował po ostatnie tchnienie :) Amen.

W linkach poniżej znajduje się projekt , który wgrałem na GitHub. Sciągamy go do MPLABX-IDE za pomocą Team --> Remote --> Clone lub w konsoli Linuxa :

git clone https://github.com/PICmajster/PIC32MM_Tutorial_Part5.git


Pozdrawiam
picmajster.blog@gmail.com


Linki :

PIC32MM Curiosity Board - schemat
PIC323MM0256GPM064 - datasheet 

PIC32 Manual Reference - UART
pic32mm_tutorial_part5 na GitHub

3 komentarze:

  1. Nic dodać nic ująć jak zawsze świetny "Tutek" :) .
    Mam jeszcze pytanie tak na szybko by zmienić prędkość z 9600 na 11520 lub jeszcze inną wystarczy tylko w MCC dokonać zmian w Baud Rate i ponownie 'przeładować" projekt? czy trzeba jeszcze dokonać jakiś zmian w programie np. w ustawieniach zegara

    OdpowiedzUsuń
  2. Uruchom MCC zmień Baud Rate na co chcesz kliknij Generate. Pojawią się dwa okienka MCC Update Code. Znajdź w lewym okienku niebieską strzałeczkę na wysokości kodu dotyczącego Baud Generate. Kliknij w tę strzałeczkę , przeniesiesz w ten sposób aktualnie wygenerowany przez MCC kod z lewego okienka do prawego , które reprezentuje stary kod w programie. Zamknij MCC, zamknij dwa okienka MCC Update Code i działaj na nowych ustawieniach Baud Generate. Żadne inne zmiany nie są potrzebne.

    OdpowiedzUsuń
  3. Ok działa Dzięki

    OdpowiedzUsuń