Simulink, Arduino i LCD

Simulink, Arduino i LCD

Biblioteka Simulink Support for Arduino zawiera całą gamę bloków umożliwiających komunikację pomiędzy Arduino i światem zewnętrznym. Można korzystać w we/wy cyfrowych i analogowych, portu szeregowego a ostatnio nawet interfejsów I2C i SPI, które zapewniają obsługę prostych układów peryferyjnych. Jednak może się zdarzyć, że będziemy chcieli wykorzystać jakiś bardziej złożony układ, który nie jest obsługiwany z poziomu Simulinka, Zestaw gotowych bloków z biblioteki Simulinka jest niewystarczający choćby w przypadku chęci obsługi podłączonego do Arduino modułu LCD. Na szczęście w takich wypadkach można zapewnić sobie obsługę niestandardowego urządzenia samemu, a jest to możliwe dzięki tak zwanej s-funkcji.

S-funkcja to mechanizm pozwalający na integrację kodu stworzonego w językach Fortan, C lub MATLAB w Simulinkowych modelach. No i właśnie z takim przypadkiem mamy do czynienia, obsługa modułu LCD została przecież zawarta w bibliotece LicquidCrystal, napisanej w języku C. S-funkcję najprościej będzie stworzyć korzystając z bloku S-Function Builder, dostępnego w sekcji User-Defined Funkctions podstawowej biblioteki Simulink. Najprościej wcale nie oznacza że prosto! 🙂

Blok należy dodać do tworzonego modelu i otworzyć go do edycji.

Widok otwartego do edycji okna S-funkcji może przytłaczać.  Głównych zakładek jest 7, jednak nie musimy wszystkich uzupełniać. Dodatkowo, w pierwszej zakładce należy ograniczyć się w wpisania w polu Number of discrete states wartości 1. W końcu nie wykorzystujemy funkcji do przeprowadzania skomplikowanych obliczeń, a jedynie do prostego wyświetlenia danych na zewnętrznym urządzeniu. Nieco więcej pracy będzie z kolejną zakładką Data Properties.

W tej sekcji należy określić jakich danych spodziewamy się na wejściu oraz co ma pojawić się na wyjściu.  Musimy określić nazwy portów a także rozmiar i typ danych które będą przez porty transmitowane. W przypadku modułu LCD możemy zdefiniować sobie osobny port dla każdej ze zmiennych wejściowych, które chcemy wyświetlić. Ponieważ po wyświetlaczu LCD nie spodziewamy się żadnej odpowiedzi, można usunąć wszystko co pojawia się w pod-zakładce Output ports. Natomiast w ostatniej zakładce Data types attributes możemy zastąpić domyślny typ double na coś bardziej dla Arduino odpowiedniego, np. uint16.

Kolejna zakładka to Libraries. Jak nazwa wskazuje, w tym miejscu należy umieścić biblioteki, które są niezbędne do wykonania zadania, jakie zamierzamy wykonać. Czego się jednak nie można domyślić, sama dyrektywa #include nie wystarczy.

#ifndef MATLAB_MEX_FILE
	#include <LiquidCrystal.cpp>;
	LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
#endif

Do uzupełnienia pozostały jedynie dwie z czterech dalszych zakładek i w tych zakładkach musimy umieścić kod C odpowiedzialny za proces wyświetlania. Kod w zakładce Discrete Update odpowiada za inicjalizację procedury.

if(xD[0] != 1)
{
    #ifndef MATLAB_MEX_FILE
    lcd.begin(16,2);
    lcd.print("Temp: ");
    lcd.setCursor(0,1);
    lcd.print("Time: ");
    xD[0] = 1;
    #endif
}

Kod odpowiedzialny za aktualizację wyświetlanych danych powinien trafić (niestety wbrew intuicji) do zakładki Outputs

if(xD[0] == 1)
{
    #ifndef MATLAB_MEX_FILE
    lcd.setCursor(6,0);
    lcd.print(temp[0]);
    lcd.setCursor(6,1);
    lcd.print(time[0]);
    #endif
}

Przed naciśnięciem przycisku Build należy jeszcze nadać funkcji własną nazwę (np. LCD).

Proces kompilacji powiedzie się, o ile mamy zainstalowany jakiś kompilator 🙂 Simulink Support Package for Arduino Hardware niestety nie wystarczy ale można skorzystać z MinGW, który można zainstalować z poziomu MATLABa (przycisk Add-Ons).

Ten długi, opisany powyżej proces tworzenia s-funkcji to jeszcze nie koniec zabawy. W katalogu roboczym należy odnaleźć wygenerowaną przez S-Function Builder funkcję xxx_wrapper.c (np. LCD_wrapper.c) i zmienić jej rozszerzenie na .cpp. Następnie trzeba funkcję edytować i zastąpić wszystkie deklaracje funkcji void na extern "C" void Jest to niezbędne, jeśli pominiemy ten krok funkcja nie będzie działać.  W celu wykonania powyższych operacji można posłużyć się poniższą m-funkcją.

function c2cpp(name)
%c2cpp konwersja pliku <name>_wrapper.c na <name>_wrapper.cpp
%
% c2cpp(name) name - nazwa pliku c (bez rozszerzenia)

file = [name '_wrapper.c'];
% Odczytanie zawartosci pliku
text = fileread(file);
% zamiana tekstu
text_out = strrep(text, 'void', 'extern "C" void');
% utworzenie i zapis pliku wyjsciowego 
file_out = [file 'pp'];
fid = fopen(file_out, 'w');
fprintf(fid, '%s', text_out);
fclose(fid);
% usuniecie starego pliku
delete(file)

Uff...

W końcu można cieszyć się gotową funkcją, która wyświetli nam wskazane dane na podłączonym do Arduino wyświetlaczu LCD 🙂

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *