פרסומת

מטריצת לדים

במדריך זה נבנה מטריצת לדים ענקית. המטריצה מופעלת בעזרת מעבד Arduino ושני מפענחי MAX7219

את המטריצה מתכנתים בשפת התכנות Processing. אני למשל כתבתי מספר אפליקציות קטנות (אפקטים שונים, כתיבת טקסטים,משחקים ועוד..)

החסרון היחידי במטריצה הזו היא שאת החלקים שממנה היא בנוייה צריך להזמין מחו"ל (דבר שלוקח זמן רב) אבל התוצאה משתלמת.

ניתן לראות למטה סרטון המדגים את המטריצה בפעולה

שלב ראשון – אז מה צריך?


אלו כל החלקים אותם נצטרך לבניית המטריצה:

  1. 128 לדים (סופרברייט) – בשני צבעים שונים (64 מכל צבע)
  2. חוטים – והרבה (מעל 20 מטר)
  3. שני מעבדי MAX7219 אותם ניתן להזמין בחינם מאתר http://www.maxim-ic.com
  4. דבק חם ומלחם
  5. שני פלקטים מוקצפים (בעובי סנטימטר אחד)
  6. פלקט מוקצף (בעובי חצי סנטימטר)
  7. שני בתי גוק 24 רגליים.
  8. נגד 9K
  9. קבלים: 10uF ו- 100n
  10. נייר דבק – מסקנטייפ + איזולירבנד
  11. לוח הלחמה – נקודות
כל הלדים
הלדים שקיבלתי במשלוח מסין, מופרדים לקעריות לפי הצבעים
הג'וק
הבקר 7219 ששולט על כל המטריצה
בית הג'וק
לוח ההלחמה

שלב שני – בניית מעגל הבקרה


השלב הראשון בתהליך בניית המטריצה הוא בניית מעגל הבקרה שישלוט על כל הלדים.

בבסיסו של המעגל נמצאים שני רכיבי MAX7219. כל אחד מהם ישלוט על 62 לדים (כל אחד ישלוט על צבע שונה – כל צבע מורכב מ64 לדים). הרכיבים הללו הם מעיין סוויצ'ים שממתגים את הפיקוד ללדים. הבקר המתוכנת Arduino יחובר אל מעגל הבקרה הזה באמצעות שלוש חוטים. Din, CLK וLoad.

ניתן לראות את סרטוט המעגל כאן בגלריה ובקישור הבא (כולל הסברים נוספים באנגלית)

למעגל הזה נחבר גם נגד 9K (במיקום RSet בסרטוט). בנוסף מחבר שני קבלים קטנים לבקרת המתח במעגל.

המלבן בתחתית המעגל עליו כתוב "To next Max72XX" יחובר אל הגו'ק השני.  כיוון שעדיין לא התחלתי לבנות את מטריצת הלדים עצמה. הלחמתי אל הג'וקים חוטים באופן מסודר אשר יחוברו בהמשך אל המטריצה.

לאחר הלחמת המעגל לפי הסרטוט נוכל להמשיך אל השלב הבא.

הלחמת הג'וקים
סיום ההלחמה
הלחמת הג'וקים לפי הסרטוט + הכנה למחברים בשביל המטריצה ובקר ה-ARDUINO
בקר Arduino

שלב שלישי – בניית המטריצה


את המטריצה בניתי מחומר מוקצף וקל.

כל תא (המכיל שני לדים) הוא ריבוע בעל אורך ורוחב של 7 סנטימטר.  סה"כ קיימים 8 תאים לכל כיוון = 56 סנטימטר.

נוסיף סנטימטר מכל פינה (גבול המטריצה יהיה מעט עבה) = 58 סנטימטר.

נוסיף גם את 7 הגבולות בין התאים – כל אחד בעובי חצי סנטימטר = 61.5 סנטימטר.  נוכל לעגל מעט תוצאה זו לנוחות וגם בגלל שהחיתוך וההדבקה  לעולם לא יוצאות מדוייקות לגמרי. כלומר נעגל ל60 סנטימטר.

מה שאנחנו צריכים זה פלקט מוקצף מלבני 60*60 סנטימטר (בעובי סנטימטר אחד).

פלקט נוסף כזה דרוש על מנת להסתיר את הלחמות הלדים.

שני פלקטים חתוכים 4*62 (לקצוות המטריצה)

ושני פלקטים חתוכים 4*60 גם הם לקצוות המטריצה.

בנוסף להכול, נזדקק לפלקטים דקים – בעובי חצי סנטימטר. פלקטים אלו יחצצו בין התאים במטריצה.

לאחר שנחתוך את כל הפלקטים הללו נוכל להדביק אותם אחד אל השני ליצירת המטריצה.

אחרי שהדבקנו ניתן גם לחבר את הלדים לפלקט. החיבור הוא פשוט ביותר. כיוון שהפלקט הוא בעצם קלקר דחוס. נלחץ כל לד אל הפלקט. רגלי הלד החדות כמו מחטים יעברו בקלות דרך הפלקט. לאחר שהרגליים שלו כבר בצד השני, פשוט נקפל אותן כלפי חוץ. חשוב לעבוד בדייקנות על מנת לא לעקם את הרגליים.

סימון תאי המטריצה
לוח הקאפה
בניית תאי המטריצה
המטריצה מושלמת

שלב רביעי – הלחמת הלדים


כעת נלחים את הלדים אחד אל השני.

את הלדים נלחים במעיין רשת. כל לד יולחם אל הלד שמעליו ומשמאלו. הלדים החיצוניים ביותר – בשורה הראשונה ובעמודה האחרונה, יחוברו אל לוח הבקרה של המטריצה, אשר ישלוט עליהם.

ניתן לראות סרטוט כאן בגלריה.  לאחר הלחמת הלדים נוכל לכסותאת ההלחמות והחוטים בעזרת פלקט נוסף שאותו נדביק בעזרת מסקנטיים – להסרה קלה במקרה של תקלה באחד הלדים.

הלחמת כל הלדים
תחילת ההלחמה
חיבור מעגל הבקרה אל המטריצה

שלב חמישי – כתיבת התוכנה


כעת נכתוב את התוכנה שתשלוט על המטריצה. התוכנה נצרבת בתוך הבקר Arduino.

הבקר עולה 35 דולר וניתן להזמין אותו מחול.

אני מוסיף כאן דוגמא לתוכנה פשוטה שכתבתי.

התוכנה שולטת על טקסט עברי שזז . רק כותבים טקסט והתוכנה מפענחת אותו.

בסוסף התוכנה מפעילה משחק פונק קטן שנשלט ע"י  המקלדת וכמה אפקטים.

[cc lang="js"] 


#include "LedControl.h"
unsigned long delaytime=120;
unsigned long smalldelay=35;
int dir=1;
int linePos=0;
int matlen;
byte none =  B00000000;
const int charsNum = 27; //number of characters
char chars[charsNum]={'א','ב','ג','ד','ה','ו','ז','ח','ט','י','כ','ל','מ','נ','ס','ע','פ','צ','ק','ר','ש','ת','ם','!',',',' ','ן'};
int charsCols[charsNum]={5,5,3,5,4,2,5,4,5,2,4,4,4,4,4,4,4,4,3,4,5,6,4,1,2,2,2};
byte tmp[4] ={B01010101,B10101010,B01010101,B10101010};
byte c[30][8] = {
{B01110100,B01001000,B00010000,B00100100,B01011100},//א
{B00000100,B01111100,B01000100,B01000100,B01000100},//ב
{B01111100,B01010000,B01011100},//ג
{B01000000,B01111100,B01000000,B01000000,B01000000},//ד
{B01111100,B01000000,B01000000,B01001100},//ה
{B01111100,B01000000},//ו
{B01000000,B01000000,B01110100,B01001000,B01000000},//ז
{B01111100,B01000000,B01000000,B01111100},//ח
{B01111100,B01000100,B00100100,B00000100,B01111100},//ט
{B01100000,B01000000},//י
{B01111100,B01000100,B01000100,B01000100},//כ
{B01110000,B01001000,B01000100,B11000100},//ל
{B01111100,B01000100,B00100100,B01010100},//מ
{B01111100,B01000100,B00000100,B00000100},//נ
{B01111000,B01000100,B01000100,B01111000},//ס
{B01111100,B00000100,B01111100,B00000100},//ע
{B01111100,B01000100,B01010100,B01110100},//פ
{B01001100,B00110100,B00100100,B01000100},//צ
{B01111000,B01000000,B01001111},//ק
{B01111100,B01000000,B01000000,B01000000},//ר
{B01111100,B00000100,B01111100,B00000100,B01111100},//ש
{B01111100,B01000000,B01000000,B01111100,B00000100,B00000100},//ת
{B01111100,B01000100,B01000100,B01111100},//ם
{B01110100},//!
{B00001100,B00000010},//,
{B00000000,B00000000},//,
{B01111111,B01000000}//,

};
/*
 ***** pin numbers to MAX72XX *****
 pin 7 is connected to the DataIn
 pin 4 is connected to the CLK
 pin 2 is connected to LOAD
 **********
 */
LedControl lc=LedControl(7,4,2,8);

void setup() {
  Serial.begin(9600);
  int devices=lc.getDeviceCount();
  for(int address=0;address<devices;address++) {
    lc.shutdown(address,false);
    lc.setIntensity(address,8);
    lc.clearDisplay(address);
  }
}

void loop() {
//pong();
printMsg("שלום עולם");
effect2();

for(int i=0;i<10;i++)
{
  if(i%2==0)
  {
    effect1(0);
  }
  else
  {
    effect1(1);
  }
}

//printMsg("סתמי");
}

void effect1(int color)
{
    int i,j;
 
    for(i=0;i<16;i++)
    {
        for(j=0;j<=i;j++)
        {
            lc.setLed(color,j, i-j, true);
        }
        delay(smalldelay);
        for(j=0;j<=i;j++)
        {
            lc.setLed(color,j, i-j, false);
        }
    }
}

void effect2()
{
  int i;
  for(i=0;i<8;i++)
  {
    lc.setLed(1,0, i, true);
    delay(smalldelay);
  }
    for(i=1;i<8;i++)
  {
    lc.setLed(1,i, 7, true);
    delay(smalldelay);
  }
   for(i=1;i<7;i++)
  {
    lc.setLed(1,7, 7-i, true);
    delay(smalldelay);
  }
     for(i=0;i<7;i++)
  {
    lc.setLed(1,7-i, 0, true);
    delay(smalldelay);
  }
       for(i=1;i<7;i++)
  {
    lc.setLed(1,1, i, true);
    delay(smalldelay);
  }
   for(i=2;i<7;i++)
  {
    lc.setLed(1,i, 6, true);
    delay(smalldelay);
  }
     for(i=2;i<7;i++)
  {
    lc.setLed(1,6, 7-i, true);
    delay(smalldelay);
  }
  for(i=6;i>1;i--)
  {
    lc.setLed(1,i, 1, true);
    delay(smalldelay);
  }
    for(i=2;i<6;i++)
  {
    lc.setLed(1,2, i, true);
    delay(smalldelay);
  }
      for(i=3;i<6;i++)
  {
    lc.setLed(1,i, 5, true);
    delay(smalldelay);
  }
     for(i=4;i>1;i--)
  {
    lc.setLed(1,5, i, true);
    delay(smalldelay);
  }
  lc.setLed(1,4, 2, true);
  delay(smalldelay);
    lc.setLed(1,3, 2, true);
  delay(smalldelay);
    lc.setLed(1,3, 3, true);
  delay(smalldelay);
    lc.setLed(1,3, 4, true);
  delay(smalldelay);
    lc.setLed(1,4, 4, true);
  delay(smalldelay);
    lc.setLed(1,4, 3, true);
  delay(smalldelay);
  clearall();
}

void printMsg(char* msg)
{
    
  int i,j;
  byte* mat = str2mat(msg);
  for(i=0;i<matlen;i++)
  {
    if(i>0 &&i<8)
    {

        for(j=1;j<i+1;j++)
        {
          lc.setColumn(1,j,mat[i-j]);
          lc.setColumn(0,j,mat[i-j]);
        }
      }
    else if(i>=8)
    {
      
       for(j=1;j<8;j++)
        {
          lc.setColumn(1,j,mat[i-j]);
          lc.setColumn(0,j,mat[i-j]);
        }
    }
 lc.setColumn(1,0,mat[i]);
  lc.setColumn(0,0,mat[i]);
 delay(delaytime);
  }
 
  for(i=0;i<8;i++)
  {
    for(j=7;j>=0;j--)
    {
        lc.setColumn(1,j,mat[matlen-j+i]);
         lc.setColumn(0,j,mat[matlen-j+i]);
    }
     delay(delaytime);
  }
}

byte* str2mat(char* str)
{
  byte res[255]={0};
  boolean flag;
  int i,len=0,j,p;
  for(i=0;str[i]!='';i++)
  {
    flag=false;
    for(p=0;flag==false && p<charsNum;p++)
    {
      if(str[i]==chars[p])
      {
        flag=true;
        len++;
         for(j=0;j<charsCols[p];j++)
         {
           res[len]=c[p][j];
           len++;
         }
      }
    }  
  }
  matlen=len;
  return res;
}

void clearall()
{
  for(int i=0;i<8;i++)
  {
    lc.setColumn(1,i,none);
  }
}

void pong()
{
  int i=4,j=6,t=300;
  boolean top=false;
  boolean down=false;
  boolean flag;
  while(true)
  {
    if(t>-100)
    {
      t--;
    }
    t=t-20;
   t=100;
    flag=true;
    while(top==false)
    {
      drowLine();
      if(flag==true)
      {
        j = setJ(j,true);
        flag=false;
      }
      else
      {
         j = setJ(j,false);
      }
        lc.setLed(1,i, j, true);
         delay(delaytime+t);
         lc.setLed(1,i, j, false);
        if(i==0)
        {
          top=true;
        }
        else
        {
          i--;
        }      
    }
    i++;
    top=false;
    flag=true;
    while(down==false)
    {
      drowLine();
         if(flag==true)
      {
        j = setJ(j,true);
        flag=false;
      }
      else
      {
         j = setJ(j,false);
      }
        lc.setLed(1,i, j, true);
         delay(delaytime+t);
      lc.setLed(1,i, j, false);
        if(i==7)
        {
          down=true;
          if(j!=linePos && j!=linePos+1)
          {
            effect2();//youlose
            //printMsg("הפסדת");
          }
        }
        else
        {
          i++;
        }

    }
    i--;
    down=false;
  }   
}

void drowLine()
{
  int dir=-1;
  if (Serial.available()) {
    dir=Serial.read();
    if(dir==0 && linePos<6)
    {
      linePos++;
      lc.setLed(0,7, linePos-1, false);
      lc.setLed(0,7, linePos, true);
      lc.setLed(0,7, linePos+1, true);
    }
    else if(dir==1 && linePos>0)
    {
      linePos--;
      lc.setLed(0,7, linePos+2, false);
      lc.setLed(0,7, linePos, true);
      lc.setLed(0,7, linePos+1, true);
    }
  }
}

int setJ(int pos,boolean flag)
{
  drowLine();
  drowLine();
  drowLine();
  if(flag==true && pos>0 && pos<7 )
  {
    int tmp = random(3);
    switch(tmp)
    {
      case 0: dir=2; return pos-1;
      break;
      case 1:dir=1; return pos+1;
      break;
      case 2: dir=0; return pos;
      break;
      default:
      dir=0;
      return pos;
    }
  }
  if(dir==1)
  {
    if(pos<7)
    {
      return pos+1;
    }
    else
    {
      if(dir!=0)
    {
      dir=2;
      return  pos-1;
   }
   else
   {
     return pos;
   }
      
    }
  }
  else if(dir==0)
  {
    return pos;
  }
  else
  {
    if(pos>0)
    {
      return pos-1;
    }
    else
    {
      if(dir!=0)
    {
    dir=1;
     return  pos+1;
  }
  else
  {
    return pos;
  }
    }
  }
}



[/cc]

עדיין אין תגובות למאמר זה

הגב למאמר זה

כתובת האימייל שלך לא תפורסם


*