Skocz do zawartości

Led Cube(4x4x4) sterowany ze smartphona


FRSH0109

Pomocna odpowiedź

Siemka, pokaże wam dziś jak zrobić dość efektowną, zdalnie sterowaną z poziomu telefonu zabwakę 🙂

Dokładniej jest to Led Cube (4x4x4), sam trafiłem na takie cudo przypadkiem w internecie i zrobiło na mnie to spore pierwsze wrażenie. Ale jako że każdy woli majsterkować  po swojemu to tak i ja stwierdziłem że go trochę "podrasuje".

Jest to klasyczny Led Cube 4x4x4 którym kieruje w moim przypadku Arduino Pro mini, wszystko sterowane jest prosto ze smartphona za pomocą własnej aplikacji oraz modułu Bluetooth HC-05 (którą również pokaże jak w bardzo łatwy sposób stworzyć).Z powodu ograniczonej liczby pinów użyty został rejestr przesuwny "sn74hc595n" który umożliwia w ciekawy sposób zwiększenie liczby pinów wyjściowych o 8.

Tutaj macie efekt końcowy mojej zabawy 🙂

IMG_20190109_201158.thumb.jpg.fd2a3a83efba3030aed557d7fc1888d3.jpg

A więc zacznijmy od listy gratów które bedą wam niezbędne:

  • Arduino Pro mini 
  • Moduł HC-05 (użycie HC-06 czy innego modelu nie powinno sprawić żadnych problemów)
  • Rejestr przesuwny "sn74hc595n" (dodaje nam większą liczbe pinów do zabawy, bez niego w płytce Pro Mini ich poprostu brakuje 😕
  • 64 diody 5mm (kolor dowolny, na mnie największe wrażenie robił niebieski 🙂
  • 4 rezystory 100 Ohm
  • Przełącznik bistabliny (tutaj też wybór jest dowolny, ma on nam poprostu dawać możliwość sterowania zasilaniem)
  • Źródło zasilania którym w moim przyadku jest koszyk na 6 lub 4 baterie AA. 
  • Druciki do naszego Led Cuba, dobrze sprawdzają się takie o średnicy 2-3mm
  • Jakaś podstawa w której wywiercimy otwory i umieścimy kostkę (ja użyłem płyt z plastiku, wytrzymałe ale pod wpływem dużej temperatury można je modelować)

Zaczać należy od stworzenia najważniejszej rzeczy czyli tytułowej kostki, nie jest to trudne aczkolwiek wymaga sporo czasu i pracy. Nie będe wam opisywał krok po korku co i jak, poprostu sami zobaczcie na te tutoriale. Ja korzystałem własnie z nich i są naprawde godne polecenia. A film napewno obrazuje sposób wykonania znacznie lepiej niż opis 😉. Fajnie pokazują one jak aspekty praktyczne zrobić dość sprawnie i tak żeby nie bawić się z tym nie wiadomo jak długo.

1. 

 

2.

Dobra to jak mamy już naszą kostkę czas połączenie ze spobą podzespołów.  Na pierwszy ogień idzie połączenie Arduino z Bluetooth'em, co jest rzeczą nie skomplikowaną. Moduł HC-05 posiada 6 pinów z czego używamy 4 i łączymy je w taki sposób:

HC-05 -----> Arduino

Vcc ---------> Vcc

Gnd ---------> Gnd

RX ------------>TX

TX------------->RX

Dwie ważne rzeczy które potrafią na początku zrobić duże zamieszanie!!!

WAŻNE RX i TX muszą być podłączone tak jak wyżej czyli na krzyż z RX i TX w Arduino!!

Przy wgrywaniu programu do Arduino moduł Bluetooth musi być ODŁĄCZONY, ponieważ wtedy jedyny Serial jakim komunikuje się płytka jest zajęty!

1011279670_HC05doArduino.thumb.png.d0c8e17ce1175d5c5ec1655b5d4dce4b.png

Kolejnym krokiem bedzię podłączenie naszego Arduino do rejestru przesuwnego  "sn74hc595n", a robimy to tak:

Tutaj macie schemacik samego rejestru:

    sn74hc595n.thumb.png.00122f3d3a34985bfca1030c200925da.png

A tu jak podłączamy go do Arduino, piny 10,9 i 8 będa odpowiedzialne za sterowanie rejestrem.

1758740763_rejestrdoarduino.thumb.png.e5f57bd15a282d6da705930439899153.png

W tym momencie mamy rejestr, mamy Bluettoth, mamy arduino. Ale co dalej?

Teraz połączymy poszczególne piny kostki LED do konkretnych pinów sterujących. To jest bardzo ważny krok, przecież nie chcemy żeby jej zachowaniach panował harmider. A robimy to tak jak na moim rysunku schematycznym który sobie rozpisałem podczas budowania całości.

Dla jasności:

Piny oznaczone D11, D12, D13, A4, A5... oznaczają pinyn na płytce arduino

Piny oznaczone R1, R2, R3..... oznaczają piny rejestru przesuwnego

IMG_20190109_220319.thumb.jpg.5dbda754bf5a2106b71b73ec034286bb.jpg

Niżej rozpisane jest połączenie warstw Led Cuba L1 oznacza warstwe 1 od dołu naszej kostki, L2 drugą, L3 trzecią a L4 czwartą. Łączymy je z pinami na płytce arduino A0,A1,A2,A3. Ważne jest by umieścić w każdym połączeniu rezystor 100 Ohmów. Inaczej nasze diody mogą to źle znieść 🙂

Tutaj widać połączenia wychodzące z kazdej warstwy w postaci drucików.

IMG_20190109_201221.thumb.jpg.2daa90bc6504adbe08d8647985a24fc6.jpg

Odrazu uprzedzę pytania o piny A6 i A7 które mogły zostać użyte, niestety ale są one tylko i wyłącznie wejściowe(input), nie potrafią działąć jako wyjściowe(output). Nic nam po nich 😉

Czas na podłączenie zasilania, a bedzie to szybkie i proste. I leci tak

zasialnie.thumb.png.c388f338228f094ce24ff75db0679510.png

 U mnie wygląda to w ten sposób, użyłem małej płytki uniwerslanej by ogarnąć ten haos.

IMG_20190109_201256.thumb.jpg.b3ed0dfb844d233719fa7c80e9572f6e.jpg

W tym momencie zostaje sam samiutki "soft" do zrobienia, zaczniemu od aplikacji na smartphona do sterowania tym cackiem. Ja stworzyłem ją w bardzo prostym i czytelnym środowisku jakim jest MIT APP Inventor. Sami zobaczcie że to nic trudnego, wystarczy trochę się pobwaić. Kod którym tam operujemy oparty jest na formie graficznej, dokładniej pewnego typu bloczki lub klocki. Nie ma się czego bać bo nie przypomina to tych strasznych języków proogramowania jak np Java 😉 W internecie macie wiele kursów na tą platformę, Gorąco polecam!

http://appinventor.mit.edu/

A tutaj macie moją apkę, bardzo prosta ale działa. Bo w końcu o to chodziło 🙂

BluetoothApp.rar

Co do jej działania, uruchamiamy, z listy na gorze wybieramy HC-05 czyli nasze urządzenie w kostce. Następnie czekamy na połączenie i gotowe, nic prostszego.

Teraz czas na soft zawarty w Arduino, jest on dość spory ale nie ma co się bać dokładnej analizy. Wytłumaczę tylko najważniejsze elementy, reszta powinna być jasna. Poza tym, był by to lekki masochizm 😉 Ten fragment deklaruje jakie piny sterują rejestrem, zmiana tutaj powoduje że nie bedzie on rozumiał co do niego mówimy

int clockPin = 8;
int latchPin = 9;
int dataPin = 10;

W tej części w zmiennych deklarujemy nasze piny którymi będziemy sterować. "22" i A6" są wstawione tylko ponieważ ułatwiło to pisanie kodu, nigdzie one nie prowadzą i nic nie aktywują.

 int layer[4]={A3,A2,A1,A0}; //initializing and declaring led layers
  int column[16]=        {13,12,11,A6,A6,A6 ,7 ,6 ,5 ,4 ,3 ,2 ,A6,A6,A5,A4}; //initializing and declaring led rows
  int expandercolumn[16]={22,22,22,1 ,2 ,3 ,22,22,22,22,22,22,4 ,5 ,22,22 };

Tutaj nasz program odczytuej informacje przesłane przez moduł Bluetooth i na ich podstawie ustala tryb świecenia kostki.

if(Serial.available() > 0){     
     msg = Serial.read();}
         
if (msg==1)
  {tryb=1;}
if (msg==2)
  {tryb=2;}
if (msg==3)
  {tryb=3;}
if (msg==4)
  {tryb=4;}
  if (msg==5)
  {tryb=5;}

A tutaj czysto widać  jak działa właściwie kostka, na warstwy poziome(L1,L2 itp.) dajemy zasilanie a na kolumny D13,D12 itp dajemy mase. Diodka lub diodki wtedy zaczynają świecić 😄

void turnEverythingOn()
{
  for(int i = 0; i<16; i++)
  {
    digitalWrite(column[i], 0);
    expanderWrite0(i);
  
  }
  //turning on layers
  for(int i = 0; i<4; i++)
  {
    digitalWrite(layer[i], 1);
  }
}

Kolejną ciekawą sprawą jest jak rejestr rozumie który z pinów ma włączyć. Wysyłamy do niego liczbę, 8 bitową. Maksymalna wartosć liczby 8 bitowej to 255, po rozłożeniu na system binarny daje nam to 11111111 - oznacza to że rejestr da na wszystkie piny zasilanie. Gdy wyślemy mu poprostu 0 to na system binarny otrzyma on 00000000 - co powie mu o wyłączeniu wszytskich pinów. Aby włączyć pin nr 1 musimy wysłać liczbę 2, ponieważ on rozumie to jako 00000010 i dzięki temu widzi że tylko pin nr 1 ma być włączony(  w kodzie binarnym numery pinów liczymy od zera i zaczynamy z prawej strony). A więc aby zapalić piny 2,3 i 4 to musimy mu wysłąć liczbę 28 ponieważ oznacza ona 000011100. Chyba nie trudne co? Jeśli sprawia wam to problem to użyjcie tego 🙂

https://www.rapidtables.com/convert/number/decimal-to-binary.html jest to konwerter liczb na system binarny, napewno ułatwi sprawę.

int expanderWrite1(int number){
     Led[number]=1;
    getvalue();
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST,value);
    digitalWrite(latchPin, HIGH);}

W tym fragmencie właśnie mówimy rejestrowi co ma zrobić, zmienna value zawiera informacje. Linijki z zmienną "LatchPin" otwierają i zamykają nam komunikacje. "dataPin" i "clockPin" adresują gdzie ma ona lecieć.

A tutaj łapcie juz calutki kodzik, myślę ze powinien być juz jasny schemat działania. A napewno wysarczy wam abyście sami coś wystukali i uruchomili swojego Led Cuba.

int clockPin = 8;
int latchPin = 9;
int dataPin = 10;
 
  int layer[4]={A3,A2,A1,A0}; //initializing and declaring led layers
  int column[16]=        {13,12,11,A6,A6,A6 ,7 ,6 ,5 ,4 ,3 ,2 ,A6,A6,A5,A4}; //initializing and declaring led rows
  int expandercolumn[16]={22,22,22,1 ,2 ,3 ,22,22,22,22,22,22,4 ,5 ,22,22 };
  int Led[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
  int Ledstate[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
  
 int value=0;
  int time = 250; 

  int msg;
  int tryb;


void setup() {
  // put your setup code here, to run once:

Serial.begin(9600); 
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
  pinMode(13, OUTPUT);
  for(int i = 0; i<16; i++)   
  {
    pinMode(column[i], OUTPUT);  //setting rows to ouput
   
  }
  
  for(int i = 0; i<4; i++)
  {
    pinMode(layer[i], OUTPUT);  //setting layers to output
  }
  
  randomSeed(analogRead(10));  //seeding random for random pattern


turnEverythingOff();}

void loop() {
  // put your main code here, to run repeatedly:
check();
    
  
action();

   }
 int check(){
  if(Serial.available() > 0){     
     msg = Serial.read();}
         
if (msg==1)
  {tryb=1;}
if (msg==2)
  {tryb=2;}
if (msg==3)
  {tryb=3;}
if (msg==4)
  {tryb=4;}
  if (msg==5)
  {tryb=5;}
 }
 
 void turnEverythingOff()
 {
   for(int i = 0; i<16; i++)
   {
     digitalWrite(column[i], 1);
     expanderWrite1(i);
     
     
   }
   for(int i = 0; i<4; i++)
   {
     digitalWrite(layer[i], 0);
   }
 }
 
 void turnEverythingOn()
{
  for(int i = 0; i<16; i++)
  {
    digitalWrite(column[i], 0);
    expanderWrite0(i);
  
  }
  //turning on layers
  for(int i = 0; i<4; i++)
  {
    digitalWrite(layer[i], 1);
  }
}
void turnColumnsOff()
{ check();
  for(int i = 0; i<16; i++)
  { check();
    digitalWrite(column[i], 1);
    expanderWrite1(i);
     check();
  }
}

void layerstompUpAndDown()
{check();
  int x = 75;
  for(int i = 0; i<4; i++)
  {
    digitalWrite(layer[i], 0);
        check();
  }
  
  check();
    for(int count = 0; count<1; count++)
    { check();
      for(int i = 0; i<4; i++)
      {
        check();
        digitalWrite(layer[i], 1);
        delay(x);
         check();
        digitalWrite(layer[i], 0);
     
      }
      for(int i = 4; i !=0; i--)
      {
        check();
        digitalWrite(layer[i-1], 1);
        delay(x);
         check();
        digitalWrite(layer[i-1], 0);
       
      }
    }
    for(int i = 0; i<4; i++)
    {
      check();
      digitalWrite(layer[i], 1);
      delay(x);
       check();
    }
    for(int i = 4; i!=0; i--)
    {
      check();
      digitalWrite(layer[i-1], 0);
      delay(x);
       check();
    }
  
 Serial.println("asdasdsdas");
  check();}

  void propeller()
{
  turnEverythingOff();
   check();
  int x = 90;
  for(int y = 4; y>0; y--)
  { check();
    for(int i = 0; i<6; i++)
    { check();
      //turn on layer
      digitalWrite(layer[y-1], 1);
      //a1
      check();
      turnColumnsOff();
      digitalWrite(column[0], 0);
      expanderWrite0(0);
       check();
      digitalWrite(column[5], 0);
       expanderWrite0(5);
       check();
      digitalWrite(column[10], 0);
       expanderWrite0(10);
       check();
       digitalWrite(column[15], 0);
       expanderWrite0(15);
       check();
       delay(x);
       check();
     //b1
      turnColumnsOff();
      digitalWrite(column[4], 0);
       expanderWrite0(4);
       check();
       digitalWrite(column[5], 0);
       expanderWrite0(5);
       check();
       digitalWrite(column[10], 0);
       expanderWrite0(10);
       check();
       digitalWrite(column[11], 0);
       expanderWrite0(11);
       check();
       delay(x);
       check();//c1
      turnColumnsOff();
      digitalWrite(column[6], 0);
       expanderWrite0(6);
       check();
       digitalWrite(column[7], 0);
       expanderWrite0(7);
       check();
       digitalWrite(column[8], 0);
       expanderWrite0(8);
       check();
       digitalWrite(column[9], 0);
       expanderWrite0(9);
       check();
       delay(x);
       check();//d1
      turnColumnsOff();
      digitalWrite(column[3], 0);
       expanderWrite0(3);
       check();
       digitalWrite(column[6], 0);
       expanderWrite0(6);
       check();
       digitalWrite(column[9], 0);
       expanderWrite0(9);
       check();
       digitalWrite(column[12], 0);
       expanderWrite0(12);
       check();
       delay(x);
       check();//d2
      turnColumnsOff();
      
      digitalWrite(column[2], 0);
       expanderWrite0(2);
        check();
        digitalWrite(column[6], 0);
       expanderWrite0(6);
        check();
        digitalWrite(column[9], 0);
       expanderWrite0(9);
        check();
        digitalWrite(column[13], 0);
       expanderWrite0(13);
        check();
        delay(x);
       check();//d3
      turnColumnsOff();
       check();
       digitalWrite(column[1], 0);
       expanderWrite0(1);
       check();
       digitalWrite(column[5], 0);
       expanderWrite0(5);
       check();digitalWrite(column[10], 0);
       expanderWrite0(10);
       check();
      digitalWrite(column[14], 0);
       expanderWrite0(14);
       check();
       delay(x); 
       check();
    }
  
  //d4
  turnColumnsOff();
   check();
   digitalWrite(column[0], 0);
   expanderWrite0(0);
   check();
   digitalWrite(column[5], 0);
   expanderWrite0(5);
   check();
   digitalWrite(column[10], 0);
   expanderWrite0(10);
   check();
   digitalWrite(column[15], 0);
   expanderWrite0(15);
   check();
   delay(x); 
   check();
}
}
 void randomRain()
{check();
  turnEverythingOff();
  int x = 100;
  check();
  
    int randomColumn = random(0,16);
    check();
    digitalWrite(column[randomColumn], 0);
    check();
    expanderWrite0(randomColumn);
    check();
    digitalWrite(layer[0], 1);
    check();
    delay(x+50);
    check();
    digitalWrite(layer[0], 0);
    check();
    digitalWrite(layer[1], 1);
    check();
    delay(x);
    check();
    digitalWrite(layer[1], 0);
    check();
    digitalWrite(layer[2], 1);
    check();
    delay(x);
    check();
    digitalWrite(layer[2], 0);
    check();
    digitalWrite(layer[3], 1);
    check();
    delay(x+50);
    check();
    digitalWrite(layer[3], 0);
    check();
    digitalWrite(column[randomColumn], 1);
    check();
    expanderWrite1(randomColumn);
    check();
}
 
 
 
 int getvalue()
  { 
    if(Led[3]==1){
      Ledstate[3]=2;}
    if(Led[3]==0){
      Ledstate[3]=0;}
      
     if(Led[4]==1){
      Ledstate[4]=4;}
    if(Led[4]==0){
      Ledstate[4]=0;}
      
      if(Led[5]==1){
      Ledstate[5]=8;}
    if(Led[5]==0){
      Ledstate[5]=0;}
      
      if(Led[12]==1){
      Ledstate[12]=16;}
    if(Led[12]==0){
      Ledstate[12]=0;}
      
      if(Led[13]==1){
      Ledstate[13]=32;}
    if(Led[13]==0){
      Ledstate[13]=0;}
    
    
    value=  Ledstate[3]|Ledstate[4]|Ledstate[5]|Ledstate[12]|Ledstate[13];}




  int expanderWrite0(int number){
     Led[number]=0;
    getvalue();
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST,value);
    digitalWrite(latchPin, HIGH);}
    
  int expanderWrite1(int number){
     Led[number]=1;
    getvalue();
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST,value);
    digitalWrite(latchPin, HIGH);}



int action(){
 Serial.println(tryb);
   
  if(tryb==1){turnEverythingOn();
  tryb=0;}
  if(tryb==2){turnEverythingOff();
  tryb=0;}
  while(tryb==3){turnEverythingOn();
  layerstompUpAndDown();}
  while(tryb==4){ randomRain();}
  while(tryb==5){ propeller();}
  }
  

Na zakończenie dodam że jest to tak naprawdę mój pierwszy post i wszelkie uwagi czy widoczne nie jasności będą mile widziane. W końcu jak się uczyć jak nie na błedach 😉

Dzięki za uwagę 🙂

Edytowano przez Treker
Poprawiłem formatowanie.
  • Lubię! 2
Link do komentarza
Share on other sites

Podoba Ci się ten projekt? Zostaw pozytywny komentarz i daj znać autorowi, że zbudował coś fajnego!

Masz uwagi? Napisz kulturalnie co warto zmienić. Doceń pracę autora nad konstrukcją oraz opisem.

@FRSH0109, witam na forum 😉 Widzę, że to Twoje pierwsze kroki na Forbocie, oto najważniejsze informacje na start:

  • Chcesz przywitać się z innymi członkami naszej społeczności? Skorzystaj z tematu powitania użytkowników.
  • Opis najciekawszych funkcji, które ułatwiają korzystanie z forum znajdziesz w temacie instrukcja korzystania z forum - co warto wiedzieć?
  • Poszczególne posty możesz oceniać (pozytywnie i negatywnie) za pomocą reakcji - ikona serca w prawym dolnym rogu każdej wiadomości.

30 minut temu, FRSH0109 napisał:

Siemka, pokaże wam dziś jak zrobić dość efektowną, zdalnie sterowaną z poziomu telefonu zabwakę 🙂

Właśnie zaakceptowałem Twój opis, możesz go teraz zgłosić do akcji rabatowej umieszczając link w temacie zbiorczym. Dziękuję za przedstawienie ciekawego projektu, zachęcam do prezentowania kolejnych DIY oraz aktywności na naszym forum 🙂

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.