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

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

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



지난 시간에 3x3x3 CUBE LED 패턴 포스팅에서 패턴을 만드는 것과 그걸 일정시간 유지하는 방법을 배웠습니다. 그리고 2가지 패턴을 교차로 LED를 깜박이게 하는 것까지 했었죠. 이제는 패턴을 좀 더 길게 만들고 중복되는 코딩 부분을 제거하여 코딩을 최소화하는 과정을 배워 보겠습니다.


1. 3x3x3 CUBE LED 회로도 구성


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


2. 패턴 코딩 과정


패턴 코딩 과정의 두번째 시간입니다. 지난시간의 코드에서 연장선상에서 이여가겠습니다.

[ 1층1호실2층2호실과 1층2호실2층1호실 교차 깜박이기]

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()
{
    //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<30;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문 이하의 안에 명령문들이 두번 중복되는 것을 보실거에요. 2가지여서 2번 중복되었는데 10가지라면 10번 for문을 코딩해야한다면 정말 노가다 코딩이 되겠죠.

[ 중복코드를 외부함수로 ]

이제는 그 중복되는 부분을 차라리 외부로 빼서 호출하여 명령을 수행하도록 하여 코딩하는 양을 줄이도록 하겠습니다.

void pattern(int layer1, int layer2, int room1, int room2){
  for(int i=0;i<30;i++){ //for문이 delay()함수 효과
    digitalWrite(layer1, LOW); 
    digitalWrite(room1, HIGH);  
    delay(10);
    digitalWrite(room1, LOW);  
    digitalWrite(layer1, HIGH); 
  
    digitalWrite(layer2, LOW); 
    digitalWrite(room2, HIGH);  
    delay(10);
    digitalWrite(room2, LOW);  
    digitalWrite(layer2, HIGH); 
  }  
}

새롭게 함수를 만들었습니다. 그렇게 이 로직은 사실 기존의 코딩한 로직의 연장 선상으로 표현한 것입니다. 사실은 이렇게 하면 안되고 내부 로직도 변경하고 명령문도 새롭게 만들어야 합니다. 혼동을 최소화하기 위해서 이전 코드를 그대로 인용하여 표현했다는 점을 감안하시고 보셨으면 해요.

그러면, 어떻게 loop()함수에서 코딩이 될까요.

void loop(){
    pattern(layer[0],layer[1],room[0],room[1]);  //1층1호실, 2층2호실
    pattern(layer[0],layer[1],room[1],room[0]);  //1층2호실, 2층1호실
}

  • pattern(1층,2층,1층호실,2층호실) : 2층과 2호실에 제어.

코딩이 딱 두줄로 바뀌었지요. 그리고 loop()함수만 봐도 대충 의미를 이해하실꺼에요.

좀 길게 스토리를 만들어 볼까요. 가령 1층은 1호실부터 9호실까지 순차적으로 깜박이고 2층은 9호실부터 1호실까지 순차적으로 깜박이게 명령을 내려 볼까요.

void loop(){
    pattern(layer[0],layer[1],room[0],room[8]);  
    pattern(layer[0],layer[1],room[1],room[7]);  
    pattern(layer[0],layer[1],room[2],room[6]);  
    pattern(layer[0],layer[1],room[3],room[5]);  
    pattern(layer[0],layer[1],room[4],room[4]);  
    pattern(layer[0],layer[1],room[5],room[3]);  
    pattern(layer[0],layer[1],room[6],room[2]);  
    pattern(layer[0],layer[1],room[7],room[1]);  
    pattern(layer[0],layer[1],room[8],room[0]);     
}

그런데, 또 문제가 생겼네요. 중복 제거 코딩을 했는데 또 중복이 발생했네요. 불필요한 코딩이 늘어났는데 다시 해결해 볼까요. 이번에도 순차적이니깐 for문으로 처리해 버리죠.

void loop(){
  for(int i=0;i<9;i++){
    pattern(layer[0],layer[1],room[i],room[8-i]);    
  }
}

간단히 loop()함수 내 3출 코딩으로 줄어 들었네요. 이제 더 나아가 반대로 역순으로 깜박이게 하고 싶은 충동이 안느껴지나요. 위 for문에서 room[i],room[8-i]만 서로 바꿔주면 됩니다. 그래서 아래와 같은 완성된 코드만 만들어집니다.

void loop(){
 
  //for문으로 한줄 명령으로 릴레이  
  for(int i=0;i<9;i++){
    pattern(layer[0],layer[1],room[i],room[8-i]);    
  }  
    
  //역순  
  for(int i=0;i<9;i++){
    pattern(layer[0],layer[1],room[8-i],room[i]);    
  }
}

만약에 이 명령문들을 일일히 수작업으로 명령을 다 코딩했다고 생각해보세요. pattern()함수를 릴레이 패턴 for문 당 9번 총 pattern()함수 내부의 코드를 18번 일일히 수정하면서 코딩해야 합니다. pattern()함수 내부 명령문들도 많은데 그 많은 명령문을 18번이나 중복해서 코딩해야 한다고 상상해보세요. 진정한 노가맨이 되겠죠.

프로그램 문법을 좀 배우면 표현력의 한계는 없고 남들보다 더 쉬운 코딩을 할 수 있습니다.

loop()함수안의 코드는 의미전달과 최소화만 해야합니다. 뭘 하는지만 전달해주고 세부적인 명령문들은 외부함수로 빼서 제어해야합니다. 그래야 나중에 코드를 수정하거나 다른사람들이 보기에도 편해집니다. 수작업으로 모든 명령문들을 일일히 loop() 함수에 다 집어 넣게 되면은 도대체 loop()함수 내에서 무슨 동작하는지 머리만 복잡해 집니다.

위 loop()함수 내 코드만 보더라도 pattern()함수를 for문으로 해서 순차적으로 뭘 표현했구나하고 쉽게 이해할 수 있습니다. 정확히 어떤 동작인지는 모르지만 pattern()함수라는 뭔지는 모르지만 9번 순차적으로 반복이 이루어졌고 그걸 또 역순으로 9번 순차적으로 진행했구나 정도는 쉽게 loop() 함수만 보면 알 수 있습니다. loop()함수의 동작은 pattern()함수는 아직은 뭔지 모르더라도 그걸 순차적으로 반복하고 또 역으로 반복했구나 쉽게 loop()함수의 동작을 이해 할 수 있습니다.

3. 소스


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문으로 한줄 명령으로 릴레이  
  for(int i=0;i<9;i++){
    pattern(layer[0],layer[1],room[i],room[8-i]);    
  }  

  //역순  
  for(int i=0;i<9;i++){
    pattern(layer[0],layer[1],room[8-i],room[i]);    
  }
}

void pattern(int layer1, int layer2, int room1, int room2){
  for(int i=0;i<30;i++){ //for문이 delay()함수 효과
    digitalWrite(layer1, LOW); 
    digitalWrite(room1, HIGH);  
    delay(10);
    digitalWrite(room1, LOW);  
    digitalWrite(layer1, HIGH); 
  
    digitalWrite(layer2, LOW); 
    digitalWrite(room2, HIGH);  
    delay(10);
    digitalWrite(room2, LOW);  
    digitalWrite(layer2, HIGH); 
  }  
}

4. 결과


어떻게 패턴 코딩을 진행했는지 녹화를 해 놓았으니깐 살펴보시고 마지막에 시뮬레이션 결과를 확인해 보세요. 실제 아두이노에서도 실행한 장면도 들어 있으니깐 보시고 결과물이 어떻게 나왔는지 확인해 주세요.

가상시뮬레이터에서 실험한 기록 일지

실제아두이노에서 실험한 영상

마무리


지난시간의 내용을 기반으로 오늘은 연장선상에서 이여갔습니다. 사실, 오늘 코딩한 것에도 문제점이 많습니다. 그것은 강제적으로 1층과 2층에 꼭 불이 하나는 들어와야 한다는 전재 조건이 있습니다. 그 부분을 수정하자면 pattern()함수 내부를 완전 수정해야하기 때문에 그냥 수정 안하고 그 문제점을 가지고 오늘 포스팅을 했네요. 오늘은 전달하고자 하는 바는 중복코드를 제거하는 방법입니다. 그리고 loop()함수의 명령문들은 뺄 수 있으면 외부 함수로 빼내고 하나의 묶음으로 묶어서 loop()내에서는 의미 전달코딩을 하면 보다 효율적인 코딩을 할 수 있다는 것을 보여 드리는게 목적입니다.

결론, loop()함수는 최소 동작의 의미만 표현하며 중복되는 부분은 외부함수로 빼서 표현의 최소화 입니다. 지난시간에는 서로다른 층의 다른 호실의 LED에 불이 들어오게 하는 방법과 패턴 LED가 일정시간 유지될 수 있도록 하는 방법을 배웠습니다. 이 두가지를 꼭 기억하셔서 다른 곳에서도 활용해 보세요.

마지막으로 상단에 가상 시뮬레이터에서 실험한 회로도가 공개 시켰네요. 혹시 회로도 만들기 귀찮은 분들을 위해서 패턴만 만들어보시라고 공개 했네요. 가셔서 계정이 있으면 복사하시면 본인 계정으로 회로도가 복사 됩니다. 거기서 편하게 편집하시면 됩니다.


댓글()