[아두이노] 3x3x3 CUBE LED 제어 III

IOT/아두이노|2019. 3. 21. 09:00

[아두이노] 3x3x3 CUBE LED 제어 III



오늘은 좀 더 프로그램 코딩에 관해서 이야기 하도록 하겠습니다. 그리고 제목을 3x3x3 CUBE LED를 다룬다고 해놓고 지난시간에 2x2x2 CUBE LED를 실험해서 좀 찜찜한 기분이 들어서 노가다를 감수하고 코딩이 간소화 되니깐 3x3x3 CUBE LED를 해도 되겠다 싶어서 회로도 디자인을 했네요. 우선 배치도를 구상하고 최대한 보기 편하게 만들려고 노력했네요. 전개는 우선 지난시간에 코딩한 2x2x2 CUBE LED 코딩을 기반으로 프로그래머 스타일의 문법을 가미하면서 간소화 시키는 것을 설명드리고 그다음 간소화한 코딩을 3x3x3 CUBE LED 회로도에 맞게 변경하여 실험하는 결과를 보여드리도록 하겠습니다.

1. 2x2x2 CUBE LED 코드 간소화


아래 코드만 봐도 머리가 아프죠. 이걸 프로그램 문법을 이용해서 간소화 하도록 하겠습니다.

int layer1 = 11;
int layer2 = 12;

int room1 = 2;
int room2 = 3;
int room3 = 4;
int room4 = 5;

void setup()
{
  pinMode(layer1, OUTPUT);
  pinMode(layer2, OUTPUT);

  pinMode(room1, OUTPUT);
  pinMode(room2, OUTPUT);
  pinMode(room3, OUTPUT);
  pinMode(room4, OUTPUT);

  //초기화 각 층을 막아놓습니다.
  digitalWrite(layer1, HIGH);
  digitalWrite(layer2, HIGH);
}

void loop()
{
  //1층 점등
  digitalWrite(layer1, LOW);  
  digitalWrite(room1, HIGH);  
  delay(1000);
  
  digitalWrite(room1, LOW);  
  digitalWrite(room2, HIGH);  
  delay(1000);
  
  digitalWrite(room1, LOW);  
  digitalWrite(room2, HIGH);  
  delay(1000);
  
  digitalWrite(room2, LOW);  
  digitalWrite(room3, HIGH);  
  delay(1000);

  digitalWrite(room3, LOW);  
  digitalWrite(room4, HIGH);  
  delay(1000);
  
  digitalWrite(room4, LOW);  
  digitalWrite(layer1, HIGH);  
  delay(1000);
  
  //2층 점등
  
  digitalWrite(layer2, LOW);  
  digitalWrite(room1, HIGH);  
  delay(1000);
  
  digitalWrite(room1, LOW);  
  digitalWrite(room2, HIGH);  
  delay(1000);
  
  digitalWrite(room1, LOW);  
  digitalWrite(room2, HIGH);  
  delay(1000);
  
  digitalWrite(room2, LOW);  
  digitalWrite(room3, HIGH);  
  delay(1000);

  digitalWrite(room3, LOW);  
  digitalWrite(room4, HIGH);  
  delay(1000);
  
  digitalWrite(room4, LOW);  
  digitalWrite(layer2, HIGH);  
  delay(1000);

}

1) 변수를 배열변수로 바꾼다.

기존수정
int layer1 = 11; int layer2 = 12;int layer[2] = {11, 12};
int room1 = 2; int room2 = 3; int room3 = 4; int room4 = 5;int room[4] = { 2, 3, 4, 5}




2) for문을 사용하여 중복 코드를 제거한다.

기존 코드

  pinMode(layer1, OUTPUT);
  pinMode(layer2, OUTPUT);
  //초기화 각 층을 막아놓습니다.
  digitalWrite(layer1, HIGH);
  digitalWrite(layer2, HIGH);

수정 코드

    for(int i=0;i<2;i++){
        pinMode(layer[i], OUTPUT);
        digitalWrite(layer[i], HIGH);
  }

기존 코드

  pinMode(room1, OUTPUT);
  pinMode(room2, OUTPUT);
  pinMode(room3, OUTPUT);
  pinMode(room4, OUTPUT);

수정 코드

    for(int i=0;i<4;i++){
        pinMode(room[i], OUTPUT);
    }

3) void loop() 안의 코드를 간소화

수정 코드

  for(int i=0;i<2;i++){
    digitalWrite(layer[i], LOW);              
    for(int j=0;j<4;j++){
           digitalWrite(room[j], HIGH);  
           delay(1000);
           digitalWrite(room[j], LOW);  
    }    
    digitalWrite(layer[i], HIGH);      
  }

1,2번의 수정은 코드만 보면 대충 뭘 줄였는지 알 수 있지만 3번 코드 간소화 경우는 로직이라서 간단히 설명을 드리겠습니다. for문은 순차적으로 반복하는 문법입니다.

예)

for(int i=0;i<3;i++) { 
    Serial.println("Hellow" );
}

for문은 i가 0시작해서 i<3보다 작을때까지 반복합니다. 뒤에 i++은 증감연산자로 'i=i+1'로 생각하시면 됩니다. for문이 한번씩 돌때마다 i++로 i가 1씩 증가하는데 그렇게 되면 결과는 다음과 같습니다.

결과 :

Hellow
Hellow
Hellow

이렇게 i가 0부터 0,1,2까지 참임으로 for문 안의 명령어 Serial.println()함수를 수행하지만 i가 3이되면 거짓으로 for문을 빠져 나옵니다.

이제 for문을 이해했으면 왜 수정코드를 이렇게 코딩했을까요.

2x2x2 cube led은 1층 4개, 2층 4개의 LED로 구성되어 있잖아요. 여기서 1층부터 순차적으로 1,2,3,4호실에 불이 들어와야 하니깐 4번을 순차적으로 같은 동작을 수행해야 합니다. 그래서 for문으로 4번을 순차적으로 반복할려면 아래와 같은 구조가 됩니다.

for(j=0;j<4;j++){
  명령문;
}

1호실 부터 1초 단위로 불이 들어올려면 1호실만 HIGH 상태가 1초동안 대기 되었다가 다시 LOW로 바뀌고 2호실, 3호실, 4호실 순으로 반복되어야 겠죠.

digitalWrite(layer[i], LOW);  // 해당 i층 Gnd 상태 (해당층 개방)
for(int j=0;j<4;j++){
  digitalWrite(room[j], HIGH);  //해당 j호실 전원 공급
  delay(1000);
  digitalWrite(room[j], LOW);  //해당 j호실 전원 차단  
}
digitalWrite(layer[i], HIGH);  //해당 i층 HIGH 상태 (해당층 닫힘)

이렇게 되는 것이죠. 그리고 Vcc와 Gnd은 한쌍이라고 했죠. 1층을 Gnd(-)로 하려면 1층을 LOW상태로 만들어 합니다. 그래서 for문 밖에다가 1층을 LOW상태로 만들었네요. 왜 안에다가 안넣고 밖에다가 표현했을까요. 그 이유는 아두이노가 1층을 Gnd 상태로 만들었는데 또다시 Gnd 상태 만들어라고 반복 명령을 내리면 비효율적인 코딩이 되잖아요. 구지 반복 명령을 할 필요없이 한번만 해도 되는 문장은 for문에 넣을 필요는 없습니다.

여기서 for문이 2중 for문으로 구성되었는데 그 이유는 1층 1,2,3,4호실을 깜박였으면 2층 1,2,3,4호실 깜박여야 하잖아요. 각 호실을 깜박이는 동작을 for문으로 만들었는데 그 for문을 2층이니깐 2번 반복해야 하니깐 2중 for문을 만들어야 합니다.

for(int i=0;i<2;i++){ // i=0,1 일때까지만 2번 반복 (층 반복)
 해당층 개방;
 for(int j=0;j<4;j++){ // j=0,1,2,3 일때까지만 4번 반복 (호실 반복)
    명령문;
 }
 해당층 닫힘;
}

그래서 아래와 같은 로직이 나오게 된 것이죠.

    for(int i=0;i<2;i++){
        digitalWrite(layer[i], LOW);  // 해당 i층 Gnd 상태 (해당층 개방)
        for(int j=0;j<4;j++){
            digitalWrite(room[j], HIGH);  //해당 j호실 전원 공급
            delay(1000);
            digitalWrite(room[j], LOW);  //해당 j호실 전원 차단  
        }
     digitalWrite(layer[i], HIGH);  //해당 i층 HIGH 상태 (해당층 닫힘)
    }

전체적으로 종합해보면

int layer[2] ={11,12};
int room[4] = {2,3,4,5};


void setup()
{
  for(int i=0;i<2;i++){
    pinMode(layer[i], OUTPUT);
    digitalWrite(layer[i], HIGH);
  }
  
  for(int i=0;i<4;i++){
    pinMode(room[i], OUTPUT);
  }
}

void loop()
{
    for(int i=0;i<2;i++){
        digitalWrite(layer[i], LOW);  // 해당 i층 Gnd 상태 (해당층 개방)
        for(int j=0;j<4;j++){
            digitalWrite(room[j], HIGH);  //해당 j호실 전원 공급
            delay(1000);
            digitalWrite(room[j], LOW);  //해당 j호실 전원 차단  
        }
     digitalWrite(layer[i], HIGH);  //해당 i층 HIGH 상태 (해당층 닫힘)
    }
}

2. 3x3x3 CUBE LED 회로도 구성


  • 준비물 : Red, Blue, Green LED 각각 9개, 저항 220옴 3개, 아두이노우노, 뻥판
  • 내용 : 3x3x3 CUBE LED 형태를 표현하자.


입체적 이미지를 평면적으로 뻥판에 나타내면 아래와 같은 회로도가 그려집니다.


실제로 제작을 한다면


위 그림처럼 철사를 사각형으로 만들고 빨간 꼭지점에 LED의 '-' 쪽을 각 꼭지점에 납땜하시면 됩니다. 그러면 총 9개가 하나의 극으로 연결이 되는데 이걸 1층이라고 생각하시면 됩니다. 이걸 3개를 만들어서 LED의 '+'쪽을 세로로 연결하시면 3층이 완성되어 전체 이미지는 3x3x3 CUBE LED가 됩니다. 실제로 만들면 무지 간단한데 이걸 가상시뮬레이터에서 표현하고 뻥판에 배치하니깐 무지 복잡해 보이네요.

최대한 보기 쉽게 표현 한건데 이것 역시 완성하고 나니깐 지난시간의 회로도보다 더 복잡하네요.

3. 코딩


  • 사용함수 : pinMode(), digitalWrite(), delay()
  • 내용 : 간단히 2x2x2 CUBE LED를 순차적으로 깜박이기
  • 참고 : [아두이노] LED 제어

복습

  • pinMode(사용핀, 사용모드) : 사용핀을 INPUT/OUTPUT/INPUT_PULLUP 모드중 뭘로 사용할지를 정함.
  • digitalWrite(사용핀, 출력형태) : 사용핀을 HIGH(5V) or LOW(0V) 중 출력 형태를 정함.
  • delay(1000) : 1초(1000)를 대기한다.

2x2x2 CUBE LED 간소화 코딩을 3x3x3 CUBE LED 형태로 수정

int layer[3] = {A0,A1,A2};
int room[9] = {10,9,8,7,6,5,4,3,2};
int m_layer = 3;  // 층 수
int m_room = 9; // 호실 수

void setup()
{
  for(int i=0;i<m_layer;i++){
    pinMode(layer[i], OUTPUT);
    digitalWrite(layer[i], HIGH);    
  }
  
  for(int i=0;i<m_room;i++){
    pinMode(room[i], OUTPUT);
  }
}

void loop()
{
  
  for(int i=0;i<m_layer;i++){
    digitalWrite(layer[i], LOW);  
    for(int j=0;j<m_room;j++){
      digitalWrite(room[j], HIGH);  
      delay(100);
      digitalWrite(room[j], LOW);  
    }
    digitalWrite(layer[i], HIGH);  
  }
}

층수와 호실수를 변수로 따로 빼서 setup(), loop() 함수 로직은 이제 수정하지 않는 방향으로 변경했네요. 이렇게 하면 위에 변수 선언부분만 수벙하시면 2x2x2 CUBE LED로 바꿀 수 있고 3x3x3 CUBE LED로도 쉽게 변경이 가능해집니다.

4. 결과


지난 시간에 가상시뮬레이터 결과가 지연 렉 때문에 정상적으로 결과가 안나와서 실제 아두이노로 표현했는데 브라우저 문제였네요. 오늘 크롬에서 가상시뮬레이터를 돌리니깐 어제 1초단위로 깜박이는 동작이 깔끔하게 보여줬네요. 오늘도 가상시뮬레이터로 돌린 결과와 현실 아두이노에서 돌린 결과를 실제 촬영해서 기록했네요.

그런데 실제 아두이노에서는 전선이 부족하여 정상적으로 동작은 하지만 일부 LED은 연결할 수 없어서 일부 LED에 불이 안들어온 점은 감안하고 보세요. 최대한 선들을 구햇지만 선 부족으로 1층은 9개 연결을 다 했지만 2,3층은 6개까지 연결하고 나니깐 더이상 선이 없어서 2,3층 3개의 LED은 돌릴 수 없었네요. 그래도 전달하고자하는 실험 내용의 결과는 정상적으로 얻었으며 안켜진 LED은 오류가 아니니깐 감안하시고 보세요.

추가 내용

마지막 동영상 장면에서 delay()시간차 연결을 몇초 담았는데요. 혹시 궁금하실분이 잇을 것같아서 만약 1층1호실 2층 2호실을 같은 시간대 불이 들어오게 할려면 어떻게 해야할지 의문을 품는 분들이 아마 있을꺼에요. 큐브 자체가 회로도를 저리 구성하기 때문에 물리적으로는 사실 어렵습니다. 하지만 인간의 시각을 이용한 방법으로 착시 효과로 표현은 가능합니다. 이 말은 인간의 눈은 두 LED가 있으면 delay()시간을 아주 짧게 주면 동시에 불이 들어오는 것처럼 착시 현상이 발생합니다. 아두이노에서는 그 착시효과를 이용해서 delay()시간으로 각 층에 LED에 불을 넣으면 됩니다.

  digitalWrite(layer[0], LOW);  
  digitalWrite(room[0], HIGH);   
  delay(20);
  digitalWrite(room[0], LOW);
  digitalWrite(layer[0], HIGH);

  digitalWrite(layer[1], LOW);  
  digitalWrite(room[2], HIGH);   
  delay(20);
  digitalWrite(room[2], LOW);   
  digitalWrite(layer[1], HIGH); 

즉, 1층 1호실에 불이 0.02(20)초 동안 전원 공급했다가 차단하고 바로 2층 2호실에 0.02(20)초 동안 정원 공급하면 어떻게 될까요. 분명 코딩상으로 차이가 나지만 시각적으로 보면 delay(20)초 간격으로 1층 1호실과 2층 2호실이 동시에 불이 들어오는 것처럼 착시효과가 발생합니다. 이러한 방법으로 서로 다른층의 LED를 동시에 불을 들어오게 합니다.

위 그림을 보듯이 짧게 딜레이를 줘서 각 층의 원하는 위치에 거의 동시에 불이들어오게 착시효과를 나타내고 잇네요.

마무리


원래는 한개의 포스팅으로 3편의 내용을 함축하고 싶었는데 그냥 회로도 그리고 코딩하고 결과만 딸랑 보여주면 별로 의미가 없을 것 같아서 최대한 많은 것을 설명할려고 노력했는데 빠진 부분이 아직도 너무 많네요. RGB LED를 이용한 CUBE LED도 표현하면 좋은데 실제 보유한 RGB LED가 한개 뿐이고 가상시뮬레이터로 표현하자니 2핀짜리 LED 선연결도 이리 복잡한데 4핀짜리 RGB LED를 큐브 모양으로 만들 엄두가 안나네요. 원리를 이번 포스팅에 설명한 원리랑 같기 때문에 도전하고 싶은 분들은 도전해보세요. 지금 표현한 것에 3배 노가다를 하시면 충분히 표현이 가능하실꺼에요.
전 도저히 못하겠네요. 도전하실분들은 RGB LED를 큐브로 만들어 보세요.


댓글()