[아두이노] 3x3x3 CUBE LED 패턴 코딩 I

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

[아두이노] 3x3x3 CUBE LED 패턴 코딩 I



지난 시간에 3x3x3 CUBE LED 코딩을 간소화 하는 방법을 살펴보았습니다. 오늘은 좀 더 깊게 들어가서 LED를 깜박이는 패턴을 만들어보는 시간을 갖도록 하겠습니다. 그냥 순차적으로 깜박이는 것은 for문 하나면 해결되지만 서로 다른 층과 서로 다른 호실에 동시에 불이 들어오게 하는 방법은 좀 다른 관점의 코딩이기 때문입니다. 그 이유는 동시에 서로 다른 층의 다른 호실에 불이 들어오게 할 수 없습니다. 왜냐면 각 호실은 같은 층의 연결되어 있고 각층은 동일 호실과 선이 연결되어 있기 때문입니다. 만약, 1층 1호실과 2층 2호실에 불이 들어오게 하려고 1층과 2층을 동시에 개방하면 1층 1,2호실과 2층 1,2호실에 LED가 켜지게 됩니다. 이 부분에 대해서 간단히 살펴보고 그걸 해결하기 위한 방법을 설명 드리겠습니다. 사실 힘들게 뻥판 노가다로 전선을 연결했는데 다시 원위치 시키기 아쉬워서 패턴이라는 내용으로 포스팅을 한편 더 작성하네요.


1층과 2층의 LED만 사용합니다. 전선부족으로 지난시간에 2,3층 3개의 LED에 선을 연결못했는데 3층선 일부를 2층선으로 옮겨와서 1,2층 선을 모두 연결한 상태에서 실험했네요.

1. 서로 다른 층과 호실에 동시에 불을 켤 수 없는가?


1층 1호실과 2층 2호실에 동시에 불이 들어오게 한다고 가정해 봅시다. 그러면 1층과 2층을 Gnd(-)로 개방해야하잖아요. 그런데 1층(Gnd)와 1호실(Vcc)로 해서 1층 1호실에 불이 들어옵니다. 하지만 2층 2호실의 경우도 동시에 2층(Gnd)와 2호실(Vcc)을 하게 된다면 아래와 같은 현상이 발생합니다.


1층 1,2호실과 2층 1,2호실에 불이 전부 들어오게 됩니다. 선이 층을 기준으로 모든 호실이 하나로 선(Gnd)이 연결되어 있고 호실을 기준으로 모든 층이 선(Vcc)로 연결되어 있기 때문입니다. 그래서 동시에 불이 들어오게는 불가능 합니다. 그럼 해결책이 없느냐고 물으신다면 바로 딜레이 시간을 줘서 1층과 2층을 짧은 시간에 개방하고 닫고 해서 1층1호실에 불이 들어오게 한뒤에 2층 2호실에 불이 들어오게 함으로써 착시현상이 일어나게 처리하면 해결 할 수 있습니다.


위 그림에서 A동작을 수행시 불이 충분히 켜질 시간(delay) 주고 난 뒤에 바로 B동작을 수행합니다. 참고로 A동작과 B동작의 딜레이 시간은 아주 짧아야 합니다. 착시현상으로 동시에 불이 들어오는 것처럼 느끼게 됩니다.


대충 위 그림처럼 착시로 동시에 불이 들어오게 보여야 합니다. 이제 어떻게 하는지 알아보도록 하겠습니다.

2. 3x3x3 CUBE LED 회로도 구성


  • 준비물 : Red, Blue, Green LED 각각 9개, 저항 220옴 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)를 대기한다.

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);  
  }
}

여기서, 다른 부분은 그냥두고 이부분만 수정하시면 됩니다.

  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);  
  }

이 명령은 순차적으로 깜박이는 로직입니다. 여기서 1층 1호실과 2층 2호실에 불이 동시에 들어오게 하려면 어떻게 해야 할까요. 1,2층 개방/닫힘 명령과 1,2호실 개방/닫힘 명령이 필요합니다.

  • 층 개방 : digitalWrite(해당층핀, LOW);
  • 층 닫힘 : digitalWrite(해당층핀, HIGH);
  • 호실 개방 : digitalWrite(호실핀, HIGH);
  • 호실 닫힘 : digitalWrite(호실핀, LOW);

[ 1층1호실과 2층2호실 불 들어오게 하기 ]

위 코드에서 layer[0]은 1층, layer[1]은 2층, layer[2]은 3층이고 room[0]은 1호실, room[1]은 2호실, room[2]은 3호실, room[3]은 4호실입니다. 배열변수로 그렇게 선언했기 때문에 이점을 생각하고 코딩을 해보도록 할까요.

먼저, 1층 1호실을 불이 들어오게 명령을 내려 볼까요.

digitalWrite(layer[0], LOW);  // 1층 개방
digitalWrite(room[0], HIGH);  // 1호실 개방
delay(10); //0.01초 동안 불 켜기
digitalWrite(room[0], LOW);  // 1호실 닫힘
digitalWrite(layer[0], HIGH);  // 1층 닫힘

다음 2층 2호실에 불이 들어오게 명령을 내려 볼까요.

digitalWrite(layer[1], LOW);  // 2층 개방
digitalWrite(room[1], HIGH);  // 2호실 개방
delay(10); //0.01초 동안 불 켜기
digitalWrite(room[1], LOW);  // 2호실 닫힘
digitalWrite(layer[1], HIGH);  // 2층 닫힘

결과는 다음과 같습니다.


[ 소스 ]

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()
{
  digitalWrite(layer[0], LOW);  // 1층 개방
  digitalWrite(room[1], HIGH);  // 1호실 개방
  delay(10); //0.01초 동안 불 켜기
  digitalWrite(room[1], LOW);  // 1호실 닫힘
  digitalWrite(layer[0], HIGH);  // 1층 닫힘
  
  digitalWrite(layer[1], LOW);  // 2층 개방
  digitalWrite(room[0], HIGH);  // 2호실 개방
  delay(10); //0.01초 동안 불 켜기
  digitalWrite(room[0], LOW);  // 2호실 닫힘
  digitalWrite(layer[1], HIGH);  // 2층 닫힘
}

[ 결과 ]



[ 1층2호실과 2층1호실 불 들어오게 하기 ]

위 코드를 반대로 표현하면 됩니다.

digitalWrite(layer[0], LOW);  // 1층 개방
digitalWrite(room[1], HIGH);  // 2호실 개방
delay(10); //0.01초 동안 불 켜기
digitalWrite(room[1], LOW);  // 2호실 닫힘
digitalWrite(layer[0], HIGH);  // 1층 닫힘

다음 2층 2호실에 불이 들어오게 명령을 내려 볼까요.

digitalWrite(layer[1], LOW);  // 2층 개방
digitalWrite(room[0], HIGH);  // 1호실 개방
delay(10); //0.01초 동안 불 켜기
digitalWrite(room[0], LOW);  // 1호실 닫힘
digitalWrite(layer[1], HIGH);  // 2층 닫힘

결과는 다음과 같습니다.


[ 소스 ]

... 생략

void loop()
{
  digitalWrite(layer[0], LOW);  // 1층 개방
  digitalWrite(room[1], HIGH);  // 2호실 개방
  delay(10); //0.01초 동안 불 켜기
  digitalWrite(room[1], LOW);  // 2호실 닫힘
  digitalWrite(layer[0], HIGH);  // 1층 닫힘
  
  digitalWrite(layer[1], LOW);  // 2층 개방
  digitalWrite(room[0], HIGH);  // 1호실 개방
  delay(10); //0.01초 동안 불 켜기
  digitalWrite(room[0], LOW);  // 1호실 닫힘
  digitalWrite(layer[1], HIGH);  // 2층 닫힘
}

[ 결과 ]



[ 1층1호실과 2층2호실의 불을 일정시간 단위로 깜박이기 ]

하나의 패턴은 그냥 loop()함수로 돌리면 그 패턴의 LED만 불이 들어옵니다. 둘 이상의 경우는 해당 패턴의 모양이 일정시간 유지해야 합니다. 하지만 연속해서 표현하면 아주 짧게 딜레이를 줬기 때문에 해당 패턴모양이 원하는 시간동안 유지하지 못하는 현상이 발생합니다. 또는 두가지 패턴이 하나의 패턴으로 겹치는 현상도 발생합니다. 그래서 하나의 패턴을 일정시간 유지시키기 위해서는 딜레이 함수와 같은 효과를 코딩으로 표현해야 합니다.

딜레이를 아주 짧게 줬기 때문에 짧게 패턴을 일정횟수만큼 반복하면 반복된 시간만큼이 해당 패턴의 모양을 유지하는 시간으로 만들어 낼 수 있습니다.

가령,

 for(int i=0;i<30;i++){ //for문이 delay()함수 효과
   digitalWrite(layer[0], LOW);  // 1층 개방
   digitalWrite(room[0], HIGH);  // 1호실 개방
   delay(10); //0.01초 동안 불 켜기
   digitalWrite(room[0], LOW);  // 1호실 닫힘
   digitalWrite(layer[0], HIGH);  // 1층 닫힘
  
   digitalWrite(layer[1], LOW);  // 2층 개방
   digitalWrite(room[1], HIGH);  // 2호실 개방
   delay(10); //0.01초 동안 불 켜기
   digitalWrite(room[1], LOW);  // 2호실 닫힘
   digitalWrite(layer[1], HIGH);  // 2층 닫힘
}

표현을 하면 1층1호실은 0.01초만큼 불이들어온 후에 2층2호실은 0.01초만큼 불이 들어오게 됩니다. 총 합산하면 0.02초만큼 1층1호실과 2층2호실의 시간이 소요됩니다. 그걸 30회 반복한다고 했죠. 보는 수치상으로 계산하면 0.6초여야 동안 같은 패턴을 유지하게 된다고 생각하시면 됩니다. 그런데 실제로 돌리시면 0.06초동안 유지되는게 아니라 명령어 수행시간도 합산하면 미세하지만 좀 늘어나겠죠. 신경 쓸 필요는 없는 부분이고요. 30번 반복이란 예를 든 것일뿐 다른 값으로 어느정도 시간이 유지되는지를 테스트 해보고 원하는 시간으로 보정을 해보세요. for문 안에 delay(10)도 그냥 제 아두이노로 실험했을때 대충 정한 값이라 이 값이 크면 착시효과가 낮으니깐 어느정도 다른 값들을 대입해보면서 원하는 딜레이시간으로 보정해 해보세요.

[ 1층1호실과 2층2호실 패턴과 1층2호실과 2층1호실 패턴을 교차 ]

위 for문에 반대패턴을 코딩한걸 삽입하면 되겠죠.

[ 소스 ]

... 생략

void loop()
{
    //1층1호실과 2층2호실
     for(int i=0;i<30;i++){ //for문이 delay()함수 효과
         digitalWrite(layer[0], LOW);  // 1층 개방
         digitalWrite(room[0], HIGH);  // 1호실 개방
         delay(10); //0.01초 동안 불 켜기
         digitalWrite(room[0], LOW);  // 1호실 닫힘
         digitalWrite(layer[0], HIGH);  // 1층 닫힘
  
         digitalWrite(layer[1], LOW);  // 2층 개방
         digitalWrite(room[1], HIGH);  // 2호실 개방
         delay(10); //0.01초 동안 불 켜기
         digitalWrite(room[1], LOW);  // 2호실 닫힘
         digitalWrite(layer[1], HIGH);  // 2층 닫힘
    }
    
    //1층2호실과 2층1호실
    for(int i=0;i<3[](http://)0;i++){ //for문이 delay()함수 효과
        digitalWrite(layer[0], LOW);  // 1층 개방
        digitalWrite(room[1], HIGH);  // 2호실 개방
        delay(10); //0.01초 동안 불 켜기
        digitalWrite(room[1], LOW);  // 2호실 닫힘
        digitalWrite(layer[0], HIGH);  // 1층 닫힘
  
        digitalWrite(layer[1], LOW);  // 2층 개방
        digitalWrite(room[0], HIGH);  // 1호실 개방
        delay(10); //0.01초 동안 불 켜기
        digitalWrite(room[0], LOW);  // 1호실 닫힘
        digitalWrite(layer[1], HIGH);  // 2층 닫힘
    }
}

[ 결과 ]

위 그림에서 보는것처럼 교차로 깜박이게 됩니다. 이런식으로 해서 패턴을 만들고 그 패턴을 일정시간동안 유지시킬 수 있게 되면은 다양한 패턴을 만들어 낼 수 있겠죠.

마무리


이번 포스팅은 원래 패턴 코딩을 한편으로 제작할려고 했던 내용입니다. 그런데 포스팅의 글을 쓰다가 보니 아직 제대로 코딩하는 법으로 들어가지 못했는데 분량이 장난 아니게 늘어났네요. 어쩔 수 없이 다음편으로 연장해야 할 듯 싶네요. 너무 길게 쓰면은 피로감이 밀려올 수 있으니 이번 포스팅은 패턴을 만들고 그 패턴을 일정시간 유지하는 것에서 마무리 하도록 하겠습니다.

다음편에서는 이렇게 패턴을 만들고 for문을 통해서 일정시간을 유지시키는 방법으로 매 패턴들을 표현한다면 코딩량이 엄청나겠죠. 단 두가지 패턴을 코딩했는데도 이정도인데 10개이상 되는 패턴을 만든다면 노가다 코딩이 되겠죠.

그래서 중복되는 부분을 제거하는 코딩을 다음 포스팅에 연재 하도록 하겠습니다. 오늘은 이렇게 패턴을 만드는 것과 일정시간 유지하는 걸 배웠으니 어떤 패턴을 만들지 머리속에서 구상해보세요. 사실 전체과정을 동영상으로 기록하고 실제 아두이노에서도 결과까지 다 준비 됐는데 그건 다음에 올리도록 하겠습니다.

댓글()