LinkedIn YouTube Facebook
Szukaj

Newsletter

Proszę czekać.

Dziękujemy za zgłoszenie!

Wstecz
SoM / SBC

Język programowania Arduino – jedyny słuszny wybór

Decyzja dotycząca wyboru języka programowania w świecie Arduino z pewnością nie była łatwa. Od wielu już lat jedynym słusznym wyborem dla systemów mikroprocesorowych jest język C, który dzięki wysokiej efektywności i elastyczności wyparł asembler z ogromnej większości projektów. Tylko, że język C ma opinię trudnego do nauczenia (bzdura!), a przecież z założeń Arduino wynika, że praca ma być łatwa i przyjemna. Jednak również w tym przypadku autorzy Arduino stanęli na wysokości zadania. Otóż w świecie Arduino programy piszemy w zasadzie w języku C. To „w zasadzie” wynika z tego, że twórcy Arduino wzięli z najpopularniejszego języka programowania to co uznali za potrzebne i jednocześnie postarali się (niestety z różnym skutkiem), żeby język ten był stosunkowo łatwy do opanowania przez amatorów.

Jak powszechnie wiadomo, język C pozwala programiście na dosyć dużo, można nawet zaryzykować stwierdzenie, że niektórym programistom pozwala na zbyt dużo. Oczywiście, „wirtuozi” programowania są w wymarzonym raju, jednak zbyt często programy napisane przez nich wyglądają jak przekaz od obcej cywilizacji. Przykładem takiego „tworu” może być poniższa instrukcja, powodująca ustawienie wysokiego poziomu na linii 3 wejścia-wyjścia w wybranym mikrokontrolerze:
  GPIO7->DR[0x3fc]=(1<<3);

Oczywiście można tak robić i z pewnością ta instrukcja była czytelna i zrozumiała dla programisty wyspecjalizowanego w pisaniu aplikacji dla konkretnego mikrokontrolera. Warto jednak zadać sobie pytanie czy za kilka lat, gdy konieczne będzie zmodyfikowanie programu, analiza jego działania nie pochłonie zbyt dużo coraz cenniejszego czasu. A przecież można ten sam efekt (dla tego samego mikrokontrolera) uzyskać wywołaniem funkcji:

  GPIO_WriteBit(GPIO_LED, LED3, Bit_SET);

Prawda, że jest to czytelniejsze? Z pewnością nawet za kilka lat taki kod będzie zrozumiały nie tylko dla autora programu.

 

To nie język C powoduje, że niektóre kody źródłowe programów w nim napisanych mogłyby startować w konkursach kryptograficznych! To powodują niedouczeni programiści, a fakt, że w wielu miejscach można łatwo znaleźć przykłady kalamburów programistycznych napisanych właśnie w języku C wynika tylko i wyłącznie z tego, że jest to najpopularniejszy język programowania, a nie z powodu stopnia skomplikowania tego języka.

Tak więc z możliwości zagmatwania kodu programu (co przecież jest łatwe w każdym języku programowania, a nie tylko w C) nie wynika konieczność tego czynienia! Z popularnej wśród programistów anegdoty mówiącej, że program trudno było napisać, więc również trudno powinno się go czytać, można się pośmiać, ale w praktyce warto zadbać o czytelność i przejrzystość pisanego programu.

 

 Fot. 1. Dołączenie diody LED do zestawu Arduino Uno Fot. 1. Dołączenie diody LED do zestawu Arduino Uno

 

Wiemy już, że język, którym będziemy posługiwać się pisząc programy w środowisku Arduino wywodzi się z języka C. Porównajmy więc dwa elementarne programy powodujące miganie diodą LED dołączoną do linii 13 zestawu (czyli linii PB5 mikrokontrolera) napisane w tych językach. Na fotografii 1 pokazano sposób dołączenia diody do zestawu Arduino Uno. Na listingu 1 znajduje się program napisany w języku C. Do jego skompilowania został wykorzystany kompilator AVR GCC z biblioteką avr-libc. Na listingu 2 znajduje się analogiczny program przygotowany w środowisku Arduino. Podobieństwa w formalnym zapisie używanym w obu przypadkach są widoczne na pierwszy rzut oka – tak samo używa się nawiasów zwykłych u klamrowych, podobnie wyglądają definicje i wywołania funkcji itd. Natomiast budowa programów jest już różna. Program w języku C rozpoczyna się od deklaracji używanych bibliotek, ewentualnie zmiennych, stałych itp. a działanie programu rozpoczyna się od funkcji int main(), która jak widać zwraca wartość całkowitą do programu wywołującego. Oczywiście w świecie małych mikrokontrolerów taka deklaracja funkcji main() nie ma sensu, gdyż w olbrzymiej większości przypadków tego typu programy nie są wywoływane z nadrzędnego systemu, pracują natomiast samodzielnie i ich zakończenie nigdy nie powinno nastąpić. Ciągłość pracy przygotowywanego programu zapewnia nieskończona pętla while(1), więc wykonanie instrukcji return 1 nigdy nie nastąpi, ale tego typu zapis jest konieczny ze względu na wymogi kompilatora języka C.
Natomiast program dla Arduino jest zbudowany z dwóch bloków, czyli funkcji setup(), wywoływanej po uruchomieniu/wyzerowaniu mikrokontrolera, oraz funkcji loop(), do której jest przekazywane sterowanie po wykonaniu funkcji setup(). Nazwy tych funkcji w zasadzie same się komentują. W ciele funkcji setup() należy zawrzeć wszelkie instrukcje konfigurujące nasz system do pracy, natomiast funkcja loop() to wspomniana wcześniej pętla nieskończona. Przed wspomnianymi funkcjami oraz w ich „wnętrzu” można deklarować zmienne i stałe o zasięgu zgodnym z zasadami obowiązującymi w języku C – przykład takich deklaracji można zobaczyć w listingu 2.

 

 

Listing 1. Program w języku C powodujący miganie diodą LED

#define F_CPU 16000000UL // częstotliwość rezonatora kwarcowego

#define LED 0x20         // linia, do której dołączono diodę LED
                         // = linia 13 w Arduino Uno
                         // = linia 5 portu mikrokontrolera

#include 
#include 

int main(void)
{
  DDRB = LED;           // ustawienie linii PB5 jako wyjściowej

  while (1)             // pętla nieskończona
  {
    PORTB = LED;        // ustawienie bitu 5 w porcie PB
    _delay_ms(1000);    // opóźnienie 1s (1000 ms)
    PORTB = 0x00;       // wyzerowanie bitów w porcie PB
  _delay_ms(1000);      // opóźnienie 1s (1000 ms)
  }
  return 1;             // sztuczne zakończenie programu, gdyż 
                        // ze względu na prototyp funkcji main
                        // musi ona zwracać wartość
}                       // koniec funkcji main

 

Listing 2. Program migania diodą LED w wersji Arduino

const int LED = 13;     // dioda LED jest dołączona do linii 13 zestawu

void setup()            // funkcja konfigurująca
{
  pinMode(LED, OUTPUT); // ustawienie linii LED jako wyjściowej
}

void loop()             // pętla nieskończona
{
  digitalWrite(LED, HIGH);  // ustawienie bitu
  delay(1000);              // opóźnienie 1 s (1000 ms)
  digitalWrite(LED, LOW);   // wyzerowanie bitu
  delay(1000);              // opóźnienie 1 s (1000 ms)
}

Zależność pomiędzy programem Arduino i programem w języku C (pamiętajmy, że „finalnym” kompilatorem Arduino jest AVR GCC, czyli kompilator języka C) pokazano na listingu 3.

List. 3. Zależność pomiędzy programem Arduino i programem w języku C

int main(void)
{
  init();       // inicjalizacja zestawu narzucona przez
                // środowisko Arduino (np. typ zestawu,
                // częstotliwość pracy mikrokontrolera)

  setup();      // inicjalizacja zestawu przez użytkownika
                // (np. incjalizacja sposobu pracy interfejsu
                // szeregowego, konfiguracja linii we/wy)

  while (1)     // pętla nieskończona
  {
    loop();     // właściwy program
  }

  return 0;
}

Nawet w przypadku tak prostych programów, jak pokazane na listingach 1 i 2, widoczna jest różnica w ich czytelności, chociaż tak naprawdę oba programy są napisane w języku C. Co zatem powoduje, że program przygotowany w Arduino jest bardziej przyjazny? Otóż jest on napisany z wykorzystaniem jednej z wielu bibliotek standardowo zawartych w Arduino. I tak naprawdę to obecność bibliotek do obsługi najpopularniejszych układów peryferyjnych jest jednym z mocniejszych argumentów przemawiających za tym środowiskiem. Co więcej, standardowe biblioteki są przygotowane dla różnych platform sprzętowych, więc zamiast pokazanego na fotografii 2 zestawu Arduino Uno z mikrokontrolerem ATmega328 (rodzina AVR firmy Atmel), można użyć pokazanego na fotografii 3 zestawu ChipKit Uno32 z mikrokontrolerem PIC32MX320F128 (rodzina PIC32 firmy Microchip) czy też zestawu Itead Maple (fotografia 4) z mikrokontrolerem STM32F103RBT6 (rodzina STM32 firmy STMicroelectronics). Daje to projektantowi możliwość dobrania sprzętu odpowiedniego do danego zastosowania.

Fot. 2. Zestaw Arduino Uno z mikrokontrolerem z rodziny AVR

Fot. 3. Zestaw ChipKit Uno32 z mikrokontrolerem z rodziny PIC32

 

Fot. 4. Zestaw Itead Maple z mikrokontrolerem z rodziny STM32

Fot. 4. Zestaw Itead Maple z mikrokontrolerem z rodziny STM32

Warto zwrócić jeszcze uwagę na kilka zalet wynikających ze stosowania dobrze przygotowanych bibliotek. W programie z listingu 1 instrukcja:

  PORTB = LED;

powoduje zmianę stanu wszystkich linii portu B mikrokontrolera, a nie tylko na linii, do której jest dołączona dioda LED. Wynika to z braku instrukcji modyfikujących stan pojedynczej linii. Oczywiście bez problemu można znaleźć przygotowane przez kogoś biblioteki z odpowiednimi funkcjami, można takie biblioteki również przygotować samemu lub uzyskać oczekiwany efekt za pomocą operacji logicznych, np. ustawienie linii 5 portu B można osiągnąć przez instrukcję sumy logicznej:

  PORTB |= 0x20;

Jednak czy zapis:

  digitalWrite(LED, HIGH);

nie jest czytelniejszy?

 

 

Autoryzowanym dystrybutorem zestawów Arduino w Polsce jest KAMAMI.pl.

Autor: Anna Kubacka