ArduinoIDE posiada zestaw standardowych funkcji umożliwiających zarządzanie wejściem/wyjściem. W prosty sposób można obsłużyć zarówno sygnały cyfrowe jak i analogowe. Poniżej zamieszczamy listę funkcji wraz z krótkim opisem i przykładami wykorzystania.


Cyfrowe wejście/wyjście

Cyfrowe piny ARDUINO mogą być wykorzystane jako wejścia lub jako wyjścia. Niezbędne są więc funkcje, które umożliwią ustawienie (skonfigurowanie) pinów oraz zapis lub odczyt danych.

pinMode()

Polecenie pinMode() umożliwia określenie pracy poszczególnych pinów. Jego składnia jest następująca:

pinMode(pin, tryb_pracy);

pin to określenie numeru pinu układu ARDUINO, tryb_pracy to jedna z predefiniowanych stałych: INPUT, OUTPUT, INPUT_PULLUP. Stałe zostały opisane w innym artykule kursu. Przykładowe deklaracje trybu pracy pinów:

pinMode(13,OUTPUT);
pinMode(8,INPUT);

#define ledPin 10
pinMode(ledPin,OUTPUT);

const byte przycisk=4;
pinMode(przycisk,INPUT_PULLUP);

int przycisk2=5;
pinMode(przycisk2,INPUT_PULLUP);

Jak widać deklaracja sposobu funkcjonowania pinu jest prosta. Warto zwrócić uwagę na fakt, że ten sam efekt można osiągnąć na kilka sposobów. Pierwsze dwa przykłady bazują na bezpośrednim podaniu numeru pinu i określeniu trybu jego działania. Jest to deklaracja prawidłowa, jednak nie zaleca się jej stosowania. Warto skorzystać z jednego z kolejnych sposobów. Bezpośrednie odwoływanie się do numerów pinów może prowadzić do zaciemnienia kodu i pomyłek. Przez cały czas pisania i testowania programu należy pamiętać co jest podłączone do konkretnego pinu ARDUINO. Lepszym rozwiązaniem jest zastosowanie definicji, stałej lub zmiennej. Definiując nazwę dla konkretnego pinu określamy (poprzez nazwę) jego zastosowanie. Zdecydowanie łatwiej zapamiętać, że ledPin to pin, do którego podłączono diodę LED w projekcie niż, że LED podłączono do pinu 10. Warto pamiętać, że deklarując odpowiednie nazwy będziemy się do nich odwoływać w programie, nie tylko podczas definicji trybu pracy. Definicja nazwy za pomocą dyrektywy define, lub const jest tożsama z praktycznego punktu widzenia. Kompilator zastąpi podaną nazwę przez przypisaną do niej wartość. Programiści ArduinoIDE zalecają stosowanie const. Ja w odniesieniu do pinów układu zalecam stosowanie define jako jednoznacznego wyróżniającego się przyporządkowania pinu do nazwy. Dodatkową zaletą stosowania define jest zwyczajowe jego umieszczanie na początku kodu, co ułatwia modyfikację układu elektronicznego w przyszłości. Zmieniając przyporządkowanie poszczególnych elementów układu zmieniamy wyłącznie numery pinów w definicji i cały program działa prawidłowo.

W ostatnim przykładzie pokazano definicję zmiennej jako nazwy do pinu układu. Taka definicja występuje na oficjalnej stronie dokumentacji ARDUINO. Moim zdaniem nie jest to najlepszy przykład, ponieważ zmienna zabiera cenne miejsce w pamięci. Jedynym uzasadnionym przykładem stosowania zmiennej może być sytuacja, gdy chcemy w pętli wykonywać operacje na wielu pinach. Są to jednak sytuacje szczególne. Pokazany schemat połączeń umożliwia przetestowanie opisanych w artykule funkcji cyfrowych. Podłączenie przycisku do masy układu zakłada wykorzystanie wewnętrznego rezystora pullup.

Czasami nie wykorzystujemy pinów analogowych układu, a chcielibyśmy wykorzystać je jako wejście lub wyjście cyfrowe. W takim przypadku za pomocą funkcji pinMode() ustawiamy odpowiedni tryb dla pinów A0 - A5..

#define zasilanie A0

void setup()
   {
     pinMode(zasilanie,OUTPUT);
   }

Wykorzystanie jednego z pinów A0 - A5 jako cyfrowych nie powoduje braku możliwości wykorzystania innych jako wejścia analogowe. Możliwe jest korzystanie np. z 2 wejść analogowych i 4 wyjść cyfrowych w ramach pinów A0 - A5.


    digitalWrite()

Funkcja digitalWrite() umożliwia ustawienie stanu pinu zdefiniowanego jako cyfrowe wyjście. Jej składnia jest zbliżona do pinMode(). Wymaga dwóch parametrów. pierwszym jest numer pinu, drugim wartość logiczna LOW lub HIGH. Ustawienie wartości LOW spowoduje wystawienie na pinie napięcia 0V (zwarcie do masy układu), wartość HIGH to w zależności od wersji układu 3,3V lub 5V (zależne od napięcia zasilania układu ARDUINO). Poniżej przykład zastosowania funkcji digitalWrite():

#define ledPin 13
void setup()
   {
     pinMode(ledPin,OUTPUT);
   }

void loop()
   {
    digitalWrite(ledPin,HIGH);          //zapal LED
    delay(500);                         //poczekaj 500ms (0,5s)
    digitalWrite(ledPin,LOW);           //zgaś LED
    delay(500);                         //poczekaj 500ms (0,5s)
   }

Jak widać na przykładzie możliwe jest ustawienie odpowiedniego stanu na wyjściu. Zastosowana w przykładzie funkcja delay() umożliwia wykonanie opóźnienia i będzie omówiona w dalszej części artykułu.

Wykorzystanie funkcji digitalWrite() w przypadku, gdy pin jest ustawiony jako wejście spowoduje włączenie lub wyłączenie trybu PULLUP czyli podanie zasilania przez rezystor podciągający do napięcia zasilania. W nowszych wersjach ArduinoIDE zdecydowanie lepiej stosować pinMode() z parametrem INPUT_PULLUP;

    digitalRead()

Funkcja digitalRead() umożliwia odczytanie stanu wejścia z pinu zdefiniowanego jako wejście cyfrowe. Funkcja ta zwraca wartość LOW lub HIGH. Należy podać numer pinu z którego chcemy odczytać stan.

digitalRead(pin);

Jeżeli pin, z którego czytamy nie jest podłączony w danej chwili do masy ani do zasilania funkcja może zwrócić losowo wartość LOW lub HIGH. Należy o tym pamiętać podczas projektowania układu elektronicznego. Często stosuje się rezystor podciągający wewnętrzny lub zewnętrzny, żeby zapobiec odczytywaniu przypadkowych informacji. Poniżej przykłady odczytu wartości cyfrowej z pinu wejściowego:

#define ledPin  13         // dioda LED podłączona do pinu 13
#define inPin   7           // przycisk podłączony do pinu 7
int val = 0;                // zmienna przechowująca odczytany stan wejścia

void setup()
{
  pinMode(ledPin, OUTPUT);  // pin 13 jako wyjście
  pinMode(inPin, INPUT_PULLUP);    // pin 7 jako wejście
}

void loop()
{
  val = digitalRead(inPin); // odczyta stanu z pinu 7
  digitalWrite(ledPin, val);// ustawienie stanu diody zależne od stanu wejścia
}

Powyższy przykład pokazuje jak odczytać stan wejścia i wykorzystać tą informację do sterowania wyjściem. Zmienna val przechowuje wartość LOW lub HIGH w zależności od stanu wejścia. Funkcja digitalWrite() ustawia stan wyjścia na podstawie zmiennej val. Często uzależniamy wykonanie jakiejś operacji bezpośrednio od stanu pinu. Wtedy możemy napisać:

#define ledPin  13         // dioda LED podłączona do pinu 13
#define inPin   7           // przycisk podłączony do pinu 7

void setup()
{
  pinMode(ledPin, OUTPUT);  // pin 13 jako wyjściet
  pinMode(inPin, INPUT_PULLUP);    // pin 7 jako wejście
}

void loop()
{
  if(digitalRead(inPin)) //bardziej jawny sposób: if(digitalRead(inPin)==HIGH)
      digitalWrite(ledPin, HIGH);
  else
      digitalWrite(ledPin, LOW);
}

Powyższy przykładowy program również zapala i gasi diodę w zależności od stanu podłączonego przycisku. Działanie to samo, składnia programu trochę inna. Często można zastosować zamiennie powyższe dwa rozwiązania, w pewnych przypadkach łatwiej jest zastosować pierwszy przykład, w innych drugi.


Analogowe wejście/wyjście

Układy ARDUINO umożliwiają obsługę sygnałów analogowych. W przypadku sygnałów wejściowych mamy do dyspozycji przetwornik A/C (analogowo-cyfrowy), w przypadku wyjść możliwa jest modulacja PWM (modulacja szerokości impulsów). Dokładniejsze informacje można znaleźć na stronie pl.wikipedia.org:

W przypadku ARDUINO, którego sercem jest jeden z układów ATMEGA mamy do dyspozycji jeden 10-bitowy przetwornik A/C. Oznacza to, że wartość odczytanego napięcia może zawierać się w przedziale 0 - 1023. W zależności od napięcia odniesienia 1024 wartości przetwornika A/C rozłożone zostaną na odpowiedni zakres. W efekcie możemy otrzymać różną dokładność i różny zakres napięć odczytywanych przez przetwornik. W przypadku podania napięcia odniesienia 1,024V każdej kolejnej wartości odczytanej z przetwornika będzie odpowiadał 1mV. W przypadku, gdy napięcie referencyjne wzrośnie do 5V każda kolejna wartość będzie odpowiadała ok. 5mV. Należy zaznaczyć, że przetworniki A/C nie mają idealnej charakterystyki liniowej. Oznacza to, że w pewnych przedziałach mogą wystąpić różnice pomiędzy napięciem podanym, a wartością napięcia odczytanego. Jak widać z powyższego zwiększając zakres pomiarowy tracimy na jakości pomiaru, zmniejszając zakres zwiększamy dokładność pomiaru.

Uwaga: ARDUINO posiada kilka (w zależności od wersji) wejść analogowych, jednak przetwornik A/C jeden. Oznacza to, że jeden przetwornik może odczytywać jednocześnie wartość napięcia analogowego z jednego wybranego pinu A0 - A5... (A0 - A15 dla ARDUINO MEGA)

    analogReference()

Do prawidłowej pracy przetwornika analogowo - cyfrowego wymagane jest podanie napięcia odniesienia (referencyjnego). W przypadku ARDUINO napięcie referencyjne może zawierać się w przedziale 0 - 5V(lub 0 - 3,3V dla układów zasilanych tym napięciem). W zależności od typu wykorzystanego mikrokontrolera możemy dysponować różnymi napięciami odniesienia. Dodatkowo można korzystać z wewnętrznego lub zewnętrznego źródła napięcia odniesienia. Funkcja analogReference() umożliwia ustawienie odpowiedniego napięcia odniesienia. Do dyspozycji są następujące opcje:

  • DEFAULT: napięcie odniesienia wynosi 5V lub 3,3V - w zależności od zasilania układu - czyli jest równe napięciu zasilania układu,
  • INTERNAL: napięcie odniesienia wynosi 1.1V dla ATmega168 i ATmega328 i 2.56V dla ATmega8,
  • INTERNAL1V1: napięcie odniesienia wynosi 1.1V - tylko ARDUINO MEGA,
  • INTERNAL2V56: napięcie odniesienia wynosi 2.56V -  tylko ARDUINO MEGA,
  • EXTERNAL: napięcie podłączone do pinu AREF - 0 do 5V.

Opcję DEFAULT wybieramy, by skorzystać z napięcia odniesienia 5V (zasilanie układu). Jest to najprostsza metoda, jednocześnie najmniej dokładna. Wymaga zapewnienia dobrej stabilizacji układu. Jedna z opcji INTERNAL jest dobrym rozwiązaniem, w sytuacji, gdy tworzymy układ dedykowany dla konkretnej wersji ARDUINO. Wewnętrzne napięcie odniesienia jest w miarę stabilne i wystarcza w większości zastosowań. Najdokładniejszym rozwiązaniem jest zastosowanie zewnętrznego źródła napięcia odniesienia. Dostępne są specjalne układy podające wymagane stabilne napięcie odniesienia. Minusem tego rozwiązania jest ewentualny koszt układu. Dodatkowym plusem jest możliwość uzyskania wymaganego dokladnego napięcia odniesienia np. 1,024V czy 2,048V, co ułatwia interpretację odczytanych danych z przetwornika A/C.

Składnia funkcji analogReference() pokazana została na poniższym przykładzie:

analogReference(DEFAULT);     //napięcie odniesienia = napięcie zasilania

analogReference(INTERNAL);    //napięcie odniesienia = 1,1V lub 2,56V 

analogReference(EXTERNAL);    //napięcie odniesienia = napięcie na AREF

 

    analogRead()

Funkcja analogRead() umożliwia odczytanie wartości z jednego z pinów analogowych. Wartość odczytana jest z przedziału 0 - 1023 (10-bitowy przetwornik). Należy podać numer wejścia analogowego, z którego nastąpi odczyt danych. Poniższy przykład ilustruje sposób wykorzystania wejść analogowych:

#define analogPin  0            // potencjometr podłączony do A0
int val = 0;                     // zmienna przechowująca odczytaną wartość

void setup()
{
  Serial.begin(9600);            // inicjalizacja portu szeregowego
}

void loop()
{
  val = analogRead(analogPin);   // odczyt wartości napięcia z portu A0
  Serial.println(val);           // wysłanie odczytanej wartości na terminal
}

Jak widać na powyższym przykładzie odczytana wartość podanego napięcia jest przesyłana poprzez port szeregowy do komputera. W przykładzie nie wykorzystano funkcji analogReference(), ponieważ domyślnie układ pobiera napięcie odniesienia z zasilania. Warto jednak w funkcji setup dodać jawnie wybór napięcia odniesienia, ponieważ ułatwia to zrozumienie kodu oraz jego modyfikację w przyszłości.

    analogWrite() - PWM

Funkcja analogWrite() umożliwia sterowanie wyściem za pomocą sygnału PWM, co często jest stosowane jako zamiennik typowego sygnału analogowego. W zależności od typu zastosowanego w ARDUINO mikrokontrolera zmiena się liczba dostępnych pinów mogących pracować jako wyjścia PWM. Układy z mikrokontrolerem ATMEGA8 udostępniają piny 9, 10, 11. ATMEGA 168 i 328 pozwala na skorzystanie z pinów 3, 5, 6, 9, 10, i 11, natomiast wersje ARDUINO MEGA (ATMEGA 1280, itp.) udostępniają PWM na pinach 2 do 13 i 44 do 46. Częstotliwość kluczowania sygnału PWM większości pinów to 490Hz. Stopień wypełnienia kształtowany jest za pomocą liczb z przedziału 0 do 255. 0 - brak wypełnienia, 255 - pełne wypełnienie. Jeżeli podłączymy diodę LED do pinu PWM i będziemy zmieniać wypełnienie sygnału, to zaobserwujemy zmianę intensywności świecenia LED. Poniżej znajduje się przykładowy program sterujący diodą LED:

#define ledPin  11              // LED podpięte do pinu 11
#define analogPin  0            // potencjometr na A0
int val = 0;                     // zmienna przechowująca wartość z A0

void setup()
{
  pinMode(ledPin, OUTPUT);       // pin 11 jako wyjście
}

void loop()
{
  val = analogRead(analogPin);   // odczyt z potencjometru
  analogWrite(ledPin, val / 4);  // zapis do PWM
}

Jak widać wartość odczytana z wejścia analogowego zostaje zamieniona na odpowiadającą jej wartość PWM. Ze względu na przedział  - wartość z A0 należy podzielić przez cztery, żeby proporcjonalnie działał PWM. W tym przykładzie zastosowano proste dzielenie. ArduinoIDE udostępnia również specjalną funkcję do tworzenia proporcji (czyli proporcjonalnego przeliczania wartości) o nazwie map(), zostanie ona opisana w innym miejscu kursu.


Zaawansowane funkcje wejścia/wyjscia

powyżej opisane funkcje obsługujące wejście i wyjście analogowo-cyfrowe nie wyczerpują wszystkich możliwości pakietu ArduinoIDE.

    tone()

Funkcja tone() umożliwia wygenerowanie przebiegu prostokątnego o wypełnieniu 50%. Zakres możliwych do wygenerowania częstotliwości to 31 do 65535Hz. Wygenerowanie przebiegu o częstotliwości mniejszej niż 31Hz nie jest możliwe. Składnia funkcji jest następująca:

tone(pin, częstotliwość);
tone(pin, częstotliwość, czas);

Możliwe są dwa sposoby wywołania. Podaje się numer pinu i częstotliwość lub numer pinu, częstotliwość i czas trwania. W pierwszym przypadku przebieg generowany jest do czasu, aż nie zostanie zatrzymany za pomocą funkcji noTone(), w drugim natomiast generowanie trwa tyle ile podano w wywołaniu funkcji. czas podawany w wywołaniu funkcji podajemy w milisekundach. W przypadku, gdy chcemy uzyskać generowany sygnał o różnych częstotliwościach na różnych pinach należy wyłączyć generowanie przebiegu na jednym pinie przed rozpoczęciem generowania go na drugim pinie. Nie jest możliwe jednoczesne generowanie różnych przebiegów na różnych pinach. Przykłady wykorzystania funkcji tone():

tone(3,1000);
delay(1500);
noTone(3);

tone(4,1000,1500);

Pierwsza część kodu umożliwia wygenerowanie przebiegu o częstotliwości 1000Hz i czasie trwania 1500ms. Druga część kodu wykonuje to samo zadanie. Różnica polega na tym, że w pierwszym przypadku korzystamy z odrębnych funkcji do odmierzania czasu i wyłączenia generowania sygnału, w drugim przypadku wszystko ustalane jest w funkcji tone().

    noTone()

Funkcja noTone() umożliwia wyłączenie generowania przebiegu za pomocą funkcji tone(). Składnia noTone() sprowadza się do podania numeru pinu, który chcemy wyłączyć. 

noTone(pin);

Wyłączenie generowania przebiegu dla pinu, na którym przebieg nie był generowany nie powoduje żadnej akcji.

    shiftOut()

Funkcja shiftOut() umożliwia szeregowe wystawienie wartości liczby int na podanym pinie. Umożliwia to prostą obsługę zewnętrznych rejestrów szeregowo-równoległych, czy wykonania kilku programowych portów szeregowych. 

    shiftIn()

Za pomocą funkcji shiftIn() możliwe jest szeregowe odczytanie wartości z podanego pinu. Umożliwia to obsługę zewnętrznych rejestrów równoległo-szeregowych i innych.

    pulseIn()

Funkcja pulseIn() umożliwia zmierzenie czasu trwania impulsu podanego na zdefiniowany pin. Możliwy jest pomiar czasu stanu wysokiego, jak również stanu niskiego - w zależności od podanego parametru. Składnia wywołania funkcji jest następująca:

pulseIn(pin, stan);

pulseIn(pin, stan,czas);

Pin określa z którego pinu odczytujemy stan, stan to jedna z wartości HIGH lub LOW, dodatkowo opcjonalny parametr czas określa jak długo funkcja ma czekać na zdarzenie. Wykorzystanie czasu umożliwia zaniechanie oczekiwania w przypadku, gdy zdarzenie (zmiana stanu pinu) nie wystąpi. Przykład wykorzystania pulseIn() przedstawiono poniżej:

#define pin  7
unsigned long czas;

void setup()
{
  pinMode(pin, INPUT);
  Serial.begin(9600);
}

void loop()
{
  czas = pulseIn(pin, HIGH);
  Serial.println(czas);
  delay(1000);
}

W przykładzie co sekundę odczytywany jest czas trwania stanu wysokiego na pinie 7. Czas przesyłany jest poprzez port szeregowy do komputera.


Funkcje związane z pomiarem czasu

 

    millis()

Funkcja millis() umożliwia odczytanie czasu, który upłynął od uruchomienia bieżącego programu. Funkcja zwraca wartość unsigned long i umozliwia odczytanie wartości do 50 dni od uruchomienia programu. Po tym czasie zliczanie rozpocznie się od nowa. Poniżej znajduje się przykład wykorzystania funkcji millis():

unsigned long time;

void setup(){
  Serial.begin(9600);
}
void loop(){
  Serial.print("Czas od włączenia: ");
  time = millis();      // zapamiętanie wartości czasu
  Serial.println(time); // wysłanie informacji poprzez port szeregowy
  delay(1000);
}

W powyższym przykładzie co sekundę zostanie przesłana informacja o czasie, który upłynął od uruchomienia programu. Ponieważ czas jest mierzony w milisekundach, więc kolejne przesłane wartości będą się różniły o ok. 1000. Dokładność odczytu zależy od stabilności rezonatora kwarcowego układu ARDUINO.

 

    micros()

Funkcja micros() jest odpowiednikiem funkcji millis(), różnica polega głównie na dokładności dokonanego pomiaru. Za pomocą funkcji micros() otrzymamy czas od uruchomienia bieżącego programu podany w mikrosekundach. Licznik zliczanych mikrosekund zostanie wyzerowany po upływie 70 minut. Poniżej podano przykład wykorzystania funkcji micros():

unsigned long time;

void setup(){
  Serial.begin(9600);
}
void loop(){
  Serial.print("Czas od uruchomienia: ");
  time = micros();
  Serial.print(time);
  Serial.println(" mikrosekund ");
  delay(1000);
}

Tak jak w przykładzie funkcji millis(), również w powyższym przykładzie co sekundę zostanie wysłana informacja o odmierzonym czasie, różnica polega tylko na tym, że w tym przypadku czas mierzony jest w mikrosekundach.

    delay()

Funkcja delay() umożliwia zatrzymanie aktualnie wykonywanego programu na określony w parametrze czas. Składnia polecenia jest następująca:

//polecenia
delay(500);      //zatrzymanie na 0,5s
//polecenia
delay(1000);   //zatrzymanie na 1s

Czas podajemy w milisekundach (1s = 1000ms). Podawany parametr może być typu unsigned long czyli wartość zawiera się w przedziale 0 do 4 294 967 295. Poniżej przykład wykorzystania polecenia delay():

#define ledPin 13
void setup()
   {
     pinMode(ledPin,OUTPUT);
   }

void loop()
   {
    digitalWrite(ledPin,HIGH);          //zapal LED
    delay(500);                         //poczekaj 500ms (0,5s)
    digitalWrite(ledPin,LOW);           //zgaś LED
    delay(1000);                        //poczekaj 1000ms (1s)
   }

W powyższym przykładzie dioda LED zapali się na 0,5 sekundy, następnie zgaśnie na sekundę i tak na przemian do czasu wyłączenia zasilania ARDUINO.

    delayMicroseconds()

Funkcja delayMicroseconds() jest odmianą funkcji delay(). Różnica polega na ilości i dokładności odmierzania czasu. Funkcja delay() umożliwia odmierzanie czasu z dokładnością do ok. jednej milisekundy, natomiast delayMicroseconds() z dokładnością do ok. 1 mikrosekundy. Wartość, jaką można podać w parametrze zawiera się w przedziale 0 do 16383. Dla dłuższych przedziałów czasowych należy skorzystać z funkcji delay() lub kilkukrotnie wykorzystać delayMicroseconds().

#define outPin  8                 

void setup()
{
  pinMode(outPin, OUTPUT);      // pin 8 jako wyjście
}

void loop()
{
  digitalWrite(outPin, HIGH);   // pin 8 stan wysoki
  delayMicroseconds(50);        // przerwa 50 mikrosekund      
  digitalWrite(outPin, LOW);    // pin 8 stan niski
  delayMicroseconds(50);        // przerwa 50 mikrosekund
}

Powyższy przykład generuje przebieg prostokątny o okresie 100 mikrosekund i wypełnieniu 50%.


Funkcje matematyczne

Funkcje matematyczne w ArduinoIDE ułatwiają wykonanie porównań i przeliczeń wartości otrzymanych w wyniku pomiaru, czy transmisji danych. Twórcy ArduinoIDE odradzają stosowanie inkrementacji i dekrementacji wewnątrz funkcji matematycznych, uzasadniają to tym, że może pojawić się wynik niezgodny z oczekiwaniami... Osobiście nie zauważyłem nieprawidłowego działania takiej składni.

    min()

Funkcja min() zwraca mniejszą wartość z dwóch podanych jako parametry. Przykładowe zastosowanie funkcji min() podano poniżej:

int x;
x=min(100,200);      //x=100
x=min(a,b)           // gdy a<b x=a, gdy a>b x=b

W pierwszym przypadku zmienna x będzie miała wartość 100, w drugim natomiast w zależności od wartości zmiennych a i b zmiennej x przypiszemy mniejszą wartość.

    max()

Analogicznie do funkcji min() funkcja max() zwraca wartość liczby większej podanej jako jeden z dwóch parametrów. Przykład wykorzystania funkcji max() znajduje się poniżej:

int x;
x=max(100,200);      //x=200
x=max(a,b)           // gdy a>b x=a, gdy a<b x=b

    abs()

Funkcja abs() zwraca wartość bezwzględną z podanego parametru. W przypadku, gdy podanym parametrem jest liczba większa lub równa zero funkcja zwraca tą samą wartość. W przypadku, gdy jako parametr podamy liczbę ujemną funkcja zwraca zanegowaną wartość. Kilka przykładów zastosowania funkcji abs() znajduje się poniżej:

int x=5, y=-3, z;
z=abs(x);            //z=5
z=abs(y);            //z=3
z=abs(0);            //z=0
z=abs(-12);         //z=12

    constrain()

Funkcja constrain() umożliwia dokonanie konwersji wartości do podanego przedziału. Składnia funkcji jest następująca:

constrain(x, a, b);

X to wartość, którą porównujemy, a to najmniejsza wartość z przedziału, b największa wartość z przedziału. Funkcja zwraca wartość x w przypadku, gdy x>a i x<b. Dla x<a funkcja zwraca wartość a, natomiast dla x>b funkcja zwraca wartość b. Za pomocą funkcji constrain() możemy ograniczyć zbiór wartości otrzymanych z wejścia analogowego do określonego przedziału. Poniżej przykładowe zastosowanie funkcji constrain():

sensVal = constrain(sensVal, 10, 150);  
//ograniczenie przedziału odczytanych wartości do 10 - 150

    map()

Funkcja map umożliwia zamapowanie (przeliczenie)  wartości z jednego zakresu na drugi. Jest to często wykorzystywanie w sytuacji, gdy chcemy dokonać proporcjonalnego sterowania. Przykładowo na podstawie odczytanego napięcia wejściowego sterujemy wypełnieniem sygnału PWM. Składnia funkcji map() jest podana poniżej:

map(x,a1,a2,b1,b2);

X to wartość, która ma zostać przeliczona, a1 i a2 to graniczne wartości przedziału z jakiego należy przeliczyć, b1 i b2 to graniczne wartości przedziału na jaki przeliczamy. Funkcja zwróci wartość z przedziału b1 - b2.

Poniżej przykład zastosowania funkcji map():

#define analogPin A0;
#define digitalPin 9

void setup() 
   {
     pinMode(analogPin,INPUT);
     pinMode(digitalPin,OUTPUT);
   }

void loop()
   {
    int val = analogRead(analogPin);
    val = map(val, 0, 1023, 0, 255);//konwersja z liczby 10-bitowej na 8-bitową
    analogWrite(pwmPin, val);
   }

W przykładzie wartość odczytana z dziesięcio-bitowego przetwornika A/C zostale przeliczona na 8-bitową wartość dopuszczalną w sterowaniu PWM.

    pow()

Funkcja pow() oblicza wartość potęgi dla podanych parametrów:

pow(x,y);

X to liczba podnoszona do potęgi (wykładnik), y wyznacznik potęgi (wykładnik). 2^3=2*2*2=8. Przykłady zastosowania funkcji pow():

float x;
int a;

x = pow(2,3);      //x=8.00
a = pow(2,3);      //a=8
a = pow(3,2);      //a=9 

    sqrt()

Funkcja sqrt() umożliwia obliczenie kwadratu podanej liczby. Przykłady zastosowania funkcji sqrt() podano poniżej:

int a=3,x;
x = sqrt(a);      // x = 9
x = sqrt(2);      // x = 4

sin(), cos(), tan()

Funkcje trygonometryczne zawarte w ArduinoIDE umożliwiają obliczenie wartości sin, cos, tg dla konta podanego w radianach. Wywołanie funkcji jest proste, każda z nich wymaga podania jako parametr wywołania wartości kąta w radianach i zwraca obliczoną wartość.


Generowanie liczb losowych

ArduinoIDE ma zaimplementowane funkcje umożliwiające generowanie liczb pseudolosowych. Do dyspozycji mamy dwie funkcje: random() oraz randomSeed().

    randomSeed()

Funkcja randomSeed() umożliwia zainicjowanie generatora liczb pseudolosowych.

    random()

Funkcja random() umożliwia wygenerowanie liczby  pseudolosowej z podanego zakresu. Składnia polecenia podana została poniżej:

random(x);       // zakres 0 - (x-1)
random(a,b);     // zakres a - (b-1)

Podając jeden parametr generujemy liczbę z zakresu od zera do liczby o jeden mniejszej od parametru. Dla dwóch parametrów zakres rozpoczyna się od pierwszego parametru, a kończy na liczbie o jeden mniejszej od drugiego parametru. Przykład losowania liczb podano poniżej:

long randNumber;

void setup()
  {
   Serial.begin(9600);
   randomSeed(analogRead(0));
  }

void loop() 
  {
   randNumber = random(300);
   Serial.println(randNumber);  
   randNumber = random(10, 20);
   Serial.println(randNumber);
   delay(150);
  }

W przykładzie zastosowano inicjalizację generatora za pomocą wartości odczytanej z wejścia analogowego. Pierwsza z pary liczb losowana jest z zakresu 0 - 299, druga z zakresu 10 - 19.


Operacje na bitach i bajtach

 ArduinoIDE dysponuje zestawem funkcji umożliwiających wykonywanie operacji na bitach i bajtach. Możliwe jest odczytanie wartości bitu lub jej ustawienie. 

    lowByte(), highByte()

Funkcja lowByte() umożliwia wyodrębnienie młodszego bajtu z zapisanej liczby. W przypadku, gdy zadeklarujemy zmienną jako int jej wartość przechowywana jest w dwóch bajtach. Wysłanie tej wartości poprzez port szeregowy wymaga wysłania starszego i młodszego bajtu. Funkcja lowByte() poda nam wartość młodszego bajtu, natomiast highByte() wartość starszego bajtu. Poniżej przedstawiono składnię poleceń:

int x;
lowByte(x);
highByte(x);

Funkcje wywołujemy z parametrem, który jest "większego" typu (wielobajtowy), zwracają natomiast jeden bajt. Tu nasuwa się pytanie, co zwróci funkcja w przypadku, gdy jako parametr podamy zmienną czterobajtową? W rzeczywistości funkcje umożliwiają podanie najstarszego i najmłodszego bajtu. Oznacza to, że dla liczby czterobajtowej otrzymamy bajt pierwszy lub czwarty. Bajty drugi i trzeci nie są dostępne bezpośrednio. Poniżej przedstawiono przykład zastosowania funkcji lowByte() i highByte():

int test = 0xABCD;              // liczba 16-bitowa
long int test2 = 0xABCDEF98     // liczba 32-bitowa
byte hi, lo;                    // dwie zmienne 8-bitowe

hi = HighByte(test);            // hi = 0xAB
lo = LowByte(test);             // lo = 0xCD.

hi = HighByte(test2);           // hi = 0xAB
lo = LowByte(test2);            // lo = 0x98.  

    bitRead(), bitWrite()

Funkcja bitRead() umożliwia odczytanie wartości konkretnego bitu w podanej zmiennej. Wywołujemy ją zawsze z dwoma parametrami. Pierwszy z nich to nazwa zmiennej, z jakiej chcemy odczytać wartość bitową, druga, to numer bitu do odczytu. Numerujemy zawsze od zera, czyli mamy bit zerowy, pierwszy, drugi itd. Funkcja zwróci wartość LOW lub HIGH. Funkcja bitWrite() umożliwia zapisanie konkretnego bitu. Wywoływana jest z trzema parametrami pierwszy z nich to zmienna, drugi to numer bitu, trzeci natomiast to informacja, czy bit ma zostać ustawiony (HIGH), czy skasowany (LOW).

byte x=0xF0;          // binarnie 11110000

bitRead(x,3);         // funkcja zwróci LOW
bitRead(x,7);         // funkcja zwróci HIGH

bitWrite(x,1,HIGH);   // x = 11110010
bitWrite(x,7,LOW);    // x = 01110010

Operacje bitowe często wykorzystywane są podczas programowania do ustawiania lub odczytu stanu rejestrów czy pinów na podstawie przechowywanych lub przesłanych danych. 

    bitSet(), bitClear()

Alternatywnym sposobem zmiany stanu (wartości) bitów dla funkcji bitWrite() są funkcje bitSet() oraz bitClear(). W funkcji bitWrite() jako parametr podajemy czy bit zostanie ustawiony, czy skasowany. Za pomocą jednej z funkcji bitSet() lub bitClear() jednoznacznie określamy, czy chcemy dany bit ustawić, czy skasować. Poniżej kilka przykładów zastosowania funkcji bitSet() oraz bitClear():

byte a=0xAA;              // binarnie 10101010
bitSet(a,6);              //      a = 11101010
bitClear(a,7);            //      a = 01101010
bitClear(a,7);            //      a = 01101010
bitClear(a,6);            //      a = 00101010
bitSet(a,7);              //      a = 10101010

    bit()

Funkcja bit() podaje wartość określonego podanego bitu. Dla przypomnienia w systemie binarnym każdej liczbie odpowiada wartość w zależności od pozycji jej występowania: binarne 0110 = dziesiętnie 0*2^3+1*2^2+1*2^1+0*2^0. Funkcja  bit() zwraca wartość dla podanej pozycji. Poniżej przykłady:

byte x;

x = bit(0);    // x = 1
x = bit(2);    // x = 4
x = bit(4);    // x = 16
x = bit(7);    // x = 128