poniedziałek, 18 września 2017

Modulo - przyjaciel programisty.

Operator Modulo dostępny jest praktycznie w każdym języku programowania skoro tak to wypadałoby przynajmniej mieć podstawową wiedzę na jego temat. Co to za zwierz i do czego można go wykorzystać traktuje poniższy krótki wpis.

Z Wikipedii dowiemy się tyle, że "..Modulo – operacja wyznaczania reszty z dzielenia jednego typu liczbowego przez drugi. W dalszym ciągu napis będzie oznaczał, iż jest resztą z dzielenia przez ."
I wzorek teoretyczny :

gdzie : to całkowita część wyniku dzielenia..

Nadal nic nie kumamy więc przykład łopatologiczny :

Działanie operacji modulo można zobrazować następująco:

25 mod 2 = 1
Ponieważ:
25 / 2 = 12.5,
12.5 bez reszty to 12 (25 div 2 = 12),
25 – (12*2) = 1,
W 25 mieszczą się dwie pełne dwunastki i zostaje 1,
Reszta z dzielenia 25/2 wynosi 1.

Gdzie to może się przydać bo na razie nadal nie kumamy po co to cholerstwo .

Przykład wykorzystania np. test parzystości liczby.

Liczbę nazywamy parzystą, gdy możemy podzielić ją bez reszty przez dwa. Czyli liczba a jest parzysta, gdy reszta z dzielenia a przez 2 wynosi 0. W praktyce oznacza to że, by określić czy liczba a jest parzysta wystarczy sprawdzić czy spełnia warunek: a mod 2 = 0
Czy liczba 25 jest parzysta?
25 mod 2 = 1
25 nie jest liczbą parzystą.

Czy liczba 38 jest parzysta?
38 mod 2 = 0
38 jest liczbą parzystą.

Czy 0 jest liczbą parzystą?
0 mod 2 = 0
Nasz program uzna że 0 jest liczbą parzystą.

Modulo ma jednak więcej do zaoferowania niż tylko test parzystości. Mianowicie przy wykorzystaniu operacji Modulo możemy zaimplementować prostą quasi wielowątkowość.

Załóżmy zatem że chcemy cyklicznie odpalać 4 procesy :

Proces nr 1 : Polecenie konwersji temperatury dla Czujnika nr 1 i Czujnika nr 2
Proces nr 2 : Polecenie odczytania temperatury z Czujnika nr 1
Proces nr 3 : Polecenie odczytania temperatury z Czujnika nr 2
Proces nr 4 : Polecenie wyświetlenia temperatury z Czujnika nr 1 i Czujnika nr 2

Każdy z procesów chcemy aby był  wyzwalany cyklicznie następująco :

Proces nr 1 w każdej zerowej sekundzie
Proces nr 2 w każdej pierwszej sekundzie
Proces nr 3 w każdej drugiej sekundzie
Proces nr 4 w każdej trzeciej sekundzie

W typowym  podejściu implementację zagadnienia byśmy próbowali uzyskać za pomocą delay(). W efekcie struktura programu wyglądałaby mniej więcej tak :

Proces 1
delay(1s)
Proces 2
delay(1s)
Proces 3
delay(1s)
Proces 4
delay(1s)

Intuicyjne widzimy , że powyższe podejście ma wiele słabych stron.

I tutaj z pomocą przychodzi Modulo :

Na początku musimy stworzy sobie za pomocą Timera sprzętowego lub programowego zmienną , która będzie inkrementowana co 1 sekundę. Zmienną nazwijmy np : Tick.
W języku C/C++ operator Modulo oznaczamy za pomocą symbolu %.

Zapis za pomocą Modulo

if( 0 = = Tick % 4) Proces 1 ;

if( 1 = = Tick % 4) Proces 2 ;
 
if( 2 = = Tick % 4) Proces 3 ;

if( 3 = = Tick % 4) Proces 4 ;

Zmienna Tick będzie inkrementowana co 1 sekundę w zakresie  0...3  (jeśli Tick będzie większe od 3 to zerujemy zmienną). Dlaczego Modulo 4 ? wynika to z ilości procesów jakie chcemy obsłużyć .

Przyjrzyjmy się zatem jak będzie wyglądać wynik działania Modulo dla kolejnych wartości zmiennej Tick :

 0 % 4 = 0
 1 % 4 = 1
 2 % 4 = 2
 3 % 4 = 3

Zerknijmy też co się dzieje poza zakresem zmiennej Tick czyli powyżej 3.

4 % 4 = 0
5 % 4 = 1
6 % 4 = 2
7 % 4 = 3

Widzimy że wchodzimy w cykl powtarzających się wyników od 0 do 3, niezależnie od tego jaką liczbę dzielimy za pomocą Modulo.

I ta własność operacji Modulo czyli cykliczność wyniku jest chętnie wykorzystywana w programowaniu do różnych celów. W naszym przypadku do uzyskania quasi wielowątkowości bez wstrzymywania pętli głównej po każdym procesie.

Powyższy przykład jest w pełni zaimplementowany w kodzie (w pliku main.c) dotyczącym czujnika temperatury DS18B20 w artykule : ds18b20 budujemy bibliotekę inną niż wszyscy

Gorąco polecam wykorzystywanie Modulo w kodzie do realizacji pierwszych amatorskich wielowątkowych operacji. To jest taki pierwszy krok w kierunku dalszego rozwoju czyli poznania m.in algorytmu karuzelowego a skończywszy na RTOS-ach. Jeśli ktoś chce sięgać gwiazd to taka droga jest właściwa.


Pozdrawiam
picmajster.blog@gmail.com

3 komentarze:

  1. Przeczytałem kilka razy i już czaję o co chodzi :)
    Poradziłem sobie z EEPROMEM 16k SPI-25AA160C/D Microchipa,za to mam problem z SRAM 64K SPI - 23A640 Microcipa,gdzie podobieństwo w sterowaniu jest praktycznie takie same! masakra :(

    OdpowiedzUsuń
  2. Cieszę się , że wpis był w czymś pomocny. SPI na PIC-ach jeszcze nie przerabiałem więc tutaj szybko nie pomogę ale nie wykluczone , że się za to wezmę za chwilę i za tę konkretnie pamięć jeśli zagadnienie stwarza jakiś problem to tym lepiej będzie większa satysfakcja, muszę tylko je zakupić :) Jeśli chciałbyś w międzyczasie ogarnąć genialne pamięci EERAM Microchipa to szukaj tam niżej wpisy.

    OdpowiedzUsuń
  3. Ok chyba wiem o co i jak.Pojawił mi się ten sam problem przy zabawie z
    ADESTO AT25DF256 - 256-Kbit FLASH ,pomogło czyszczenie stron/bloków :) .Przy eepromach, przed zapisem kostka kasowała bloki/strony za nas.W SRAM i flash widocznie trzeba to robić samemu :).

    OdpowiedzUsuń