[084] Układamy wiedzę - cz. 10
Najmniejszą komórką społeczną świata komputerów jest bit. Zawiera zmienną, która może przyjmować dwa stany: zero i jeden. Być może, żeby nie było mu smutno, można go też obsługiwać na dwa inne sposoby, zadając pytania o stany LOW i HIGH oraz fałsz i prawdę. O tym pisałem w kontekście zmiennych i tę określono jako bool.
W przykładzie z ostatniego artykułu dobieraliśmy się jednak do bitów siedzących w zmiennej byte.
#include // Dołącz bibliotekę sterującą układem MCP23008
Adafruit_MCP23008 ekspander; // Nadaj układowi nazwę "ekspander"
const byte tablica[10] = {
B00111111, // 0, Tablica zawierająca wzorce znaków wyświetlacza siedmiosegmentowego.
B00000110, // 1, połączenia kolejno: P-G-F-E-D-C-B-A
B01011011, // 2
B01001111, // 3
B01100110, // 4
B01101101, // 5
B01111101, // 6
B00000111, // 7
B01111111, // 8
B01101111, // 9
};
byte licznik; // Licznik do wyświetlenia na wyświetlaczu siedmiosegmentowym.
void setup() {
ekspander.begin(36); // Inicjuj bibliotekę sterującą układem MCP23008 pod adresem 0x4
for (byte x = 0; x < 8; x++) { // Zadeklaruj wszystkie porty jako wyjścia.
ekspander.pinMode(x, OUTPUT);
}
}
void loop() {
for (licznik = 0; licznik < 10; licznik++) { // Wyświetlaj kolejno cyfry od 0 do 9
for (byte x = 0; x < 8; x++) // Ustawiaj każdy z ośmiu bitów - segmentów wyświetlacza.
ekspander.digitalWrite(x, bitRead(tablica[licznik], x)); // Pobierz stan owych segmentów z tablicy.
delay(250); // Zaczekaj ćwierć sekundy.
}
}
Ta zawiera osiem takich jednostek – i co bywa przydatne – powstała możliwość manipulacji każdą z nich z osobna. Wówczas wyciągaliśmy bity ze zmiennej pozyskanej z tablicy, a x oznaczał numer bitu – od zerowego do siódmego, jeśli grzebiemy w bajcie. Ale możemy także grzebać w zmiennej int i wówczas zakres adresów powiększa się dwukrotnie.
Skoro można czytać bitRead(), można też zapisywać bitRead() Dokładnie tak samo, z tym że argumenty są trzy: ostatni zawiera wartość do zapisania – zero albo jedynkę. Uproszczoną formą jest bitClear() i bitSet() Pierwszy ma wybranej pozycji wpisuje zero, a drugi jedynkę.
Na koniec cyklu powtórkowego rzućmy okiem na różne elementy, cięższe do jednoznacznego zakwalifikowania. Zrobimy to sprawnie, już nie zagłębiając się w szczegóły, bo wiele tych elementów kiedyś już pojawiło się w moich przykładach. Do czego służy delay() chyba każdy wie. Dodam, że ten element bardzo się przydaje podczas pisania programów, ale dobrze pozbyć się go w gotowej już aplikacji na rzecz przerwań czy timerów. O tym już było i jeszcze będzie.
delayMicroseconds() jest opcją lepszą, choć ideologicznie także blokuje działanie komputerka. Jest dokładny, ale ograniczony do nieco ponad 16 milisekund. Nadaje się dobrze do wyliczania opóźnień niezbędnych w np. automatyce, wówczas gdy ze względu na tak krótki czas zastąpienie go metodami eleganckimi nie przyniesie żadnych zysków, a wręcz zaszkodzi ze względu na opóźnienia i niedokładności.
micros() zwraca stan licznika pracującego bez przerwy w tle. Przyrasta co mikrosekundę i po 70 minutach przewija się. Można go użyć do wyzwalania funkcji praktycznie w pełni losowych, inicjowanych przez człowieka.
milis() natomiast to bliźniak robiący to samo, tylko tysiąc razy rzadziej. Przewija się zatem po 50 dniach.
Do wydawania pisków przydaje się prosta funkcja tone(). Na wybranych pinach pojawia się przebieg o ustalonej częstotliwości i czasie trwania. Zawsze można go przerwać funkcją noTone()
Funkcja pulseIn() jest wielce interesująca, bo mierzy czasy z dokładnością do mikrosekund. Deklarujemy pin, poziom, który ma włączyć stoper i czas, po którym funkcja ma przestać działać, gdyby oczekiwany poziom się nie pojawił. W oparciu o ten element buduje się czujniki odległości, mierniki częstotliwości, powtarzalności i w ogóle mnóstwo automatyki.
To oczywiście nie koniec. Nie napisałem wiele o elementach związanych z transmisją danych, przerwaniami, obsługą peryferiów, operacjach na tekstach, o skrótach i sztuczkach. Na to jednak przyjdzie czas kiedy indziej.