안녕하세요! 여러분의 AI-IT 멘토, '파이컴'입니다. 😊
지난 시간에는 7-세그먼트에 숫자 '0'을 띄워보는 실습을 했었죠? digitalWrite() 함수를 여러 번 써서 겨우 숫자 하나를 만들었는데요. 만약 0부터 9까지 모든 숫자를, 그것도 1초마다 자동으로 바뀌게 만들려면 어떻게 해야 할까요? 설마 코드를 100줄 넘게 복사-붙여넣기 해야 할까요? 생각만 해도 머리가 아프죠.
오늘은 바로 이 문제를 해결해 줄 아주 똑똑하고 효율적인 프로그래밍 기법을 배워볼 거예요. '2차원 배열'과 '중첩 반복문'이라는 강력한 도구를 사용해서, 복잡한 작업을 단 몇 줄의 코드로 깔끔하게 처리하는 방법을 알려드릴게요. 그럼, 아두이노로 '자동 숫자 카운터'를 만들러 함께 떠나볼까요?
Slide 1: 03. 자동 숫자 카운터 만들기
이번 시간에 우리가 만들 프로젝트는 바로 '자동 숫자 카운터'입니다. 7-세그먼트 디스플레이에 0부터 9까지 숫자가 1초 간격으로 착착 바뀌는 멋진 작품이죠.
이 프로젝트를 통해 우리는 단순히 결과를 만들어내는 것을 넘어, 복잡하고 반복적인 데이터를 어떻게 체계적으로 정리하고, 또 어떻게 효율적으로 처리할 수 있는지에 대한 중요한 프로그래밍 원리를 배우게 될 거예요.
Slide 2: 자동 카운터 회로
본격적으로 코드를 작성하기 전에, 먼저 회로부터 살펴볼게요.
📌 준비물
- 아두이노 우노
- 7-세그먼트
- 저항 (220옴 권장)
- 브레드보드 및 점퍼선
📌 회로 구성
슬라이드에 보이는 회로도는 낯이 익죠? 맞아요! 지난번 숫자 '0'을 표시했던 실습과 완전히 똑같습니다. 이미 회로를 잘 연결해 두었다면, 아무것도 바꿀 필요 없이 그대로 사용하면 된답니다. 혹시 처음이거나 해체했다면, 위 그림을 보고 차근차근 연결해주세요.
Slide 3: 자동 카운터 코드 (1) - 데이터 준비하기
자, 이제 마법 같은 코드의 비밀을 파헤쳐 볼 시간이에요. 코드가 겉보기엔 조금 복잡해 보이지만, 원리를 알면 정말 편리하답니다. 핵심은 "정답표를 미리 만들어두고, 아두이노가 그 표를 보고 따라 그리게 하는 것" 이에요.
❶ 핀 배열 선언
| 01 | int pin[7] = {2, 3, 4, 5, 6, 7, 8}; |
먼저, 7-세그먼트의 각 LED 조각(a, b, c, d, e, f, g)에 연결된 아두이노 핀 2번부터 8번까지를 pin이라는 이름의 배열(서랍장)에 순서대로 담아둬요. 이렇게 하면 나중에 핀 번호를 일일이 기억할 필요 없이 pin[0], pin[1]처럼 순서만으로 쉽게 꺼내 쓸 수 있어 편리해요.
❷ 모양 지도 (2차원 배열)
| 01 | int segmentArray[10][7] = { |
| 02 | {1, 1, 1, 1, 1, 1, 0}, // 0 |
| 03 | {0, 1, 1, 0, 0, 0, 0}, // 1 |
| 04 | {1, 1, 0, 1, 1, 0, 1}, // 2 |
| 05 | // ... (이하 생략) |
| 06 | }; |
이 코드의 심장, 바로 '모양 지도'라고 불리는 segmentArray입니다. 이것이 바로 2차원 배열이에요. 데이터를 마치 아파트처럼 '층(행)'과 '호수(열)'로 정리하는 방법이죠.
segmentArray[10][7]의 의미는 "10층짜리 아파트를 짓고, 각 층마다 7개의 방을 만들어줘!" 라는 뜻이에요.- 층(행): 0층부터 9층까지는 우리가 표시할 숫자 0부터 9를 의미해요.
- 방(열): 각 층의 7개 방에는 해당 숫자를 만들기 위해 7개 LED 조각(a~g)을 켤지(1) 끌지(0)에 대한 정보가 들어있어요.
예를 들어, 0층의 {1, 1, 1, 1, 1, 1, 0}은 숫자 '0'을 만들기 위해 g 조각만 끄고(0) 나머지는 모두 켠다(1)는 약속인 셈이죠. 이렇게 0부터 9까지 모든 숫자 모양을 미리 표로 만들어 두는 거예요.
Slide 4: 자동 카운터 코드 (2) - 똑똑하게 실행하기
'모양 지도'라는 멋진 설계도를 만들었으니, 이제 아두이노가 이 지도를 보고 실제로 그림을 그리도록 만들어야겠죠?
❶ 핀 모드 설정 (setup)
| 01 | void setup() { |
| 02 | // for문을 이용해 핀 7개를 한 번에 설정하기 |
| 03 | for (int n = 0; n < 7; n++) { |
| 04 | pinMode(pin[n], OUTPUT); |
| 05 | } |
| 06 | } |
이전에는 pinMode() 함수를 7번이나 썼지만, 이번엔 for 반복문을 사용해서 단 3줄로 끝냈어요. pin 배열에 저장된 핀 번호(2~8번)를 n이 0부터 6까지 변하는 동안 하나씩 꺼내서 모두 출력(OUTPUT) 모드로 설정하는 거죠. 정말 깔끔하고 효율적이지 않나요?
❷ 중첩 반복문 (loop)
| 01 | void loop() { |
| 02 | // 바깥쪽 for문: 0부터 9까지 숫자를 하나씩 바꿉니다. |
| 03 | for (int i = 0; i < 10; i++) { |
| 04 | // 안쪽 for문: 각 숫자에 맞는 7개의 조각(a~g)을 켜거나 끕니다. |
| 05 | for (int j = 0; j < 7; j++) { |
| 06 | digitalWrite(pin[j], segmentArray[i][j]); |
| 07 | } |
| 08 | delay(1000); // 1초 동안 보여주기 |
| 09 | } |
| 10 | } |
loop() 함수 안에는 반복문이 2개 겹쳐있는 중첩 반복문이 사용되었어요.
- 바깥쪽 for문 (변수
i): 0부터 9까지, 즉 어떤 숫자를 표시할지 결정하는 역할을 해요. - 안쪽 for문 (변수
j):i가 정해진 숫자일 때, 그 숫자를 만들기 위한 7개의 LED 조각을 하나씩 제어하는 역할을 하죠.
digitalWrite(pin[j], segmentArray[i][j]); 이 한 줄이 바로 마법의 핵심이에요!
"i번째 숫자를 만들기 위해, j번째 LED 조각을 켤지 끌지는 모양 지도 segmentArray의 i층 j호실에 적힌 값을 보고 결정해!" 라는 뜻이랍니다.
Slide 5: 2차원 배열의 개념
이번 실습의 핵심 개념인 2차원 배열에 대해 조금 더 자세히 알아볼게요.
- 형식:
자료형 배열이름[행개수][열개수];- 우리가 사용한
int segmentArray[10][7];는 정수(int) 데이터를 담는, 10행 7열짜리segmentArray라는 이름의 2차원 배열을 만들겠다는 의미예요.
- 우리가 사용한
- 구조:
- 행 (Row): 가로줄, 아파트의 층수에 해당해요. 우리 코드에서는 표시할 숫자의 종류(0~9, 총 10개)를 의미했죠.
- 열 (Column): 세로줄, 각 층마다 있는 방의 개수예요. 우리 코드에서는 각 숫자를 이루는 LED 조각의 개수(a~g, 총 7개)를 의미했고요.
- 사용 예시:
segmentArray[1][2]- 이건 '아파트 1층(숫자 1)의 2호실(c 조각)에 있는 값을 알려줘!' 라는 뜻이에요. 우리가 만든 모양 지도를 보면, 숫자 1을 나타내는
{0, 1, 1, 0, 0, 0, 0}에서 세 번째 값(인덱스는 0부터 시작하므로 2)은1이죠. 즉, 숫자 1을 표시할 때 c 조각은 켜야 한다는 걸 알 수 있어요.
- 이건 '아파트 1층(숫자 1)의 2호실(c 조각)에 있는 값을 알려줘!' 라는 뜻이에요. 우리가 만든 모양 지도를 보면, 숫자 1을 나타내는
- ⚠️ 주의사항:
- 컴퓨터의 세계에서는 모든 순서가 0부터 시작한다는 점, 정말 중요해요! 첫 번째 데이터의 주소는
[1][1]이 아니라[0][0]이라는 사실, 꼭 기억해주세요!
- 컴퓨터의 세계에서는 모든 순서가 0부터 시작한다는 점, 정말 중요해요! 첫 번째 데이터의 주소는
Slide 6: 중괄호 초기화의 의미
"선생님, 코드가 너무 복잡해 보여요!" 라고 생각할 수도 있어요. 하지만 우리가 중괄호 {...}를 사용한 덕분에 코드가 놀랍도록 짧아진 거랍니다.
- 간편한 방법 (중괄호 사용):
int arr[2][2] = {{1,2}, {3,4}};- 배열을 선언하는 동시에 중괄호를 이용해 초기값을 한 번에 싹 채워 넣는 방식이에요. 우리가 쓴
segmentArray코드가 바로 이 방법을 사용한 거죠.
- 배열을 선언하는 동시에 중괄호를 이용해 초기값을 한 번에 싹 채워 넣는 방식이에요. 우리가 쓴
- 원래 방법 (하나씩 대입):
CODE 6.1 | 원래 방법 (하나씩 대입)
01 int segmentArray[10][7]; // 1. 빈 아파트를 짓고, 02 03 // 2. 70개의 방에 하나하나 값을 넣어줌 04 segmentArray[0][0] = 1; 05 segmentArray[0][1] = 1; 06 ... 07 segmentArray[9][6] = 1; // 총 70줄 필요! - 만약 중괄호 초기화 기능을 쓰지 않는다면, 먼저 빈 배열(아파트)을 만들고, 70개의 모든 칸(방)에 값을 하나씩 일일이 넣어주는 코드를 작성해야 해요. 무려 70줄이 넘게 필요하죠!
- 장점:
- 결국 중괄호 초기화는 이 70줄이 넘는 지루한 과정을 단 몇 줄로 깔끔하게 정리해주는 아주 고마운 기능이랍니다.
Slide 7: 중첩 반복문의 원리
마지막으로, 중첩 반복문이 어떻게 그렇게 효율적으로 동작하는지 시계바늘에 비유해서 알아볼게요.
- 시계바늘 비유:
- 안쪽 반복문 (분침): 빠르게 회전해요. 한 바퀴(0~6까지 7번)를 싹 돌아야 자기 임무가 끝나요.
- 바깥쪽 반복문 (시침): 천천히 움직여요. 안쪽 반복문(분침)이 한 바퀴를 다 돌아야만, 겨우 한 칸(예:
i가 0에서 1로) 움직이죠.
- 실행 순서:
- 바깥쪽 루프 시작 (
i = 0): "자, 숫자 '0'을 만들 차례야!" - 안쪽 루프 실행 (
j = 0~6): '0'을 만들기 위해 a~g 조각 7개를segmentArray[0]줄을 보며 7번 제어해요. → 숫자 '0' 모양 완성! - 안쪽 루프 종료, 바깥쪽 루프 진행 (
i = 1): "이제 숫자 '1'을 만들 차례야!" - 안쪽 루프 다시 실행 (
j = 0~6): '1'을 만들기 위해 a~g 조각 7개를segmentArray[1]줄을 보며 7번 제어해요. → 숫자 '1' 모양 완성! - ... 이 과정을
i가 9가 될 때까지 반복해요.
- 바깥쪽 루프 시작 (
- 효율성:
- 결과적으로 (숫자 10개) × (LED 조각 7개) = 총 70번의 동작을 단 몇 줄의 코드로 완벽하게 처리하는 놀라운 효율을 보여주는 거죠!
어떤가요? 오늘 우리는 2차원 배열로 복잡한 데이터를 '모양 지도'처럼 깔끔하게 정리하고, 중첩 반복문으로 이 지도를 읽어 70번의 반복 작업을 자동화하는 방법을 배웠어요. 처음에는 조금 낯설 수 있지만, 이 두 가지 개념은 앞으로 여러분이 더 복잡하고 멋진 프로젝트를 만드는 데 아주 중요한 무기가 될 거예요.
오늘 배운 내용을 응용해서 카운터가 9부터 0까지 거꾸로 세게 하거나, 홀수나 짝수만 표시하도록 코드를 직접 수정해보는 건 어떨까요? 직접 코드를 만져보면서 오늘 배운 내용을 완벽히 여러분의 것으로 만들어보세요!
궁금한 점이 있다면 언제든 댓글로 질문해주세요. 그럼, 다음 시간에 더 재미있는 주제로 다시 만나요! 👋
이 포스팅의 내용은 교재 [주니어 공학교실 아두이노의 기초] - 페이지에 수록된 내용입니다.
댓글 없음:
댓글 쓰기