<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Starter Kit</title>
	
	<link>http://starter-kit.nettigo.pl</link>
	<description>Arduino, DIY - przykłady, pomoc, pomysły</description>
	<lastBuildDate>Tue, 15 May 2012 21:44:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/StarterKit" /><feedburner:info uri="starterkit" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Programowanie ATtiny2313 dla opornych</title>
		<link>http://feedproxy.google.com/~r/StarterKit/~3/Ia3K42B6P_Q/</link>
		<comments>http://starter-kit.nettigo.pl/2012/04/programowanie-attiny2313-dla-opornych/#comments</comments>
		<pubDate>Sun, 15 Apr 2012 22:32:56 +0000</pubDate>
		<dc:creator>netmaniac</dc:creator>
				<category><![CDATA[arduino]]></category>
		<category><![CDATA[dla początkujących]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[ATMEL]]></category>
		<category><![CDATA[attiny]]></category>
		<category><![CDATA[attiny2313]]></category>
		<category><![CDATA[AVR]]></category>

		<guid isPermaLink="false">http://starter-kit.nettigo.pl/?p=997</guid>
		<description><![CDATA[Arduino jest fantastyczną platformą dla początkujących. Łatwa w użyciu, prosta w programowaniu. Jednak gdy już nabierzemy pewnej wprawy dostrzegamy projekty w których użycie Arduino wydaje się pewną przesadą (głównie chodzi o finanse, ale czasem również o miejsce). Co zrobić jeżeli potrzebujemy sterować tylko jednym, czasem dwoma wyjściami? Wówczas możemy sięgnąć po mikrokontroler w rodzaju ATtiny2313. [...]]]></description>
			<content:encoded><![CDATA[<p>Arduino jest fantastyczną platformą dla początkujących. Łatwa w użyciu, prosta w programowaniu. Jednak gdy już nabierzemy pewnej wprawy dostrzegamy projekty w których użycie Arduino wydaje się pewną przesadą (głównie chodzi o finanse, ale czasem również o miejsce). Co zrobić jeżeli potrzebujemy sterować tylko jednym, czasem dwoma wyjściami?</p>
<p>Wówczas możemy sięgnąć po mikrokontroler w rodzaju <a href="http://nettigo.pl/products/46" title="ATtiny2313">ATtiny2313</a>. Nie uruchomimy na nim środowiska Arduino. Nie ma bootloadera, do programowania potrzebujemy jakiś programator. Ponadto nie ma biblioteki Arduino, tak więc nie ma wygodnych funkcji jak <code>digitalWrite</code>, <code>analogRead</code> itp. Trzeba się nieco ‘ubrudzić’ pisząc program, ale chyba już czas na to?</p>
<p>Sam doświadczenie poza Arduino posiadam niewielkie, ale właśnie mam okazję by zmierzyć się z małym projektem, w którym chcę użyć ATtiny2313. Ten wpis jest właśnie pokłosiem moich eksperymentów.<br />
<span id="more-997"></span></p>
<p>Pierwsza przeszkoda &#8211; programator. Ponieważ nie ma bootloadera, więc do wgrania naszego programu potrzebujemy programatora tzw <a href="http://en.wikipedia.org/wiki/In-circuit_serial_programming">ICSP</a> (In Circuit  Serial Programming). W świecie układów ATMELa spotkać można programatory o dwóch rodzajach złącz 6-cio lub 10-cio pinowych. Są to gniazda 2 x 3 lub 2 x 5 w odstępach 2.54 mm, więc złącze programatora można zrobić np z goldpina. Ja już od dłuższego czasu korzystam z programatora <a href="http://nettigo.pl/products/114">USBtinyISP</a>, którego trzeba przed pierwszym użyciem zlutować (jest też dostępny <a href="http://nettigo.pl/products/307" title="Programator ICSP">gotowy do pracy programator ICSP typu USBAP</a>), który ma złącza zarówno 6 jak i 10 pinowe.</p>
<div id="attachment_998" class="wp-caption aligncenter" style="width: 285px"><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/04/avr_programmer.jpg"><img class="size-full wp-image-998" title="Złącze ICSP" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/04/avr_programmer.jpg" alt="Złącze ICSP" width="275" height="118" /></a><p class="wp-caption-text">Złącze ICSP</p></div>
<p>Opis wyprowadzeń programatorów. Uwaga! Jest to opis wyprowadzeń widzianych od góry &#8211; od strony kabla. Trzymając wtyczkę programatora i zaglądając w głąb wtyczki należy rysunki odbić w pionie.</p>
<p>USBtinyISP ma zworkę, która gdy założona podaje napięcie zasilające na Vcc (jest to 5V z USB). Można je wykorzystać do zasilania programowanego ATtiny2313, tak więc pozostaje podłączyć sygnały do wyprowadzeń ATtiny2313 korzystając z tej ściągi:</p>
<div id="attachment_999" class="wp-caption aligncenter" style="width: 410px"><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/04/avr_programmer2.jpg"><img class="size-full wp-image-999" title="Jak podłączyć ICSP do ATtiny/ATmega" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/04/avr_programmer2.jpg" alt="Jak podłączyć ICSP do ATtiny/ATmega" width="400" height="230" /></a><p class="wp-caption-text">Jak podłączyć ICSP do ATtiny/ATmega</p></div>
<p>Cały nasz układ, gotowy do programowania wygląda tak:</p>
<div id="attachment_1001" class="wp-caption aligncenter" style="width: 310px"><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/04/sDSC03425.jpg"><img class="size-medium wp-image-1001" title="ATtiny2313 gotowy do programowania" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/04/sDSC03425-300x225.jpg" alt="ATtiny2313 gotowy do programowania" width="300" height="225" /></a><p class="wp-caption-text">ATtiny2313 gotowy do programowania</p></div>
<p>Jak widać, korzystam z małej płytki stykowej (<a title="Mała płytka stykowa" href="http://nettigo.pl/products/7">BB-170</a>), w którą wsadzamy <a title="ATtiny2313" href="http://nettigo.pl/products/46">ATtiny2313</a> (wycięcie na obudowie jest słabo widoczne ale jest w górnej części zdjęcia). Wyjście z 6-cio pinowego złącza <a title="Programator ICSP do samodzielnego montażu" href="http://nettigo.pl/products/114">USBtinyISP</a> jest rozprowadzone przewodami montażowymi (<a title="Przewody montażowe do płytek stykowych" href="http://nettigo.pl/products/13">JW-75</a>). I tak:</p>
<ul>
<li>czarny &#8211; masa</li>
<li>czerwony &#8211; +5V</li>
<li>biały &#8211; SCK</li>
<li>zielony &#8211; MISO</li>
<li>żółty &#8211; MOSI</li>
<li>niebieski &#8211; RESET</li>
</ul>
<p>Czemu nie potrzeba żadnych dodatkowych elementów? Większość mikrokontrolerów AVR ma wbudowany prosty oscylator, który zapewnia zegar niezbędny do pracy. Jest on słabej jakości &#8211; nieprecyzyjny, częstotliwość pływa z czasem i temperaturą otoczenia, ale jeżli nasz projekt nie wymaga specjalnie mierzenia czasu i dokładności w tej mierze &#8211; wewnętrzny oscylator jest <em>good enough</em>.</p>
<p>Częstotliwość tego wewnętrznego zegara to 8 MHz, jednak możliwe jest włączenie dzielnika przez 2, 8 lub 64 uzyskując odpowiednio 4 MHz, 1 MHz lub 128 kHz. Po co zmniejszać prędkość działania? Głównie dla oszczędności prądu &#8211; im niższe taktowanie tym mniej prądu pobiera układ. Jak zmieniać częstotliwość &#8211; o tym następnym razem (dla chcących szukać samemu &#8211; szukajcie informacji o <em>fuse bits</em>).</p>
<p>OK, teraz pozostaje &#8211; co tam wgrać? Zacznijmy od klasycznego blink czyli migania diodą. Ponieważ moim celem było przetestowanie procesu wgrywania &#8211; znalazłem gotowca. Zwłaszcza mam na myśli <code>Makefile</code>. Dzięki temu plikowi wystarczy napisać <code>make</code> w linii poleceń i projekt się skompiluje i wgra na ATtiny2313 (przynajmniej u mnie na Ubuntu &#8211; <code>Makefile</code> wydaje się być użytecznym pod Windowsem, ale nie mogę powiedzieć co dokładnie trzeba zainstalować aby działało).</p>
<p>Nasz cały program wygląda tak:</p>
<pre>#include &lt;avr/interrupt.h&gt;	// Definicje nazw pinow układu

#define F_CPU 1000000UL		// Zapisanie predkosci procesora w Hz dla biblioteki delay.h
#include &lt;util/delay.h&gt;

// Deklaracja funkcji mrugajacej dioda
void blinkEm(uint8_t count);

// Glowna funkcja programu
int main()
{
  DDRD = _BV(PD4); // Ustawienie PORT D 4 (noga 8)jako wyjscie

  while (1) // Petla, ktora nigdy sie nie konczy
  {
    blinkEm(1); // Wywolanie funkcji mrugajacej dioda
  }
}

// Funkcja mrugajaca dioda LED ustalona ilosc razy
void blinkEm(uint8_t count)
{
  // petla ilosci mrugniec
  // dziala az zmienna count osiagnie wartosc 0
  while (count &gt; 0)
  {
    // Wlaczenie diody led
    PORTD = _BV(PD4);
    // oczekiwanie 1 s
    _delay_ms(1000);

    // wylaczenie diody led
    PORTD = ~_BV(PD4);
    _delay_ms(1000);

    // odliczanie ilosci mrugniec
    count--;
  }
}</pre>
<p>Wystarczy podłączyć <a title="Czerwone diody z rezystorami" href="http://nettigo.pl/products/1">diodę z rezystorem</a> do pinu 8, +5V oraz masę i działa:</p>
<p><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/04/sDSC03423.jpg"><img class="aligncenter size-medium wp-image-1000" title="sDSC03423" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/04/sDSC03423-300x225.jpg" alt="" width="300" height="225" /></a></p>
<p>To zdjęcie pokazuje, czemu naprawdę warto zainteresować się tego typu rozwiązaniami &#8211; nic poza ATtiny nie jest nam potrzebne, żadnych dodatkowych elementów niezbędnych do działania (tak długo jak wewnętrzny zegar jest dla nas wystarczająco dobry).</p>
<p>W stosunku do równoważnego szkicu w Arduino IDE widać następujące różnice:</p>
<ul>
<li>nie ma <code>setup</code> i <code>loop</code>. Jest tylko <code>main</code>, które w C jest domyślnie uruchamianą pierwszą funkcją programu. loop jest zastąpione przez pętlę zrobioną za pomocą <code>while (1)</code></li>
<li>definicja funkcji main wygląda tak jak by wyglądała w Arduino IDE. Natomiast <code>blinkEm</code> jest zdefiniowane tak jakby dwa razy. W linii 5 oraz 19. W linii 5 jest tak zwany nagłówek &#8211; określamy nazwę funkcji, jakie argumenty przyjmuje oraz jaką wartość zwraca. Sama funkcja wraz z kodem ją realizującym jest określona w linii 19 i następnych. Po co to? Bo bez nagłówka funkcji kompilator w linii 13 nie mógłby określić czy wywołanie funkcji jest poprawne. Dlatego w C jeżeli chcemy korzystać z funkcji  w programie w miejscu, do którego kompilator dociera zanim znalazł tą funkcję, musimy określić parametry niezbędne dla kompilatora w tym momencie &#8211; czyli właśnie jakie argumenty przyjmuje funkcja i jaką wartość zwraca. W Arduino IDE przed kompilacją naszego szkicu IDE dodaje nagłówki funkcji automatycznie.</li>
<li>Nie mamy do dyspozycji funkcji znanych z biblioteki Arduino &#8211; czyli właśnie <code>analogWrite</code>, <code>digitalRead</code> itp. Dlatego operacje na portach dokonuję się za pomocą magicznych akronimów jak <code>_BV</code>, <code>PD4</code>. O tym co dokładnie znaczą i jak z nich korzystać postaram się napisać następnym razem.</li>
</ul>
<p>Kod jest udostępniony na githubie:</p>
<p><a href="https://github.com/netmaniac/AVRtest">https://github.com/netmaniac/AVRtest</a></p>
<p>Ponieważ planuję na potrzeby następnych przykładów ten kod przerobić i rozbudować, to link do wersji dokładnie z tej której korzystałem w tym przykładzie jest taki:</p>
<p><a href="https://github.com/netmaniac/AVRtest/tree/fb828f9edcccfc5945897b9e546b858af37022fd">https://github.com/netmaniac/AVRtest/tree/fb828f9edcccfc5945897b9e546b858af37022fd</a></p>
<p><strong>LinkLove</strong> &#8211; na podstawie tych materiałów udało mi się ruszyć z programowaniem ATtiny, tam możecie szukać dalszych informacji, jeżeli nie macie cierpliwości aż powstaną następne przykłady :</p>
<p><a href="http://www.evilmadscientist.com/article.php/avrtargetboards">http://www.evilmadscientist.com/article.php/avrtargetboards</a><br />
<a href="http://www.instructables.com/id/Reading-Switches-with-ATtiny2313/step2/Blinkenlights-for-a-Signal/">http://www.instructables.com/id/Reading-Switches-with-ATtiny2313/step2/Blinkenlights-for-a-Signal/</a><br />
<a href="http://www.engbedded.com/fusecalc/">http://www.engbedded.com/fusecalc/</a><br />
<a href="http://www.ladyada.net/learn/avr/programming.html">http://www.ladyada.net/learn/avr/programming.html</a></p>
<p>Udział wzięli:</p>
<ul>
<li><a href="http://nettigo.pl/products/46" title="ATtiny2313">ATtiny2313</a>. Ewentualnie <a href="http://nettigo.pl/products/303" title="ATtiny2313V">2313V</a>, jego brat bliźniak, który może pracować już od napięcia zasilającego 1.8V (vs 2.7 w wersji podstawowej), kosztem maksymalnej częstotliwości pracy 10 MHz</li>
<li><a href="http://nettigo.pl/products/114" title="USBtinyISP">USBtinyISP</a> &#8211; sugeruję użycie <a href="http://nettigo.pl/products/307" title="Programator ICSP">gotowego programatora USBASP</a>, który już jest w ofercie Nettigo</li>
<li><a href="http://nettigo.pl/products/7" title="BB-170">BB-170</a> mała płytka stykowa, niezastąpiona do takich niewielkich, prostych prototypów</li>
<li><a href="http://nettigo.pl/products/13" title="Kable do płytek stykowych">JW-75</a> &#8211; uniwersalne kable do łączenia nie tylko płytek stykowych</li>
<li><a href="http://nettigo.pl/products/1" title="Czerwone diody z rezystorami">Coś do migania</a>, jeżeli jeszcze jakimś cudem nie masz w szufladzie baterii diod LED i rezystorów</li>
</ul>
<p>Ten wpis jest początkiem nieco dłuższej serii (mam nadzieję), w której postaram się przybliżyć nieco to co można zrobić bez Arduino&#8230;</p>
<img src="http://feeds.feedburner.com/~r/StarterKit/~4/Ia3K42B6P_Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://starter-kit.nettigo.pl/2012/04/programowanie-attiny2313-dla-opornych/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		<feedburner:origLink>http://starter-kit.nettigo.pl/2012/04/programowanie-attiny2313-dla-opornych/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=programowanie-attiny2313-dla-opornych</feedburner:origLink></item>
		<item>
		<title>Akcelerometry, żyroskopy i kompasy czyli badanie położenia z Arduino cz. 1</title>
		<link>http://feedproxy.google.com/~r/StarterKit/~3/mQqrz3KjM3A/</link>
		<comments>http://starter-kit.nettigo.pl/2012/02/akcelerometry-zyroskopy-i-kompasy-czyli-badanie-polozenia-z-arduino-cz-1/#comments</comments>
		<pubDate>Mon, 20 Feb 2012 20:35:03 +0000</pubDate>
		<dc:creator>sprae</dc:creator>
				<category><![CDATA[arduino]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[ADXL345]]></category>
		<category><![CDATA[akcelerometr]]></category>
		<category><![CDATA[podstawy]]></category>

		<guid isPermaLink="false">http://starter-kit.nettigo.pl/?p=966</guid>
		<description><![CDATA[Ostatnio bardzo popularne stały się różnego rodzaju czujniki położenia. Jest to spowodowane głównie za sprawą smartfonów w nie wyposażonych, kontrolerów gier (np Wiimote) lub quadkopterów, którym potrzebne są do stabilizacji lotu. W tym wpisie dowiesz się jak można je wykorzystać do własnych celów. Akcelerometr Akcelerometr to czujnik badający przyspieszenie. Przyspieszenie występuje wtedy, kiedy jakaś rzecz [...]]]></description>
			<content:encoded><![CDATA[<p dir="ltr">Ostatnio bardzo popularne stały się różnego rodzaju czujniki położenia. Jest to spowodowane głównie za sprawą smartfonów w nie wyposażonych, kontrolerów gier (np Wiimote) lub quadkopterów, którym potrzebne są do stabilizacji lotu. W tym wpisie dowiesz się jak można je wykorzystać do własnych celów.</p>
<p><span id="more-966"></span></p>
<h3 dir="ltr">Akcelerometr</h3>
<p dir="ltr">Akcelerometr to czujnik badający przyspieszenie. Przyspieszenie występuje wtedy, kiedy jakaś rzecz zmienia prędkość. Opisuje to <a href="http://www.fizykon.org/dynamika/dyn_druga_zasada_dynamiki_opis.htm">druga zasada dynamiki Newtona</a>.</p>
<p dir="ltr">Jeśli jadąc samochodem naciśniesz na “gaz”, to samochód zacznie przyśpieszać, bo silnik zadziałał na niego większą siła przezwyciężając inną siłę &#8211; siłę tarcia, która stara się samochód zatrzymać.</p>
<p dir="ltr">Jeśli puścisz pedał “gazu”, to znowu siła tarcia będzie większa i będzie dążyła do zatrzymania samochodu. Czyli przyspieszenie będzie ujemne.</p>
<p dir="ltr">Jest jeszcze jedna siła. Siła grawitacji, która nie pozwala by samochód odfrunął, bo dociska go do ziemi. Siła grawitacji powoduje, że wszystko spada na ziemie z takim samym przyspieszeniem 9,81 m/s2. Ta siła  oznaczona jest jednostką 1 g (nie mylić z gramem).</p>
<p dir="ltr">Ta jednostka symbolizuje, że coś działa na jakąś rzecz z siłą grawitacji. W samolotach przy wykonywaniu manewrów siły działające na pilota dochodzą do 9 g. Popularnie się wtedy mówi, że jego ciało waży wtedy 9 razy więcej niż na ziemi. Za to na orbicie Ziemi panuje siła 0 g. Dlatego przedmioty mogą tam swobodnie latać.</p>
<p dir="ltr">Akcelerometr mierzy te siły w jednostkach g. Najpopularniejsze dziś akcelerometry 3-osiowe to tak naprawdę 3 akcelerometry w jednym układzie ułożone tak, by mierzyć przyspieszenie w 3 różnych kierunkach. W dół, w bok i do przodu. Kierunki te nazywane są osiami X, Y i Z i tak określają je twórcy urządzeń.</p>
<p dir="ltr">Jeśli zadziałasz na czujnik przyspieszeniem o przeciwnym kierunku niż został skierowany czujnik, to on zwróci nam wartość przyspieszenia jako ujemną.</p>
<h3 dir="ltr">Czujnik przyspieszenia i matematyka</h3>
<p dir="ltr">Jeśli czujnik leży nieruchomo na ziemi, to wskazuje tylko siłę grawitacji skierowaną w dół do środka Ziemi.</p>
<p dir="ltr">W czujnikach 3-osiowych ta właściwość pozwala na określenie kąta pod jakim jest urządzenie względem ziemi. Wystarczy sprawdzić z jaką siłą grawitacja działa na poszczególne czujniki.</p>
<p dir="ltr">Zakładając, że czujnik skierowany w lewo to X, w przód to Y, a w dół to Z, to akcelerometr leżąc płasko na ziemi, powinien zwrócić wartości:</p>
<pre style="display: block;"><code>
X = 0g
Y = 0g
Z = 1g
</code></pre>
<p dir="ltr">Oznacza to, że dół urządzenia skierowany jest do ziemi.</p>
<p dir="ltr">Natomiast jeśli przechylisz urządzenie na lewy bok, to czujniki pokażą:</p>
<pre style="display: block;"><code>
X = 1g
Y = 0g
Z = 0g
</code></pre>
<p dir="ltr">Jak widzisz siła grawitacji przestała działać na czujnik Z i zaczęła działać z pełną siłą na czujnik X.</p>
<p dir="ltr">A co będzie, jeśli przechylisz urządzenie  między ziemią i lewym bokiem (o kąt 45°)?</p>
<pre style="display: block;"><code>
X = 0.7g
Y = 0g
Z = 0.7g
</code></pre>
<p dir="ltr">Okazało się, że grawitacja podzieliła po równo siły na czujnik X i na czujnik Z. Im urządzenie jest skierowane bardziej dołem do ziemi, tym większa jest wartość Z, a mniejsza wartość X. Im urządzenie jest skierowane bardziej lewym bokiem tym większa wartość X, a mniejsza Z.</p>
<p dir="ltr">Jeśli zaczniesz przechylać urządzenie na prawy bok, to czujnik X zacznie zwracać wartości ujemne, bo siła grawitacji będzie działać w jego drugim kierunku. Jeśli położysz urządzenie górą do ziemi to czujnik Z zwróci wartość -1.</p>
<p dir="ltr">Specjalną funkcją trygonometryczną występującą w wielu językach programowania jest “atan2(y, x)”, przetwarzająca te wartości na dokładny kąt przechylenia urządzenia.</p>
<p dir="ltr">Funkcja ta bierze współrzędne punktu x, y i podaje pod jakim kątem jest ten punkt względem środka układu współrzędnych czyli punktu o współrzędnych 0, 0.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/atan2xy.png"><img class="aligncenter size-full wp-image-971" title="atan2xy" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/atan2xy.png" alt="" width="371" height="376" /></a></strong></strong></p>
<p dir="ltr">Jak zapewne wiesz w fizyce wartość siły określa się długością strzałki zwanej “wektorem”. Jej kierunek czyli “zwrot” to kierunek w jakim działa siła.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/1vec.png"><img class="aligncenter size-full wp-image-967" title="1vec" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/1vec.png" alt="" width="371" height="376" /></a></strong></strong></p>
<p dir="ltr">Jeśli na coś działa kilka sił w różnych kierunkach, to od tego odchodzi kilka wektorów w różnych kierunkach o określonej długości.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/2vec.png"><img class="aligncenter size-full wp-image-968" title="2vec" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/2vec.png" alt="" width="371" height="376" /></a></strong></strong></p>
<p dir="ltr">Jednak wynikiem działania tych sił jest wypadkowa siła działająca w jednym kierunku. Siłę tą można wyznaczyć poprzez “złożenie” innych sił, za pomocą linii pomocniczych. Ich przecięcie wyznaczy wypadkową siłę działającą na coś.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/2vec_wyp.png"><img class="aligncenter size-full wp-image-969" title="2vec_wyp" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/2vec_wyp.png" alt="" width="371" height="376" /></a></strong></strong></p>
<p dir="ltr">Możesz to sobie wyobrazić tak, że kwadrat jest samolotem, który leci w kierunku dłuższego wektora i wieje na niego boczny wiatr z kierunku krótszego wektora i go spycha. Czyli tak na serio samolot będzie leciał zgodnie z kierunkiem wektora siły wypadkowej.</p>
<p dir="ltr">Tak samo jest i w akcelerometrze. Jego czujniki zwracają wartości, które można przedstawić jako długości wektorów. Te wektory mają kierunek zgodny z kierunkiem czujników. Siłę wypadkową w przypadku akcelerometru wyznaczać będzie kierunek działania siły grawitacji, czyli kąt urządzenia względem ziemi.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/deggrawi.png"><img class="aligncenter size-full wp-image-972" title="deggrawi" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/deggrawi.png" alt="" width="371" height="376" /></a></strong></strong></p>
<p dir="ltr">To pozwala na proste użycie funkcji “atan2” do ustalenia kierunku siły wypadkowej złożonej z wartości sił poszczególnych czujników.</p>
<p><!--more--></p>
<h3 dir="ltr">Wykorzystanie funkcji atan2</h3>
<p dir="ltr">W jezyku programowania <a href="http://python.org/">Python</a> funkcja <a href="http://docs.python.org/library/math.html#math.atan2">“atan2”</a> znajduje się w module funkcji matematycznych <a href="http://docs.python.org/library/math.html#module-math">“math”</a>. Można ją testować podstawiając pod jej argumenty różne wartości z powyższych przykładów (argument “x” to wartość czujnika “Z”, a argument “y” to wartość czujnika “X”).</p>
<pre style="display: block;"><code>
import math

print "Dol urzadzenia jest skierowany do ziemi"
print math.atan2(0, 1)

print "Lewy bok urzadzenia jest skierowany do ziemi"
print math.atan2(1, 0)

print "Urzadzenie skierowane w polowie miedzy ziemia i lewym bokiem"
print math.atan2(0.5, 0.5)

print "Urzadzenie skierowane jak w ostatnim przykladzie dzialania sil"
print math.atan2(0.66, 0.33)
</code></pre>
<p dir="ltr">Wynik działania programu może niektórym wydawać się dziwny:</p>
<pre style="display: block;"><code> Dol urzadzenia jest skierowany do ziemi
0.0
Lewy bok urzadzenia jest skierowany do ziemi
1.57079632679
Urzadzenie skierowane w polowie miedzy ziemia i lewym bokiem
0.785398163397
Urzadzenie skierowane jak w ostatnim przykladzie dzialania sil
1.10714871779</code></pre>
<p dir="ltr">Nie są to wartości przedstawione w stopniach. Są przedstawione w radianach.</p>
<p dir="ltr">Radian to jednostka kąta (używana w nauce i programowaniu), w której kąt zamiast w stopniach przedstawiany jest w wielokrotności liczby PI. Liczba PI czyli około 3,1415 odpowiada kątowi 180°. Połowa liczby PI czyli 1.57 to połowa kąta 180° czyli 90°. Tak samo jak 2*PI to kąt 2*180° czyli 360°.</p>
<p dir="ltr">Radiany przelicza się bardzo łatwo na stopnie. Służy do tego wzór:</p>
<pre style="display: block;"><code>stopnie = radiany * 180 / PI</code></pre>
<p dir="ltr">Można też użyć specjalnej funkcji języka Python, która przerabia radiany na stopnie. Nosi ona nazwę <a href="http://docs.python.org/library/math.html#math.degrees">“degrees”</a> i jest z modułu “math”.</p>
<pre style="display: block;"><code>import math

print "Dol urzadzenia jest skierowany do ziemi"
print math.degrees(math.atan2(0, 1))

print "Lewy bok urzadzenia jest skierowany do ziemi"
print math.degrees(math.atan2(1, 0))

print "Urzadzenie skierowane w polowie miedzy ziemia i lewym bokiem"
print math.degrees(math.atan2(0.5, 0.5))

print "Urzadzenie skierowane jak w ostatnim przykladzie dzialania sil"
print math.degrees(math.atan2(0.66, 0.33))</code></pre>
<p dir="ltr">Teraz wynik działania programu jest już bardziej zrozumiały i zgadza się z wcześniejszym teoretyzowaniem.</p>
<pre style="display: block;"><code>Dol urzadzenia jest skierowany do ziemi
0.0
Lewy bok urzadzenia jest skierowany do ziemi
90.0
Urzadzenie skierowane w polowie miedzy ziemia i lewym bokiem
45.0
Urzadzenie skierowane jak w ostatnim przykladzie dzialania sil
63.4349488229</code></pre>
<p dir="ltr">Wspomne jeszcze o dwóch rodzajach kątów. Na co dzień przyzwyczajeni jesteśmy przez szkołę, że istnieją kąty od 0 do 360°. Jenak nie jest tak zawsze.  Często też liczy się tak, że kąty na prawo od 0° to 1°, 2°, 3° … 180°, a na lewo to -1°, -2°, -3° &#8230; -179°. Zatem zamiast 181° jest -179°, a zamiast 359° jest -1°.</p>
<p dir="ltr">W Arduino używanie funkcji <a href="http://www.nongnu.org/avr-libc/user-manual/group__avr__math.html#ga054230cd7e4c12958dbfac75ab6886e5">“atan2”</a> jest podobne, z tą różnicą, że nie ma funkcji konwertującej na stopnie, dlatego zastosowałem wzór.</p>
<pre style="display: block;"><span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(9600);

  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(F(<span style="color: #006699;">"Dol urzadzenia jest skierowany do ziemi"</span>));
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(<span style="color: #cc6600;">atan2</span>(0, 1) * 180 / <span style="color: #006699;">PI</span>);

  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(F(<span style="color: #006699;">"Lewy bok urzadzenia jest skierowany do ziemi"</span>));
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(<span style="color: #cc6600;">atan2</span>(1, 0) * 180 / <span style="color: #006699;">PI</span>);

  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(F(<span style="color: #006699;">"Lewy bok urzadzenia jest skierowany do ziemi"</span>));
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(<span style="color: #cc6600;">atan2</span>(0.5, 0.5) * 180 / <span style="color: #006699;">PI</span>);

  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(F(<span style="color: #006699;">"Urzadzenie skierowane jak w ostatnim przykladzie dzialania sil"</span>));
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(<span style="color: #cc6600;">atan2</span>(0.66, 0.33) * 180 / <span style="color: #006699;">PI</span>);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
}</pre>
<h3 dir="ltr">Czujnik przyspieszenia ADXL345</h3>
<p dir="ltr"><a href="http://nettigo.pl/products/tagged/akcelerometr">Wiele płytek z czujnikami w ofercie Nettigo</a> ma w sobie czujnik przyspieszenia <a href="http://www.sparkfun.com/datasheets/Sensors/Accelerometer/ADXL345.pdf">ADXL345</a>. Jest to cyfrowy czujnik przyspieszenia. Pracuje on w standardzie 3,3V. Komunikuje się za pomocą interfejsów TWI (i2c) lub SPI. Czujnik może mierzyć przyspieszenia do +/- 16 g. Przy pełnym zakresie pomiarów rozdzielczość wynosi 13 bitów, a dokładność 0,004 g. Jednak można też zawęzić zakres pomiarowy do +/- 2/4/8/16 g i rozdzielczość do 10 bitów w ten sposób zmniejszając dokładność. Czujnik może mierzyć przyspieszenie z częstotliwością od 6,25 do 3200 razy na sekundę. Urządzenie ma bufor FIFO. Pozwala on na to, żeby procesor nie musiał odczytywać wyników w określonym czasie wyznaczonym przez częstotliwość, tylko odczytał je potem w większej ilości na raz.</p>
<h3 dir="ltr">Podłączenie czujnika ADXL345</h3>
<p dir="ltr">Czujnik występujący na płytkach ma zazwyczaj wyprowadzone piny magistrali i2c i zasilania. Zasilanie wynosi 3,3V i w takim też standardzie działa płytka. Jeśli chcesz podłączyć ja do Arduino musisz zastosować dwukierunkowy konwerter poziomów logicznych opisany w poprzednim wpisie.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/ahrs_connect.png"><img class="aligncenter size-full wp-image-970" title="ahrs_connect" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/ahrs_connect.png" alt="" width="704" height="534" /></a></strong></strong></p>
<p dir="ltr">Wyjście magistrali TWI w nowym <a href="http://arduino.cc/en/Main/ArduinoBoardUno">Arduino UNO R3</a> znajduje się tak jak na rysunku nad pinem AREF.</p>
<p dir="ltr">W <a href="http://arduino.cc/en/uploads/Main/ArduinoUno_r2_front.jpg">starszych płytkach</a> magistrala miała wyprowadzenia w grupie pinów ANALOG IN. Sygnał SDA jest w pinie Analog In 4, a sygnał SCL jest w Analog In 5.</p>
<p dir="ltr">W <a href="http://arduino.cc/en/Main/ArduinoBoardMega2560">Arduino MEGA</a> sygnały TWI są w grupie pinów COMMUNICATION. Sygnał SDA to pin 20, a SCL to pin 21.</p>
<p dir="ltr">Wyjście magistrali TWI (i2c) w standardzie 5V podłączone są do dwukierunkowych wejść <a href="http://nettigo.pl/products/126">konwertera poziomów logicznych</a> za pomocą przewodów pomarańczowego (SDA) i zielonego (SCL).</p>
<p dir="ltr">Do konwertera podłączone jest też zasilanie 5V (czerwony przewód) i 3,3V (niebieski przewód). Masa czyli GND podłączona jest czarnym przewodem.</p>
<p dir="ltr">Dwukierunkowe wyjście magistrali TWI z konwertera w standardzie 3,3V oznaczone jest przewodem fioletowym (SCL) i żółtym (SDA), które wraz z zasilaniem 3,3V (niebieski przewód) i GND (czarny przewód) trafia do czujnika.</p>
<p dir="ltr">Ponieważ jest wiele wersji płytek czujników, musisz sam sprawdzić w jego dokumentacji do jakich pinów trafiają jakie sygnały. W przykładzie wybrałem płytkę najbardziej rozbudowanego <a href="http://nettigo.pl/products/252">czujnika 9dof</a>.</p>
<h3 dir="ltr">Programowanie czujnika ADXL345</h3>
<p dir="ltr">Do sterowania czujnikiem najlepiej użyć wbudowanej w <a href="http://arduino.cc/en/Main/Software">Arduino IDE</a> biblioteki <a href="http://arduino.cc/en/Reference/Wire">“Wire.h”</a>. Zapewnia ona komunikację z urządzeniami magistrali i2c (TWI).</p>
<p dir="ltr">Biblioteka udostępnia obiekt o nazwie “Wire” przez który wywołujemy różne metody obsługujące magistralę. W funkcji “setup” należy najpierw wywołać metodę <a href="http://arduino.cc/en/Reference/WireBegin">“Wire.begin()”</a> przygotowującą bibliotekę do działania.</p>
<pre style="display: block;">#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">begin</span>();
}</pre>
<p dir="ltr">Aby wysłać coś do urządzenia potrzebne są kolejne 3 metody.</p>
<ul>
<li>
<p dir="ltr"><a href="http://arduino.cc/en/Reference/WireBeginTransmission">“Wire.beginTransmission(adres)”</a>, która przygotowuje przesyłanie danych do urządzenia, którego adres (numer identyfikacyjny określający do którego urządzenia wysyła się dane) jest argumentem metody.</p>
</li>
<li>
<p dir="ltr"><a href="http://arduino.cc/en/Reference/WireWrite">“Wire.write(dane)”</a>, która wysyła dane do urządzenia.</p>
</li>
<li>
<p dir="ltr"><a href="http://arduino.cc/en/Reference/WireEndTransmission">“Wire.endTransmission()”</a>, która kończy wysyłanie danych do wybranego urządzenia.</p>
</li>
</ul>
<p dir="ltr">Czujnik ADXL348 ma adres w magistrali TWI o numerze szesnastkowym 0&#215;53. Czujnik ten ma kilkanaście rejestrów. Rejestry to takie sprzętowe zmienne wewnątrz urządzenia, które ustawiają parametry działania urządzenia i przechowują wyniki jego pracy. Aby zapisać coś do rejestru, trzeba wysłać do urządzenia 2 bajty. Pierwszym jest numer rejestru, a kolejnym wartość jaką trzeba zapisać do rejestru.</p>
<p dir="ltr">Ponieważ czujnik wymaga ustawienia kilku rejestrów napisałem specjalną funkcję ustawiającą rejestr.</p>
<pre style="display: block;"><span style="color: #cc6600;">void</span> twiSetRegister(<span style="color: #cc6600;">int</span> address, <span style="color: #cc6600;">byte</span> reg, <span style="color: #cc6600;">byte</span> data)
{
  <span style="color: #7e7e7e;">// przygotowanie transmisji</span>
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">beginTransmission</span>(address);
  <span style="color: #7e7e7e;">// wysylanie numeru rejestru</span>
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">write</span>(reg);
  <span style="color: #7e7e7e;">// wysylanie wartosci do zapisania w rejestrze</span>
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">write</span>(data);
  <span style="color: #7e7e7e;">// koniec transmisji</span>
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">endTransmission</span>();
  <span style="color: #cc6600;">delay</span>(5);
}</pre>
<p dir="ltr">Argumenty tej funkcji to adres urządzenia, numer rejestru i wartość do zapisania w tym rejestrze.</p>
<p dir="ltr">Aby uruchomić czujnik trzeba ustawić 3 rejestry.</p>
<p dir="ltr">Rejestr o numerze 0x2d to jakby włącznik czujnika. Ustala on czy urządzenie ma działać czy być w trybie uśpienia regulując tym samym jego pobór prądu. Bity tego rejestru oznaczają:</p>
<div dir="ltr">
<table>
<colgroup>
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" /></colgroup>
<tbody>
<tr>
<td>
<p dir="ltr">D7</p>
</td>
<td>
<p dir="ltr">D6</p>
</td>
<td>
<p dir="ltr">D5</p>
</td>
<td>
<p dir="ltr">D4</p>
</td>
<td>
<p dir="ltr">D3</p>
</td>
<td>
<p dir="ltr">D2</p>
</td>
<td>
<p dir="ltr">D1</p>
</td>
<td>
<p dir="ltr">D0</p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">Link</p>
</td>
<td>
<p dir="ltr">AUTO_SLEEP</p>
</td>
<td>
<p dir="ltr">Measure</p>
</td>
<td>
<p dir="ltr">Sleep</p>
</td>
<td>
<p dir="ltr">Wakeup1</p>
</td>
<td>
<p dir="ltr">Wakeup0</p>
</td>
</tr>
</tbody>
</table>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p dir="ltr">Bit Link ustawia urządzenie w tryb nieaktywności, i pomiary są robione dopiero kiedy procesor potwierdzi, że chce je otrzymać.</p>
<p dir="ltr">Bit AUTO_SLEEP ustawia czujnik w tryb oszczędzania energii, z którego wychodzi po wykryciu przyspieszenia o jakiejś minimalnej wartości.</p>
<p dir="ltr">Bit Measure włącza tryb normalnej pracy czujnika. Czujnik robi ciągle pomiary i zapisuje ich wyniki w odpowiednich rejestrach.</p>
<p dir="ltr">Bit Sleep przełącza urządzenie w tryb oszczędzania energii</p>
<p dir="ltr">Bity Wakeup regulują czas, co jaki urządzenie w trybie oszczędzania energii ma się budzić i sprawdzać przeciążenie. Od 1 do 8 razy na sekundę.</p>
<p dir="ltr">W programie ustawiam ten rejestr na wartość 0&#215;08 czyli binarnie 00001000. Oznacza to, że włączę tylko bit Measure rejestru. Przestawi to czujnik w tryb ciągłego pomiaru bez żadnego oszczędzania energii.</p>
<p dir="ltr">Rejestr o numerze 0&#215;31 ustala w jakim formacie mają być wyniki pomiarów czujnika.</p>
<div dir="ltr">
<table>
<colgroup>
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" /></colgroup>
<tbody>
<tr>
<td>
<p dir="ltr">D7</p>
</td>
<td>
<p dir="ltr">D6</p>
</td>
<td>
<p dir="ltr">D5</p>
</td>
<td>
<p dir="ltr">D4</p>
</td>
<td>
<p dir="ltr">D3</p>
</td>
<td>
<p dir="ltr">D2</p>
</td>
<td>
<p dir="ltr">D1</p>
</td>
<td>
<p dir="ltr">D0</p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">SELF_TEST</p>
</td>
<td>
<p dir="ltr">SPI</p>
</td>
<td>
<p dir="ltr">INT_INVERT</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">FULL_RES</p>
</td>
<td>
<p dir="ltr">Justify</p>
</td>
<td>
<p dir="ltr">Range1</p>
</td>
<td>
<p dir="ltr">Range0</p>
</td>
</tr>
</tbody>
</table>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p dir="ltr">Bit SELF_TEST służy do testowania czujnika. Po jego włączeniu zamiast normalnych wartości pomiarów zwraca specjalne liczby, których zakres jeśli się zgadza z dokumentacją, to czujnik jest dobry.</p>
<p dir="ltr">Bit SPI służy do ustawiania trybu pracy magistrali SPI. Jeśli jest włączony to magistrala jest 3 przewodowa (sygnał danych jest 2 kierunkowy), jeśli wyłączony to magistrala jest standardowa 4 przewodowa z 2 przewodami przesyłania danych.</p>
<p dir="ltr">Bit INT_INVERT określa czy wyjście przerwania jest aktywne w stanie wysokim (bit włączony) lub aktywne w stanie niskim (bit wyłączony).</p>
<p dir="ltr">Bit FULL_RES włącza tryb pełnej rozdzielczości czujnika (13 bitów), gdzie wynik ma dokładnośc 0,004 g na jednostkę. Wyłączenie bitu skaluje wynik na wartość 10 bitową, której zakres ustala się kolejnymi bitami.</p>
<p dir="ltr">Bit Justify. Wynik pomiaru w zależności bitu FULL_RES jest 10 albo 13 bitowy. Rejestry z wynikiem są 2*8 bitów czyli 16 bitowe. Włączenie tego bitu powoduje, że wynik będzie zapisany od ostatniego bitu rejestru wyniku (binarnie nnnnnnnnnn000000 n-to bity wyniku), a wyłączenie, że od pierwszego (binarnie 000000nnnnnnnnnn).</p>
<p dir="ltr">Bity Range0 i Range1 ustalają zakres pomiarów czujnika od +/-2 do +/-16 g. Zakres ten pozwala określić dokładność w jakiej pracuje czujnik w trybie 10 bitowym. Np. dla zakresu +/-2g dokładność wyjścia 10 bitów (1024 poziomy) będzie wynosiła(od -2 do 2 są 4 jednostki)  4 / 1024 = 0,004 g czyli taka sama jak w trybie “FULL_RES”. Dla kolejnych zakresów dokładność będzie spadała z każdym krokiem o połowę.</p>
<p dir="ltr">W programie ustawiłem ten rejestr na wartość szesnastkową 0&#215;08 czyli binarnie 00001000. Oznacza to włączony tylko bit FULL_RES ustawiający wyjścia na dokładność 0.004g na jednostkę.</p>
<p dir="ltr">Rejestr o numerze 0x2c ustawia częstotliwość z jaką czujnik ma mierzyć przyspieszenie.</p>
<div dir="ltr">
<table>
<colgroup>
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" /></colgroup>
<tbody>
<tr>
<td>
<p dir="ltr">D7</p>
</td>
<td>
<p dir="ltr">D6</p>
</td>
<td>
<p dir="ltr">D5</p>
</td>
<td>
<p dir="ltr">D4</p>
</td>
<td>
<p dir="ltr">D3</p>
</td>
<td>
<p dir="ltr">D2</p>
</td>
<td>
<p dir="ltr">D1</p>
</td>
<td>
<p dir="ltr">D0</p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">LOW_POWER</p>
</td>
<td>
<p dir="ltr">Rate3</p>
</td>
<td>
<p dir="ltr">Rate2</p>
</td>
<td>
<p dir="ltr">Rate1</p>
</td>
<td>
<p dir="ltr">Rate0</p>
</td>
</tr>
</tbody>
</table>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p dir="ltr">Bit LOW_POWER włącza tryb oszczędzania energii (o 30%). W tym trybie pomiar może być wykonywany normalnie, lecz jest bardziej zaszumiony.</p>
<p dir="ltr">Bity Rate3..Rate0 określają cześtotliwość pomiarów (w Hz) z jaką wyniki będą zapisywane do rejestrów.</p>
<div dir="ltr">
<table>
<colgroup>
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" /></colgroup>
<tbody>
<tr>
<td>
<p dir="ltr">Częstotliwość</p>
</td>
<td>
<p dir="ltr">Rate3</p>
</td>
<td>
<p dir="ltr">Rate2</p>
</td>
<td>
<p dir="ltr">Rate1</p>
</td>
<td>
<p dir="ltr">Rate0</p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">3200</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">1600</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">800</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">400</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">9</p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">200</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">100</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">50</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">25</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">12,5</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">6,25</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
</tr>
</tbody>
</table>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p dir="ltr">Rejestr ten ustawiłem na wartość 0&#215;09 czyli binarnie 00001001, co daje częstotliwość pomiarów 50 razy na sekundę.</p>
<p dir="ltr">Rozwinięty program z ustawianiem rejestrów wygląda tak:</p>
<pre style="display: block;">#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #7e7e7e;">// Adres czujnika </span>
#define ADXL_ADDR 0x53

<span style="color: #7e7e7e;">// Funkcja ustawiania rejestru</span>

<span style="color: #cc6600;">void</span> twiSetRegister(<span style="color: #cc6600;">int</span> address, <span style="color: #cc6600;">byte</span> reg, <span style="color: #cc6600;">byte</span> data)
{
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">beginTransmission</span>(address);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">write</span>(reg);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">write</span>(data);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">endTransmission</span>();
  <span style="color: #cc6600;">delay</span>(5);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">begin</span>();

  <span style="color: #7e7e7e;">// Ustawianie rejestrow</span>
  twiSetRegister(ADXL_ADDR, 0x2d, 0x08);
  twiSetRegister(ADXL_ADDR, 0x31, 0x08);
  twiSetRegister(ADXL_ADDR, 0x2c, 0x09);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
}</pre>
<p dir="ltr">Po uruchomieniu programu czujnik powinien działać już prawidłowo jednak do pełni szczęścia zostało&#8230;</p>
<h3 dir="ltr">Odczytywanie danych z czujnika ADXL345</h3>
<p dir="ltr">Wyniki pomiarów czujnika to liczby typu <a href="http://arduino.cc/en/Reference/Int">“int”</a> (16 bitowa wartość ze znakiem [+/-]). Ponieważ rejestry czujnika są 8 bitowe, to wynik przechowywany jest w 2 rejestrach dla każdego kierunku. W pierwszym są bity od 0 do 7 (zwane też LSB), a w drugim od 8 do 15 (zwane też MSB).</p>
<p dir="ltr">Za zamianę 2 zmiennych 8 bitowych na jedną 16 bitową odpowiada funkcja <a href="http://arduino.cc/en/Reference/WordCast">“word(h, l)”</a>. Jej pierwszym argumentem jest zmienna 8 bitowa przechowująca bity od 8 do 15, a drugim zmienna trzymająca bity od 0 do 7. Można ją wykorzystać tak:</p>
<pre style="display: block;"><span style="color: #cc6600;">int</span> wynik = <span style="color: #cc6600;">word</span>(rejestr1, rejestr0);</pre>
<p dir="ltr">Jeśli jest ustawiony bit FULL_RES rejestru 0&#215;31 to jednostka wyniku daje dokładność 0,004 g. Co można łatwo przeliczyć na siłę w jednostkach g.</p>
<pre style="display: block;"><span style="color: #cc6600;">float</span> sila_g = wynik * 0.004;</pre>
<p dir="ltr">Do odebrania danych z rejestrów musisz poznać kolejne 3 metody obiektu “Wire”.</p>
<ul>
<li>
<p dir="ltr"><a href="http://arduino.cc/en/Reference/WireRequestFrom">“Wire.requestFrom(adres, ilosc)”</a> &#8211; przygotowuje magistrale TWI do odbioru danych z urządzenia o adresie podanym w pierwszym argumencie, a ilość danych do odbioru określa się w drugim argumencie.</p>
</li>
<li>
<p dir="ltr"><a href="http://arduino.cc/en/Reference/WireAvailable">“Wire.available()”</a> &#8211; zwraca ilość bajtów oczekujących na odebranie.</p>
</li>
<li>
<p dir="ltr"><a href="http://arduino.cc/en/Reference/WireRead">“Wire.read()”</a> &#8211; zwraca jeden bajt danych odebranych z magistrali TWI.</p>
</li>
</ul>
<p dir="ltr">Przygotowałem funkcję ułatwiającą odczyt kilku rejestrów napisaną na podstawie tych metod.</p>
<pre style="display: block;"><span style="color: #cc6600;">byte</span> twiGetRegisters(<span style="color: #cc6600;">int</span> address, <span style="color: #cc6600;">byte</span> reg, <span style="color: #cc6600;">byte</span> *buffer, <span style="color: #cc6600;">byte</span> length)
{
  <span style="color: #7e7e7e;">// liczinik odebranych danych</span>
  <span style="color: #cc6600;">byte</span> count = 0;

  <span style="color: #7e7e7e;">// wyslanie numeru pierwszego rejestru</span>
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">beginTransmission</span>(address);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">write</span>(reg);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">endTransmission</span>();

  <span style="color: #7e7e7e;">// odbieranie wartosci z rejestrow</span>
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">beginTransmission</span>(address);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">requestFrom</span>(address, (<span style="color: #cc6600;">int</span>) length);
  <span style="color: #cc6600;">while</span> (<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">available</span>())
  {
    buffer[count] = <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">read</span>();
    count++;
  }
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">endTransmission</span>();

  <span style="color: #7e7e7e;">// zwracanie ilosci odebranych danych</span>
  <span style="color: #cc6600;">return</span> count;
}</pre>
<p dir="ltr">Argumenty tej funkcji to adres urządzenia z którego chcesz pobrać dane, numer rejestru od którego chcesz zacząć pobieranie, nazwa tablicy do której mają być zapisane dane i ilość danych do odczytania.</p>
<p dir="ltr">Funkcja zwraca liczbę odczytanych rejestrów.</p>
<p dir="ltr">Rejestry z wynikami zaczynają się od numeru 0&#215;32. Ułożone są parami x0, x1, y0, y1, z0, z1.</p>
<pre style="display: block;">#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #7e7e7e;">// Adres czujnika </span>
#define ADXL_ADDR 0x53

<span style="color: #7e7e7e;">// Funkcja ustawiania rejestru</span>
<span style="color: #cc6600;">void</span> twiSetRegister(<span style="color: #cc6600;">int</span> address, <span style="color: #cc6600;">byte</span> reg, <span style="color: #cc6600;">byte</span> data)
{
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">beginTransmission</span>(address);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">write</span>(reg);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">write</span>(data);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">endTransmission</span>();
  <span style="color: #cc6600;">delay</span>(5);
}

<span style="color: #7e7e7e;">// Funkcja odczytywania rejestrow</span>
<span style="color: #cc6600;">byte</span> twiGetRegisters(<span style="color: #cc6600;">int</span> address, <span style="color: #cc6600;">byte</span> reg, <span style="color: #cc6600;">byte</span> *buffer, <span style="color: #cc6600;">byte</span> length)
{
  <span style="color: #cc6600;">byte</span> count = 0;

  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">beginTransmission</span>(address);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">write</span>(reg);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">endTransmission</span>();

  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">beginTransmission</span>(address);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">requestFrom</span>(address, (<span style="color: #cc6600;">int</span>) length);
  <span style="color: #cc6600;">while</span> (<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">available</span>())
  {
    buffer[count] = <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">read</span>();
    count++;
  }
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">endTransmission</span>();

  <span style="color: #cc6600;">return</span> count;
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">begin</span>();

  <span style="color: #7e7e7e;">// Ustawianie rejestrow</span>
  twiSetRegister(ADXL_ADDR, 0x2d, 0x08);
  twiSetRegister(ADXL_ADDR, 0x31, 0x08);
  twiSetRegister(ADXL_ADDR, 0x2c, 0x09);

  <span style="color: #7e7e7e;">// Ustawienie komunikacji z komputerem</span>
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(57600);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #7e7e7e;">// tablica do zapisywania danych z rejestrow</span>
  <span style="color: #cc6600;">byte</span> buffer[6];
  <span style="color: #7e7e7e;">// odczytywanie 6 rejestrow do tablicy buffer</span>
  <span style="color: #cc6600;">byte</span> readed = twiGetRegisters(ADXL_ADDR, 0x32, buffer, 6);
  <span style="color: #7e7e7e;">// sprawdzenie czy odebrano 6 rejestrow</span>
  <span style="color: #cc6600;">if</span> (readed != 6)
  {
    <span style="color: #7e7e7e;">// jesli nie to wyswietl error</span>
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(F(<span style="color: #006699;">"ERROR"</span>));
  }
  <span style="color: #cc6600;">else</span>
  {
    <span style="color: #7e7e7e;">// jesli tak to wyswietl wartosc pomiaru akcelerometru Z</span>
    <span style="color: #7e7e7e;">//odczytywanie wartosci cyfrowej z akcelerometru</span>
    <span style="color: #cc6600;">int</span> result = <span style="color: #cc6600;">word</span>(buffer[5], buffer[4]);
    <span style="color: #7e7e7e;">// zamiana cyfrwej wartosci na jednostke g</span>
    <span style="color: #cc6600;">float</span> g_force = result * 0.004;
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(g_force);
  }
  <span style="color: #7e7e7e;">// oczekiwianie na kolejny wynik 20 ms czyli 1/50 s</span>
  <span style="color: #7e7e7e;">// dla czujnika ustawionego na 50 pomiarow/s</span>
  <span style="color: #cc6600;">delay</span>(20);
}</pre>
<p dir="ltr">Program odczytuje wartość pomiaru z czujnika przyśpieszenia “Z” i wyświetla w jednostkach g. Jeśli czujnik leżał płasko na ziemi to powinien zwracać wartość około 1.00 g. Wraz z przechylaniem czujnika wartość ta powinna maleć.</p>
<h3 dir="ltr">Odczytywanie przechylenia i pochylenia czujnika</h3>
<p>Na początku wpisu opisałem funkcję <a href="http://www.nongnu.org/avr-libc/user-manual/group__avr__math.html#ga054230cd7e4c12958dbfac75ab6886e5">“atan2(y, x)”</a>. Teraz przyszedł czas na jej wykorzystanie.<br />
Kąt przechylenia (na boki) obliczasz składając wektory czujników “X” i “Z”.</p>
<p>&nbsp;</p>
<pre style="display: block;"><span style="color: #cc6600;">float</span> roll = <span style="color: #cc6600;">atan2</span>(gX, gZ) * 180 / <span style="color: #006699;">PI</span>;</pre>
<p>Kąt pochylenia (do przodu i do tyłu) obliczasz składając wektory czujników “Y” i “Z”.</p>
<p>&nbsp;</p>
<pre style="display: block;"><span style="color: #cc6600;">float</span> pitch = <span style="color: #cc6600;">atan2</span>(gY, gZ) * 180 / <span style="color: #006699;">PI</span>;</pre>
<p>W ten sposób możesz przerobić funkcję “loop” programu do odczytywania kąta położenia urządzenia względem Ziemi.</p>
<p>&nbsp;</p>
<pre style="display: block;"><span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #cc6600;">byte</span> buffer[6];
  <span style="color: #cc6600;">byte</span> readed = twiGetRegisters(ADXL_ADDR, 0x32, buffer, 6);
  <span style="color: #cc6600;">if</span> (readed != 6)
  {
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(F(<span style="color: #006699;">"ERROR"</span>));
  }
  <span style="color: #cc6600;">else</span>
  {
    <span style="color: #7e7e7e;">// odczytanie wartości pomiarów</span>
    <span style="color: #cc6600;">int</span> resultX = <span style="color: #cc6600;">word</span>(buffer[1], buffer[0]);
    <span style="color: #cc6600;">int</span> resultY = <span style="color: #cc6600;">word</span>(buffer[3], buffer[2]);
    <span style="color: #cc6600;">int</span> resultZ = <span style="color: #cc6600;">word</span>(buffer[5], buffer[4]);

    <span style="color: #7e7e7e;">// zamiana na jednostki g</span>
    <span style="color: #cc6600;">float</span> gX = resultX * 0.004;
    <span style="color: #cc6600;">float</span> gY = resultY * 0.004;
    <span style="color: #cc6600;">float</span> gZ = resultZ * 0.004;

    <span style="color: #7e7e7e;">// obliczenie przechylenia</span>
    <span style="color: #cc6600;">float</span> roll = <span style="color: #cc6600;">atan2</span>(gX, gZ) * 180 / <span style="color: #006699;">PI</span>;
    <span style="color: #7e7e7e;">// obliczenie pochylenia</span>
    <span style="color: #cc6600;">float</span> pitch = <span style="color: #cc6600;">atan2</span>(gY, gZ) * 180 / <span style="color: #006699;">PI</span>;

    <span style="color: #7e7e7e;">// wyslanie danych do komputera</span>
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(roll); <span style="color: #7e7e7e;">// przechylenie</span>
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">","</span>);
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(pitch); <span style="color: #7e7e7e;">// pochylenie</span>
  }
  <span style="color: #cc6600;">delay</span>(20);
}</pre>
<p>Program powinien zwracać w “Serial Monitor” (pamiętaj o ustawieniu 57600 bodów) 2 liczby rozdzielone przecinkiem. Pierwsza to kąt przechylenia, a druga to kąt pochylenia.</p>
<h3 dir="ltr">Praktyczne wykorzystanie</h3>
<p dir="ltr">Byś mógł lepiej prześledzić działanie czujnika, napisałem za pomocą języka <a href="http://python.org/">Python</a> i modułów <a href="http://pyserial.sourceforge.net/">“pyserial”</a> i <a href="http://developer.gnome.org/pygtk/stable/">“PyGtk2”</a> program wizualizujący jego działanie. Program składa się z 3 widgetów. Pierwszym jest wyświetlanie przyspieszeń w 3 osiach. Widget jest podobny do tego <a href="http://www.youtube.com/watch?feature=player_detailpage&amp;v=AlLSWVkpxF8#t=83s">wykorzystywanego kiedyś w transmisjach F1</a> pokazujący przeciążenia działające na kierowce.</p>
<p dir="ltr">Drugim widgetem jest znany z samolotów <a href="http://www.youtube.com/watch?v=xTvDP5lT-H4">sztuczny horyzont</a> pokazujący przechylenie i pochylenie samolotu względem ziemi.</p>
<p dir="ltr">Trzecim widgetem jest symulacja znanej u majsterkowiczów poziomnicy, którą się przykłada do różnych konstrukcji, by sprawdzić czy trzymają poziom.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/program.png"><img class="aligncenter size-full wp-image-973" title="program" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/program.png" alt="" width="654" height="682" /></a></strong></strong></p>
<p dir="ltr">Żółty wskaźnik to wektor siły z akcelerometru “X”, czerwony/zielony akcelerometru “Y”, a niebieski “Z”.</p>
<p><iframe width="500" height="369" src="http://www.youtube.com/embed/hWLUFxe3Yj0" frameborder="0" allowfullscreen></iframe></p>
<p dir="ltr">Program wymaga, aby Arduino dostarczyło do komputera odpowiednie dane o siłach przyspieszenia, pochyleniu i przechyleniu w formacie:</p>
<pre style="display: block;"><code>#ACC=fx,fy,fz,roll,pitch\r\n</code></pre>
<p dir="ltr">Dlatego przerobiłem funkcję “loop” z ostatniego przykładu na taką:</p>
<pre style="display: block;"><span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #cc6600;">byte</span> buffer[6];
  <span style="color: #cc6600;">byte</span> readed = twiGetRegisters(ADXL_ADDR, 0x32, buffer, 6);
  <span style="color: #cc6600;">if</span> (readed != 6)
  {
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(F(<span style="color: #006699;">"ERROR"</span>));
  }
  <span style="color: #cc6600;">else</span>
  {
    <span style="color: #cc6600;">int</span> resultX = <span style="color: #cc6600;">word</span>(buffer[1], buffer[0]);
    <span style="color: #cc6600;">int</span> resultY = <span style="color: #cc6600;">word</span>(buffer[3], buffer[2]);
    <span style="color: #cc6600;">int</span> resultZ = <span style="color: #cc6600;">word</span>(buffer[5], buffer[4]);

    <span style="color: #cc6600;">float</span> gX = resultX * 0.004;
    <span style="color: #cc6600;">float</span> gY = resultY * 0.004;
    <span style="color: #cc6600;">float</span> gZ = resultZ * 0.004;

    <span style="color: #cc6600;">float</span> roll = <span style="color: #cc6600;">atan2</span>(gX, gZ) * 180 / <span style="color: #006699;">PI</span>;
    <span style="color: #cc6600;">float</span> pitch = <span style="color: #cc6600;">atan2</span>(gY, gZ) * 180 / <span style="color: #006699;">PI</span>;

    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(F(<span style="color: #006699;">"#ACC="</span>));
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(gX);
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">","</span>);
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(gY);
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">","</span>);
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(gZ);
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">","</span>);
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(roll);
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">","</span>);
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(pitch);
  }
  <span style="color: #cc6600;">delay</span>(20);
}</pre>
<p dir="ltr">Program w Pythonie do uruchomienia wymaga tylko jednej drobnej zmiany. Ustalenia w zmiennej “ACC_PORT” na początku pliku, nazwy portu szeregowego do którego podłączyłeś Arduino.</p>
<pre style="display: block;"><code>ACC_PORT = 'com4:'</code></pre>
<h3 dir="ltr">Kalibracja akcelerometru</h3>
<p dir="ltr">Świat nie jest idealny. Montując czujnik w urządzeniu nie masz gwarancji, że umieścisz go tam idealnie prosto, lub wymaga to zbyt wiele wysiłku. Kładąc potem urządzenie na wypoziomowanym podłożu może się okazać, że czujnik wskazuje jakiś kąt przechylenia/pochylenia. Taka sytuacja wymaga kalibracji czujnika.</p>
<p dir="ltr">Korekcja polega na dodaniu lub odjęciu jakiejś wartości od wyników czujnika tak, żeby podawał wartości jakich oczekujesz.</p>
<p dir="ltr">Do korekcji osi czujników służą specjalne rejestry o numerach 0x1e, 0x1f, 0&#215;20 odpowiadające osiom “X”, “Y”, “Z&#8221;. Pozwalają one dodać lub odjąć jakąś wartość do rejestrów wynikowych czujnika. Maksymalną korekcję jaką można dokonać to +/- 2g. Rejestry przyjmują wartości 8 bitowe ze znakiem, czyli typ <a href="http://arduino.cc/en/Reference/Char">“char”</a> (przechowujący liczby od -128 do 127). Minimalna jednostka z jaką można przesunąć wartość wyniku to:</p>
<pre style="display: block;"><code>2.0 / 128 = 0.015625 g</code></pre>
<p dir="ltr">Jeśli moje urządzenie leżąc płasko na ziemi ma wyniki X:0,05g, Y:-0,11g, Z:1,0g, to oprócz “Z”, które jest prawidłowo, trzeba przesunąć inne o odwrotną wartość, czyli:</p>
<pre style="display: block;"><code> X: -0,05 / 0,015625 = -3 Y: 0,11 / 0,015625 = 7 </code></pre>
<p dir="ltr">Zatem do rejestru 0x1e trzeba wpisać liczbę -3, do 0x1f trzeba wpisać 7, a do 0&#215;20 trzeba wpisać 0.</p>
<pre style="display: block;"><span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(57600);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">begin</span>();
  twiSetRegister(ADXL_ADDR, 0x2d, 0x08);
  twiSetRegister(ADXL_ADDR, 0x31, 0x08);
  twiSetRegister(ADXL_ADDR, 0x2c, 0x09);

  <span style="color: #7e7e7e;">// kalibracja</span>
  twiSetRegister(ADXL_ADDR, 0x1e, (<span style="color: #cc6600;">char</span>) -3);
  twiSetRegister(ADXL_ADDR, 0x1f, (<span style="color: #cc6600;">char</span>) 7);
  twiSetRegister(ADXL_ADDR, 0x20, (<span style="color: #cc6600;">char</span>) 0);
}</pre>
<p dir="ltr">Typ “(char)” w nawiasie określa jakiego typu mają być liczby przekazywane w argumencie.</p>
<p dir="ltr">Innym rodzajem kalibracji jest określenie, czy każdy czujnik po skierowaniu w kierunki grawitacji i w przeciwnym ma takie same wielkości wartości (czyli 1.0g i -1.0g). Jeśli się różnią to trzeba je odpowiednio przeskalować.</p>
<p dir="ltr">Zakładając, że przy dokładności 0.004 g, wartość cyfrowa czujnika czyli zmiennej “resultX” dla 1g wynosi 1 / 0.004 = 250</p>
<p dir="ltr">Jeśli czujnik “X” skierowany w kierunku grawitacji zwracałby wartość cyfrową 256, a w przeciwnym -270, to należałoby go skalibrować za pomocą takiego algorytmu:</p>
<pre style="display: block;"><span style="color: #cc6600;">if</span> (resultX &gt;= 0)
{
  resultX = <span style="color: #cc6600;">map</span>(resultX, 0, 256, 0, 250);
}

<span style="color: #cc6600;">else</span>
{
  resultX = <span style="color: #cc6600;">map</span>(resultX, -270, 0, -250, 0);
}</pre>
<p dir="ltr">Wykorzystałem tu funkcje skalującą “map” z biblioteki Arduino. Funkcja ta przetwarza zakres wartości jakimi dysponujesz (argumenty 0, 256), na wartości jakich oczekujesz (argumenty 0, 250). Dzięki temu jeśli czujnik skierowany w kierunku grawitacji zwróci 256, to funkcja “map” przerobi tą wartość na 250 czyli 1g.</p>
<h3 dir="ltr">Niedoskonałości czujnika przyspieszenia</h3>
<p><iframe width="500" height="369" src="http://www.youtube.com/embed/KOeiVcd1YCE" frameborder="0" allowfullscreen></iframe></p>
<p>Czujnik przyspieszenia nie jest idealnym rozwiązaniem do badania położenia. O tym samym przekonani się producenci telefonów i konsol. Wystarczy, że nim potrząśniesz (czyli dodasz kilka wektorów przyspieszenia), a już gubi kierunek grawitacji. Można próbować to eliminować różnymi filtrami i algorytmami, ale one tylko spowalniają pomiar, a tym samym szybkość reakcji urządzenia na zmianę położenia.</p>
<p dir="ltr">Inną niedogodnością jest to, że sam czujnik przyspieszenia wykrywa tylko przechylenie i pochylenie (pitch i roll), ale nie wykrywa odchylenia (yaw) czyli kierunku wg stron świata.</p>
<p dir="ltr">Te niedogodności rozwiązują inne czujniki (znajdujące się zwykle na płytkach z akcelerometrem), które opiszę w kolejnych odcinkach.</p>
<h3 dir="ltr">Linki</h3>
<ul>
<li><a href="http://static.nettigo.pl/code/adxl345.zip" title="Przykładowy program pokazany we wpisie">Przykładowy program w Pythonie</a></li>
<li><a href="http://nettigo.pl/products/category/7">Wszystkie czujniki w sklepie Nettigo</a>, w tym <a href="http://nettigo.pl/products/tagged/akcelerometr" title="Akcelerometry">wszystkie akcelerometry</a> oraz dokładnie <a href="http://nettigo.pl/products/tagged/ADXL+345" title="ADXL 345">ADXL 345</a></li>
<li><a href="http://www.sparkfun.com/datasheets/Sensors/Accelerometer/ADXL345.pdf">Dokumentacja czujnika ADXL345</a></li>
</ul>
<img src="http://feeds.feedburner.com/~r/StarterKit/~4/mQqrz3KjM3A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://starter-kit.nettigo.pl/2012/02/akcelerometry-zyroskopy-i-kompasy-czyli-badanie-polozenia-z-arduino-cz-1/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		<feedburner:origLink>http://starter-kit.nettigo.pl/2012/02/akcelerometry-zyroskopy-i-kompasy-czyli-badanie-polozenia-z-arduino-cz-1/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=akcelerometry-zyroskopy-i-kompasy-czyli-badanie-polozenia-z-arduino-cz-1</feedburner:origLink></item>
		<item>
		<title>USB Host Shield od SparkFun i biblioteka od CircuitsAtHome</title>
		<link>http://feedproxy.google.com/~r/StarterKit/~3/TL4LWKvry_k/</link>
		<comments>http://starter-kit.nettigo.pl/2012/02/usb-host-shield-od-sparkfun-i-biblioteka-od-circuitsathome/#comments</comments>
		<pubDate>Mon, 13 Feb 2012 17:21:40 +0000</pubDate>
		<dc:creator>netmaniac</dc:creator>
				<category><![CDATA[arduino]]></category>
		<category><![CDATA[usb]]></category>
		<category><![CDATA[usb-host-shield]]></category>

		<guid isPermaLink="false">http://starter-kit.nettigo.pl/?p=960</guid>
		<description><![CDATA[W ofercie Nettigo już od dłuższego czasu znajduje się USB Host Shield. Shield ten pozwala zamienić Arduino w USB hosta. Normalnie Arduino jest urządzeniem USB &#8211; czyli da się podłączyć do hosta (np komputer) ale do niego nie można podłączyć innego urządzenia USB. Począwszy od UNO można wgrać nowy firmware zmieniający obsługę USB, ale to [...]]]></description>
			<content:encoded><![CDATA[<p>W ofercie Nettigo już od dłuższego czasu znajduje się <a href="http://nettigo.pl/products/194?utm_source=StarterKit&#038;utm_medium=article" title="USB Host Shield dla Arduino">USB Host Shield</a>. Shield ten pozwala zamienić Arduino w USB hosta. Normalnie Arduino jest urządzeniem USB &#8211; czyli da się podłączyć do hosta (np komputer) ale do niego nie można podłączyć innego urządzenia USB. Począwszy od UNO można wgrać nowy firmware zmieniający obsługę USB, ale to co można osiągnąć to zmiana rodzaju urządzenia, którym jest Arduino po podłączeniu do hosta (czyli nie jako port szeregowy ale np klawiatura).</p>
<p>Aby móc obsłużyć inne urządzenia USB niezbędny jest właśnie USB Host Shield. Shield ten jest produkowany przez SparkFun na podstawie projektu wykonanego przez CircuitsAtHome. Autor shielda utrzymuje też <a href="https://github.com/felis/USB_Host_Shield_2.0">bibliotekę</a> go obsługującego. Sęk w tym, że ta wersja bibliotki jest przeznaczona dla nieco zmodyfikowanej płytki sprzedawanej przez CircuitsAtHome. Wersja SparkFun (i sprzedawana przez Nettigo) wymaga drobnej modyfikacji aby działało oprogramowanie:</p>
<div id="attachment_961" class="wp-caption aligncenter" style="width: 310px"><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/usb-host-shield.jpg"><img src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/02/usb-host-shield-300x225.jpg" alt="USB Host shield działający z wersją biblioteki 2.0" title="USB Host shield działający z wersją biblioteki 2.0" width="300" height="225" class="size-medium wp-image-961" /></a><p class="wp-caption-text">USB Host shield działający z wersją biblioteki 2.0</p></div>
<p>Wystarczy połączyć cyfrowe wyjście D7 z RST (obok zasilania 3.3V) i od tego momentu test płytki (<code>board_qc</code> w <code>Examples</code>) działa poprawnie:<br />
<span id="more-960"></span></p>
<pre>
Circuits At Home 2011
USB Host Shield Quality Control Routine
Reading REVISION register... Die revision 03
SPI long test. Transfers 1MB of data. Each dot is 64K................
SPI long test passed
GPIO test. Connect GPIN0 to GPOUT7, GPIN1 to GPOUT6, and so on
Test failed. Value written: 00 Value read: FF
Press any key to continue...
GPIO test passed.
PLL test. 100 chip resets will be performed
Resetting oscillator Reset number 0 Time to stabilize - 445 cycles Reset
number 1 Time to stabilize - 446 cycles Reset number 2 Time to stabilize
- 446 cycles Reset number 3 Time to stabilize - 446 cycles Reset number
4 Time to stabilize - 446 cycles Reset number 5 Time to stabilize - 456
cycles Reset number 6 Time to stabilize - 476 cycles Reset number 7 Time
to stabilize - 476 cycles Reset number 8 Time to stabilize - 477 cycles
Reset number 9 Time to stabilize - 476 cycles Reset number 10 Time to
stabilize - 476 cycles Reset number 11 Time to stabilize - 476 cycles
Reset number 12 Time to stabilize - 476 cycles Reset number 13 Time to
stabilize - 477 cycles Reset number 14 Time to stabilize - 476 cycles
Reset number 15 Time to stabilize - 477 cycles Reset number 16 Time to
stabilize - 476 cycles Reset number 17 Time to stabilize - 477 cycles
Reset number 18 Time to stabilize - 476 cycles Reset number 19 Time to
stabilize - 477 cycles Reset number 20 Time to stabilize - 476 cycles
Reset number 21 Time to stabilize - 476 cycles Reset number 22 Time to
stabilize - 476 cycles Reset number 23 Time to stabilize - 476 cycles
Reset number 24 Time to stabilize - 477 cycles Reset number 25 Time to
stabilize - 476 cycles Reset number 26 Time to stabilize - 477 cycles
Reset number 27 Time to stabilize - 476 cycles Reset number 28 Time to
stabilize - 477 cycles Reset number 29 Time to stabilize - 476 cycles
Reset number 30 Time to stabilize - 478 cycles Reset number 31 Time to
stabilize - 476 cycles Reset number 32 Time to stabilize - 476 cycles
Reset number 33 Time to stabilize - 476 cycles Reset number 34 Time to
stabilize - 476 cycles Reset number 35 Time to stabilize - 478 cycles
Reset number 36 Time to stabilize - 476 cycles Reset number 37 Time to
stabilize - 477 cycles Reset number 38 Time to stabilize - 476 cycles
Reset number 39 Time to stabilize - 477 cycles Reset number 40 Time to
stabilize - 476 cycles Reset number 41 Time to stabilize - 478 cycles
Reset number 42 Time to stabilize - 476 cycles Reset number 43 Time to
stabilize - 476 cycles Reset number 44 Time to stabilize - 476 cycles
Reset number 45 Time to stabilize - 476 cycles Reset number 46 Time to
stabilize - 477 cycles Reset number 47 Time to stabilize - 476 cycles
Reset number 48 Time to stabilize - 478 cycles Reset number 49 Time to
stabilize - 476 cycles Reset number 50 Time to stabilize - 477 cycles
Reset number 51 Time to stabilize - 476 cycles Reset number 52 Time to
stabilize - 478 cycles Reset number 53 Time to stabilize - 476 cycles
Reset number 54 Time to stabilize - 476 cycles Reset number 55 Time to
stabilize - 476 cycles Reset number 56 Time to stabilize - 476 cycles
Reset number 57 Time to stabilize - 478 cycles Reset number 58 Time to
stabilize - 476 cycles Reset number 59 Time to stabilize - 477 cycles
Reset number 60 Time to stabilize - 476 cycles Reset number 61 Time to
stabilize - 477 cycles Reset number 62 Time to stabilize - 476 cycles
Reset number 63 Time to stabilize - 477 cycles Reset number 64 Time to
stabilize - 476 cycles Reset number 65 Time to stabilize - 477 cycles
Reset number 66 Time to stabilize - 477 cycles Reset number 67 Time to
stabilize - 476 cycles Reset number 68 Time to stabilize - 478 cycles
Reset number 69 Time to stabilize - 476 cycles Reset number 70 Time to
stabilize - 477 cycles Reset number 71 Time to stabilize - 476 cycles
Reset number 72 Time to stabilize - 477 cycles Reset number 73 Time to
stabilize - 476 cycles Reset number 74 Time to stabilize - 477 cycles
Reset number 75 Time to stabilize - 476 cycles Reset number 76 Time to
stabilize - 476 cycles Reset number 77 Time to stabilize - 476 cycles
Reset number 78 Time to stabilize - 476 cycles Reset number 79 Time to
stabilize - 477 cycles Reset number 80 Time to stabilize - 476 cycles
Reset number 81 Time to stabilize - 477 cycles Reset number 82 Time to
stabilize - 476 cycles Reset number 83 Time to stabilize - 477 cycles
Reset number 84 Time to stabilize - 476 cycles Reset number 85 Time to
stabilize - 477 cycles Reset number 86 Time to stabilize - 476 cycles
Reset number 87 Time to stabilize - 476 cycles Reset number 88 Time to
stabilize - 476 cycles Reset number 89 Time to stabilize - 476 cycles
Reset number 90 Time to stabilize - 477 cycles Reset number 91 Time to
stabilize - 476 cycles Reset number 92 Time to stabilize - 477 cycles
Reset number 93 Time to stabilize - 476 cycles Reset number 94 Time to
stabilize - 477 cycles Reset number 95 Time to stabilize - 476 cycles
Reset number 96 Time to stabilize - 476 cycles Reset number 97 Time to
stabilize - 476 cycles Reset number 98 Time to stabilize - 476 cycles
Reset number 99 Time to stabilize - 476 cycles Reset number 100 Time to
stabilize - 476 cycles
Checking USB device communication.

Device connected. Resetting Reset complete. Waiting for the first SOF...
Getting device descriptor
Descriptor Length:	12
Descriptor type:	01
USB version:		0110
Device class:		00
Device Subclass:	00
Device Protocol:	00
Max.packet size:	40
Vendor  ID:		055F
Product ID:		021D
Revision ID:		0100
Mfg.string index:	00
Prod.string index:	01
Serial number index:	00
Number of conf.:	01

All tests passed. Press RESET to restart test
</pre>
<p>GPIO na shieldzie są nie podłączone więc test ma prawo się nie udać. Do portu USB na shieldzie podłączyłem skaner Musteka (vendorID 055F).</p>
<img src="http://feeds.feedburner.com/~r/StarterKit/~4/TL4LWKvry_k" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://starter-kit.nettigo.pl/2012/02/usb-host-shield-od-sparkfun-i-biblioteka-od-circuitsathome/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://starter-kit.nettigo.pl/2012/02/usb-host-shield-od-sparkfun-i-biblioteka-od-circuitsathome/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=usb-host-shield-od-sparkfun-i-biblioteka-od-circuitsathome</feedburner:origLink></item>
		<item>
		<title>Komunikacja układów 3,3V i 5V</title>
		<link>http://feedproxy.google.com/~r/StarterKit/~3/9ejnRU_Swvs/</link>
		<comments>http://starter-kit.nettigo.pl/2012/01/komunikacja-ukladow-3-3v-i-5v/#comments</comments>
		<pubDate>Mon, 30 Jan 2012 12:05:22 +0000</pubDate>
		<dc:creator>sprae</dc:creator>
				<category><![CDATA[arduino]]></category>
		<category><![CDATA[dla początkujących]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[podstawy]]></category>

		<guid isPermaLink="false">http://starter-kit.nettigo.pl/?p=941</guid>
		<description><![CDATA[Wstęp Podczas rozwoju podzespołów elektronicznych, wraz z ich przyśpieszaniem i zmniejszaniem poboru energii, zmieniały się też standardy w jakich te układy pracowały. Obecnie w elektronice amatorskiej (także w Arduino) panuje standard 5V. Oznacza to, że zasilanie układów scalonych i ich stany logiczne odnoszą się właśnie do tego napięcia. Wiadomo, że stan niski “LOW” to GND, [...]]]></description>
			<content:encoded><![CDATA[<div>
<h3 dir="ltr">Wstęp</h3>
<p dir="ltr">Podczas rozwoju podzespołów elektronicznych, wraz z ich przyśpieszaniem i zmniejszaniem poboru energii, zmieniały się też standardy w jakich te układy pracowały. Obecnie w elektronice amatorskiej (także w Arduino) panuje standard 5V. Oznacza to, że zasilanie układów scalonych i ich stany logiczne odnoszą się właśnie do tego napięcia. Wiadomo, że stan niski “LOW” to GND, a stan wyoki “HIGH” to napięcie w okolicach 5V.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Coraz częściej spotyka się układy scalone pracujące w standardzie 3,3V. Oznacza to, że ich zasilanie i stany logiczne nie pasują do obecnych rozwiązań. W tym wpisie dowiesz się jak sprawić, by urządzenia obydwu standardów mogły się ze sobą łączyć i komunikować.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">W Arduino w grupie pinów “POWER” jest wyjście napięcia 3,3V. W nowszych wersjach Arduino grupy R3 pojawił się tam dodatkowy pin o nazwie “IOREF”. Jest na nim napięcie w jakim pracuje dana płytka Arduino. To taki wybieg jego projektantów dla przyszłych wersji płytek, które mogą pracować już w standardzie 3,3V. Ten pin pozwoli dopasowywać komunikację układów podczas okresu przejściowego.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Opisywane wcześniej układy PCF8574 i TLC5940 potrafią pracować w obydwu standardach. Jeśli zasilisz je napięciem 5V, to pracują w standardzie 5V. Jeśli zasilisz napięciem 3,3V, to będą pracować w standardzie 3,3V.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Są też jeszcze inne układy przejściowe, które mają opcję “5V Compilant”. Są zasilane napięciem 3,3V, jednak jeśli podłączysz do nich sygnały logiczne standardu 5V, to będą działały bez przeszkód. Przykładem takiego układu jest opisany niżej bufor 74AHC125.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Coraz częsciej spotykane są układy używające tylko standardu 3,3V. Podłączenie do nich innych stanów logicznych lub zasilania może spowodować ich uszkodzenie. Aby komunikowały się ze starszym standardem potrzebne są układy dopasowujące, które tu opiszę.</p>
<p><span id="more-941"></span></p>
<h3 dir="ltr">Zasilanie układów 3,3V</h3>
<p dir="ltr">Pin 3V3 w Arduino ma ograniczoną wydajność do 40 mA. Często zdarza się, że zasilane tym napięciem układy pobierają znacznie więcej prądu.</p>
<p dir="ltr">Jeśli tak jest i w twoim przypadku, należy zbudować sobie odpowiedni układ zasilający.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/power_bb.png"><img class="aligncenter size-full wp-image-948" title="power_bb" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/power_bb.png" alt="" width="464" height="233" /></a><br />
</strong></strong></p>
<p dir="ltr">Układ jest dość prosty. Składa się ze stabilizatora liniowego (o oznaczeniu MCP1700-3302E/TO) i dwóch kondensatorów ceramicznych 1µF. Stabilizator to rodzaj układu scalonego, który mimo różnych napięc na wejściu, zawsze ma cały czas takie samo napięcie na wyjściu. Ten typ stabilizatora wytrzymuje prąd do 250 mA. Jest on w obudowie typu TO-92 znanej z różnego rodzaju tranzystorów. Układ ma trzy wyprowadzenia. Patrząc od jego ściętej strony od lewej  - pierwsze to GND, kolejne to wejście napięcia (do 6V), a ostatnie to wyjście stabilizowanego napięcia 3,3V. Do wejścia i wyjścia należy podłączyć kondensatory jak na rysunku.</p>
<p dir="ltr">Układ można zasilić napięciem z pinu 5V Arduino.</p>
<p dir="ltr">Układ pochodzi z modułu Adafruit XBee Adapter v1.1 i został w nim sprawdzony.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Są też inne stabilizatory wytrzymujące prąd o natężeniu do 3A. Podłączenie ich jest podobne do tego na rysunku, jednak zawsze należy się tego upewnić zaglądając do ich noty katalogowej.</p>
<h3 dir="ltr">Podłączenie wyjścia układu 5V do wejścia układu 3,3V</h3>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/5to3div_bb.png"><img class="aligncenter size-full wp-image-943" title="5to3div_bb" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/5to3div_bb.png" alt="" width="587" height="646" /></a><br />
</strong></strong></p>
<p dir="ltr">Schemat przedstawia połączenie Arduino pracującego w standardzie 5V z modułem typu XBee, pracującym w standardzie 3,3V. Sygnał wyjścia szeregowego Arduino ma trafić do wejścia szeregowego XBee i być przystosowany do jego napięcia pracy.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Wyjście pinu arduino podłączone jest do 2 rezystorów połączonych szeregowo. Wyjście drugiego rezystora podłączone jest do GND. Połączenie między rezystorami trafia do wejścia XBee.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/5to3div_schem.png"><img class="aligncenter size-full wp-image-944" title="5to3div_schem" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/5to3div_schem.png" alt="" width="457" height="372" /></a></strong></strong></p>
<p>&nbsp;</p>
<p dir="ltr">Tak połączone rezystory tworzą tzw. dzielnik napięcia, pozwalający zmniejszyć napięcie. Napięcie wyjściowe ustala się ze wzoru:</p>
<p><strong><strong><br />
</strong></strong></p>
<pre dir="ltr">Uwy = Uwe * R2 / (R1 + R2)</pre>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">W tym układzie są 2 rezystory o takim samym oporze 10 kΩ. Daje to dzielnik napięcia przez 2.</p>
<p><strong><strong><br />
</strong></strong></p>
<pre dir="ltr">Uwy = 5V * 10 kΩ / (10 kΩ + 10 kΩ) = 5V * 10 / 20 = 5V * 1 / 2 = 2,5 V</pre>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Co sprawia, że stan wysoki wychodzący z pinu 1 Arduino zostanie zmniejszony do 2,5V i trafi do XBee.</p>
<p dir="ltr">Ponieważ napięcie 2,5V jest mniejsze niż 3,3V to nie zepsuje XBee. Takie napięcie mieści się też na granicy zakresu tolerancji stanu wysokiego układów na 3,3V. Układ pochodzi z modułu Arduino XBee Shield v1.1 i działa w nim poprawnie.`</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/74ahct125_bb.png"><img class="aligncenter size-full wp-image-945" title="74ahct125_bb" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/74ahct125_bb.png" alt="" width="464" height="427" /></a><br />
</strong></strong></p>
<p dir="ltr">Innym sposobem dopasowania wyjścia 5V do wejścia 3,3V jest zastosowanie różnego rodzaju dopasowujących układów scalonych (buforów). Jednym z nich jest układ 74AHC125, posiadający 4 takie bufory.</p>
<p dir="ltr">Układ zasilany jest napięciem od 2 do 5V. Od napięcia zasilania zależy to w jakim standardzie będą działały wyjścia. W tym przypadku zasiliłem układ napięciem 3,3V (czerwony przewód).</p>
<p dir="ltr">Układ posiada 4 bufory. Wejścia buforów (oznaczone kolorem niebieskim) tolerują napięcie do 5V. Wyjścia (oznaczone kolorem żółtym) mają w stanie wysokim w tym przypadku napięcie do 3,3V. Każde wejście bufora jest powiązane z wyjściem i oznaczone na rysunku cyfrą.</p>
<p dir="ltr">Układ pochodzi z modułu Adafruit XBee Adapter v1.1 i działał w nim poprawnie.</p>
<h3 dir="ltr">Podłączenie wyjścia układu 3,3V do wejścia układu 5V</h3>
<p dir="ltr">Tutaj sprawa jest ułatwiona. Wyjścia standardu 3,3V można łączyć bezpośrednio do wejść standardu 5V. Tolerancja wejść tego standardu pokrywa się z zakresem napięć wyjścia 3,3V.</p>
<h3 dir="ltr">Połączenie dwukierunkowe standarów 5V i 3,3V</h3>
<p dir="ltr">Sygnały magistrali I2C (TWI) mogą być przesyłane w obydwu kierunkach. To utrudnia sprawę z dopasowaniem sygnału dla obydwu standardów i wymaga trudniejszego schematu.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/2way.png"><img class="aligncenter size-full wp-image-942" title="2way" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/2way.png" alt="" width="352" height="254" /></a><br />
</strong></strong></p>
<p dir="ltr">Układ składa się z tranzystora MOSFET typu N z wbudowaną diodą o oznaczeniu BSS138 i 2 rezystorów 10 kΩ.</p>
<p dir="ltr">LV to wejście zasilania 3,3V, a HV to wejście zasilania 5V. TX_LV to miejsce podpięcia sygnału w standardzie 3,3V, natomiast TX_HV to miejsce podłączenia sygnału w standardzie 5V.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Wysyłając sygnały, urządzenia magistrali TWI ustawiają się albo w stan niski, albo nieustalony. Zapobiega to przeciążeniu układu w przypadku gdyby 2 urządzenia na raz zaczęły nadawać różne sygnały (jeden HIGH drugi LOW). Dlatego magistrala we własnym zakresie musi zapewnić rezystory podciągające PullUp zapewniające na niej bezpieczny stan wysoki jako domyślny. Układ na schemacie zapewnia takie rezystory dla każdej ze stron standardu oznaczone jako R3 i R4.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Tranzystor MOSFET (Q1) składa się z trzech wyprowadzeń. Bramka (Gate) to wyprowadzenie podłączone do zasilania LV (3,3V). Źródło (Source) to wyprowadzenie podłączone do wyjścia TX_LV. Ostatnie wyprowadzenie o nazwie dren podłączono do wyjścia TX_HV. Tranzystor jest rodzajem przełącznika, który przewodzi prąd między drenem i źródłem w zależności od napięcia jakie znajduje się między bramką i źródłem. Jeśli to napięcie nie różni się to tranzystor nie przewodzi. Jeśli się różni o jakąś minimalną wartość, to zaczyna przewodzić.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">W przypadku, gdy żaden z układów magistrali nie ustawił jej w stan niski, napięcie na źródle i drenie nie różni się i dla obydwu wynosi 3,3V.</p>
<p dir="ltr">Gdy układ po stronie standardu 3,3V ustawi magistralę w stan niski, wtedy na źródle pojawi się stan LOW czyli GND czyli 0V, a na bramce pozostanie dalej napięcie 3,3V. W ten sposób powstanie różnica napięć i tranzystor zacznie przewodzić prąd. Czyli ustawi stan niski LOW po stronie standardu 5V.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Po stronie standardu 5V, gdy panuje stan wysoki HIGH, dioda nie przewodzi prądu i po stronie standardu 3,3V napięcie stanu wysokiego ustala rezystor PullUp R3. Gdy po stronie 5V urządzenie ustawi magistralę w stan niski, wtedy dioda zacznie przewodzić stan niski, który jest taki sam dla obydwu standardów.</p>
<h3 dir="ltr">Moduł konwersji stanów logicznych z Nettigo</h3>
<p dir="ltr"><a title="Konwerter poziomów logicznych" href="http://nettigo.pl/products/126">Sklep Nettigo oferuje gotową płytkę</a>, która zawiera 2 kanały dwukierunkowej konwersji standardów 3,3V i 5V, oraz dwa kanały konwersji standardów opartych na dzielnikach napięcia.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/conv_bb.png"><img class="aligncenter size-full wp-image-946" title="conv_bb" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/conv_bb.png" alt="" width="313" height="281" /></a><br />
</strong></strong></p>
<ul>
<li>
<p dir="ltr">HV &#8211; zasilanie 5V</p>
</li>
<li>
<p dir="ltr">LV &#8211; zasilanie 3,3V</p>
</li>
<li>
<p dir="ltr">GND &#8211; masa GND</p>
</li>
<li>
<p dir="ltr">TXO &#8211; strona standardu 5V dla dwukierunkowego połączenia</p>
</li>
<li>
<p dir="ltr">TXI &#8211; strona standardu 3,3V dla dwukierunkowego połączenia</p>
</li>
<li>
<p dir="ltr">RXI &#8211; wejście standardu 5V do dzielnika napięcia</p>
</li>
<li>
<p dir="ltr">RXO &#8211; wyjście standardu 3,3V z dzielnika</p>
</li>
</ul>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/i2cconv_bb.png"><img class="aligncenter size-full wp-image-947" title="i2cconv_bb" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/i2cconv_bb.png" alt="" width="511" height="735" /></a><br />
</strong></strong></p>
<p dir="ltr">Przykład pokazuje jak wykorzystać moduł do konwersji standardu TWI w Arduino UNO R3. Wykorzystuje on 2 konwertery dwukierunkowe modułu.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/xbee2_bb.png"><img class="aligncenter size-full wp-image-949" title="xbee2_bb" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/xbee2_bb.png" alt="" width="475" height="779" /></a><br />
</strong></strong></p>
<p dir="ltr">Ten przykład jest kopią układu z początku artykułu. Pokazuje sposób podłączenie wyjścia szeregowego Arduino w standardzie 5V do wejścia szeregowego modułu typu XBee w standardzie 3,3V. Przykład wykorzystuje dzielnik napięcia kanału 1.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Oczywiście można wykorzystywać na raz dzielniki i 2 kanałowe połączenia.</p>
<h3 dir="ltr">Zakończenie</h3>
<p>Na koniec wypada mi jeszcze wspomnieć o tym, że są też inne rodzaje Arduino, które pracują z różnymi standardami stanów logicznych. Arduino LilyPad można zasilać napięciami od 2,7 do 5 V. Zatem jego standard pracy zależy od tego jakim napięciem go zasilisz. Arduino Fio i Pro Mini (model 3,3V)  pracują już tylko w standardzie 3,3V.<br />
Wpis ten jest wstępem do kolejnych, w których opiszę serię urządzeń pracujących tylko w standardzie 3,3V. Jakie to urządzenia? Przekonasz się o tym już za jakiś czas.<strong><strong><br />
</strong></strong></p>
<h3 dir="ltr">Linki</h3>
<ul>
<li><a href="http://nettigo.pl/products/126">Moduł konwersji stanów logicznych z Nettigo</a></li>
<li><a href="http://pdf1.alldatasheet.com/datasheet-pdf/view/115220/MICROCHIP/MCP1700.html">Nota katalogowa stabilizatorów MCP1700</a></li>
<li><a href="http://www.ti.com/lit/ds/symlink/sn74ahc125.pdf">Nota katalogowa układu 74AHC125</a></li>
<li><a href="http://pl.wikipedia.org/wiki/Dzielnik_napi%C4%99cia">Dzielnik napięcia na Wikipedii</a></li>
</ul>
</div>
<p>&nbsp;</p>
<img src="http://feeds.feedburner.com/~r/StarterKit/~4/9ejnRU_Swvs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://starter-kit.nettigo.pl/2012/01/komunikacja-ukladow-3-3v-i-5v/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://starter-kit.nettigo.pl/2012/01/komunikacja-ukladow-3-3v-i-5v/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=komunikacja-ukladow-3-3v-i-5v</feedburner:origLink></item>
		<item>
		<title>TLC5940 czyli co najmniej 16 dodatkowych pinów PWM w Arduino</title>
		<link>http://feedproxy.google.com/~r/StarterKit/~3/V_09LcZYoN4/</link>
		<comments>http://starter-kit.nettigo.pl/2012/01/tlc5940-czyli-co-najmniej-16-dodatkowych-pinow-pwm-w-arduino/#comments</comments>
		<pubDate>Wed, 04 Jan 2012 09:14:13 +0000</pubDate>
		<dc:creator>sprae</dc:creator>
				<category><![CDATA[arduino]]></category>
		<category><![CDATA[dla początkujących]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[led]]></category>
		<category><![CDATA[pwm]]></category>
		<category><![CDATA[tlc5940]]></category>

		<guid isPermaLink="false">http://starter-kit.nettigo.pl/?p=907</guid>
		<description><![CDATA[TLC5940 to układ scalony zawierający 16 wyjść PWM. Generator PWM układu ma rozdzielczość 12 bitów czyli 4096 stopni wypełnienia. Jedną z głównych zalet tego chipu jest możliwość podłączenia do jego wyjść bezpośrednio diod LED (bez rezystorów). Jego wyjścia mogą wytrzymać do 120 mA obciążenia. Wyprowadzenia układu TLC5940 OUT0..OUT15 &#8211; 16 wyjść PWM generatorów układu. Wyjścia [...]]]></description>
			<content:encoded><![CDATA[<div>
<h1 dir="ltr"></h1>
<p style="text-align: left;" dir="ltr"><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/intro.jpg"><img class="aligncenter size-full wp-image-909" title="intro" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/intro.jpg" alt="" width="500" height="375" /></a></p>
<p dir="ltr"><a title="TLC5940NT na Nettigo" href="http://nettigo.pl/products/50">TLC5940</a> to układ scalony zawierający 16 wyjść PWM. Generator PWM układu ma rozdzielczość 12 bitów czyli 4096 stopni wypełnienia. Jedną z głównych zalet tego chipu jest możliwość podłączenia do jego wyjść bezpośrednio diod LED (bez rezystorów). Jego wyjścia mogą wytrzymać do 120 mA obciążenia.</p>
<h3 dir="ltr">Wyprowadzenia układu TLC5940</h3>
<p><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/tlc5940.png"><img class="aligncenter size-full wp-image-914" title="tlc5940" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/tlc5940.png" alt="" width="500" height="826" /></a></p>
<p><span id="more-907"></span></p>
<p dir="ltr"><strong>OUT0..OUT15</strong> &#8211; 16 wyjść PWM generatorów układu. Wyjścia są typu “otwarty kolektor” czyli przewodzą albo stan niski, albo stan nieustalony. Wyjścia można obciążać maksymalnie od 5 do 120 mA. Prąd wyjść reguluje się za pomocą wyprowadzenia IREF i/lub specjalnych rejestrów “DC” układu.</p>
<p dir="ltr"><strong>VPRG</strong> &#8211; Wejście trybu programowania układu &#8211; podłączasz do GND w Arduino.<br />
Stan niski to programowanie rejestrów wypełnienia PWM (GS), stan wysoki to programowanie rejestrów korekcji prądu wyjść (DC).</p>
<p dir="ltr"><strong>SIN</strong> &#8211; Wejście szeregowe  - podłączasz do pinu cyfrowego 11 w Arduino UNO</p>
<p dir="ltr"><strong>SCLK</strong> &#8211; Wejście szeregowe zegara zatwierdzającego bity danych &#8211; podłączasz do pinu cyfrowego 13 w Arduino UNO</p>
<p dir="ltr"><strong>XLAT</strong> &#8211; Wejście zatwierdzające wysłane dane &#8211; podłączasz do pinu cyfrowego 9 w Arduino UNO</p>
<p dir="ltr"><strong>BLANK</strong> &#8211; Wejście wyłączania wyjść i resetowania liczników generatora PWM &#8211; podłączasz do pinu cyfrowego 10 w Arduino UNO</p>
<p dir="ltr"><strong>GND</strong> &#8211; Wejście zasilania masa &#8211; podłączasz do GND w Arduino</p>
<p dir="ltr"><strong>VCC</strong> &#8211; Wejście zasilania +5 V &#8211; podłączasz do pinu zasilania 5V w Arduino</p>
<p dir="ltr"><strong>IREF</strong> &#8211; Wejście ustalania prądu na wyjściach OUT. Do wejścia podłączasz rezystor o oporze dostosowanym do prądu wyjścia, gdzie druga noga rezystora jest podłączona do GND.</p>
<p dir="ltr">Prąd wyjścia oblicza się ze wzoru:</p>
<pre dir="ltr">Imax = (Vref / Rref) * 31,5 = (1.24 / Rref) * 31,5</pre>
<p dir="ltr">Rref = Wartość oporu rezystora podłączonego między IREF i GND.</p>
<p dir="ltr">Przyjmując, że diody LED wymagają prądu 20 mA, to rezystor powinien mieć wartość 2 KOhm.</p>
<p dir="ltr"><strong>DCPRG</strong> &#8211; Wejście wybierania danych dokładnej regulacji prądu wyjścia &#8211; podłączasz do +5V</p>
<p dir="ltr"><strong>GSCLK</strong> &#8211; Wejście zegara, którego impulsy powodują zliczanie przez liczniki generatorów PWM układu &#8211; podłączasz do pinu cyfrowego 3 w Arduino UNO</p>
<p dir="ltr"><strong>SOUT</strong> &#8211; Szeregowe wyjście danych z układu. W konfiguracji wielu układów złączonych szeregowo to wyjście jest podłączone do SIN następnego układu.</p>
<p dir="ltr"><strong>XERR  </strong>- Wyjście błędów układu. Jeśli układ się przegrzeje, lub jakaś dioda LED podłączona do wyjść generatora PWM się przepali, na wyjściu pojawią się impulsy stanu niskiego. Wyjście jest typu “otwarty dren”, co powoduje, że ma albo stan niski, albo nieustalony.</p>
<h3 dir="ltr">Podłączenie układu TLC5940 do Arduino</h3>
<p><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/tlc5940_arduino.png"><img class="aligncenter size-full wp-image-915" title="tlc5940_arduino" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/tlc5940_arduino.png" alt="" width="565" height="565" /></a></p>
<p dir="ltr">Schemat przedstawia sposób podłączenia układu do Arduino. Połączenie zabiera 5 cyfrowych pinów Arduino. Do wyjść od OUT0 do OUT15 można podłączyć bezpośrednio diody LED, katodą do OUT, anodą do 5V (pod warunkiem zastosowania odpowiedniego rezystora IREF). W przykładzie podłączyłem diodę LED do wyjścia OUT1.</p>
<div dir="ltr">
<table>
<colgroup>
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" /></colgroup>
<tbody>
<tr>
<td>
<p style="text-align: center;" dir="ltr"><strong>Noga TLC5940</strong></p>
</td>
<td style="text-align: center;">
<p dir="ltr"><strong>Pin Arduino</strong></p>
</td>
<td style="text-align: center;">
<p dir="ltr"><strong>Nazwa sygnału</strong></p>
</td>
<td>
<p style="text-align: center;" dir="ltr"><strong>Checklista</strong></p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">27</p>
</td>
<td>
<p dir="ltr">GND</p>
</td>
<td>
<p dir="ltr">VPRG</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">26</p>
</td>
<td>
<p dir="ltr">Digital 11</p>
</td>
<td>
<p dir="ltr">SIN</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">25</p>
</td>
<td>
<p dir="ltr">Digital 13</p>
</td>
<td>
<p dir="ltr">SCLK</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">24</p>
</td>
<td>
<p dir="ltr">Digital 9</p>
</td>
<td>
<p dir="ltr">XLAT</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">23</p>
</td>
<td>
<p dir="ltr">Digital 10</p>
</td>
<td>
<p dir="ltr">BLANK</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">22</p>
</td>
<td>
<p dir="ltr">GND</p>
</td>
<td>
<p dir="ltr">GND</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">21</p>
</td>
<td>
<p dir="ltr">5V</p>
</td>
<td>
<p dir="ltr">VCC</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">20</p>
</td>
<td>
<p dir="ltr">&#8211;Rezystor&#8211;GND</p>
</td>
<td>
<p dir="ltr">IREF</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">19</p>
</td>
<td>
<p dir="ltr">5V</p>
</td>
<td>
<p dir="ltr">DCPRG</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">18</p>
</td>
<td>
<p dir="ltr">Digital 3</p>
</td>
<td>
<p dir="ltr">GSCLK</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">17</p>
</td>
<td>
<p dir="ltr">do drugiego TLC5940</p>
</td>
<td>
<p dir="ltr">SOUT</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">16</p>
</td>
<td></td>
<td>
<p dir="ltr">XERR</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
</tbody>
</table>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3 dir="ltr">Podłączenie do Arduino MEGA</h3>
<p><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/tlc5940mega_bb.png"><img class="aligncenter size-full wp-image-917" title="tlc5940mega_bb" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/tlc5940mega_bb.png" alt="" width="526" height="691" /></a></p>
<p dir="ltr">Ponieważ Arduino MEGA ma wyjście SPI w nieco innym miejscu, podłączenie do niego TLC5940 wymaga innego schematu elektrycznego.</p>
<div dir="ltr">
<table>
<colgroup>
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" /></colgroup>
<tbody>
<tr>
<td>
<p style="text-align: center;" dir="ltr"><strong>Noga TLC5940</strong></p>
</td>
<td style="text-align: center;">
<p dir="ltr"><strong>Pin Arduino MEGA</strong></p>
</td>
<td style="text-align: center;">
<p dir="ltr"><strong>Nazwa sygnału</strong></p>
</td>
<td>
<p style="text-align: center;" dir="ltr"><strong>Checklista</strong></p>
</td>
</tr>
<tr>
<td>
<p dir="ltr">27</p>
</td>
<td>
<p dir="ltr">GND</p>
</td>
<td>
<p dir="ltr">VPRG</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">26</p>
</td>
<td>
<p dir="ltr">Digital 51</p>
</td>
<td>
<p dir="ltr">SIN</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">25</p>
</td>
<td>
<p dir="ltr">Digital 52</p>
</td>
<td>
<p dir="ltr">SCLK</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">24</p>
</td>
<td>
<p dir="ltr">Digital 11</p>
</td>
<td>
<p dir="ltr">XLAT</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">23</p>
</td>
<td>
<p dir="ltr">Digital 12</p>
</td>
<td>
<p dir="ltr">BLANK</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">22</p>
</td>
<td>
<p dir="ltr">GND</p>
</td>
<td>
<p dir="ltr">GND</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">21</p>
</td>
<td>
<p dir="ltr">5V</p>
</td>
<td>
<p dir="ltr">VCC</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">20</p>
</td>
<td>
<p dir="ltr">&#8211;Rezystor&#8211;GND</p>
</td>
<td>
<p dir="ltr">IREF</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">19</p>
</td>
<td>
<p dir="ltr">5V</p>
</td>
<td>
<p dir="ltr">DCPRG</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">18</p>
</td>
<td>
<p dir="ltr">Digital 9</p>
</td>
<td>
<p dir="ltr">GSCLK</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">17</p>
</td>
<td>
<p dir="ltr">do drugiego TLC5940</p>
</td>
<td>
<p dir="ltr">SOUT</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
<tr>
<td>
<p dir="ltr">16</p>
</td>
<td></td>
<td>
<p dir="ltr">XERR</p>
</td>
<td>
<input type="checkbox" /></td>
</tr>
</tbody>
</table>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3 dir="ltr">Programowanie układu TLC5940</h3>
<p>&nbsp;</p>
<pre>#include &lt;Tlc5940.h&gt;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  Tlc.init();

  Tlc.set(1, 2048);

  <span style="color: #cc6600;">while</span> (Tlc.update());
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
}</pre>
<pre></pre>
<p>&nbsp;</p>
<p dir="ltr">Społeczność Arduino napisała również dla układu TLC5940 odpowiednią bibliotekę. Przykład zapala diodę LED podłączoną do wyjścia OUT1 na połowę jasności.</p>
<p>&nbsp;</p>
<p dir="ltr">Programowanie układu rozpoczyna się od załadowania odpowiedniej biblioteki poprzez “#include &lt;Tlc5940.h&gt;”. Następnie w funkcji “setup” biblioteka musi zostać zainicjowana za pomocą metody “Tlc.init();”. Metodę “Tlc.update()” umieściłem w pętli “while”. Metoda ta odpowiada za wysłanie danych do do układu i zaktualizowanie jego rejestrów. Trzeba wywoływać ja tak długo aż zwróci wartość 0. Jeśli nie jest to krytyczne, możesz umieścić też tą metodę w funkcji “loop”.</p>
<p>&nbsp;</p>
<p dir="ltr">Za ustawianie poszczególnych wyjść PWM układu TLC5940 odpowiada metoda “Tlc.set”. Jej pierwszym parametrem jest numer wyjścia od 0 do 15, a drugim wartość wypełnienia generatora PWM od 0 do 4095.</p>
<p>&nbsp;</p>
<p dir="ltr">Bibioteka wykorzystuje do swojej pracy układy Timer1 i Timer2 oraz SPI kontrolera Arduino, dlatego warto uważać, czy nie koliduje to z inną biblioteką w twoim projekcie.</p>
<p>&nbsp;</p>
<p dir="ltr">Metody obiektu Tlc:</p>
<ul>
<li><strong>Tlc.init()</strong> Uaktywnia działanie biblioteki i inicjuje komunikacje z układem TLC5940. Ma opcjonalny argument, który jest liczbą od 0 do 4095. Argument ustawia początkową wartość wypełnienia na wszystkich wyjściach układu. Wywołanie metody bez argumentu sprawia, że wyjścia ustawiają się na 0.</li>
<li><strong>Tlc.clear()</strong> Ustawia wszystkie wyjścia na wartość 0.</li>
<li>
<p dir="ltr"><strong>Tlc.setAll(value)</strong> Ustawia wszystkie wyjścia na wartość wypełnienia podaną w argumencie (od 0 do 4095).</p>
<p>&nbsp;</li>
<li><strong>Tlc.set(out, value)</strong> Ustawia wyjście określone w argumencie “out” (od 0 do 15) na wartość określoną w argumencie “value” (od 0 do 4095).</li>
<li><strong>Tlc.get(out)</strong> Zwraca wartość wypełnienia dla wyjścia podanego w argumencie “out” (od 0 do 15).</li>
<li><strong>Tlc.update()</strong> Wysyła dane do układu. Zwraca 0 jeśli dane zostaną zatwierdzone lub 1 jeśli jeszcze nie.</li>
</ul>
<p>&nbsp;</p>
<h3 dir="ltr">Wskaźnik diodowy</h3>
<pre>#include &lt;Tlc5940.h&gt;

<span style="color: #cc6600;">void</span> tlc_progress(<span style="color: #cc6600;">word</span> value, <span style="color: #cc6600;">word</span> prefix)
{
  <span style="color: #cc6600;">byte</span> out_num = value / 4096;
  <span style="color: #cc6600;">word</span> out_brg = value % 4096;

  <span style="color: #cc6600;">for</span> (<span style="color: #cc6600;">byte</span> out=0; out&lt;16; out++)
  {
    <span style="color: #cc6600;">if</span> (out &lt; out_num)
    {
      Tlc.set(out, prefix);
    }

    <span style="color: #cc6600;">else</span> <span style="color: #cc6600;">if</span> (out == out_num)
    {
      Tlc.set(out, out_brg);
    }

    <span style="color: #cc6600;">else</span>
    {
      Tlc.set(out, 0);
    }
  }
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  Tlc.init();
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #cc6600;">int</span> value = <span style="color: #cc6600;">analogRead</span>(0);
  value = <span style="color: #cc6600;">map</span>(value, 0, 1023, 0, 65535);
  tlc_progress(value, 4095);
  Tlc.update();
}</pre>
<p dir="ltr">Jako temat przykładu użycia biblioteki wykorzystałem pomysł na wskaźnik typu “linijka diodowa”. Zakłada on podłączenie do wszystkich pinów OUT układu TLC5940 diod LED. Działanie wskaźnika można opisać w ten sposób, że im program dostanie większe napięcie na pin Arduino Analog 0 tym więcej diod na kolejnych wyjściach się będzie świeciło. Przy napięciu 5V świecą się wszystkie diody. Dodatkową zaletą wykorzystania PWM jest to, że ostatnia zapalona dioda wskaźnika zapala się stopniowo wraz ze wzrostem napięcia na wejściu.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Najważniejszą funkcją programu jest “tlc_progress”. Steruje ona zapalaniem diod podłączonych do układu. Jej pierwszy arguement to wartość od 0 do 65535. Im większa liczba tym kolejne diody wskaźnika się płynnie zapalają. Kolejnym argumentem funkcji jest argument jasności świecenia lampek poprzedzających ostatnią zapaloną. Jeśli ustawisz mu wartość 0, to będzie paliła się na raz tylko jedna dioda &#8211; imitując wskazówkę.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/single_low.jpg"><img class="alignnone size-full wp-image-913" title="single_low" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/single_low.jpg" alt="" width="250" height="188" /></a><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/single_hi.jpg"><img class="alignnone size-full wp-image-912" title="single_hi" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/single_hi.jpg" alt="" width="250" height="188" /></a></strong></strong></p>
<p>&nbsp;</p>
<p dir="ltr">Jeśli wstawisz tam wartość maksymalną, czyli 4095, to będą zapalały się kolejne diody aż do maksymalnej jasności.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/multi_lo.jpg"><img class="alignnone size-full wp-image-911" title="multi_lo" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/multi_lo.jpg" alt="" width="250" height="188" /></a><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/multi_hi.jpg"><img class="alignnone size-full wp-image-910" title="multi_hi" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/multi_hi.jpg" alt="" width="250" height="188" /></a></strong></strong></p>
<p>&nbsp;</p>
<p dir="ltr">W funkcji “loop” program odczytuje wartość z pinu Analog 0. Ponieważ funkcja “analogRead” odczytuje wartości z zakresu od 0 do 1023, to trzeba je przeskalować za pomocą funkcji “map” na wartości zakresu funkcji “tlc_progress”, czyli od 0 do 65535.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Wskaźnik diodowy ma zastosowanie tam, gdzie nie liczy się zbytnia dokładność, ale ważne jest szybkie zorientowanie się co do poziomu jakiegoś sygnału. Program możesz łatwo przerobić na fajny “analogowy” termometr, obrotomierz lub wskaźnik poziomu głośności w zestawie audio.</p>
<p><iframe src="http://www.youtube.com/embed/1BIZE6g9o_I" frameborder="0" width="500" height="369"></iframe></p>
<p dir="ltr">W nagraniu do wejścia analogowego 0 podłączyłem potencjometr.</p>
<h3 dir="ltr">Inne przykłady z biblioteki układu</h3>
<p dir="ltr">Oprócz podstawowego nagłówka “Tlc5940.h”, biblioteka posiada jeszcze kilka ciekawych nagłówków z dodatkowymi funkcjami pomagającymi szybko rozwiązać pewne pomysły.</p>
<h4 dir="ltr">Fades</h4>
<p dir="ltr">Pierwszym z nich jest “tlc_fades.h”, ułatwiający tworzenie płynnie zapalających się i gasnących efektów świetlnych.</p>
<pre>#include &lt;Tlc5940.h&gt;
#include &lt;tlc_fades.h&gt;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  Tlc.init();

  tlc_addFade(1, 0, 4095, 5000, 10000);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  tlc_updateFades();
}</pre>
<p dir="ltr">Użycie biblioteki rozpoczynasz od dodania nagłówka “#include &lt;tlc_fades.h&gt;”. Potem należy normalnie zainicjować układ w funkcji “setup”. W funkcji “loop” powinna być funkcja “tlc_updateFades();” odpowiedzialna za synchronizowanie działania całej biblioteki.</p>
<p dir="ltr">Za przygotowanie zapalania/gaśnięcia odpowiada funkcja “tlc_addFade”. Jej pierwszym argumentem jest numer wyjścia układu TLC5940 na którym ma się odbyć animacja. Kolejnym jest wartość początkowa jasności animacji (od 0 do 4095). Trzecim argumentem jest wartość końcowa jasności animacji o parametrach jak poprzednia.</p>
<p dir="ltr">Dwa ostatnie argumenty to czas w milisekundach liczony od chwili włączenia Arduino. Przedostatni mówi o tym w jakiej milisekundzie ma się rozpocząć animacja, a kolejny w jakiej ma się skończyć.</p>
<p dir="ltr">Funkcja w przykładzie tworzy animacje zapalenia się diody na wyjściu “OUT1” od wartości 0 do wartości 4095. Rozświetlenie ma się odbyć w czasie od 5 do 10 sekundy od chwili włączenia Arduino.</p>
<p dir="ltr">Można wykonać do 24 animacji na raz (wywołań funkcji “tlc_addFade”). Potem trzeba poczekać, aż któraś animacja się skończy. Pomocną przy tym funkcją jest “tlc_isFading”. Jej argumentem jest numer wyjścia, a zwraca 1 jeśli na danym wyjściu jest przewidziana jakaś animacja lub 0 jeśli nie jest.</p>
<p dir="ltr">Jest jeszcze funkcja “tlc_removeFades”. Jej argumentem jest numer wyjścia. Usuwa ona wszystkie animacje dla danego wyjścia.</p>
<pre>#include &lt;Tlc5940.h&gt;
#include &lt;tlc_fades.h&gt;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  Tlc.init();
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #cc6600;">if</span> (!tlc_isFading(1))
  {
    <span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">long</span> time = <span style="color: #cc6600;">millis</span>();
    tlc_addFade(1, 0, 4095, time+1000, time+1250);
    tlc_addFade(1, 4095, 0, time+1500, time+2000);
  }
  tlc_updateFades();
}</pre>
<p dir="ltr">W tym przykładzie zrealizowałem animację mrugania diody LED na wyjściu OUT1. Warunek “if” sprawdza czy jest tam aktualnie animacja i jeśli nie ma to tworzy kolejną.</p>
<p dir="ltr">Animacja powstaje tak, że pobierany jest aktualny czas do zmiennej “time”. Sekundę po tym czasie rozpoczyna się rozświetlanie trwające 250 ms. Po 1.5 s zaczyna się gaśnięcie trwające 500 ms. Daje to ładny efekt płynnego mrugania.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Funkcja “tlc_updateFades” ma opcjonalny argument, którym są aktualne milisekundy. Jeśli nie odpowiada ci w animacji czas od chwili włączenia Arduino, możesz w argumencie dostarczyć swoją aktualną wartość czasu wyrażoną w milisekundach.</p>
<p><iframe src="http://www.youtube.com/embed/w1929ihNjKQ" frameborder="0" width="500" height="339"></iframe></p>
<h4 dir="ltr">Shifts</h4>
<p dir="ltr">Biblioteka “tlc_shifts.h” odpowiada za efekt przesuwania wartości wypełnienia z jednego wyjścia na kolejne.</p>
<pre>#include &lt;Tlc5940.h&gt;
#include &lt;tlc_shifts.h&gt;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  Tlc.init();
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #cc6600;">static</span> <span style="color: #cc6600;">byte</span> counter = 0;
  <span style="color: #cc6600;">if</span> (counter % 4)
    tlc_shiftUp(0);

  <span style="color: #cc6600;">else</span>
    tlc_shiftUp(4095);

  counter++;
  Tlc.update();
  <span style="color: #cc6600;">delay</span>(100);
}</pre>
<p dir="ltr">Przykład tworzy efekt “wąż świetlny”, który polega na złudzeniu, że światło w diodach ustawionych w linię pełza.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Funkcja “tlc_shiftUp” powoduje zapisanie do wyjścia OUT0 nowej wartości wypełnienia, podanej w argumencie, podczas gdy reszta wartości jest przesuwana do kolejnych wyjść (z OUT0 do OUT1, z OUT1 do OUT2 itp.). Ostatnia wartość, która była w rejestrze wypełnienia OUT15 jest zwracana przez tą funkcję (ułatwia to zapętlanie).</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Jest też odwrotnie działająca funkcja o nazwie “tlc_shiftDown”, której argument zapisuje wartość wypełnienia do OUT15 i przesuwa wartości rejestrów w dół (z OUT15 do OUT14, z OUT14 do OUT13 itp.). Zwraca ona wartość rejestru OUT0 przed przesunięciem.</p>
<p><strong><strong><br />
</strong></strong></p>
<p><iframe src="http://www.youtube.com/embed/1u2Yg2vANYc" frameborder="0" width="500" height="369"></iframe></p>
<h4 dir="ltr">Dane z pamięci programu</h4>
<p dir="ltr">Czasem zachodzi potrzeba przeniesienia na wyjścia PWM jakiś danych z pamięci. Kontroler AVR w Arduino ma kilka pamięci z których najbardziej pojemna jest pamięć Flash, gdzie przechowywany jest program. Pamięć RAM jest kilka razy mniej pojemna, dlatego najlepiej przechowuje się w niej aktualne zmienne, a nie tablice ze stałymi danymi. Dlatego autorzy biblioteki układu TLC5940 zadbali o możliwość współpracy z pamięcią programu.</p>
<pre>#include &lt;Tlc5940.h&gt;
#include &lt;tlc_progmem_utils.h&gt;

<span style="color: #cc6600;">byte</span> pwm_data[24] PROGMEM = {
  GS_DUO(4095, 3839), GS_DUO(3583, 3327), GS_DUO(3071, 2815), GS_DUO(2559, 2303), 
  GS_DUO(2047, 1791), GS_DUO(1535, 1279), GS_DUO(1023, 767), GS_DUO(511, 255)
};

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  Tlc.init();

  tlc_setGSfromProgmem(pwm_data);

  <span style="color: #cc6600;">while</span> (Tlc.update());
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
}</pre>
<p dir="ltr">Biblioteka “tlc_progmem_utils.h” zawiera narzędzia do obsługi danych z pamięci programu.</p>
<p dir="ltr">Aby przygotować tablice wartości wypełnienia dla rejestrów PWM układu, trzeba ją zadeklarować w odpowiedni sposób. oprócz standardowego określenia typu “byte”, nazwy tablicy “pwm_data” i jej rozmiaru, trzeba jeszcze dodać odpowiednią dyrektywę informującą, że tablica ma być przechowywana w pamięci programu a nie w normalnej pamięci RAM. Ta dyrektywa to “PROGMEM”. Rozmiar tablicy określony jest przez ilość danych potrzebnych do zaprogramowania układu. Wynika on z tego, że układ potrzebuje szesnastu 12 bitowych wartości. W języku C nie ma typu, który by przechowywał dokładnie 12 bitowe wartości. Jest albo 16 bitowy “word”, albo 8 bitowy “byte”. Aby nie było niepotrzebnych strat danych biblioteka używa 8 bitowego “byte”. 24 elementy tablicy typu “byte” wynikają z tego, że 16&#215;12 bitów /  8 (typ byte) = 24. Tablica jest poukładana od ostatniego rejestru GS OUT15 do pierwszego GS OUT0.</p>
<p dir="ltr">Aby było łatwiej układać dane, w bibliotece jest makro o nazwie GS_DUO, które ma dwa argumenty reprezentujące kolejne 2 wyjścia PWM (OUT15, OUT14 aż do OUT1, OUT0).</p>
<p dir="ltr">Wysłaniem danych z tablicy zajmuje się funkcja “tlc_setGSfromProgmem”. Jej argumentem jest nazwa tablicy z danymi do wyświetlenia.</p>
<h4 dir="ltr">Animacje z pamięci programu</h4>
<p dir="ltr">Jeśli chciałbyś wysyłać do układu TLC5940 sekwencje danych np. w postaci animacji lub danych do wyświetlacza widmowego, możesz skorzystać z biblioteki “tlc_animations.h”, która działa podobnie do poprzedniej.</p>
<pre>#include &lt;Tlc5940.h&gt;
#include &lt;tlc_animations.h&gt;

<span style="color: #cc6600;">byte</span> pwm_data[24*2] PROGMEM = {
  GS_DUO(4095, 0), GS_DUO(4095, 0), GS_DUO(4095, 0), GS_DUO(4095, 0), 
  GS_DUO(4095, 0), GS_DUO(4095, 0), GS_DUO(4095, 0), GS_DUO(4095, 0), 

  GS_DUO(0, 4095), GS_DUO(0, 4095), GS_DUO(0, 4095), GS_DUO(0, 4095), 
  GS_DUO(0, 4095), GS_DUO(0, 4095), GS_DUO(0, 4095), GS_DUO(0, 4095)
};

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  Tlc.init();
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #cc6600;">if</span> (!tlc_onUpdateFinished)
  {
    tlc_playAnimation(pwm_data, 2, 500);
  }
}</pre>
<p dir="ltr">Tym razem wielkość tablicy “pwm_data” musi być pomnożona o liczbę klatek animacji. W tym przykładzie stworzyłem 2 klatki animacji. Pierwsza klatka to maksymalne świecenie diod wyjść nieparzystych, a druga to maksymalne świecenie diod parzystych. Klatki rozdzieliłem pustą linia.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Za uruchomienie animacji odpowiada funkcja “tlc_playAnimation”. Jej pierwszy argument to tablica z danymi animacji, drugi to liczba klatek animacji, a ostatni to czas po jakim mają się wyświetlać kolejne klatki animacji. Czas jest wyrażony w cyklach licznika PWM, a jeden cykl trwa 1,024 ms. Zatem 500 oznacza, że klatki będą pojawiać się co około pół sekundy.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Ponieważ funkcja “tlc_playAnimation” nie zapętla animacji, dlatego po wyświetleniu ostatniej klatki animacji trzeba ją uruchamiać ponownie. Zmienna “tlc_onUpdateFinished” zwraca 0 jeśli animacja się skończyła i 1 jeśli wciąż trwa. Dlatego zastosowałem ją w “if” do zapętlania animacji.</p>
<h3 dir="ltr">Korekcja prądu wyjść układu TLC5940</h3>
<p dir="ltr">Jeśli podłączasz do wyjść układu TLC5940 różnokolorowe diody LED, często ich światło nie jest jednakowo jasne. Można to ustawić tworząc skomplikowane wzory przeliczające wartość rejestru wypełnienia i ograniczając rozdzielczość kanałów PWM. Ten układ ma jednak dodatkowy sprzęt, który pomoże dokonać korekty jasność.</p>
<p dir="ltr">Rejestry DC (Dot Correct) odpowiadają za dokładniejszą regulację prądu na wyjściach PWM. Ich rozdzielczość jest 6 bitowa, czyli przyjmują wartości od 0 do 63. Dzielą one wartość maksymalnego prądu na wyjściu ustalanego przez rezystor na wejściu IREF.</p>
<p dir="ltr">Aby dobrać się do rejestrów DC należy dokonać drobnej zmiany w układzie elektrycznym i bibliotece programu.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/tlc5940vprg_bb.png"><img class="aligncenter size-full wp-image-921" title="tlc5940vprg_bb" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/tlc5940vprg_bb.png" alt="" width="566" height="553" /></a><br />
</strong></strong></p>
<p dir="ltr">Na schemacie dodałem kolejny przewód do cyfrowego pinu Arduino. Przewód prowadzi od wejścia VPRG (noga 27 układu TLC5940) do pinu cyfrowego 8 w Arduino. W Arduino MEGA należy podłączyć ten sygnał do cyfrowego pinu 50.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Potem w katalogu biblioteki układu znajdź plik “tlc_config.h”, który odpowiada za ustawianie parametrów biblioteki i znajdz w nim definicję “#define VPRG_ENABLED 0” i zmień na “#define VPRG_ENABLED 1”. Uaktywni to dodatkowe elementy biblioteki odpowiedzialne za rejestry DC.</p>
<pre>#include &lt;Tlc5940.h&gt;
#include &lt;tlc_progmem_utils.h&gt;

<span style="color: #cc6600;">byte</span> DC_data[12] PROGMEM = {
  DC_QUARTET(3, 3, 3, 3), DC_QUARTET(3, 3, 3, 3), 
  DC_QUARTET(14, 14, 14, 14), DC_QUARTET(14, 14, 14, 14)
};

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  Tlc.init(4095);

  tlc_setDCfromProgmem(DC_data);

  <span style="color: #cc6600;">while</span> (Tlc.update());
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
}</pre>
<p dir="ltr">Rejestry najłatwiej obsługiwać za pomocą biblioteki “tlc_progmem_utils.h”.</p>
<p dir="ltr">Ustawianie rejestrów DC wygląda podobnie do opisywanej wcześniej funkcji ustawiania rejestrów wypełnienia z pamięci programu Flash. W tym przypadku potrzebna jest tablica w pamięci programu zawierająca 12 elementów typu “byte”. Do łatwego ustawiania poszczególnych rejestrów potrzebne są makra “DC_QUARTET”, które mają po 4 argumenty, reprezentujące poszczególne wyjścia w odwrotnej kolejności. Do ustawienia wszystkich rejestrów potrzeba czterech makr.</p>
<p dir="ltr">Za zapisanie danych z tablicy do układu TLC5940 odpowiada funkcja “tlc_setDCfromProgmem”, której jedynym argumentem jest nazwa tablicy z danymi rejestrów DC.</p>
<p dir="ltr">W przykładzie miałem do wyjść OUT0 &#8211; OUT7 podłączone diody zielone i do wyjść OUT8 &#8211; OUT15 diody czerwone. Diody czerwone były bardzo jaskrawe i dużo jaśniejsze od zielonych, dlatego dostały wartość 3, a diody zielone, mniej jaskrawe wartość 14.</p>
<p dir="ltr">Wszystko dlatego ma tak niskie wartości, aby nie raziło, a jednocześnie świeciło na tyle jasno by widzieć dokładnie które diody świecą.</p>
<h3 dir="ltr">Sterowanie serwomechanizmem</h3>
<p dir="ltr">Jak dowidziałeś się z poprzedniego wpisu, kąt obrotu serwomechanizmu zależy od szerokości impulsu PWM. Do układu TLC5940 możesz też podłączyć 16 serwomechanizmów.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/tlc5940servo_bb.png"><img class="aligncenter size-full wp-image-920" title="tlc5940servo_bb" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/tlc5940servo_bb.png" alt="" width="597" height="640" /></a><br />
</strong></strong></p>
<p dir="ltr">Wyjścia układu TLC 5940 są typu “otwarty kolektor” i przekazują tylko albo stan niski, albo nieustalony. Dlatego aby wysterować wejście sterujące sewomechanizmu, trzeba podłączyć rezystor PullUp. Rezystor ten wg. dokumentacji biblioteki powinien mieć od 2k do 5k Ohm.</p>
<pre>#include &lt;Tlc5940.h&gt;

#define SERVO_MIN_WIDTH 177
#define SERVO_MAX_WIDTH 571

#include &lt;tlc_servos.h&gt;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  tlc_initServos();
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #cc6600;">int</span> value = <span style="color: #cc6600;">analogRead</span>(0);
  value = <span style="color: #cc6600;">map</span>(value, 0, 1023, 0, 180);

  tlc_setServo(1, value);
  Tlc.update();
}</pre>
<p dir="ltr">Do używania serwomechanizmów przez układ służy specjalna biblioteka “tlc_servos.h”. Ponieważ biblioteka ma ustawione dość bezpieczne czasy minimalnego i maksymalnego impulsu serwomechanizmu, dlatego przed załadowaniem biblioteki trzeba zdefiniować własne ich czasy w makrach “SERVO_MIN_WIDTH” i “SERVO_MAX_WIDTH”. Wartości te są wyrażone w liczbie czasu wypełnienia w rejestrze PWM czyli od 0 do 4095. Pierwsza wartość wypełnienia jest przy serwie ustawionym na 0 stopni, a druga na 180 stopni. Czas wypełnienia dla 1000 mikrosekund to 204. Moje serwomechanizmy (HTX900) mają zakres od 870 do 2800 mikrosekund, dlatego dałem im wartości wypełnienia od 177 do 571. Wartości te można obliczyć ze wzoru:</p>
<pre dir="ltr">GSvalue = czas_impulsu_us * 204 / 1000</pre>
<p dir="ltr">W funkcji “setup” biblioteka wymaga wywołania funkcji “tlc_initServos();”, której opcjonalny argument to kąt obrotu serw podłączonych do wyjść.</p>
<p dir="ltr">Serwomechanizmy ustawia się za pomocą funkcji “tlc_setServo”, której pierwszym argumentem jest numer wyjścia, do którego podłączone jest serwo, a drugim kąt obrotu jego osi.</p>
<p dir="ltr">Na końcu należy oczywiście zatwierdzić wysłanie danych do układu za pomocą metody “Tlc.update();”</p>
<p dir="ltr">Dane do serwomechanizmu można też przekazywać za pomocą metody “Tlc.set”, pamiętając by nie przekraczać minimalnego i maksymalnego impulsu. Zanim poda się parametr wypełnienia dla tej metody, trzeba go odjąć od liczby 4095 (“Tlc.set(4095-imp_width);”).</p>
<p dir="ltr">Korzystając z biblioteki serwomechanizmów, do można do wyjść podłączyć też inne elementy, pamiętając o tym, że teraz generują impulsy z częstotliwością 50 Hz.</p>
<p dir="ltr">Program w przykładzie odczytuje wartość z wejścia analogowego i po przeskalowaniu ustawia oś serwomechanizmu proporcjonalnie do napięcia na wejściu.</p>
<p dir="ltr">UWAGA:</p>
<p dir="ltr">Biblioteka wymaga drobnej poprawki, gdyż wynik zakresu impulsu moich serwomechanizmów wywołał w niej błąd. W katalogu biblioteki w pliku “tlc_servos.h” funkcja “tlc_angleToVal” powinna wyglądać tak:</p>
<pre><span style="color: #7e7e7e;">/** Converts and angle (0 - SERVO_MAX_ANGLE) to the inverted tlc channel value</span>
<span style="color: #7e7e7e;">    (4095 - 0). */</span>
uint16_t tlc_angleToVal(uint8_t angle)
{
    <span style="color: #cc6600;">return</span> 4095 - SERVO_MIN_WIDTH - (
            ((uint32_t) (angle) * (uint16_t)(SERVO_MAX_WIDTH - SERVO_MIN_WIDTH))
            / SERVO_MAX_ANGLE);
}</pre>
<h3 dir="ltr">Sterowanie silnikiem</h3>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/tlc5940motor_bb.png"><img class="aligncenter size-full wp-image-918" title="tlc5940motor_bb" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/tlc5940motor_bb.png" alt="" width="598" height="570" /></a><br />
</strong></strong></p>
<p dir="ltr">Silnikiem elektrycznym steruje się jak w poprzednim wpisie za pomocą tranzystora MOSFET. Pamiętając oczywiście o zapewnieniu rezystora PullUp na wyjściu układu TLC5940.</p>
<pre>#include &lt;Tlc5940.h&gt;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  Tlc.init();
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #cc6600;">int</span> value = <span style="color: #cc6600;">analogRead</span>(0);
  value = <span style="color: #cc6600;">map</span>(value, 0, 1023, 0, 4095);

  Tlc.set(1, value);
  Tlc.update();
}</pre>
<p dir="ltr">Przykład nie różni się od poprzednich, nie wymaga specjalnej biblioteki. Steruje prędkością silnika w zależności od napięcia na analogowym wejściu 0 w Arduino, skalując wartość do poziomu zakresu wartości rejestru wypełnienia GS.</p>
<h3 dir="ltr">Łączenie wielu układów TLC5940</h3>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/tlc5940duo_bb.png"><img class="aligncenter size-full wp-image-916" title="tlc5940duo_bb" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/tlc5940duo_bb.png" alt="" width="601" height="552" /></a><br />
</strong></strong></p>
<p dir="ltr">Aby zyskać kolejne wyjścia PWM należy podłączyć kolejny układ TLC5940. Nie trzeba do tego wykorzystywać żadnych dodatkowych pinów Arduino. Kolejne układy podłączamy tak samo jak ten pierwszy, przekazując kolejnym te same sygnały z jednym wyjątkiem. Sygnał SIN (noga 26) następnego układu łączysz z sygnałem SOUT (noga 17) poprzedniego. W ten sposób zyskujesz kolejne 16 wyjść PWM. Układów możesz tak łączyć dowolną ilość pamiętając, że przesadne ilości wymagają więcej modyfikacji w bibliotece sterującej.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Aby program mógł skorzystać z dodatkowych układów należy otworzyć plik z katalogu biblioteki o nazwie “tlc_config.h”. Jest w nim zdefiniowane makro “#define NUM_TLCS 1”. Liczba za nazwą odpowiada liczbie podłączonych układów TLC5940. W moim przypadku będzie to “#define NUM_TLCS 2”.</p>
<pre>#include &lt;Tlc5940.h&gt;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  Tlc.init();

  Tlc.set(1, 2048);
  Tlc.set(17, 2048);

  <span style="color: #cc6600;">while</span> (Tlc.update());
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
}</pre>
<p dir="ltr">W programie sterującym układami prawie nic się nie zmienia. Różnica polega tylko na tym, że kolejne wyjścia mają kolejne numery. Zatem czerwona dioda LED podłączona do OUT1 pierwszego układu ma numer 1, a zielona dioda LED podłączona do wyjścia OUT1 drugiego układu ma numer 17. Jest to bardzo proste rozwiązanie.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Podobnie jest z innymi elementami biblioteki układu. W każdej ilość wyjść zwiększa się o wielokrotność układów. Biblioteki korzystające z pamięci Flash muszą mieć powiększone tablice do ilości wyjść układów.</p>
<h3 dir="ltr">Zakończenie</h3>
<p dir="ltr">TLC5940 to bardzo ciekawy układ scalony. Jego możliwości w połączeniu z Arduino są bardzo duże. Dzięki niemu możesz robić kroczące roboty, na których mięśnie składa się kilkanaście serwomechanizmów, lub zaskakujące efekty świetlne na przyszłoroczną choinkę. Zdecydowanie najciekawszym efektem jaki można zrobić przy pomocy tych układów jest wyświetlacz widmowy. Nie chciałem odbierać ci tej przygody i dlatego postaraj się zrealizować go sam :-). Tylko pamiętaj o solidnym przymocowaniu LED-ów najlepiej na płytce uniwersalnej.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/end.jpg"><img class="aligncenter size-full wp-image-908" title="end" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/end.jpg" alt="" width="500" height="375" /></a><br />
</strong></strong></p>
<h3 dir="ltr">Linki</h3>
<ul>
<li><a title="TLC5940NT na Nettigo" href="http://nettigo.pl/products/50">TLC5940NT do kupienia na Nettigo</a></li>
<li><a href="http://code.google.com/p/tlc5940arduino/">Biblioteka Tlc5940.h</a></li>
<li><a href="http://alex.kathack.com/codes/tlc5940arduino/html_r014/index.html">Opis biblioteki Tlc5940.h [en]</a></li>
</ul>
</div>
<img src="http://feeds.feedburner.com/~r/StarterKit/~4/V_09LcZYoN4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://starter-kit.nettigo.pl/2012/01/tlc5940-czyli-co-najmniej-16-dodatkowych-pinow-pwm-w-arduino/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		<feedburner:origLink>http://starter-kit.nettigo.pl/2012/01/tlc5940-czyli-co-najmniej-16-dodatkowych-pinow-pwm-w-arduino/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=tlc5940-czyli-co-najmniej-16-dodatkowych-pinow-pwm-w-arduino</feedburner:origLink></item>
		<item>
		<title>Co to jest PWM?</title>
		<link>http://feedproxy.google.com/~r/StarterKit/~3/kvlrTKHxbIA/</link>
		<comments>http://starter-kit.nettigo.pl/2012/01/co-to-jest-pwm/#comments</comments>
		<pubDate>Mon, 02 Jan 2012 20:41:55 +0000</pubDate>
		<dc:creator>sprae</dc:creator>
				<category><![CDATA[arduino]]></category>
		<category><![CDATA[dla początkujących]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[pwm]]></category>
		<category><![CDATA[starter-kit]]></category>
		<category><![CDATA[starter-kit-lite]]></category>

		<guid isPermaLink="false">http://starter-kit.nettigo.pl/?p=891</guid>
		<description><![CDATA[Wstęp Wielu użytkowników Arduino zapewne zauważyło, że wśród pinów z grupy DIGITAL jest kilka oznaczonych jako “PWM” lub “~”. W tym artykule postaram się wyjaśnić co to znaczy i jak dokładnie działa. Napiszę też jak można to praktycznie wykorzystać. PWM w teorii PWM to skrót od angielskich słów “Pulse Width Modulation”, co oznacza po polsku [...]]]></description>
			<content:encoded><![CDATA[<div>
<h3 dir="ltr">Wstęp</h3>
<p dir="ltr">Wielu użytkowników Arduino zapewne zauważyło, że wśród pinów z grupy DIGITAL jest kilka oznaczonych jako “PWM” lub “~”. W tym artykule postaram się wyjaśnić co to znaczy i jak dokładnie działa. Napiszę też jak można to praktycznie wykorzystać.</p>
<h3 dir="ltr">PWM w teorii</h3>
<p dir="ltr">PWM to skrót od angielskich słów “Pulse Width Modulation”, co oznacza po polsku “Modulacja Szerokości Impulsu”.</p>
<p dir="ltr">W życiu codziennym posługujesz się przełącznikami. One powodują, że włączasz jakieś urządzenie lub wyłączasz. Włączenie oznacza dostarczenie do urządzenia 100% energii elektrycznej, a wyłączenie zmniejsza tą ilość do 0%.</p>
<p dir="ltr">Jeśli masz w domu jakieś urządzenie z silnikiem to możesz zauważyć, że włączając i wyłączając je wiele razy w ciągu sekundy silnik nie zdąży się rozpędzić do maksymalnych obrotów. Wynika to z tego, że wolno się rozpędza. Zatem jeśli odetniesz mu prąd zanim osiągnie maksymalne obroty to będzie kręcił się wolniej i zwalniał do czasu, aż znowu go włączysz. W ten sposób można regulować jego prędkość.</p>
<p dir="ltr">Działanie PWM polega właśnie na tym, że im dłużej silnik jest włączony w ciągu sekundy, tym szybciej się kręci. A jeśli dłużej trwa czas wyłączenia tym wolniej. Czas włączenia to właśnie ten “Impuls” (“Pulse”) w nazwie, którego “Szerokość” (“Width”) regulujesz.</p>
<p dir="ltr">Fizycznie rzecz ujmując działanie PWM polega na dostarczeniu mniejszej ilości energii elektrycznej do urządzenia w przeciągu jakiegoś czasu. Czego skutkiem ubocznym są takie właśnie miłe efekty jak regulacja szybkości lub jasności.</p>
<p><span id="more-891"></span></p>
<h3 dir="ltr">Parametry PWM</h3>
<p dir="ltr">W rzeczywistości urządzenia PWM są dużo szybsze. Te w Arduino działają z prędkością około 400 razy na sekundę, co pozwala regulować urządzenia mające dużo szybszy czas reakcji np. jasność żarówek lub diod LED.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Parametrów pracy PWM jest kilka. Najważniejsze z nich są 3.</p>
<ul>
<li>
<p dir="ltr">Szybkość działania: To częstotliwość w jakiej mieszczą się czasy włączenia i wyłączenia. 400 Hz oznacza, że PWM włącza i wyłącza coś 400 razy na sekundę. Od tego zależy płynność pracy urządzenia.</p>
</li>
<li>
<p dir="ltr">Wypełnienie: Oznacza ile czasu na jeden okres włączenia/wyłączenia PWM jest w stanie wysokim. 50% oznacza, że pół czasu urządzenie jest włączone, a drugie pół wyłączone. 75% oznacza, że ¾ czasu urządzenie jest włączone.</p>
</li>
<li>
<p dir="ltr">Czas impulsu: Jest parametrem pochodzącym od powyższych. Oznacza to ile czasu trwa impuls włączenia. Jeśli PWM pracuje z prędkością 400 Hz, to czas całej fali PWM (włączony/wyłączony) trwa 1/400 = 0,0025s. Jeśli wypełnienie zajmuje 25% to czas impulsu wynosi 0,0025 * 25% = 0,0025 * 0,25 = 0,000625 s czyli 625 mikrosekund.</p>
</li>
</ul>
<h3 dir="ltr">PWM w praktyce</h3>
<p dir="ltr">Działanie generatora PWM w urządzeniach cyfrowych polega na tym, że w rejestrze przechowującym jakąś liczbę trzymana jest wartość wypełnienia. Od wielkości tego rejestru zależy ile jest stopni wypełnienia. 8 bitowy rejestr może mieć 256 stopni wypełnienia, a 16 bitowy 65 tysięcy. Oznacza to z jaką dokładnością będzie można regulować długość impulsu.</p>
<p><strong><strong><br />
</strong></strong></p>
<pre><code>1 / 256 * 100 = 0,39</code></pre>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Wynik ten podaje, że 8 bitowy rejestr PWM jest w stanie regulować wypełnienie z dokładnością 0,39%.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Oprócz rejestru w generatorze PWM jest też licznik. Licznik to urządzenie, które przechowuje liczbę i co jakiś czas dodaje do niej +1. Od szybkości dodawania tej wartości zależy szybkość z jaką pracuje PWM.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Ostatnim elementem generatora PWM jest układ, który porównuje wartość licznika z wartością rejestru wypełnienia. Jeśli te wartości są sobie równe to wyjście PWM zmienia się w stan niski czyli wyłącza urządzenie.</p>
<p dir="ltr">Po dojściu licznika do ostatniej wartości jaką może policzyć, stan wyjścia PWM zmieniany jest na wysoki &#8211; włączający urządzenie i licznik zaczyna liczyć od nowa.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/pwm10.png"><img class="aligncenter size-full wp-image-892" title="pwm10" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/pwm10.png" alt="" width="500" height="304" /></a><br />
</strong></strong></p>
<p dir="ltr">Wykres działania generatora PWM dla wartości 10 w 8 bitowym rejestrze wypełnienia.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/pwm15.png"><img class="aligncenter size-full wp-image-893" title="pwm15" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/pwm15.png" alt="" width="500" height="304" /></a><br />
</strong></strong></p>
<p dir="ltr">Wykres działania generatora PWM dla wartości 15 w 8 bitowym rejestrze wypełnienia.</p>
<h3 dir="ltr">Programowy PWM</h3>
<p dir="ltr">Z pewnością mogłeś mi nie uwierzyć, że to jest takie proste ;-). Dlatego, aby ci to udowodnić napiszę program do Arduino, który będzie udawał działanie generatora PWM i regulował jasność wbudowanej w Arduino diody LED.</p>
<pre><span style="color: #7e7e7e;">// numer pinu z wbudowaną diodą</span>
#define LED_PIN 13

<span style="color: #7e7e7e;">// Zmienna z wartością licznika</span>
<span style="color: #cc6600;">byte</span> pwmCounter = 0;
<span style="color: #7e7e7e;">// Zmienna z wartością rejestru wypełnienia</span>
<span style="color: #cc6600;">byte</span> pwmValue = 10;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #7e7e7e;">// Ustawienie pinu diody na wyjście</span>
  <span style="color: #cc6600;">pinMode</span>(LED_PIN, <span style="color: #006699;">OUTPUT</span>);
  <span style="color: #7e7e7e;">// Ustawienie pinu diody na stan niski</span>
  <span style="color: #cc6600;">digitalWrite</span>(LED_PIN, <span style="color: #006699;">LOW</span>);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #7e7e7e;">// Jeśli stan licznika się przekręci to ustaw pin w stan wysoki</span>
  <span style="color: #cc6600;">if</span> (pwmCounter == 0)
  {
    <span style="color: #cc6600;">digitalWrite</span>(LED_PIN, <span style="color: #006699;">HIGH</span>);
  }

  <span style="color: #7e7e7e;">// Jeśli stan licznika jest równy stanu rejestru to ustaw pin w stan niski</span>
  <span style="color: #cc6600;">if</span> (pwmCounter == pwmValue)
  {
    <span style="color: #cc6600;">digitalWrite</span>(LED_PIN, <span style="color: #006699;">LOW</span>);
  }

  <span style="color: #7e7e7e;">// Zwiększanie wartości licznika o 1</span>
  pwmCounter++;
}</pre>
<p dir="ltr">Działanie programu odpowiada temu co opisałem w zasadzie działania generatora PWM. Zmienna “pwmValue” reprezentuje rejestr regulujący szerokość impulsu czyli poziom wypełnienia. Wartość 10 odpowiada wypełnieniu 3,90%.</p>
<p><strong><strong><br />
</strong></strong></p>
<pre><code>10 / 256 * 100 = 3,90</code></pre>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Zmienna “pwmCounter” to zmienna reprezentująca licznik generatora. Zarówno ta zmienna, jak i “pwmValue” są typu “byte”, zatem reprezentują wartości 8 bitowe, czyli mogą przechowywać liczby od 0 do 255. Jeśli licznik podczas dodawania przekroczy tą liczbę, to zaczyna liczyć od nowa od 0.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Cały mechanizm działania generatora PWM znajduje się w funkcji “loop”. W pierwszym warunku “if” sprawdzane jest czy licznik nie zaczął liczyć od nowa. Jeśli tak to wyjście PWM ustawiane jest w stan wysoki.</p>
<p dir="ltr">W drugim warunku “if” program sprawdza, czy wartość licznika jest równa wartości rejestru wypełnienia. Jeśli tak to zmienia stan wyjścia PWM na niski, który będzie utrzymany aż licznik zacznie liczyć od nowa czyli od 0.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Jeśli uruchomiłeś ten program to powinieneś zauważyć w Arduino, że wbudowana dioda świeci bardzo słabo. Zmieniając wartość zmiennej “pwmValue” możesz zmieniać jasność świecenia tej diody. Wartość 255 to maksymalne świecenie, a 0 to minimalne.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Takie rozwiązanie programowe jest proste, ale ma kilka wad. Pierwszą jest to, że dodając nowe elementy do programu powodujesz, że szybkość działania generatora spada, bo musi się on dzielić czasem procesora z innymi elementami programu. Inną wadą jest to, że wyjście takiego generatora może być niestabilne, przez to, że na działanie głównego programu mogą wpływać przerwania. Jednym z nich jest np. komunikacja Serial.</p>
<h3 dir="ltr">Sprzętowy PWM</h3>
<p dir="ltr">Arduino UNO posiada w grupie pinów “DIGITAL” 6 wyjść PWM. Oznaczone są one na płytce przez napisy “PWM” lub znaczek “~”. Generowane przez te wyjścia sygnały PWM są tworzone sprzętowo przez wbudowane w procesor Arduino liczniki/timery. Oznacza to, że program procesora ani ich nie zwalania, ani nie wpływa na zakłócenia ich pracy. Domyślnie pracują one z prędkością 490 Hz i przyjmują wartości 8 bitowe.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Funkcja odpowiadająca za działanie tych pinów nosi nazwę “analogWrite”. Jej pierwszym argumentem jest numer pinu PWM, a drugim wartość wypełnienia od 0 do 255.</p>
<p dir="ltr">Aby ta funkcja zadziałała pin musi być najpierw ustawiony jako wyjście.</p>
<p><strong><strong><br />
</strong></strong></p>
<pre>#define PWM_PIN 3

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;">pinMode</span>(PWM_PIN, <span style="color: #006699;">OUTPUT</span>);

  <span style="color: #cc6600;">analogWrite</span>(PWM_PIN, 10);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
}</pre>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Jak widzisz w funkcji “loop” nie trzeba już niczego zamieszczać. Sygnał generuje się automatycznie po wywołaniu “analogWrite”.</p>
<h3 dir="ltr">Co można podłączyć do PWM?</h3>
<p dir="ltr">Niestety nie ma sprzętowego wyjścia PWM do pinu 13 wbudowanej diody LED. Zatem aby sprawdzić działanie wyjścia możesz podłączyć do niego inną diodę połączoną szeregowo z rezystorem 220 Ohm. Jej anodę podłączasz do wyjścia PWM, a katodę do GND.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/pwmex_exled.png"><img class="aligncenter size-full wp-image-894" title="pwmex_exled" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/pwmex_exled.png" alt="" width="373" height="493" /></a><br />
</strong></strong></p>
<p dir="ltr">Można też w ten sposób podłączyć 3-kolorową diodę LED ze wspólną katodą, tak by każde wyjście PWM sterowało osobnym kolorem, co da płynną możliwość dobierania kolorów.</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/pwmex_rgbled.png"><img class="aligncenter size-full wp-image-896" title="pwmex_rgbled" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/pwmex_rgbled.png" alt="" width="326" height="511" /></a><br />
</strong></strong></p>
<p dir="ltr">Taka dioda LED składa się z 3 niezależnych diod w jednej obudowie. Barwy emitowane przez diody są podstawowymi barwami składowymi RGB &#8211; Czerwony, Zielony, Niebieski. Każda z tych barw podłączona jest do innego wyjścia PWM (pin 3 &#8211; zielony, pin 5 &#8211; niebieski, pin 6 &#8211; czerwony) przez rezystor 220 Ohm. Wspólna katoda diod podłączona jest do GND. Takie połączenie powinno dać teoretycznie 16 mln barw (256 poziomów na składową czyli 256^3 = 16777216).</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Do wyjścia PWM możesz podłączyć też silnik elektryczny i regulować prędkość jego wału. Ponieważ silnik pobiera znacznie więcej prądu niż może wygenerować cyfrowe wyjście Arduino, zalecam zastosowanie tranzystora MOSFET typu N. Tranzystory te wytrzymują znaczne prądy obciążenia i duże napięcia (w moim przypadku do 12A i 60V &#8211; tranzystor o oznaczeniu D12N06 (typu N) ze starej drukarki).</p>
<p><strong><strong><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/pwmex_mosfet.png"><img class="aligncenter size-full wp-image-895" title="pwmex_mosfet" src="http://starter-kit.nettigo.pl/wp-content/uploads/2012/01/pwmex_mosfet.png" alt="" width="497" height="653" /></a><br />
</strong></strong></p>
<p dir="ltr">Bramkę (Gate) tranzystora podłączyłem przez rezystor 1 KOhm do wyjścia PWM pin 3. Źródło (Source) tranzystora podłączyłem do GND. Natomiast Dren (Drain) połączyłem z silnikiem. Drugie wyprowadzenie silnika podłączyłem z jego zasilaniem. Do tego może służyć osobny zasilacz silnika lub pin Vin Arduino, jeśli silnik nie pobiera zbyt dużej mocy.</p>
<p dir="ltr">W przypadku silnika, nie każda wartość wypełnienia impulsu PWM może wpływać na jego działanie. W moim przypadku silnik zaczął się kręcić dopiero od wartości 60 (wypełnienie 23,5%).</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Serwomechanizmy są elementami zależnymi od czasu trwania impulsu PWM. Szerokość impulsu decyduje o tym jak będzie ustawiony kąt osi serwomechanizmu. Moje serwomechanizmy (HTX900) przyjmują szerokości impulsów od 580 (0 stopni) do 2800 (180 stopni) mikrosekund. Do ich obsługi stosuje się raczej bibliotekę “Servo.h”, która dobrze spełnia swoje zadanie.</p>
<p><strong><strong><br />
</strong></strong></p>
<p dir="ltr">Wyjście PWM może sterować też głośnikiem lecz wymaga generatora PWM o częstotliwości pracy w zakresie ultradzwięków (powyżej 20000 Hz). Częstotliwości niższe są słyszalne dla ucha człowieka i powodują, że zamiast sygnału jaki chciałeś wygenerować, słyszysz pisk sygnału PWM. W tym artykule nie napiszę o sposobach generowania takiego sygnału, ale pojawiło się już wiele takich projektów w społeczności Arduino i można je wyszukać.</p>
<p dir="ltr">Sterowanie głośnikiem przez PWM pozwala na wytwarzanie przez głośnik fal o dowolnych kształtach i głośności, a nawet odtwarzanie sampli. Eksperymentatorzy będą mieli zapewne wiele zabawy.</p>
<h3 dir="ltr">Zakończenie</h3>
<p dir="ltr">Mam nadzieję, że tym wpisem rozwiałem twoje wątpliwości dotyczące tego jak działają i do czego służą wyjścia PWM. Jeśli masz jeszcze jakieś pytania dotyczące PWM, możesz zamieścić je w komentarzach pod artykułem.</p>
<p dir="ltr">W nastepnym wpisie przedstawię jak można uzyskać 16 kanałów PWM o rozdzielczości 12 bitów (4096 poziomów wypełnienia).</p>
<h3 dir="ltr">Linki</h3>
<ul>
<li><a href="http://arduino.cc/en/Reference/AnalogWrite">Opis funkcji “analogWrite” [EN]</a></li>
<li><a href="http://pl.wikipedia.org/wiki/Modulacja_szeroko%C5%9Bci_impuls%C3%B3w">Opis działania PWM na Wikipedii [Paskudne akademickie teoretyzowanie ;-)]</a></li>
<li><a href="http://arduino.cc/en/Reference/Servo">Opis biblioteki “Servo.h” [EN]</a></li>
</ul>
</div>
<p>&nbsp;</p>
<img src="http://feeds.feedburner.com/~r/StarterKit/~4/kvlrTKHxbIA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://starter-kit.nettigo.pl/2012/01/co-to-jest-pwm/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://starter-kit.nettigo.pl/2012/01/co-to-jest-pwm/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=co-to-jest-pwm</feedburner:origLink></item>
		<item>
		<title>PCF8574 czyli jak łatwo zwiększyć liczbę pinów w Arduino</title>
		<link>http://feedproxy.google.com/~r/StarterKit/~3/0wa-z8PWPCM/</link>
		<comments>http://starter-kit.nettigo.pl/2011/11/pcf8574-czyli-jak-latwo-zwiekszyc-liczbe-pinow-w-arduino/#comments</comments>
		<pubDate>Sun, 27 Nov 2011 23:19:20 +0000</pubDate>
		<dc:creator>sprae</dc:creator>
				<category><![CDATA[arduino]]></category>
		<category><![CDATA[dla początkujących]]></category>
		<category><![CDATA[i2c]]></category>
		<category><![CDATA[PCF8574]]></category>
		<category><![CDATA[pcf8574p]]></category>
		<category><![CDATA[podstawy]]></category>
		<category><![CDATA[starter-kit]]></category>
		<category><![CDATA[starter-kit-lite]]></category>
		<category><![CDATA[TWI]]></category>

		<guid isPermaLink="false">http://starter-kit.nettigo.pl/?p=866</guid>
		<description><![CDATA[Wstęp Arduino z rodziny UNO posiada 14 pinów cyfrowych. Jest to wystarczająca ilość do większości prostych zastosowań z dziedziny automatyki. Zdarzają się jednak sytuacje, jak np. podłączenie wyświetlacza, które drastycznie tą liczbę mogą zmniejszyć. Co wtedy robić? Można przesiąść się na 2 razy droższe Arduino MEGA i mieć ponad 50 dodatkowych pinów. Można też użyć [...]]]></description>
			<content:encoded><![CDATA[<div>
<div>
<h3 dir="ltr">Wstęp</h3>
<p dir="ltr">Arduino z rodziny UNO posiada 14 pinów cyfrowych. Jest to wystarczająca ilość do większości prostych zastosowań z dziedziny automatyki. Zdarzają się jednak sytuacje, jak np. podłączenie wyświetlacza, które drastycznie tą liczbę mogą zmniejszyć.</p>
<p dir="ltr">Co wtedy robić? Można przesiąść się na 2 razy droższe Arduino MEGA i mieć ponad 50 dodatkowych pinów. Można też użyć rejestru przesuwnego 74HC595, który da dodatkowe 8 wyjść cyfrowych za cenę 2 zł i użycia 3 pinów cyfrowych. Można też użyć układu <a title="PCF8574" href="http://nettigo.pl/product/PCF8574P---8-portow-cyfrowych-po-I2C,pcf8574p">PCF8574</a> i mieć dodatkowe 8 pinów (lub nawet 128 łącząc więcej układów) wejścia/wyjścia o możliwościach przekraczających te w Arduino za cenę użycia 2 pinów analogowych.</p>
<h3 dir="ltr">Układ scalony PCF8574</h3>
<p style="text-align: center;"><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/pcf8574.png"><img class="aligncenter size-full wp-image-868" title="pcf8574" src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/pcf8574.png" alt="" width="500" height="245" /></a></p>
<ul>
<li>
<p dir="ltr">Vcc &#8211; Pin zasilania, podłączany w Arduino do pinu 5V.</p>
</li>
<li>
<p dir="ltr">GND &#8211; Pin masy zasilania podłączany w Arduino do GND.</p>
</li>
<li>
<p dir="ltr">P0..P7 &#8211; Cyfrowe piny do własnego wykorzystania.</p>
</li>
<li>
<p dir="ltr">SDA &#8211; Sygnał danych magistrali I2C podłączany w Arduino do Analog In 4.</p>
</li>
<li>
<p dir="ltr">SCL &#8211; Sygnał zegara magistrali I2C podłączany w Arduino do Analog In 5.</p>
</li>
<li>
<p dir="ltr">A0, A1, A2 &#8211; Wybór adresu układu, jeśli używasz jednego układu, wszystkie można podłączyć do GND.</p>
</li>
<li>
<p dir="ltr">/INT &#8211; Zanegowany sygnał przerwania. Można go używać do wykrywania zmiany stanu na jednym z cyfrowych wejść.</p>
</li>
</ul>
<h3 dir="ltr">Magistrala I2C</h3>
<p dir="ltr">Układ PCF8574 komunikuje się z Arduino za pomocą magistrali I2C. Jest to synchroniczna magistrala szeregowa wykorzystywana powszechnie w sprzęcie RTV. Szeregowa oznacza, że bity są przesyłane jednym pinem po kolei &#8211; pinem SDA. Synchroniczna oznacza, że każdy wysłany bit jest zatwierdzany sygnałem na drugim pinie &#8211; SCL. Synchroniczność przyczynia się do zwiększenia prędkości komunikacji i eliminuje błędy transmisji.</p>
<p dir="ltr">Magistrala I2C ma też własny protokół komunikacji, dzięki któremu do jej sygnałów SDA/SCL można podłączyć więcej niż jeden układ scalony. Każdy układ w magistrali ma swój adres. Adres jest to liczba, która identyfikuje układ, wybierając tą liczbę masz pewność, że dane które wysyłasz trafią do właściwego układu. Układ PCF8574 ma dodatkowo piny A0, A1, A2 za pomocą których możesz konfigurować część adresu. Pozwala to na podłączenie do magistrali więcej takich samych układów scalonych, dzięki modyfikacji stanów logicznych na tych pinach. Trzy piny adresu oznaczają, że możesz podłączyć do magistrali 8 takich układów scalonych, co da 64 dodatkowe piny cyfrowe. Jeśli i to jest za mało to istnieje też wersja układu PCF8574A, która ma zmieniony adres, co sprawia, że oprócz tamtych 8 można podłączyć jeszcze 8 układów i mieć w sumie 128 pinów.</p>
<p dir="ltr">W Arduino magistrala I2C ze względu na problemy licencyjne nazywa się TWI (TwoWires [dwa przewody] &#8211; od liczby przewodów używanych przez nią). Mikrokontroler AVR zawarty na płytce zawiera sprzętową obsługę tej magistrali. Jej wyprowadzenia znajdują się na dwóch ostatnich pinach grupy “ANALOG IN”. Sygnał danych SDA znajduje się na pinie 4, a sygnał zegarowy SCL na pinie 5.</p>
<h3 dir="ltr">Adres układu PCF8574</h3>
<p dir="ltr">Układy z rodziny PCF8574 mają 7 bitowy adres. Pierwsze 3 bity adresu nadaje mu użytkownik, przez ustawienie pinów A0, A1, A2. Kolejne 4 są nadane fabrycznie na stałe. Układ PCF8574 ma je ustawione na 0100, a układ PCF8574A ustawione na 0111.</p>
<h4 dir="ltr">Binarny adres układu PCF8574</h4>
<div dir="ltr">
<table>
<colgroup>
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" /></colgroup>
<tbody>
<tr>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">A2</p>
</td>
<td>
<p dir="ltr">A1</p>
</td>
<td>
<p dir="ltr">A0</p>
</td>
</tr>
</tbody>
</table>
</div>
<p dir="ltr">Co oznacza, że minimalny adres (dla wszystkich A = LOW) to dziesiętnie 32, szesnastkowo 0&#215;20. Maksymalny adres (dla wszystkich A = HIGH) to dziesiętnie 39, a szesnastkowo 0&#215;27.</p>
<h4 dir="ltr">Binarny adres układu PCF8574A</h4>
<div dir="ltr">
<table>
<colgroup>
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" />
<col width="*" /></colgroup>
<tbody>
<tr>
<td>
<p dir="ltr">0</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">1</p>
</td>
<td>
<p dir="ltr">A2</p>
</td>
<td>
<p dir="ltr">A1</p>
</td>
<td>
<p dir="ltr">A0</p>
</td>
</tr>
</tbody>
</table>
</div>
<p dir="ltr">Co oznacza, że minimalny adres (dla wszystkich A = LOW) to dziesiętnie 56, szesnastkowo 0&#215;38. Maksymalny adres (dla wszystkich A = HIGH) to dziesiętnie 63, a szesnastkowo 0x3F.</p>
<h3 dir="ltr">Podłączenie do Arduino</h3>
<p><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/pcf8574_bb.png"><img class="aligncenter size-full wp-image-869" title="pcf8574_bb" src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/pcf8574_bb.png" alt="" width="454" height="472" /></a></p>
<p>Podłączenie nie sprawia trudności i wykorzystuje tylko 4 przewody. Vcc układu łącze z pinem 5V Arduino, GND układu łącze z pinem GND Arduino w sekcji zasilania. Sygnały SDA łącze z pinem 4, a SCL z pinem 5 sekcji “ANALOG IN” Arduino.</p>
<p dir="ltr">Ponieważ używam w tej konfiguracji tylko jednego układu, podłączyłem wszystkie linie adresowe w stan niski (LOW) łącząc je z GND. Jeśli w twojej konfiguracji jest więcej takich samych układów, powinieneś do linii adresowych stosować różne kombinacje stanów (LOW &#8211; GND, HIGH &#8211; 5V) innych dla każdego układu. Pozostałe piny P0 do P7 możesz wykorzystywać dowolnie jako piny cyfrowe (DIGITAL), jak to robisz w Arduino.</p>
<h3 dir="ltr">Programowanie układu PCF8574</h3>
<h4 dir="ltr">Przygotowanie</h4>
<div>
<pre>#include &lt;<span style="color: #cc6600;">PCF8574</span>.h&gt;
#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #cc6600;">PCF8574</span> expander;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  expander.<span style="color: #cc6600;">begin</span>(0x20);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
}</pre>
</div>
<p dir="ltr">Jak zawsze społeczność Arduino nie zawiodła i jeden z miłośników platformy przygotował odpowiednią bibliotekę. Aby rozpocząć komunikacje z układem PCF8574 musisz najpierw podłączyć 2 biblioteki &#8211; PCF8574.h (dostarczającą funkcje obsługi układu) i Wire.h (do obsługi magistrali TWI).</p>
<p dir="ltr">Następnie trzeba zadeklarować obiekt klasy “PCF8574”, który nazwałem “expander”. Deklaruje się to jak inne zmienne czyli “PCF8574 expander;”.</p>
<p dir="ltr">Potem w funkcji “setup” należy za pomocą metody “expander.begin” ustawić adres układu, który ma reprezentować zadeklarowany obiekt. W tym przypadku ustawiłem wartość szesnastkową 0&#215;20 odpowiadającą układowi z liniami adresowymi w stanie “LOW” &#8211; jak na schemacie.</p>
<p><span id="more-866"></span></p>
<h4 dir="ltr">Ustawienie kierunku działania pinów</h4>
<pre>#include &lt;<span style="color: #cc6600;">PCF8574</span>.h&gt;
#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #cc6600;">PCF8574</span> expander;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  expander.<span style="color: #cc6600;">begin</span>(0x20);
  expander.<span style="color: #cc6600;">pinMode</span>(0, <span style="color: #006699;">OUTPUT</span>);
  expander.<span style="color: #cc6600;">pinMode</span>(1, <span style="color: #006699;">INPUT</span>);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
}</pre>
<p dir="ltr">Nazwy funkcji biblioteki obsługującej układ zostały tak dobrane, by przypominać te z biblioteki obsługującej piny Arduino. z tym, że zamiast “pinMode” jest “expander.pinMode”, gdyż dotyczy obiektu układu. Działanie funkcji jest bliźniaczo podobne do tych w Arduino. Pierwszy argument to numer pinu układu od 0 do 7, a drugi to kierunek działania pinu “INPUT” &#8211; wejście, “OUTPUT” &#8211; wyjście.</p>
<p dir="ltr">W tym przykładzie ustawiłem pin 0 na wyjście, a pin 1 na wejście.</p>
<h4 dir="ltr">Ustawienie stanu pinów</h4>
<pre>#include &lt;<span style="color: #cc6600;">PCF8574</span>.h&gt;
#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #cc6600;">PCF8574</span> expander;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  expander.<span style="color: #cc6600;">begin</span>(0x20);
  expander.<span style="color: #cc6600;">pinMode</span>(4, <span style="color: #006699;">OUTPUT</span>);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  expander.<span style="color: #cc6600;">digitalWrite</span>(4, <span style="color: #006699;">LOW</span>);
  <span style="color: #cc6600;">delay</span>(1000);
  expander.<span style="color: #cc6600;">digitalWrite</span>(4, <span style="color: #006699;">HIGH</span>);
  <span style="color: #cc6600;">delay</span>(1000);
}</pre>
<p dir="ltr">Podobnie jak w Arduino, tak i tutaj do ustawienia stanu pinów służy bliźniacza funkcja “expander.digitalWrite”. Jej pierwszym argumentem jest numer pinu od 0 do 7, a kolejnym stan jaki ma być ustawiony. “LOW” to stan niski odpowiadający GND, “HIGH” to stan wysoki odpowiadający 5V. Oczywiście można ustawiać tylko stan pinów wyjściowych “OUTPUT”.</p>
<p dir="ltr">Ten przykład co sekundę zmienia stan pinu 4 układu.</p>
<p dir="ltr"><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/pcf8574_led.png"><img class="aligncenter size-full wp-image-872" title="pcf8574_led" src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/pcf8574_led.png" alt="" width="440" height="460" /></a></p>
<p>Jeśli teraz podłączysz do pinu 4 (noga układu 9) rezystor 220 Ohm, a drugie wyprowadzenie rezystora do katody diody LED, potem anodę diody LED do zasilania 5V, to powinna zgodnie z programem mrugać.</p>
<h4 dir="ltr">Odwracanie stanu pinów wyjściowych</h4>
<pre>#include &lt;<span style="color: #cc6600;">PCF8574</span>.h&gt;
#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #cc6600;">PCF8574</span> expander;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{ 
  expander.<span style="color: #cc6600;">begin</span>(0x20);
  expander.<span style="color: #cc6600;">pinMode</span>(4, <span style="color: #006699;">OUTPUT</span>);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  expander.toggle(4);
  <span style="color: #cc6600;">delay</span>(1000);
}</pre>
<p dir="ltr">Przykład z poprzedniego rozdziału można odrobinę skrócić. Biblioteka PCF8574 zawiera dodatkową funkcję “expander.toggle”, która automagicznie odwraca stan na wyjściu układu na przeciwny. Argumentem metody jest numer pinu od 0 do 7, którego stan chcesz odwrócić.</p>
<p dir="ltr">Przykładowy program robi to samo co poprzedni z tym, że krócej.</p>
<h4 dir="ltr">Mruganie</h4>
<pre>#include &lt;<span style="color: #cc6600;">PCF8574</span>.h&gt;
#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #cc6600;">PCF8574</span> expander;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{ 
  expander.<span style="color: #cc6600;">begin</span>(0x20);
  expander.<span style="color: #cc6600;">pinMode</span>(4, <span style="color: #006699;">OUTPUT</span>);

  expander.<span style="color: #cc6600;">blink</span>(4, 10, 500);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
}</pre>
<p dir="ltr">Metoda “expander.blink” odpowiada za mruganie stanem pinu. Jej pierwszy argument to numer pinu od 0 do 7, drugi argument to ilość mrugnięć, a trzeci, czas w jakim ma trwać jeden stan mrugania w milisekundach.</p>
<p dir="ltr">Przykład sprawia, że na pinie 4 (noga 9) pojawi się 10 impulsów &#8211; naprzemiennych stanów LOW &#8211; HIGH. Każdy stan będzie trwał 500 milisekund, czyli 0,5 s.</p>
<h4 dir="ltr">Odczytywanie stanu pinów</h4>
<pre>#include &lt;<span style="color: #cc6600;">PCF8574</span>.h&gt;
#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #cc6600;">PCF8574</span> expander;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(9600);

  expander.<span style="color: #cc6600;">begin</span>(0x20);
  expander.<span style="color: #cc6600;">pinMode</span>(0, <span style="color: #006699;">INPUT</span>);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #cc6600;">byte</span> value = expander.<span style="color: #cc6600;">digitalRead</span>(0);

  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(value, DE);
  <span style="color: #cc6600;">delay</span>(100);
}</pre>
<p dir="ltr">Odczyt stanu pinu ustawionego na wejście “INPUT” odczytujesz za pomocą “expander.digitalRead”. Jedynym argumentem tej metody jest numer pinu od 0 do 7.</p>
<p dir="ltr">Powyższy przykład odczytuje wartość pinu 0 (noga 4) i zapisuje go do zmiennej “value”. Jeśli na pinie 0 jest stan niski, to zmienna “value” będzie miała wartość “LOW” (0), a jeśli wysoki, to zmienna będzie miała wartość “HIGH” (1). Wartość zmiennej jest wysyłana do komputera (dzięki Serial.println), dzięki czemu możesz ją podglądać w Serial Monitor z Arduino IDE.</p>
<h4 dir="ltr">Rezystory PullUp wejść układu PCF8574</h4>
<pre>#include &lt;<span style="color: #cc6600;">PCF8574</span>.h&gt;
#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #cc6600;">PCF8574</span> expander;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(9600);

  expander.<span style="color: #cc6600;">begin</span>(0x20);
  expander.<span style="color: #cc6600;">pinMode</span>(4, <span style="color: #006699;">INPUT</span>);
  expander.pullUp(4);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #cc6600;">byte</span> value = expander.<span style="color: #cc6600;">digitalRead</span>(4);

  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(value, <span style="color: #006699;">DEC</span>);
  <span style="color: #cc6600;">delay</span>(100);
}</pre>
<p dir="ltr">Wejścia cyfrowych układów scalonych mogą mieć 3 stany. LOW &#8211; wejście ustawione w stan niski np. przez podłączenie do GND, HIGH &#8211; wejście ustawione w stan wysoki np. podłączone do 5V i stan nieustalony. Stan nieustalony jest wtedy, kiedy w przewodzie wejścia cyfrowego nie ma żadnego konkretnego stanu wysyłanego przez inne podłączone układy. Stan nieustalony jest interpretowany przez wejście układu jako stan losowy w zależności od zakłóceń ustawiany raz na LOW, a raz na HIGH.</p>
<p dir="ltr"><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/pcf8574_pullup.png"><img class="aligncenter size-full wp-image-874" title="pcf8574_pullup" src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/pcf8574_pullup.png" alt="" width="438" height="487" /></a>Wiele elementów jak np. przełącznik, albo przewodzą prąd, albo nie. Jeśli podłączysz przełącznik do wejścia cyfrowego, to gdy nie będzie przewodził, będzie stan nieustalony i układ może dostawać błędne sygnały.</p>
<p dir="ltr">Rezystory pullup wymyślono po to, aby gdy wejście nie ma ustalonego stanu, same ustalały stan domyślny, dopóki na wejściu nie pojawi się konkretny stan. Pullup oznacza “podciągnij w górę”, znaczy to, że domyślnym stanem niepodłączonego wejścia będzie stan wysoki “HIGH”. Dlatego na schemacie podłączyłem przełącznik do pin 4 układu, a jego drugie wyprowadzenie do GND. Wobec czego gdy przełącznik nie przewodzi, dzieki pullup jest domyślnie stan wysoki. Gdy przełącznik przewodzi, zwiera wejście do GND przez co ustala stan na niski “LOW”.</p>
<p dir="ltr">Za ustalenie domyślnie stanu wysokiego na wejściu układu PCF8574 odpowiada funkcja “expander.pullUp”, której argumentem jest numer pinu układu od 0 do 7.</p>
<p dir="ltr">Przykład programu ustawia pullup na wejście numer 4 (noga 9) i wysyła jego stan do komputera.</p>
<h4 dir="ltr">Rezystory Pull Down układu PCF8574</h4>
<pre>#include &lt;<span style="color: #cc6600;">PCF8574</span>.h&gt;
#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #cc6600;">PCF8574</span> expander;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(9600);

  expander.<span style="color: #cc6600;">begin</span>(0x20);
  expander.<span style="color: #cc6600;">pinMode</span>(4, <span style="color: #006699;">INPUT</span>);
  expander.pullDown(4);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #cc6600;">byte</span> value = expander.<span style="color: #cc6600;">digitalRead</span>(4);

  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(value, <span style="color: #006699;">DEC</span>);
  <span style="color: #cc6600;">delay</span>(100);
}</pre>
<p>Układ PCF8574 jest na tyle uniwersalny, że zapewnia też rezystory pulldown. Ustalają one domyślnie wejście cyfrowe na stan niski “LOW”. Zatem teraz podłączenie wejścia do 5V ustala jego stan na wysoki “HIGH”, a brak stanu to domyślnie stan niski.</p>
<h4 dir="ltr">Równoległy dostęp do pinów</h4>
<p>Równoległy dostęp do pinów to funkcje dzięki którym za jednym wywołaniem program może obsłużyć wszystkie piny układu PCF8574 na raz.</p>
<ul>
<li>expander.write(value)<br />
Pozwala ustawić wartość binarną argumentu “value” na wszystkich pinach wyjściowych układu.</li>
<li>expander.read()<br />
Pozwala odczytać wartość binarną wszystkich pinów.</li>
<li>expander.clear()<br />
Ustawia na wszystkich wyjściowych pinach stan niski “LOW”.</li>
<li>expander.set()<br />
Ustawia na wszystkich pinach stan wysoki “HIGH”.</li>
</ul>
<pre>#include &lt;<span style="color: #cc6600;">PCF8574</span>.h&gt;
#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #cc6600;">PCF8574</span> expander;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{ 
  expander.<span style="color: #cc6600;">begin</span>(0x20);
  <span style="color: #cc6600;">for</span> (<span style="color: #cc6600;">byte</span> i=0; i&lt;8; i++)
    expander.<span style="color: #cc6600;">pinMode</span>(i, <span style="color: #006699;">OUTPUT</span>);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #cc6600;">byte</span> value = <span style="color: #cc6600;">random</span>(0, 255);

  expander.<span style="color: #cc6600;">write</span>(value);
  <span style="color: #cc6600;">delay</span>(100);
}</pre>
<p>Przykład ustawia wszystkie piny jako wyjścia i zmienia ich stan losowo.</p>
<h4 dir="ltr">Przerwania &#8211; układ elektryczny</h4>
<p dir="ltr">Układ PCF8574 na nodze 13 posiada sygnał /INT. Jest to sygnał przerwania, informujący Arduino, “że coś się dzieje”, bez potrzeby ciągłego sprawdzania stanu pinu układu. Sygnał ten wykorzystywany jest do tego, że gdy na pinie wejściowym pojawi się odpowiedni stan, sygnał /INT ustawia się w stan niski. Sygnał ten jest w standardzie “otwarty dren”. Oznacza to, że jego wyjście ma albo stan niski, albo nieustalony. Umożliwia to podłączenie do tego samego pinu Arduino wyjść przerwań z większej ilości układów PCF8574, gdyż nie następuje kolizja stanów logicznych.</p>
<p dir="ltr"><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/pcf8574_int.png"><img class="aligncenter size-full wp-image-871" title="pcf8574_int" src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/pcf8574_int.png" alt="" width="433" height="492" /></a>Sygnał przerwania /INT możesz podłączyć do dowolnego pinu cyfrowego Arduino. Ja wybrałem pin numer 2, do którego prowadzi niebieski przewód.</p>
<h4 dir="ltr">Przerwania &#8211; program podstawowy</h4>
<pre>#include &lt;<span style="color: #cc6600;">PCF8574</span>.h&gt;
#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #cc6600;">PCF8574</span> expander;

<span style="color: #cc6600;">void</span> onInterrupt()
{
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(<span style="color: #006699;">"Przerwanie"</span>);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(9600);

  expander.<span style="color: #cc6600;">begin</span>(0x20);

  expander.<span style="color: #cc6600;">pinMode</span>(4, <span style="color: #006699;">INPUT</span>);
  expander.pullUp(4);

  <span style="color: #cc6600;">pinMode</span>(2, <span style="color: #006699;">INPUT</span>);
  <span style="color: #cc6600;">digitalWrite</span>(2, <span style="color: #006699;">HIGH</span>);

  expander.enableInterrupt(2, onInterrupt);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
}</pre>
<p dir="ltr">W przykładzie ustawiłem pin 4 układu PCF8574 jako wejście i włączyłem mu domyślny stan wysoki (“pullUp”).</p>
<p dir="ltr">Następnie ustawiłem pin 2 Arduino na wejście. Ponieważ wyjście /INT może mieć albo stan niski, albo nieustalony, ustawiłem wejście pin 2 Arduino też jako “pullup” za pomocą “digitalWrite”.</p>
<p dir="ltr">Za pomocą metody “expander.enableInterrupt” wyberasz pin w Arduino do którego przyłączyłeś sygnał /INT układu (pierwszy argument) i rejestrujesz funkcję, która będzie automatycznie wywoływana po nastąpieniu przerwania (drugi argument). Ja zarejestrowałem funkcje o nazwie “onInterrupt”, która wysyła do komputera napis “Przerwanie”, gdy zostanie wywołana.</p>
<p dir="ltr">Po uruchomieniu programu, zmiana stanu pinu 4 układu (noga 9) na przeciwny niż domyślny, powoduje uruchomienie zarejestrowanej funkcji. Jak widzisz bez żadnego sprawdzania stanu pinów można dzięki przerwaniu automatycznie wywoływać funkcje. To rozwiązanie ma jedną wadę. Tą samą funkcję wywołuje dowolny pin wejściowy układu.</p>
<p dir="ltr">Powiązanie przerwania z funkcją można zlikwidować za pomocą funkcji “expander.disableInterrupt”, która nie ma żadnego argumentu.</p>
<h4 dir="ltr">Przerwania &#8211; program rozszerzony</h4>
<pre>#include &lt;<span style="color: #cc6600;">PCF8574</span>.h&gt;
#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #cc6600;">PCF8574</span> expander;

<span style="color: #cc6600;">void</span> onPin0()
{
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(<span style="color: #006699;">"Pin 0"</span>);
}

<span style="color: #cc6600;">void</span> onPin1()
{
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(<span style="color: #006699;">"Pin 1"</span>);
}

<span style="color: #cc6600;">void</span> onInterrupt()
{
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(<span style="color: #006699;">"Przerwanie"</span>);
  expander.checkForInterrupt();
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(9600);

  expander.<span style="color: #cc6600;">begin</span>(0x20);

  expander.<span style="color: #cc6600;">pinMode</span>(0, <span style="color: #006699;">INPUT</span>);
  expander.pullUp(0);
  expander.<span style="color: #cc6600;">pinMode</span>(1, <span style="color: #006699;">INPUT</span>);
  expander.pullUp(1);

  <span style="color: #cc6600;">pinMode</span>(2, <span style="color: #006699;">INPUT</span>);
  <span style="color: #cc6600;">digitalWrite</span>(2, <span style="color: #006699;">HIGH</span>);

  expander.enableInterrupt(2, onInterrupt);

  expander.<span style="color: #cc6600;">attachInterrupt</span>(0, onPin0, <span style="color: #006699;">FALLING</span>);
  expander.<span style="color: #cc6600;">attachInterrupt</span>(1, onPin1, <span style="color: #006699;">FALLING</span>);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
}</pre>
<p dir="ltr">Jeśli w funkcji obsługującej przerwanie (“onInterrupt”) umieścisz wywołanie metody “expander.checkForInterrupt”, biblioteka zdobędzie nowe możliwości.</p>
<p dir="ltr">Od tej chwili możesz używać metod “expander.attachInterrupt” do rejestrowania funkcji wywoływanych osobno dla każdego pinu układu PCF8574. Ułatwia to pisanie nowych programów.</p>
<p dir="ltr">Metoda “expander.attachInterrupt” ma 3 argumenty. Pierwszym z nich jest numer pinu wejściowego układu, do którego chcesz podłączyć swoją funkcję. Kolejny argument to nazwa funkcji, która chcesz podłączyć. Ostatnim jest rodzaj zdarzenia jaki ma wywoływać funkcję. Istnieją 4 rodzaje zdarzeń.</p>
<ul>
<li>
<p dir="ltr">CHANGE &#8211; wywołuje funkcje przy każdej zmianie stanu pinu</p>
</li>
<li>
<p dir="ltr">LOW &#8211; wywołuje funkcje jeśli pin układu ma stan niski</p>
</li>
<li>
<p dir="ltr">FALLING &#8211; wywołuje funkcję przy zmianie stanu z wysokiego na niski</p>
</li>
<li>
<p dir="ltr">RISING &#8211; wywołuje funkcje przy zmianie stanu z niskiego na wysoki</p>
</li>
</ul>
<p dir="ltr">W przykładzie ustawiłem piny 0 i 1 układu na wejścia o domyślnym stanie wysokim. Potem zarejestrowałem dla nich funkcje “OnPin0” i “OnPin1” wywoływane podczas zmiany stanu z wysokiego “HIGH” na niski “LOW” (“FALLING”).</p>
<p dir="ltr">Powiązanie pinu z funkcją można zlikwidować za pomocą funkcji “expander.detachInterrupt”. Jej jednym parametrem jest numer pinu układu.</p>
<h3 dir="ltr">Podłączenie większej ilości układów PCF8574</h3>
<h4 dir="ltr">Układ elektryczny</h4>
<p><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/pcf8574_dbl.png"><img class="aligncenter size-full wp-image-870" title="pcf8574_dbl" src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/pcf8574_dbl.png" alt="" width="443" height="506" /></a>Włączając w obwód dodatkowe układy PCF8574 należy połączyć ich linie sygnałowe i zasilania. SDA, łączysz z SDA pierwszego układu. SCL łączysz z SCL pierwszego układu. /INT łączysz z /INT pierwszego układu. To samo z zasilaniem. 5V łączysz z 5v, a GND z GND.</p>
<p dir="ltr">Nieco inaczej ma się sprawa z liniami adresowymi. Tu należy ustawić binarnie inny adres niż układu pierwszego. W przykładzie podłączyłem linię A0 do 5V &#8211; czyli wymusiłem na niej stan wysoki “HIGH”. A1 i A2 zostawiłem bez zmian, czyli podłączone do GND. Sprawia to, że adres drugiego układu zwiększył się o 1. Teraz pierwszy układ ma adres szesnastkowy 0&#215;20, a drugi 0&#215;21.</p>
<h4 dir="ltr">Programowanie</h4>
<pre>#include &lt;<span style="color: #cc6600;">PCF8574</span>.h&gt;
#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;

<span style="color: #cc6600;">PCF8574</span> expander1;
<span style="color: #cc6600;">PCF8574</span> expander2;

<span style="color: #cc6600;">void</span> onInterrupt()
{
  expander1.checkForInterrupt();
  expander2.checkForInterrupt();
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{

  expander1.<span style="color: #cc6600;">begin</span>(0x20);
  expander2.<span style="color: #cc6600;">begin</span>(0x21);

  <span style="color: #cc6600;">pinMode</span>(2, <span style="color: #006699;">INPUT</span>);
  <span style="color: #cc6600;">digitalWrite</span>(2, <span style="color: #006699;">HIGH</span>);

  expander1.enableInterrupt(2, onInterrupt);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
}</pre>
<p dir="ltr">Po dodaniu drugiego układu program też trzeba zmodyfikować. Teraz każdy układ reprezentują 2 niezależne obiekty &#8211; expander1 i expander2. Każdy z obiektów trzeba połączyć z innym układem przez adres danego układu. Zajmuje się tym metoda “begin” w funkcji “setup”. Jak ustaliłem na schemacie jeden układ ma adres 0&#215;20, a kolejny 0&#215;21. W funkcji “onInterrupt” trzeba rozdzielić metodę “checkForInterrupt” na 2 układy. Cała reszta programowania jest taka sama, z tym, że należy pamiętać który pin należy do którego układu i co za tym idzie do którego obiektu. Piny w obydwu układach liczone są od 0 do 7.</p>
<h3 dir="ltr">Inne rodzaje Arduino</h3>
<h4 dir="ltr">Arduino MEGA</h4>
<p><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/pcf8574_mega.png"><img class="aligncenter size-full wp-image-873" title="pcf8574_mega" src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/pcf8574_mega.png" alt="" width="489" height="528" /></a></p>
<p>W Arduino MEGA magistrala TWI wyprowadzona jest w nieco innym miejscu. Dlatego jeśli jesteś użytkownikiem tej płytki to musisz nieco zmodyfikować schemat połączeń. Sygnał SDA jest tam na pinie 20, a SCL na pinie 21 z grupy “COMMUNICATION”.</p>
<h4 dir="ltr">Arduino R3</h4>
<p dir="ltr">Nadchodzące wersje Arduino z serii R3 mają powiększoną ilość pinów. Powyższe schematy nie wymagają modyfikacji, jednak dla wygody użytkowników wyprowadzono tam sygnały TWI w dodatkowe miejsce. Znajdują się one w grupie “DIGITAL” na lewo od pinu “AREF”. Pierwszy z nich licząc od lewej to SCL, a następny to SDA.</p>
<p dir="ltr"><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/r3.png"><img class="aligncenter size-full wp-image-875" title="r3" src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/11/r3.png" alt="" width="578" height="471" /></a></p>
<div style="text-align: center;">Zdjęcie Arduino UNO R3 należy do zespołu Arduino (<a href="http://www.arduino.cc/">www.arduino.cc</a>). Zostało pobrane z <a href="http://arduino.cc/en/Main/ArduinoBoardUno">http://arduino.cc/en/Main/ArduinoBoardUno</a> i zmodyfikowane.</div>
<h3 dir="ltr">Zakończenie</h3>
<p dir="ltr">Teraz jeśli brak ci pinów masz już o jedno rozwiązanie więcej. Jest to rozwiązanie o tyle elastyczne, że bez problemu w razie potrzeb możesz dokładać i dokładać, aż do 128 pinów.</p>
<p dir="ltr">Zatem zapraszam do lutownicy i życzę nowych oraz ekscytujących projektów. No i nie zapomnij się nimi pochwalić.</p>
<h3 dir="ltr">Linki</h3>
<ul>
<li><a href="http://nettigo.pl/product/PCF8574P---8-portow-cyfrowych-po-I2C,pcf8574p">PCF8574 do kupienia na Nettigo</a></li>
<li><a href="http://skyduino.wordpress.com/librairies/librairie-arduino-pcf8574-pcf8575/">Strona projektu biblioteki PCF8574</a> [eng/fr]</li>
<li><a href="http://nettigo.pl/pub/files/Dokumenty/software/1322435581_PCF8574.zip">Plik biblioteki PCF8574 do pobrania z Nettigo</a></li>
<li><a href="http://www.nxp.com/documents/data_sheet/PCF8574.pdf">Nota katalogowa PCF8574</a> [pdf]</li>
<li><a href="http://pl.wikipedia.org/wiki/I%C2%B2C">Opis magistrali I2C</a> [wikipedia/pl]</li>
</ul>
</div>
</div>
<img src="http://feeds.feedburner.com/~r/StarterKit/~4/0wa-z8PWPCM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://starter-kit.nettigo.pl/2011/11/pcf8574-czyli-jak-latwo-zwiekszyc-liczbe-pinow-w-arduino/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
		<feedburner:origLink>http://starter-kit.nettigo.pl/2011/11/pcf8574-czyli-jak-latwo-zwiekszyc-liczbe-pinow-w-arduino/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=pcf8574-czyli-jak-latwo-zwiekszyc-liczbe-pinow-w-arduino</feedburner:origLink></item>
		<item>
		<title>Sygnalizator revisited czyli przyciski i debouncing</title>
		<link>http://feedproxy.google.com/~r/StarterKit/~3/v7lpBsy8fnI/</link>
		<comments>http://starter-kit.nettigo.pl/2011/09/sygnalizator-revisited-czyli-przyciski-i-debouncing/#comments</comments>
		<pubDate>Tue, 13 Sep 2011 06:02:15 +0000</pubDate>
		<dc:creator>netmaniac</dc:creator>
				<category><![CDATA[arduino]]></category>
		<category><![CDATA[dla początkujących]]></category>
		<category><![CDATA[bounce]]></category>
		<category><![CDATA[button]]></category>
		<category><![CDATA[debounce]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[podstawy]]></category>
		<category><![CDATA[starter-kit]]></category>
		<category><![CDATA[starter-kit-lite]]></category>

		<guid isPermaLink="false">http://starter-kit.nettigo.pl/?p=841</guid>
		<description><![CDATA[Dawno temu pisałem o tym jak można korzystać z przycisków (tactile switch, pushbutton) na przykładzie kartonowego sygnalizatora. Wróćmy do tematu, tym razem na poważniej zajmując się przyciskami. Jeśli spojrzycie na kod tamtego sygnalizatora, możecie dostrzec następującą pętlę loop: void loop() { &#160;&#160;val&#160;=&#160;digitalRead(buttonPin); &#160;&#160;if (val == HIGH &#38;&#38; prev == LOW) { &#160;&#160;&#160;&#160;next_status(); &#160;&#160;} &#160;&#160;prev&#160;=&#160;val; &#160;&#160;display_status(); [...]]]></description>
			<content:encoded><![CDATA[<p>Dawno temu pisałem o tym jak można korzystać z przycisków (tactile switch, pushbutton) na <a href="http://starter-kit.nettigo.pl/2009/06/sygnalizator-czyli-jak-wykorzystac-przycisk/">przykładzie kartonowego sygnalizatora</a>. Wróćmy do tematu, tym razem na poważniej zajmując się przyciskami.</p>
<p>Jeśli spojrzycie na kod tamtego sygnalizatora, możecie dostrzec następującą pętlę <code>loop</code>:</p>
<pre>
<span style="color: #CC6600;">void</span> <span style="color: #CC6600;"><b>loop</b></span>()
{
&nbsp;&nbsp;val&nbsp;=&nbsp;<span style="color: #CC6600;">digitalRead</span>(buttonPin);
&nbsp;&nbsp;<span style="color: #CC6600;">if</span> (val == <span style="color: #006699;">HIGH</span> &amp;&amp; prev == <span style="color: #006699;">LOW</span>) {
&nbsp;&nbsp;&nbsp;&nbsp;next_status();
&nbsp;&nbsp;}
&nbsp;&nbsp;prev&nbsp;=&nbsp;val;
&nbsp;&nbsp;display_status();
&nbsp;&nbsp;<span style="color: #CC6600;">delay</span>(50);

}
</pre>
<p>Wykrywanie naciśnięcia odbywa się przez porównanie bieżącej wartości wejścia cyfrowego z poprzednią. Jeżeli aktualna wartość to HIGH a poprzednia to LOW, to wykonujemy akcję <code>next_status()</code>, która zmienia stan sygnalizatora. I wszystko działa. Ale nie ma problemów, tylko dzięki ostatniej linii kodu w <code>loop</code>: <code>delay(50);</code>. </p>
<p>Przycisk jest urządzeniem mechanicznym i włączenie lub wyłączenie nie jest jednoznaczne, jeżeli będziemy stan przycisku badać dostatecznie często. W momencie dociskania/zwalniania przycisku jest taki moment, w którym styk <em>już łapie/puszcza</em> przez co włączenie wyłączenie nie jest czystym przełączeniem między LOW a HIGH tylko migotaniem. Angielska <a href="http://en.wikipedia.org/wiki/Debouncing#Contact_bounce" title="Contact bounce">Wikipedia przy haśle</a> <em>contact bounce</em> (bo tak się zjawisko to nazywa) ma ten piękny obrazek ilustrujący ten problem:<br />
<div id="attachment_842" class="wp-caption aligncenter" style="width: 310px"><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2011/09/bounce.jpg"><img src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/09/bounce-300x225.jpg" alt="Ilustracja migotania przełącznika (CC Wikipedia)" title="Ilustracja migotania przełącznika (CC Wikipedia)" width="300" height="225" class="size-medium wp-image-842" /></a><p class="wp-caption-text">Ilustracja migotania przełącznika (CC Wikipedia)</p></div></p>
<p>Opóźnienie w <code>loop</code> załatwia nam ten problem, bowiem jeżeli zauważymy zmianę stanu klawisza odczekanie 50 ms przed następnym odczytem zapewnia margines wykluczający błędny odczyt. Gdyby nie ono, wówczas w następnym przebiegach moglibyśmy odczytać migotanie jako kolejne przyciśnięcia. Rezultat? Z punktu widzenia użytkownika &#8211; on nacisnął przycisk jeden raz, a sygnalizator przeskoczył o 1 lub więcej stanów za jednym razem.</p>
<p>Rozwiązanie z użyciem delay nie zawsze jest dopuszczalne, bo może nasze Arduino musi robić coś więcej niż tylko czekać na naciśnięcie klawisza.</p>
<h2>Jak się zabezpieczyć przed złymi odczytami?</h2>
<p><span id="more-841"></span><br />
Najlepszą metodą jest zapamiętanie czasu w którym odczytaliśmy zmianę stanu klawisza i przez następne kilkanaście, kilkadziesiąt milisekund nie reagować na zmiany stanu wejścia. Ale wówczas kod znacznie się komplikuje, a taki jest znacznie bardziej podatny na błędy. Na szczęście jest gotowe rozwiązanie w postaci <a href="http://arduino.cc/playground/Code/Bounce" title="Bounce na Arduini Playground">biblioteki Bounce</a>.</p>
<p>Instalujemy bibliotekę w <code>sketchbook/libraries</code> i teraz możemy korzystać z dobrodziejstw klasy <code>Bounce</code>. Zamiast odczytywać wartość przez <code>digitalRead</code> i samemu starać się rozszyfrować co znaczy odczyt w zależności od poprzedniej wartości i czasu który upłynął od ostatniej zmiany, definiujemy obiekt w naszym szkicu:</p>
<pre>
<span style="color: #CC6600;">int</span> buttonPin = 4;
<span style="color: #CC6600;">Bounce</span> button(buttonPin,20);
</pre>
<p>Od teraz cyfrowe wejście nr 4 będzie obsługiwane przez Bounce, z 20-sto milisekundowym marginesem. W czasie 20 milisekund od wykrycia zmiany stanu wejścia jego następne zmiany będą ignorowane. Dopiero po upływie tego czasu obiekt może zmienić swój stan.</p>
<p>Pierwszym krokiem jest uaktualnienie stanu przycisku przez funkcję <code>update()</code>. To właśnie w tym momencie jest odczytywana wartość na wejściu:</p>
<pre>
&nbsp;&nbsp;button.<span style="color: #CC6600;">update</span>();
</pre>
<p><code>update</code> zwraca wartość true lub false &#8211; w zależności czy stan przycisku uległ zmianie czy jest taki jak poprzednio.</p>
<p>Po tej operacji możemy sprawdzić czy przycisk jest wciśnięty lub nie (<code>read()</code>) albo jeżeli interesuje nas tylko czy został właśnie wciśnięty lub zwolniony informacji dostarczy nam <code>risingEdge()</code> lub <code>fallingEdge()</code>. W wypadku sygnalizatora nas interesuje kiedy został wciśnięty klawisz:</p>
<pre>
&nbsp;&nbsp;<span style="color: #CC6600;">if</span> (button.<span style="color: #CC6600;">risingEdge</span>()) {
&nbsp;&nbsp;&nbsp;&nbsp;next_status();
&nbsp;&nbsp;};
</pre>
<p><code>next_status</code> zostanie wywołany tylko kiedy zostanie wykryta zmiana ze stanu LOW na HIGH. W następnym przebiegu, jeżeli przycisk jest nadal wciśnięty, <code>risingEdge()</code> już zwróci <code>false</code>.</p>
<p>Biblioteka ma sobie jeszcze kilka przydatnych funkcji, pozwalających określić jak długo już przycisk jest w aktualnym stanie, albo przydatnych do generowania wirtualnych &#8216;przyciśnięć&#8217; (to drugie świetnie się sprawdza do powtarzania akcji gdy przycisk jest ciągle wciśnięty).</p>
<p>To jeszcze nie koniec o sygnalizatorze, bo on nadal istnieje. Oczywiście kartonowy v1 został zastąpiony przez v2 ze <a href="http://allegro.pl/listing/search.php?sg=0&#038;string=spienione+pcw" title="Spienione PCW na Allegro">spienionego PCW</a>, które jest świetnym materiałem do budowy prostych konstrukcji. Sygnalizator dorobił się dodatku w postaci zapory napędzanej przez serwomechanizm, co widać też w kodzie. </p>
<p>O tym jak korzystać z serwomechanizmów na przykładzie zapory i tego szkicu postaram się napisać już niedługo.</p>
<p>Cały kod <a href="http://static.nettigo.pl/code/sygnalizator_v2.pde" title="Sygnalizator i zapora w jednym domu stali...">sygnalizatora v2</a>.</p>
<img src="http://feeds.feedburner.com/~r/StarterKit/~4/v7lpBsy8fnI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://starter-kit.nettigo.pl/2011/09/sygnalizator-revisited-czyli-przyciski-i-debouncing/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://starter-kit.nettigo.pl/2011/09/sygnalizator-revisited-czyli-przyciski-i-debouncing/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=sygnalizator-revisited-czyli-przyciski-i-debouncing</feedburner:origLink></item>
		<item>
		<title>Rezystor – co o nim trzeba wiedzieć</title>
		<link>http://feedproxy.google.com/~r/StarterKit/~3/rLy0nm2iZws/</link>
		<comments>http://starter-kit.nettigo.pl/2011/09/rezystor-co-o-nim-trzeba-wiedziec/#comments</comments>
		<pubDate>Mon, 05 Sep 2011 21:39:50 +0000</pubDate>
		<dc:creator>netmaniac</dc:creator>
				<category><![CDATA[dla początkujących]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[prawo ohma]]></category>
		<category><![CDATA[rezystory]]></category>
		<category><![CDATA[starter-kit]]></category>
		<category><![CDATA[starter-kit-lite]]></category>
		<category><![CDATA[teoria]]></category>
		<category><![CDATA[teoria obwodów]]></category>

		<guid isPermaLink="false">http://starter-kit.nettigo.pl/?p=822</guid>
		<description><![CDATA[Rezystory to jeden z podstawowych elementów wszystkich układów elektronicznych. Jako, że jest to element naprawdę podstawowy i powszechny, spróbujemy się o nim dowiedzieć kilku rzeczy. Teoria związana z przepływem prądów w układach RLC (R &#8211; rezystory, L &#8211; cewki, C &#8211; kondensatory) jest cała najeżona wzorami, których nie chcecie widzieć :) (a jeżeli ktoś musi [...]]]></description>
			<content:encoded><![CDATA[<p>Rezystory to jeden z podstawowych elementów wszystkich układów elektronicznych. Jako, że jest to element naprawdę podstawowy i powszechny, spróbujemy się o nim dowiedzieć kilku rzeczy.</p>
<p>Teoria związana z przepływem prądów w układach RLC (R &#8211; rezystory, L &#8211; cewki, C &#8211; kondensatory) jest cała najeżona wzorami, których nie chcecie widzieć :) (a jeżeli ktoś musi się przekonać to np <a title="Szereg Fouriera" href="http://zasoby1.open.agh.edu.pl/dydaktyka/automatyka/c_teoria_obwodow/szf.htm" target="_blank">zobaczcie to</a> i wrócicie zaraz tutaj :) ). </p>
<p>Teraz podam kilka uproszczeń, które wystarczą do zmierzenia się z użyciem rezystorów w kontekście Arduino.</p>
<p>Ważną cechą układów elektronicznych jest to, że jeżeli mamy jakieś napięcie w układzie (coś je wytwarza), to jeżeli obwód jest zamknięty (nie ma żadnej przerwy), napięcie to się odłoży na wszystkich elementach w taki sposób, że sumując napięcia na każdym elemencie z osobna otrzymamy napięcie z naszego źródła. Jest to zgodne z intuicyjnym rozumieniem &#8211; napięcie nie bierze się znikąd i nie może nigdzie znikać.</p>
<p><span id="more-822"></span></p>
<p>Druga ważna informacja, to <a title="Prawo Ohma" href="http://pl.wikipedia.org/wiki/Prawo_Ohma">prawo Ohma</a> &#8211; mówiące że napięcie (U) na danym elemencie jest proporcjonalne do prądu (I) przez niego płynącego, a jaka jest to konkretnie wartość mówi nam właśnie rezystancja (R):</p>
<div id="attachment_831" class="wp-caption aligncenter" style="width: 75px"><img class="size-full wp-image-831" title="Prawo Ohma" src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/09/prawo_ohma.png" alt="Prawo Ohma" width="65" height="14" /><p class="wp-caption-text">Prawo Ohma</p></div>
<p>Oczywiście dotyczy to elementów o charakterze rezystancyjnym &#8211; właśnie rezystorów, sprawa np z diodą jest inna.</p>
<p>Może podłączmy sobie dwa rezystory do baterii:</p>
<div id="attachment_823" class="wp-caption aligncenter" style="width: 510px"><img class="size-full wp-image-823" title="Prosty układ z dwoma rezystorami" src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/09/zrodlo2rezystory.jpg" alt="Prosty układ z dwoma rezystorami" width="500" height="300" /><p class="wp-caption-text">Prosty układ z dwoma rezystorami</p></div>
<p>Zgodnie z tym co właśnie napisaliśmy napięcia U<sub>1</sub> i U<sub>2</sub> zsumowane dadzą napięcie równe napięciu baterii. Jeżeli bateria daje 5V to napięcia U<sub>1</sub> i U<sub>2</sub> po dodaniu wyniosą 5V.</p>
<p><strong>Ważne</strong> &#8211; jest to połączenie szeregowe, czyli mówiąc po ludzku &#8211; rezystory są łączone po kolei. W takim wypadku rezystancja całego układu dwóch rezystorów jest sumą ich rezystancji. </p>
<p>W teorii układów RLC jest kilka twierdzeń, które w wielkim uproszczeniu można zastąpić zdaniem, że <em>z punktu widzenia baterii</em> jest obojętne czy podłączymy jeden rezystor 10k czy 2 rezystory 5k połączone szeregowo &#8211; prąd płynący w takim układzie będzie taki sam. </p>
<p>Inaczej &#8211; dowolny układ rezystorów możemy zastąpić jednym o rezystancji będącej wypadkową rezystancji składowych przeliczonych w zależności od tego jak połączone są te rezystory (jak dotąd była mowa o połączeniu szeregowym, może być jeszcze równoległe i wszelkie kombinacje tych dwóch)</p>
<p>Kolejną intuicyjnie rozumianą rzeczą jest, że prąd płynący przez elementy w połączeniu szeregowym jest taki sam w każdym elemencie.</p>
<p>Przypomnijmy sobie prawo Ohma &#8211; jeżeli przyłożymy napięcie z baterii wówczas przez oba rezystory popłynie jednakowy prąd równy napięcie baterii/sumaryczna rezystancja. Skoro prąd jest taki sam w obu rezystorach to napięcie na każdym z nich będzie wynosić rezystancja tego jednego rezystora * prąd.</p>
<p>Na przykład weźmy układ dwóch rezystorów połączonych szeregowo o sumarycznej rezystancji 10 Ohm. Podłączmy je do baterii 20V &#8211; prąd płynący przez rezystory (wyliczony z prawa Ohma) to 2A &#8211; bo 20V/10Ohm = 2A. Teraz jeżeli są to dwa rezystory po 5 Ohm (suma rezystancji wynosi 10 Ohm), prąd nadal jest 2A. Napięcie na każdym z rezystorów to 5 Ohm * 2 A = 10V. W sumie &#8211; 20V, czyli wszystko się zgadza.</p>
<p>Jeżeli jednak weźmiemy rezystor o różnych wartościach &#8211; na przykład 1 Ohm i 9 Ohm (suma nadal 10 Ohm) to mamy na pierwszym 1 Ohm * 2A = 2V a na drugim &#8211; 9 Ohm * 2A = 18V. Suma napięć &#8211; nadal 20V, czyli tyle ile daje nasza bateria. Ale w tym wypadku rozkład napięć U<sub>1</sub> U<sub>2</sub> jest zupełnie inny. Powiedzmy że na naszym schemacie górny rezystor to 1 Ohm a dolny to 9 Ohm. Napięcie na górnym rezystorze to 2V, na dolnym 18V.</p>
<p>Mierząc napięcie między minusem baterii (tutaj jest to tak zwana masa) a punktem pomiędzy rezystorami otrzymamy 18V &#8211; 90% wartości napięcia baterii. 9 Ohm stanowi 90% sumarycznej rezystancji układu. Zmieniając proporcje rezystancji, w tym punkcie otrzymamy odpowiednio zmienione napięcie. Gdy dolny rezystor będzie stanowił 30% sumarycznej rezystancji obu rezystorów, napięcie w punkcie pomiędzy rezystorami będzie wynosiło 30% napięcia baterii. Widzicie zależność? Właśnie poznaliście zasadę działania dzielnika napięcia, bo tak taki układ rezystorów się nazywa.</p>
<p>W rzeczywistym zastosowaniu trzeba pamiętać o jednym &#8211; nie możemy pobierać (dużo) prądu z punktu pomiaru pomiędzy rezystorami. Bo powyższe rozumowanie zakładało, że przez oba rezystory płynie równy prąd, prawda? Czyli nadaje się to uzyskania jakiegoś napięcia odniesienia, ale nie bardzo aby uzyskać napięcie zasilające.</p>
<h3>Do czego jeszcze może się nam przydać rezystor?</h3>
<p>Kolejnym podstawowym zastosowaniem oporników (jak też są nazywane rezystory) jest ograniczanie (czy raczej wymuszanie) wartości prądu w gałęzi układu. Jeżeli wiemy jakie napięcie zostanie odłożone na oporniku to dobierając odpowiednią wartość rezystancji możemy określić jaki prąd będzie płynął w gałęzi. Jeżeli wiemy, że na rezystorze będzie napięcie 1.7V to jeżeli użyjemy rezystora 220 Ohm, prąd płynący w gałęzi będzie wynosił 1.7/220 = 7.73 mA. Wartość tę wyliczyliśmy dzięki przekształceniu prawa Ohma &#8211; zależność prądu od napięcia i rezystancji: </p>
<div id="attachment_833" class="wp-caption aligncenter" style="width: 64px"><img src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/09/prawo_ohma2.png" alt="Inny zapis prawa Ohma" title="Inny zapis prawa Ohma" width="54" height="41" class="size-full wp-image-833" /><p class="wp-caption-text">Inny zapis prawa Ohma</p></div>
<p>Ma to zastosowanie np przy podłączaniu diod LED, ale bardziej szczegółowo o tym wkrótce.</p>
<img src="http://feeds.feedburner.com/~r/StarterKit/~4/rLy0nm2iZws" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://starter-kit.nettigo.pl/2011/09/rezystor-co-o-nim-trzeba-wiedziec/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://starter-kit.nettigo.pl/2011/09/rezystor-co-o-nim-trzeba-wiedziec/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=rezystor-co-o-nim-trzeba-wiedziec</feedburner:origLink></item>
		<item>
		<title>Gameduino – czyli zróbmy fajną grę</title>
		<link>http://feedproxy.google.com/~r/StarterKit/~3/KGWiVzwjqS0/</link>
		<comments>http://starter-kit.nettigo.pl/2011/08/gameduino-czyli-zrobmy-fajna-gre/#comments</comments>
		<pubDate>Mon, 01 Aug 2011 22:50:15 +0000</pubDate>
		<dc:creator>netmaniac</dc:creator>
				<category><![CDATA[arduino]]></category>
		<category><![CDATA[projekty]]></category>
		<category><![CDATA[dla początkujących]]></category>
		<category><![CDATA[fun]]></category>
		<category><![CDATA[gameduino]]></category>
		<category><![CDATA[games]]></category>
		<category><![CDATA[gry]]></category>

		<guid isPermaLink="false">http://starter-kit.nettigo.pl/?p=800</guid>
		<description><![CDATA[W zasadzie od momentu kiedy w ofercie Nettigo pojawił się pierwszy czujnik przyspieszenia miałem ochotę zrobić pewien hack i wykorzystać go jako główny czujnik do jakiegoś urządzenia sterującego. Myślałem o grze sportowej i podłączeniu czujnika do komputera. Ale, czasu ciągle brakowało, a przynajmniej odnosiłem wrażenie, że hack będzie długi i skomplikowany. Odczyt z czujnika przetworzyć [...]]]></description>
			<content:encoded><![CDATA[<p>W zasadzie od momentu kiedy w <a href="http://nettigo.pl/product/Trojosiowy-analogowy-czujnik-przyspieszenia,accel-3-axis" title="Czujnik przyspieszenia">ofercie Nettigo pojawił się pierwszy czujnik przyspieszenia</a> miałem ochotę zrobić pewien hack i wykorzystać go jako główny czujnik do jakiegoś urządzenia sterującego. Myślałem o grze sportowej i podłączeniu czujnika do komputera. Ale, czasu ciągle brakowało, a przynajmniej odnosiłem wrażenie, że hack będzie długi i skomplikowany. Odczyt z czujnika przetworzyć na ciąg wciśnięć klawiszy w komputerze. Arduino, serial, jakaś biblioteka odczytująca serial, potem emulacja wciśnięcia klawisza. Może to wszystko okaże się prostsze niż wygląda, ale sprawiało wrażenie dużej liczby <em>ruchomych części</em>, a co za tym idzie większą szansę niepowodzenia. No cóż, po prostu nie chciało mi się :)</p>
<p>Gdy pojawiło się Arduino UNO, przez chwilę pojawiła się chęć przetestowania <a href="http://arduino.cc/forum/index.php?topic=56025.0" title="Keyboard HID">klawiaturowego firmware dla ATmega8u2</a> w ramach tego właśnie hacku, ale projekt nie wystartował. Co UNO zmieniało? Otóż z nowym firmware, podłączone do komputera widziane jest jako klawiatura więc odpada cała komplikacja z odczytem seriala i wysyłania komunikatów do gry. Po prostu Arduino może &#8216;wciskać klawisze&#8217; przez port USB i całość wydaje się znacznie prostsza.</p>
<p>Ale gdy tylko zobaczyłem <a href="http://nettigo.pl/product/Gameduino---Arduino-staje-sie-platforma-do-gier,gameduino" title="Gameduino">Gameduino</a> wiedziałem że to jest to czego potrzebowałem. Ostatnie dni deszczowe były, tak więc &#8211; do dzieła!</p>
<p><span id="more-800"></span></p>
<p>Najpierw &#8211; jedno z dem dołączonych do biblioteki to Asteroids &#8211; lecisz statkiem przez pole asteroidów i strzelasz do nich. Proste. Rozpakować bibliotekę do <code>sketchbook/libraries</code>, uruchomić Arduino IDE, menu File/Examples/Gameduino/Demos/asteroids. Kompilacja, upload i mamy. Tyle, że nie mamy żadnego kontrolera do sterowania statkiem. Ja do pierwszych testów użyłem <a href="http://nettigo.pl/product/Nettigo-Keypad---odczyt-przez-wejscie-analogowe,keypad" title="Nettigo Keypad">Nettigo Keypada</a>, bo go pod ręką miałem. </p>
<p>Wystarczy zmienić kod w <code>controller_sense</code> i zamiast domyślnego kodu przeznaczonego dla game controllera od SparkFun użyć swojego. Ale to mało pasjonujące naciskać na klawisze, byle konsola to ma :)</p>
<h3>Czas na Level 2</h3>
<p>Podłączyć czujnik przyspieszenia i zrobić jakąś platformę, na której stojąc będzie się sterować statkiem. Przechył w lewo &#8211; obrót w lewo. Przechył w prawo &#8211; obrót w prawo. Przechył do przodu &#8211; lecimy. W tył &#8211; strzelamy. Taki Segway. No może bez tego strzelania :)</p>
<p>Pierwsza rzecz jak zrobić samą platformę? Miałem pod ręką kawałek panela podłogowego. Do niego przyklejona <a href="http://nettigo.pl/product/Plytka-stykowa---mini-170,BB-170" title="Płytka stykowa 170 otworów">płytka stykowa 170</a> (dzięki swojej taśmie samoprzylepnej). Na niej czujnik przyspieszenia, kabelki zgodnie z opisem w <a href="http://starter-kit.nettigo.pl/2009/12/czujnik-przyspieszenia/" title="Dokumentacja czujnika przyspieszenia">dokumentacji czujnika</a> i możemy ustalić położenie panela. Interesują nas dwie osie &#8211; X i Y, Z na razie nam niepotrzebne :)</p>
<div id="attachment_804" class="wp-caption aligncenter" style="width: 310px"><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2011/08/plytka.jpg"><img src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/08/plytka-300x225.jpg" alt="Czujnik przyspieszenia na płytce stykowej" title="Czujnik przyspieszenia na płytce stykowej" width="300" height="225" class="size-medium wp-image-804" /></a><p class="wp-caption-text">Czujnik przyspieszenia na płytce stykowej</p></div>
<p>Pozostaje teraz rozwiązać konstrukcję modułu wychylnego. Musi to być  coś co pozwoli naszemu panelowi kiwać się na wszystkie strony, jednocześnie nie za bardzo, tak aby gracz nie spadał z niego. Po wielu testach różnych materiałów i różnych rozwiązań mocowań konsultowanych z NASA  nasze finalne rozwiązanie wygląda tak:</p>
<div id="attachment_807" class="wp-caption aligncenter" style="width: 310px"><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2011/08/calosc.jpg"><img src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/08/calosc-300x225.jpg" alt="Źródło: NASA (just joking)" title="Źródło: NASA (just joking)" width="300" height="225" class="size-medium wp-image-807" /></a><p class="wp-caption-text">Źródło: NASA (just joking)</p></div>
<p>Jak widać wybór padł na starą poduszkę :) Panel położony na niej ma dość swobody aby poruszać się w dwóch osiach na tyle aby czujnik mógł odczytać położenie.</p>
<h3>Hard za nami, teraz soft</h3>
<p>Teraz trochę kodu, czyli w zasadzie jedyna zmiana w kodzie dema, to nowa funkcja <code>controller_sense</code>:</p>
<pre>
#define&nbsp;LR_NEUTRAL&nbsp;330
#define&nbsp;UD_NEUTRAL&nbsp;345

#define&nbsp;LR_DELTA&nbsp;8
#define&nbsp;UD_DELTA&nbsp;7
<span style="color: #CC6600;">static</span> <span style="color: #CC6600;">byte</span> controller_sense(uint16_t clock)
{
<span style="color: #CC6600;">int</span> rd,a1,a2;

rd&nbsp;=&nbsp;0;
a1&nbsp;=&nbsp;<span style="color: #CC6600;">analogRead</span>(3);
a2&nbsp;=&nbsp;<span style="color: #CC6600;">analogRead</span>(4);

&nbsp;&nbsp;<span style="color: #CC6600;">if</span> (a1 &lt; LR_NEUTRAL - LR_DELTA){
<span style="color: #7E7E7E;">//&nbsp;&nbsp;&nbsp;&nbsp;Serial.println("Lewo");</span>
&nbsp;&nbsp;&nbsp;&nbsp;rd&nbsp;=&nbsp;rd&nbsp;|&nbsp;CONTROL_LEFT;
&nbsp;&nbsp;}&nbsp;&nbsp;
&nbsp;&nbsp;<span style="color: #CC6600;">else</span> <span style="color: #CC6600;">if</span> (a1 &gt; LR_NEUTRAL + LR_DELTA)
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;rd&nbsp;=&nbsp;rd&nbsp;|&nbsp;CONTROL_RIGHT;
<span style="color: #7E7E7E;">//&nbsp;&nbsp;&nbsp;&nbsp;Serial.println("Prawo");</span>
&nbsp;&nbsp;}
&nbsp;&nbsp;<span style="color: #CC6600;">if</span> (a2 &lt; UD_NEUTRAL - UD_DELTA){
&nbsp;&nbsp;&nbsp;&nbsp;rd&nbsp;=&nbsp;rd&nbsp;|&nbsp;CONTROL_DOWN;
<span style="color: #7E7E7E;">//&nbsp;&nbsp;&nbsp;&nbsp;Serial.println("Jazda");</span>
&nbsp;&nbsp;}&nbsp;&nbsp;
&nbsp;&nbsp;<span style="color: #CC6600;">else</span> <span style="color: #CC6600;">if</span> (a2 &gt; UD_NEUTRAL + UD_DELTA)
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;rd&nbsp;=&nbsp;rd&nbsp;|&nbsp;CONTROL_UP;
<span style="color: #7E7E7E;">//&nbsp;&nbsp;&nbsp;&nbsp;Serial.println("Ognia");</span>
&nbsp;&nbsp;}
&nbsp;&nbsp;<span style="color: #CC6600;">return</span> rd;
</pre>
<p>Teraz kilka słów wyjaśnienia. <code>LR_NEUTRAL</code> to wartość jaka jest odczytywana w osi X w pozycji neutralnej. LR jest od Left Right, bo przechył w osi X w naszym ułożeniu czujnika oznacza przechył w lewo/prawo. LR_DELTA to jest margines o jaki może się w każdą stronę zmienić odczyt od pozycji neutralnej zanim zostanie uznany za <em>wciśnięcie</em> lewo lub prawo.</p>
<p>Podobnie jest z UD (od up i down). Oznaczenia te pochodzą od oznaczeń używanych w kodzie dema, nie od kierunku ruchu panela :)</p>
<p><code>rd</code> jest na początku ustawiane na zero i jeżeli wychył od pozycji neutralnej jest dostatecznie duży odpowiednia wartość CONTROL_ jest <em>ORowana</em>. O co chodzi? Jeśli spojrzeć na definicję wartości CONTROL_ :</p>
<pre>
#define&nbsp;CONTROL_LEFT&nbsp;&nbsp;1
#define&nbsp;CONTROL_RIGHT&nbsp;2
#define&nbsp;CONTROL_UP&nbsp;&nbsp;&nbsp;&nbsp;4
#define&nbsp;CONTROL_DOWN&nbsp;&nbsp;8
</pre>
<p>są to kolejne potęgi 2. W zapisie binarnym odpowiada to kolejnym bitom. 1 to 0001, 2 to 0010, 4 to 0100, itd. Logiczne OR dwóch liczb (w C to symbol tzw pałki | ) zwraca wartość gdzie bity są ustawione na 1 wszędzie tam gdzie choć w jednej z liczb była jedynka. Na przykład:</p>
<ul>
<li>0000 OR 0001 = 0001</li>
<li>0000 OR 0010 = 0010</li>
<li>0100 OR 0010 = 0110</li>
<li>0100 OR 0100 = 0100</li>
</ul>
<p>W ten sposób wiedząc że 1 na ostatnim bicie to CONTROL_LEFT a 1 na pierwszym to CONTROL_DOWN, można w jednej liczbie całkowitej przekazać informację, że wciśnięte zostały dwa klawisze jednocześnie: 1001 czyli 9 dziesiętnie. Bardzo często stosowana metoda przekazywania stanu różnych rzeczy przez jedną liczbę całkowitą. </p>
<p>A jak potem łatwo można odczytać czy bit jest ustawiony? Ano z wykorzystaniem AND (znak &amp;):</p>
<ul>
<li>1001 AND 1000 = 1000</li>
<li>1001 AND 0100 = 0000</li>
<li>1001 AND 0010 = 0000</li>
<li>1001 AND 0001 = 0001</li>
</ul>
<p>Teraz już chyba jest jasne w jaki sposób przez <code>rd</code> jest zwracana informacja o równocześnie naciśniętych przyciskach.</p>
<p>Co do naszego czujnika &#8211; wartości _NEUTRAL oraz _DELTA zostały dobrane eksperymentalnie &#8211; obserwując odczyty z czujnika, które na ten czas wysyłane były na Serial. Po ich ustaleniu komendy <code>Serial.print</code> zostały usunięte, bo zajmują cenne takty procesora ;)</p>
<p>Jak to wychodzi w praktyce można zobaczyć na tym krótkim filmiku (nie wiem jak go odwrócić, aparat było mi wygodniej trzymać w pionie):<br />
<iframe width="500" height="405" src="http://www.youtube.com/embed/ofRrzhCCifE" frameborder="0" allowfullscreen></iframe></p>
<p>Ze względu na dynamikę całości :) niezbędne jest osłonięcie czujnika aby zabezpieczyć przed przypadkowym zgnieceniem:</p>
<div id="attachment_803" class="wp-caption aligncenter" style="width: 310px"><a href="http://starter-kit.nettigo.pl/wp-content/uploads/2011/08/obudowa.jpg"><img src="http://starter-kit.nettigo.pl/wp-content/uploads/2011/08/obudowa-300x225.jpg" alt="W obudowie" title="W obudowie" width="300" height="225" class="size-medium wp-image-803" /></a><p class="wp-caption-text">W obudowie</p></div>
<h3>Raport Millera &#8211; czyli co można poprawić</h3>
<p>Położenie neutralne zmienia się nieco (tzn odczyt z czujnika), w zależności od zasilania Arduino (np mój notebook zamiast 5V na USB ma 4.9, co przy niewielkich zmianach napięcia na wyjściu czujnika może mieć znaczenie &#8211; punkt odniesienia się zmienia to i odczyt zwracany przez <code>analogRead</code> się zmienia). Również z czasem czujnik może minimalnie zmienić odczyt. Wówczas zostaje ręczna zmiana wartości w kodzie, kompilacja i wgranie do Arduino.</p>
<p>Lepszym rozwiązaniem byłaby kalibracja &#8211; otóż specjalny tryb, zamiast grania wyświetli polecenie: <em>Wychyl się w lewo</em>. Potem odczytuje wartość z czujnika. Następnie <em>Wychyl się w prawo</em> i znowu. W ten sposób szkic jest sam w stanie wyznaczyć sobie wartości _NEUTRAL i _DELTA.</p>
<p>Druga uwaga &#8211; dynamika gry jest duża i chyba taki kontroler byłby lepszy dla jakiejś sportowej niż strzelanki. Ale to już lepiej byłoby jednak użyć klawiaturowego firmware i komputera, może innym razem&#8230;</p>
<img src="http://feeds.feedburner.com/~r/StarterKit/~4/KGWiVzwjqS0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://starter-kit.nettigo.pl/2011/08/gameduino-czyli-zrobmy-fajna-gre/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://starter-kit.nettigo.pl/2011/08/gameduino-czyli-zrobmy-fajna-gre/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=gameduino-czyli-zrobmy-fajna-gre</feedburner:origLink></item>
	</channel>
</rss>

