아두이노로 LED matrix 제어하기 #10 : Dot control 2

2018. 2. 23. 12:19

Arduino/Display

Arduino LedControl Library : 도트 단위로 LED 제어하기 #2

우선 이전 글에 이어서, 가로 및 세로 선 그리기 함수를 이용하여 사각형 모양의 선을 그리는 함수를 작성하겠습니다.

또, 이제 까지의 선 그리기 함수는 하나의 모듈을 대상으로 하는데, 이를 3개의 모듈로 확장하는 것까지 이번 글에서 처리하도록 하겠습니다.

사각형 모양 선 그리기 함수 만들기

이전 글에서 가로, 세로 방향으로 원하는 길이만큼 선을 그리는 함수를 작성하였고, 이제부터 두 함수를 참고하여 사각형 모양의 선을 그리는 함수를 작성하겠습니다.

void lineRect(int topX, int topY, int bottomX, int bottomY)

사각형 선 그리기 함수의 호출문은 위와 같이 작성하였습니다. 총 4개의 인수가 필요하며 각각 시작 좌표와 끝 좌표의 X, Y값입니다.

위와 같이 시작 점과 끝 점의 X, Y 좌표 4개의 인수가 필요합니다. setRow() 함수는 어느 행(row)에 출력할 지 인수로 지정해야 하는데, topX와 bottomX로 지정하면 되고, 마찬가지로 setColumn() 함수도 topY, bottomY를 출력할 위치로 지정하면 됩니다.

void loop() {
  lineRect(0, 0, 7, 7);
  delay(500);
  lineRect(1, 1, 6, 6);
  delay(500);
  lineRect(2, 2, 5, 5);
  delay(500);
  lineRect(3, 3, 4, 4);
  delay(500);
}

loop() 함수에서 위와 같이 함수를 호출합니다. 시작점과 끝점이 1씩 줄거나 늘어나고 있는데, 사각형이 점점 중앙을 향해 모여드는 모습을 표현하도록 구성하였습니다.

// 선 그리기 - 사각형
void lineRect(int topX, int topY, int bottomX, int bottomY) {
  byte data = B11111111;
  data = (data >> topY) & (data << (7 - bottomY));
  lc.setRow(0, topX, data);
}

우선, 위쪽 가로 선을 그리는 코드만 작성하였습니다. 가로 방향 선그리기 함수인 lineRow() 함수를 그대로 가져와서 인수명만 수정해도 원하는 결과를 볼 수 있습니다.

topX 인수가 위쪽 라인이 출력될 row값에 해당하고 topY와 bottomY가 라인의 길이를 계산하는 데 사용됩니다.

결과 화면입니다. 각 사각형의 위 쪽 라인만 500밀리초 간격으로 차례대로 출력됩니다.

// 선 그리기 - 사각형
void lineRect(int topX, int topY, int bottomX, int bottomY) {
  byte data = B11111111;
  data = (data >> topY) & (data << (7 - bottomY));
  lc.setRow(0, topX, data);
  lc.setRow(0, bottomX, data);
}

6번 행을 추가하여 아래쪽 라인도 함께 그리도록 했습니다. 위, 아래 라인의 길이는 동일하기 때문에 따로 계산할 필요가 없고, 아래쪽 라인이 출력될 행(row)은 bottomX 변수값을 사용하면 됩니다.

결과 화면입니다. 같은 변수(data)를 사용해서 출력했기 때문에 대칭 모양을 보이고 있습니다.

void loop() {
  lineRect(0, 0, 7, 7);
  delay(500);
  lc.clearDisplay(0);
  lineRect(1, 1, 6, 6);
  delay(500);
  lc.clearDisplay(0);
  lineRect(2, 2, 5, 5);
  delay(500);
  lc.clearDisplay(0);
  lineRect(3, 3, 4, 4);
  delay(500);
  lc.clearDisplay(0);
}

세로 변 그리는 코드를 만들기 전에, 위와 같이 함수 호출후에 화면을 지워주도록 추가했습니다. 이 코드는 중첩하여 출력하는 기능이 없기 때문에 새로 출력하기 전에 이전 것은 지워줘야 합니다.

// 선 그리기 - 사각형
void lineRect(int topX, int topY, int bottomX, int bottomY) {
  // 출력전에 화면 지움
  lc.clearDisplay(0);
  byte dataRow = B11111111;
  byte dataCol = B11111111;
  dataRow = (dataRow >> topY) & (dataRow << (7 - bottomY));
  dataCol = (dataCol >> topX) & (dataCol << (7 - bottomX));
  lc.setRow(0, topX, dataRow);
  lc.setRow(0, bottomX, dataRow);
  lc.setColumn(0, topY, dataCol);
  lc.setColumn(0, bottomY, dataCol);
}

행과 열에 대한 데이터가 있어야 하므로 변수 하나를 추가하여 dataRow, dataCol로 이름 붙였습니다. 계산식은 행과 열이 동일하기에 복사한 후 변수명만 알맞게 고쳐주었고, 세로 방향이므로 setColumn() 함수를 추가하여 좌, 우 변을 출력하도록 했습니다.

#include "LedControl.h"
LedControl lc = LedControl(12,11,10,3);
//
void setup() {
  lc.shutdown(0, false);
  lc.shutdown(1, false);
  lc.shutdown(2, false);
  //
  lc.clearDisplay(0);
  lc.clearDisplay(1);
  lc.clearDisplay(2);
}
//
void loop() {
  int i, j;
  for (i = 0; i <= 7; i++) {
    lineRow(i, 0, 7);
    delay(100);
  }
  for (i = 0; i <= 7; i++) {
    lc.setRow(0, i, 0);
    delay(100);
  }
  for (i = 0; i <= 7; i++) {
    lineCol(i, 0, 7);
    delay(100);
  }
  for (i = 0; i <= 7; i++) {
    lc.setColumn(0, i, 0);
    delay(100);
  }
  for (i = 0; i <= 7; i++) {
    lineRow(i, 0, i);
    delay(100);
  }
  for (i = 0; i <= 7; i++) {
    lineRow(i, i, 7);
    delay(100);
  }
  for (i = 0; i <= 5; i++) {
    lc.clearDisplay(0);
    lineRect(i, i, 7 - i, 7 - i);
    delay(400);
  }
}
// 선 그리기 - 행 방향
void lineRow(int row, int startLed, int endLed) {
  byte data = B11111111;
  data = (data >> startLed) & (data << (7 - endLed));
  lc.setRow(0, row, data);
}
// 선 그리기 - 열 방향
void lineCol(int col, int startLed, int endLed) {
  byte data = B11111111;
  data = (data >> startLed) & (data << (7 - endLed));
  lc.setColumn(0, col, data);
}
// 선 그리기 - 사각형
void lineRect(int topX, int topY, int bottomX, int bottomY) {
  byte dataRow = B11111111;
  byte dataCol = B11111111;
  dataRow = (dataRow >> topY) & (dataRow << (7 - bottomY));
  dataCol = (dataCol >> topX) & (dataCol << (7 - bottomX));
  lc.setRow(0, topX, dataRow);
  lc.setRow(0, bottomX, dataRow);
  lc.setColumn(0, topY, dataCol);
  lc.setColumn(0, bottomY, dataCol);
}

여기까지 해서, 하나의 모듈을 대상으로 하는 가로, 세로, 네모 선 그리기 함수를 작성해 보았고, 이들을 조합하여 간단한 출력 예제를 작성하였습니다. 결과 화면은 아래 동영상을 보시면 됩니다.

세 개의 모듈에 가로 선 그리기

이제까지의 그리기 함수는 하나의 모듈을 대상으로 했습니다. 이제, 3개의 모듈을 하나의 화면으로 삼아 선을 그리는 함수를 작성해 보겠습니다. 먼저 가로 선 그리기 함수입니다.

모듈이 3개이기 때문에, 각 모듈에 그려질 데이터를 준비하기 위한 변수로 data[3]를 사용하고, 적절한 비트 연산 등을 이용해 각 변수를 채우도록 합니다.

void lineRow(int row, int startLed, int endLed) {
  int i;
  byte data[3] = {B00000000, B00000000, B00000000};
  //
  lc.setRow(0, row, data[0]);
  lc.setRow(1, row, data[1]);
  lc.setRow(2, row, data[2]);
}

for문 첨자로 쓰일 변수 i와 각 모듈의 데이터를 담을 byte type의 변수 data[3]을 선언하였습니다. 우선 모든 비트를 "0"으로 초기화한 후, 필요한 비트만 "1"로 세팅하도록 코딩할 것입니다.

모든 데이터가 처리된 후에는 setRow() 함수를 이용하여 각 모듈에 차례대로 출력해 줍니다.

// 1번 모듈에 해당하는 데이터 구하기
  for (i = startLed; (i <= 7) && (i <= endLed); i++) {
    data[0] = data[0] | B10000000 >> i;
  }

우선, 첫 번째 모듈에 출력할 데이터를 구하는 코드입니다. 마치 펜으로 선을 그리듯이, 시작점(startLed)에서 부터 비트를 "1"로 채워 나갑니다. 만약, 시작점이 첫 번째 모듈이 아닌 두, 세 번째 모듈이라면 저 for문은 실행하지 않습니다. 시작점이 for문 반복을 위한 변수 i의 초기값(i = startLed)이기 때문에, 첫 번째 모듈의 LED 범위를 벗어날 경우(i <= 7) for문을 아예 진입하지 않기 때문입니다.

for문의 반복을 위한 조건은 두 가지입니다. i = 7 과 i <= endLed 가 AND 연산으로 연결되어 있기 때문에 둘 다 만족해야 합니다. 그리려는 선의 끝점이 첫 번째 모듈안에 있을 경우도 체크해야 하기 때문입니다.

for문 안쪽은 딱 한 줄의 코드만 있습니다. 반복할 때마다 i 값이 증가하고 그 값만큼 비트 시프트를 실행합니다. 이렇게 하면 원하는 부분의 비트값을 "1"로 만들 수 있고, 이 값을 첫 번째 모듈을 위한 데이터(data[0])에 비트OR 연산으로 합쳐 주는 것입니다.

// 2번 모듈에 해당하는 데이터 구하기
  if (endLed >= 8) {
    for (i = (startLed - 8); (i <= 7) && (i <= (endLed - 8)); i++) {
      data[1] = data[1] | B10000000 >> i;
    }
  }

출력할 데이터가 2번 모듈에 걸쳐 있을 때만 실행되는 코드입니다. if문에서 끝 점이 2번 모듈이나 3번 모듈에 있는지(endLed >= 8) 체크합니다. 끝 점이 "7" 이하라면 그릴려는 선이 1번 모듈에만 있기 때문에 이 코드는 실행하지 않습니다. 나머지는 1번 모듈을 위한 위 쪽 코드와 동일합니다.

3개 모듈의 LED를 0번에서 23번까지 번호 붙여 코딩하고 있지만, 어느 한 모듈내에서는 0번에서 7번으로 변환해야 합니다. 두 번째 모듈도 8번에서 15번까지의 인덱스값을, 시작 점과 끝 점에서 "8"씩 빼서 0번 ~ 7번으로 변환해주었습니다. 

// 선 그리기 - 행 방향
void lineRow(int row, int startLed, int endLed) {
  int i;
  byte data[3] = {B00000000, B00000000, B00000000};
  // 1번 모듈에 해당하는 데이터 구하기
  for (i = startLed; (i <= 7) && (i <= endLed); i++) {
    data[0] = data[0] | B10000000 >> i;
  }
  // 2번 모듈에 해당하는 데이터 구하기
  if (endLed >= 8) {
    for (i = (startLed - 8); (i <= 7) && (i <= (endLed - 8)); i++) {
      data[1] = data[1] | B10000000 >> i;
    }
  }
  // 3번 모듈에 해당하는 데이터 구하기
  if (endLed >= 16) {
    for (i = (startLed - 16); (i <= 7) && (i <= (endLed - 16)); i++) {
      data[2] = data[2] | B10000000 >> i;
    }
  }
  lc.setRow(0, row, data[0]);
  lc.setRow(1, row, data[1]);
  lc.setRow(2, row, data[2]);
}

완성된 함수 코드입니다. 3번 모듈도 같은 방식으로 추가했습니다.

// 선 그리기 - 행 방향
void lineRow(int row, int startLed, int endLed) {
  int i;
  byte data[3] = {B00000000, B00000000, B00000000};
  // 출력할 데이터 구하기
  for ( i = startLed; i <= endLed; i++) {
    if (i <= 7) {
      data[0] = data[0] | B10000000 >> i;
    } else if (i <= 15) {
      data[1] = data[1] | B10000000 >> (i - 8);
    } else if (i <= 23) {
      data[2] = data[2] | B10000000 >> (i - 16);
    }
  }
  lc.setRow(0, row, data[0]);
  lc.setRow(1, row, data[1]);
  lc.setRow(2, row, data[2]);
}

위 함수를 하나의 for문과 if문을 사용하여 좀 더 간단하게 표현한 코드입니다. 결과는 역시 동일합니다.

#include "LedControl.h"
LedControl lc = LedControl(12,11,10,3);
//
void setup() {
  lc.shutdown(0, false);
  lc.shutdown(1, false);
  lc.shutdown(2, false);
  //
  lc.clearDisplay(0);
  lc.clearDisplay(1);
  lc.clearDisplay(2);
}
//
void loop() {
  int i;
  for (i = 0; i <= 7; i++) {
    lineRow(i, 0, 23);
    delay(60);
  }
  for (i = 0; i <= 7; i++) {
    lc.setRow(0, i, 0);
    lc.setRow(1, i, 0);
    lc.setRow(2, i, 0);
    delay(60);
  }
  for (i = 0; i <= 7; i = i + 2) {
    lineRow(i, 0, 23);
    delay(60);
  }
  for (i = 1; i <= 7; i = i + 2) {
    lineRow(i, 0, 23);
    delay(60);
  }
  for (i = 0; i <= 7; i = i + 2) {
    lc.setRow(0, i, 0);
    lc.setRow(1, i, 0);
    lc.setRow(2, i, 0);
    delay(60);
  }
  for (i = 1; i <= 7; i = i + 2) {
    lc.setRow(0, i, 0);
    lc.setRow(1, i, 0);
    lc.setRow(2, i, 0);
    delay(60);
  }
  for (i = 0; i <= 7; i++) {
    lineRow(i, 0, 7);
    delay(60);
  }
  for (i = 0; i <= 7; i++) {
    lineRow(i, 8, 15);
    delay(60);
  }
  for (i = 0; i <= 7; i++) {
    lineRow(i, 16, 23);
    delay(60);
  }
  lc.clearDisplay(2);
  for (i = 0; i <= 23; i++) {
    lineRow(0, 0, i);
    delay(60);
  }
  for (i = 23; i >= 0; i--) {
    lineRow(1, i, 23);
    delay(60);
  }
  for (i = 0; i <= 24; i++) {
    lineRow(2, i, 24);
    delay(60);
  }
  for (i = 23; i >= -1; i--) {
    lineRow(3, 0, i);
    delay(60);
  }
  for (i = 0; i <= 24; i++) {
    lineRow(4, i, i + 8);
    delay(60);
  }
  for (i = 0; i <= 24; i++) {
    lineRow(5, i, i + 5);
    delay(30);
  }
  for (i = 0; i <= 23; i++) {
    lineRow(6, 0, i);
    delay(30);
  }
  for (i = 0; i <= 24; i++) {
    lineRow(6, i, 24);
    delay(30);
  }
  for (i = 23; i >= 0; i--) {
    lineRow(7, i, 23);
    delay(30);
  }
  for (i = 23; i >= -1; i--) {
    lineRow(7, 0, i);
    delay(30);
  }
  lc.clearDisplay(0);
  lc.clearDisplay(1);
  lc.clearDisplay(2);
}
// 선 그리기 - 행 방향
void lineRow(int row, int startLed, int endLed) {
  int i;
  byte data[3] = {B00000000, B00000000, B00000000};
  // 출력할 데이터 구하기
  for ( i = startLed; i <= endLed; i++) {
    if (i <= 7) {
      data[0] = data[0] | B10000000 >> i;
    } else if (i <= 15) {
      data[1] = data[1] | B10000000 >> (i - 8);
    } else if (i <= 23) {
      data[2] = data[2] | B10000000 >> (i - 16);
    }
  }
  lc.setRow(0, row, data[0]);
  lc.setRow(1, row, data[1]);
  lc.setRow(2, row, data[2]);
}

몇 가지 예제를 실행하는 프로그램 전체 소스입니다. 결과는 아래 동영상을 확인하시면 됩니다.

세 개의 모듈에 세로 선 그리기

우선 모듈이 옆으로 붙어 있고 아래쪽은 없기 때문에 세로 선의 길이는 이전과 동일(0 ~ 7)합니다. 단지, 출력될 위치가 세 개의 모듈중 어느 곳인지만 체크하면 됩니다.

// 선 그리기 - 열 방향
void lineCol(int col, int startLed, int endLed) {
  byte data = B11111111;
  data = (data >> startLed) & (data << (7 - endLed));
  if (col <= 7) {
    lc.setColumn(0, col, data);
  } else if (col <= 15) {
    lc.setColumn(1, col - 8, data);
  } else if (col <= 23) {
    lc.setColumn(2, col - 16, data);
  }
}

세로 선을 그리는 함수의 전체 코드입니다. 표시된 부분만 추가됐을 뿐, 나머지는 이전의 코드와 동일합니다. 출력될 위치(int col)의 값을 따져서 몇 번째 모듈인지 확인하는 부분이 5번 행부터 11번 행까지 해당하며, 세 개의 모듈에 걸쳐 출력될 일이 없기 때문에 출력 코드도 단순합니다.

#include "LedControl.h"
// 3개 모듈 세로 선 그리기
LedControl lc = LedControl(12,11,10,3);
//
void setup() {
  lc.shutdown(0, false);
  lc.shutdown(1, false);
  lc.shutdown(2, false);
  //
  lc.clearDisplay(0);
  lc.clearDisplay(1);
  lc.clearDisplay(2);
}
//
void loop() {
  int i;
  for (i = 0; i <= 23; i++) {
    lineCol(i, 0, 7);
    delay(60);
  }
  for (i = 0; i <= 7; i++) {
    lc.setColumn(0, i, 0);
    delay(60);
  }
  for (i = 0; i <= 7; i++) {
    lc.setColumn(1, i, 0);
    delay(60);
  }
  for (i = 0; i <= 7; i++) {
    lc.setColumn(2, i, 0);
    delay(60);
  }
  for (i = 23; i >= 0; i--) {
    lineCol(i, 0, 7);
    delay(60);
  }
  for (i = 7; i >= 0; i--) {
    lc.setColumn(2, i, 0);
    delay(60);
  }
  for (i = 7; i >= 0; i--) {
    lc.setColumn(1, i, 0);
    delay(60);
  }
  for (i = 7; i >= 0; i--) {
    lc.setColumn(0, i, 0);
    delay(60);
  }
  for (i = 0; i <= 7; i++) {
    lineCol(i, 0, i);
    delay(60);
  }
  for (i = 8; i <= 15; i++) {
    lineCol(i, 0, 8 - (i - 8));
    delay(60);
  }
  for (i = 16; i <= 23; i++) {
    lineCol(i, 0, i - 16);
    delay(60);
  }
  for (i = 0; i <= 7; i++) {
    lineCol(i, 0, 8 - i);
    delay(60);
  }
  for (i = 8; i <= 15; i++) {
    lineCol(i, 0, i - 8);
    delay(60);
  }
  for (i = 16; i <= 23; i++) {
    lineCol(i, 0, 8 - (i - 16));
    delay(60);
  }
  for (i = 0; i < 4; i++) {
    lineCol(i, 3 - i, 4 + i);
    delay(30);
  }
  for (i = 0; i < 4; i++) {
    lineCol(i + 4, i, 7 - i);
    delay(30);
  }
  for (i = 0; i < 4; i++) {
    lineCol(i + 8, 3 - i, 4 + i);
    delay(30);
  }
  for (i = 0; i < 4; i++) {
    lineCol(i + 12, i, 7 - i);
    delay(30);
  }
  for (i = 0; i < 4; i++) {
    lineCol(i + 16, 3 - i, 4 + i);
    delay(30);
  }
  for (i = 0; i < 4; i++) {
    lineCol(i + 20, i, 7 - i);
    delay(30);
  }
  delay(500);
  lc.clearDisplay(0);
  lc.clearDisplay(1);
  lc.clearDisplay(2);
}
// 선 그리기 - 열 방향
void lineCol(int col, int startLed, int endLed) {
  byte data = B11111111;
  data = (data >> startLed) & (data << (7 - endLed));
  if (col <= 7) {
    lc.setColumn(0, col, data);
  } else if (col <= 15) {
    lc.setColumn(1, col - 8, data);
  } else if (col <= 23) {
    lc.setColumn(2, col - 16, data);
  }
}

예제를 포함한 전체 소스입니다. 결과도 동영상으로 확인할 수 있습니다.

3개의 모듈에 사각 모양 선 그리기 함수 구현

선 그리기 함수의 마지막으로 사각 모양으로 선을 출력하는 함수를 만들겠습니다. 가로, 세로 선 그리기 함수를 합치기만 하면 되기 때문에 간단하게 만들 수 있습니다.

// 선 그리기 - 사각형
void lineRect(int topX, int topY, int bottomX, int bottomY) {
  int i;
  byte dataRow[3] = {B00000000, B00000000, B00000000};
  byte dataCol = B11111111;
  //
  //
}

우선 기본 구조는 모듈 하나를 위한 함수와 동일합니다. 가로, 세로 각각 출력 데이터를 위한 변수를 선언하고 초기화해주었습니다.

// 선 그리기 - 사각형
void lineRect(int topX, int topY, int bottomX, int bottomY) {
  int i;
  byte dataRow[3] = {B00000000, B00000000, B00000000};
  byte dataCol = B11111111;
  //
  // 가로 방향 출력할 데이터 구하기
  for ( i = topX; i <= bottomX; i++) {
    if (i <= 7) {
      dataRow[0] = dataRow[0] | B10000000 >> i;
    } else if (i <= 15) {
      dataRow[1] = dataRow[1] | B10000000 >> (i - 8);
    } else if (i <= 23) {
      dataRow[2] = dataRow[2] | B10000000 >> (i - 16);
    }
  }
  // 세로 방향 출력할 데이터 구하기
  dataCol = (dataCol >> topY) & (dataCol << (7 - bottomY)); 
  //
}

가로, 세로 출력 데이터를 구하는 코드입니다. 각각의 함수에서 복사해 온 후, 변수 이름만 맞게 고쳐주었습니다.

  // 가로 방향 윗 변 출력하기
  lc.setRow(0, topY, dataRow[0]);
  lc.setRow(1, topY, dataRow[1]);
  lc.setRow(2, topY, dataRow[2]);
  // 가로 방향 윗 변 출력하기
  lc.setRow(0, bottomY, dataRow[0]);
  lc.setRow(1, bottomY, dataRow[1]);
  lc.setRow(2, bottomY, dataRow[2]);
  // 세로 방향 왼쪽 변 출력
  if (topX <= 7) {
    lc.setColumn(0, topX, dataCol);
  } else if (topX <= 15) {
    lc.setColumn(1, topX - 8, dataCol);
  } else if (topX <= 23) {
    lc.setColumn(2, topX - 16, dataCol);
  }
  // 세로 방향 오른쪽 변 출력
  if (bottomX <= 7) {
    lc.setColumn(0, bottomX, dataCol);
  } else if (bottomX <= 15) {
    lc.setColumn(1, bottomX - 8, dataCol);
  } else if (bottomX <= 23) {
    lc.setColumn(2, bottomX - 16, dataCol);
  }

화면 출력 코드입니다. 이전 함수와 동일하고 단지, 모듈이 3개여서 한 쪽변에 3번씩 출력하는 것만 다릅니다. 아래쪽 세로 방향 출력은 역시 위에서 만든 세로 선 그리기 함수에서 가져와 변수명만 고쳤습니다.

#include "LedControl.h"
// 3개 모듈 사각모양 선 그리기
LedControl lc = LedControl(12,11,10,3);
//
void setup() {
  lc.shutdown(0, false);
  lc.shutdown(1, false);
  lc.shutdown(2, false);
  //
  lc.clearDisplay(0);
  lc.clearDisplay(1);
  lc.clearDisplay(2);
}
//
void loop() {
  int i, j;
  for (j = 0; j < 3; j++) {
    for (i = 0; i < 4; i++) {
      lineRect(0 + i, 0 + i, 23 - i, 7 - i);
      delay(100);
      lc.clearDisplay(0);
      lc.clearDisplay(1);
      lc.clearDisplay(2);
    }
  }
  for (i = 0; i < 24; i++) {
    lineRect(0 + i, 0, 3 + i, 3);
    delay(60);
    lc.clearDisplay(0);
    lc.clearDisplay(1);
    lc.clearDisplay(2);
  }
  for (i = 0; i < 7; i++) {
    lineRect(0, 0, 2 + i * 3, 0 + i);
    delay(60);
    lc.clearDisplay(0);
    lc.clearDisplay(1);
    lc.clearDisplay(2);
  }
  bool down = true;
  j = 0;
  for (i = 0; i < 24; i++) {
    if (down) {
      lineRect(0 + i, 0 + j, 2 + i, 2 + j);
      j++;
      if (j > 5) down = false;
    } else {
      j--;
      lineRect(0 + i, 0 + j, 2 + i, 2 + j);
      if ( j == 0) down = true;
    }
    delay(80);
    lc.clearDisplay(0);
    lc.clearDisplay(1);
    lc.clearDisplay(2);
  }
}
// 선 그리기 - 사각형
void lineRect(int topX, int topY, int bottomX, int bottomY) {
  int i;
  byte dataRow[3] = {B00000000, B00000000, B00000000};
  byte dataCol = B11111111;
  // 가로 방향 출력할 데이터 구하기
  for ( i = topX; i <= bottomX; i++) {
    if (i <= 7) {
      dataRow[0] = dataRow[0] | B10000000 >> i;
    } else if (i <= 15) {
      dataRow[1] = dataRow[1] | B10000000 >> (i - 8);
    } else if (i <= 23) {
      dataRow[2] = dataRow[2] | B10000000 >> (i - 16);
    }
  }
  // 세로 방향 출력할 데이터 구하기
  dataCol = (dataCol >> topY) & (dataCol << (7 - bottomY));
  //
  // 가로 방향 윗 변 출력하기
  lc.setRow(0, topY, dataRow[0]);
  lc.setRow(1, topY, dataRow[1]);
  lc.setRow(2, topY, dataRow[2]);
  // 가로 방향 윗 변 출력하기
  lc.setRow(0, bottomY, dataRow[0]);
  lc.setRow(1, bottomY, dataRow[1]);
  lc.setRow(2, bottomY, dataRow[2]);
  // 세로 방향 왼쪽 변 출력
  if (topX <= 7) {
    lc.setColumn(0, topX, dataCol);
  } else if (topX <= 15) {
    lc.setColumn(1, topX - 8, dataCol);
  } else if (topX <= 23) {
    lc.setColumn(2, topX - 16, dataCol);
  }
  // 세로 방향 오른쪽 변 출력
  if (bottomX <= 7) {
    lc.setColumn(0, bottomX, dataCol);
  } else if (bottomX <= 15) {
    lc.setColumn(1, bottomX - 8, dataCol);
  } else if (bottomX <= 23) {
    lc.setColumn(2, bottomX - 16, dataCol);
  }
}

완성된 함수와 예제 소스입니다.

이전 글부터 여기까지 가로, 세로, 네모 모양의 선을 그리는 함수를 작성하였습니다. 먼저 하나의 모듈을 대상으로 출력하는 함수를 작성하고, 이번 글에서 3개의 모듈로 확장하였습니다. 특히, 비트 연산자를 통하여 출력 데이터를 준비하는 코드를 이용하여 도트(개별 LED) 단위로 출력하는 방법을 알아 보았습니다.

이상입니다.

Comments