Wstęp
Co trzeba wiedzieć?
Układ nawet autonomicznie daje dużo ciekawych możliwości, ale jeszcze lepiej wypada w kooperacji! W skrócie rzecz ujmując zamierzam przybliżyć sposób na to, jak wydawać komendy dla Attiny poprzez I2C(TWI)(na przykład z poziomu Arduino)
Do dalszej pracy będziesz potrzebować tej biblioteki. W zamian za klilkaset bajtów pamięci oferuje ona możliwość konfiguracji urządzenia jako I2C(TWI) Slave. Dodam, że banalnie prostej konfiguracji, bo jedyne co tak naprawdę musisz zrobić, to podać wybrany przez Siebie adres! Jeśli jeszcze nie wiesz co to I2C, to po krótce tłumaczę, że jest to bardzo rozpowszechniony standard wymiany danych pomiędzy różnymi urządzeniami. Mówiąc językiem laika jest to medium do prowadzenia rozmów pomiędzy różnymi częściami elektronicznymi. Ale po kolei. Najpierw biblioteka. Folder „TinyWireS” umieść w folderze libraries swojego Arduino IDE. U mnie to: C:\Program Files (x86)\arduino-1.0.4\libraries. Żeby uzmysłowić możliwości tego rozwiązania, pokażę Ci dwa programy. Jeden do Attiny, drugi do Arduino Uno.
Ogólna zasada działania: Najpierw Arduino będzie wysyłało numery Pinów, których stan ma być zmieniony. To spowoduje włączanie i wyłączanie kolejnych diod podłączonych do Attiny. Potem Arduino wyśle numer 30, który spowoduje, że Attiny samo włączy i wyłączy po kolei wszystkie diody bez udziału Arduino.
Przykład realizowany jest na Attiny2313, ale bez większych modyfikacji można go zrealizować również na Attiny4313 Trzeba jedynie pamiętać, aby wybrać odpowiednią płytkę w Arduino IDE
Program dla Attiny
Ogólna konstrukcja kodu na Attiny powinna wyglądać mniej więcej tak:
#include "TinyWireS.h"
void setup () {
TinyWireS.begin(##numer_urządzenia##);
}
void loop () {
if (TinyWireS.available()){
temp = TinyWireS.receive();
/*część kodu rozpatrująca co z tym tempem zrobić */
}
}
I konkretny przykład:
#include "TinyWireS.h"
byte temp = 0;
boolean diodki[16];
/* Zmienne, które będą potrzebne do zrealizowania przykładu:
temp - do którego będzie zapisywany aktualnie przechwycony
bajt
diodki - tu są przetrzymywane informacje o stanie
poszczególnych pinów (1- wysoki, 0-niski) Include to
oczywiście nowa biblioteka, którą testujemy */
void setup () {
TinyWireS.begin(0x16); // W tym miejscu inicjalizujemy
//TWI i podajemy adres urządzenia. Ja wybrałem 0x16
for (int i = 0; i < 16 ; i++){
diodki[i] = 0;
pinMode(i, OUTPUT);
digitalWrite (i, LOW);
}
}
void loop () {
if (TinyWireS.available()){
temp = TinyWireS.receive();
/*Te dwie linijki powyżej to w zasadzie najważniejszy punkt
całego przykładu. Funkcja TinyWireS.available() zwraca ilość
bajtów czekających w buforze. Czyli jeśli nic nie wysyłaliśmy
do Attiny, to zwraca zero, a jeśli coś wysłaliśmy, to zwraca
ile tego czeka. Jeśli mamy oczekujące dane, to za pomocą
funkcji TinyWireS.receive() "wyciągamy" dane z bufora i
zapisujemy je w zmiennej temp. Każde użycie TinyWireS.receive(),
to zapisanie do zmiennej jednego bajtu. (tego, który przyszedł
najwcześniej) */
// Wolne przejscie sterowane przez Arduino Master
if (temp < 16){
diodki[temp] = ~diodki[temp];
digitalWrite(temp, diodki[temp]);
delay(20);
}
else {
// Szybkie przejscie sterowane tylko przez Attiny
for (int i = 0; i < 16; i++){
digitalWrite(i, ~diodki[i]);
delay(300);
digitalWrite(i, diodki[i]);
delay(300);
}
}
}
}
Śmiało możesz go skopiować do Arduino IDE i załadować na Attiny2313 lub 4313.
Program dla Arduino
Potrzebujemy jeszcze kodu, który załadujemy do Arduino, żeby działało jako Master i wysyłało do Attiny odpowiednie komendy.
#include <Wire.h>
void setup()
{
Wire.begin();
}
void loop()
{
for (int i = 0; i < 16; i++){
Wire.beginTransmission(0x16);
Wire.write(i);
Wire.endTransmission();
delay(1000);
Wire.beginTransmission(0x16);
Wire.write(i);
Wire.endTransmission();
delay(1000);
}
Wire.beginTransmission(0x16);
Wire.write(30);
Wire.endTransmission();
delay(10000);
}
Program najpierw wysyła przez TWI kolejne liczby od 1 do 16. Każda liczba wysyłana jest po dwa razy, gdyż każdorazowe otrzymanie jej przez Attiny oznacza zmianę stanu pinu, na jaki wskazuje wysyłana liczba. Czyli za pierwszym razem pin jest włączany, za drugim razem wyłączany.
Na koniec Arduino wysyła liczbę 30, która jest sygnałem dla Attiny, żeby samodzielnie zaczęło zapalać i gasić po kolei wszystkie piny.
Podłączenie układów
W tym miejscu warto dodać krótkie objaśnienie. Diody wpinamy krótką nóżką w niebieską szynę „-” a długą nóżką do pinu Attiny. Rezystory dałem 2k2, ale mogą być różne. Nie chodzi o uzyskanie super jasności, tylko zrozumienie mechanizmów. Dodam również, że można podłaczyć SPI i I2C na raz.
Co warto wiedzieć.
Warto zwrócić tu uwagę na kilka rzeczy (Łatwiej będzie Ci je dostrzec, jeśli teraz siądziesz i zbudujesz zaprezentowany układ):
- Po pierwsze funkcja write() wcale nie wysyła danych. Ustawia je tylko w kolejce do wysłania! Dopiero funkcja endTransmission() powoduje wysłanie danych przez I2C. Łatwo można to sprawdzić pozbywając się niektórych begin i end transmission.
-Po drugie co się stanie, jeśli wyślemy informację do naszego Attiny w trakcie, gdy używamy na nim funkcji delay()? Warto to sprawdzić zmniejszając czas trwania ostatniego delay() w programie Arduino do wartości 1000; Wtedy zaobserwujemy najpierw powolne przejście, potem szybkie, a potem coś nietypowego. Pierwsze 4 diody zamrugają tylko na chwilę a pozostałe będą normalnie robiły wolne przejście. To znaczy, że dane musiały być odbierane mimo tego, że na naszym Attiny trwał delay. Gromadziły się one pewnie w buforze (domyślnie o rozmiarze 32 bajtów) a następnie zostały uwolnione wszystkie na raz (stąd ta błyskawiczna falka czterech pierwszych diod). Tak naprawdę najlepiej jest unikać stosowania funkcji delay(), szczególnie przy korzystaniu z biblioteki TinyWireS, gdyż w pewnych sytuacjach może to zaburzyć cały proces komunikacji. Jako alternatywę autor biblioteki wprowadził funkcję tws_delay(). - Po trzecie nie można podłączać diod pod piny należące do I2C (choć jak pokazuje przykład można bez większych konsekwencji chwilowo zmienić ich stan. Również jest to niezalecane, ale upraszcza to przykład)
- Rozmiar pliku ładowanego do Attiny to ponad 1500 Bajtów!! na szczęście da się to zmniejszyć, ale o tym w przyszłości.
- Adres I2C urządzenia slave jest 7-mio bitowy. To znaczy, że maksymalny numer, jaki można tam wprowadzić, to 127 (0x7F)
- Jeśli podłączasz więcej niż jedno urządzenie I2C, upewnij się, że nie będzie dwóch takich samych adresów.
- W wypadku niektórych urządzeń może wystąpić konieczność dodania rezystorów pull-up (lub gdy podłączasz więcej urządzeń) do linii SDA i SCL. Polega to na tym, że umieszczasz po jednym rezystorze 4k7 lub większym pomiędzy +5V a liniami SDA i SCL.
Ten przykład pokazuje jedynie najprostszą, jednostronną komunikację, która często jest w zupełności wystarczająca.
Powinno teraz paść ważne pytanie: Po co mi to?:
- Mogę przecież podłączyć diody bezpośrednio do pinów Arduino! - Zgadzam się, ale co, jeśli będziesz potrzebował podłączyć coś jeszcze? Arduino nie ma wbrew pozorom aż tak wielu pinów.
- Mogę też zastosować PCF8574 i poprzez TWI sterować ośmioma portami. Dwa takie układy i mam odpowiednik Attiny. Jak najbardziej! Jednak cały kod odpowiadający za mryganie musi być na Arduino. Wszystkie te delay() opóźniają wykonywanie całego kodu, a nie tylko mrygania.
- Taki sam efekt można uzyskać używając Multipleksera np CD74HC4067 Zgadzam się! Powiem więcej, konstrukcja z jego użyciem będzie niezastąpiona, jeśli będziesz chciał skorzystać z dobrodziejstw pinów analogowych na Twoim Arduino. Jednak ten układ działa przez SPI, który potrzebuje 4-ech pinów sterujących. (No i wciąż cały kod jest trzymany na Arduino)
Moim celem nie było dowiedzenie, że to rozwiązanie jest najlepsze. Po prostu sprawdza się lepiej w niektórych przypadkach i na nich właśnie się skupiam. Nie ukrywam, że często szybciej i łatwiej jest zastosować prosty układ multipleksera, czy portu.
Podsumowując kiedy warto sięgnąć po Attiny?:
- Jeśli chcemy utworzyć całą sekwencję „mrygnięć” a zależy nam na czasie wykonania głównego programu na Arduino (jednym bajtem wysłanym przez I2C włączamy całą sekwencję) Np. Animacja zajętości.
- Z powodu chwilowego braku dostępności alternatywnych części (ja tak zacząłem)
- Kiedy chcemy się rozwijać i testować nowe możliwości i rozwiązania. (czyt. kiedy nuda dopada)
Przy realizacji tego przykładu warto zaopatrzyć się w Starter Kit. Ma on diody, rezystory, kabelki i wiele innych przydatnych elementów, które w przyszłości wykorzystamy.
Pamiętaj, że to nie koniec możliwości Attiny... To dopiero początek!