아이가 런닝맨을 좋아해서 런닝맨에 가끔 나오는 만보기 게임기를 만들었습니다. 포스트를 작성하는 동안에도 주머니에 넣고 온 집을 뛰어다니고 있습니다 ㅋㅋ 아래는 손으로 흔들기 데모입니다. 부저가 울리면 시작되고, 부저가 다시 울리면 흔들어도 숫자가 더 이상 늘어나지 않습니다. (어린이 날은 집에서 아두이노를 ㅡ.ㅡ)
작동 원리
수은 스위치가 기울어지거나 흔들릴 때마다 숫자를 1씩 증가 시키도록 하였습니다. 정확도가 떨어지기 때문에 만보기로 사용하기에는 무리가 있습니다. 정해진 시간(30초) 동안 누가 더 많은 숫자를 기록하느냐 게임을 하는 것을 목표로 만들어 졌습니다. 단순하지만 상당히 좋아합니다. 손으로 흔들지 않고 주머니에 넣고 뛰어 다니면서 게임을 하였습니다. (운동량이 상당하네요)
사용 된 부품
프로토타입은 [그림 1] 빵판에서 작업하였습니다.
[그림 1] 빵판에 작업 중인 만보기
[그림 2] 완성 된 작품의 뒷면
[그림 3] 완성 된 작품의 앞면
아래는 사용 된 소스 코드입니다. 기본적인 라이브러리는 미리 준비해 주고 아이가 코딩을 하는 동안 옆에서 계속 코치해주었습니다. 이번에는 제 코딩 방식을 대부분 따라하도록 하였기 때문에 코딩 시간이 평소보다 상당히 길어 졌습니다.
[소스]
unsigned char LED_BCD[16] = { 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e }; int data = 1; int rck = 3; int sck = 4; int pin_switch = 2; int pin_buzzer = 0; volatile int count = 0; unsigned long old_tick; unsigned long tick; void setup() { // Serial.begin(9600); pinMode( data, OUTPUT ); pinMode( rck, OUTPUT ); pinMode( sck, OUTPUT ); pinMode(pin_switch, INPUT); digitalWrite(pin_switch, HIGH); pinMode(pin_buzzer, OUTPUT); tone(pin_buzzer, 262, 500); delay(550); tone(pin_buzzer, 262, 500); delay(550); tone(pin_buzzer, 524, 1000); attachInterrupt(0, on_rising, RISING); old_tick = millis(); } int interval = 1000 * 30; int is_finished = 0; void loop() { // Serial.println(count); // delay(100); display_integer(count); tick = millis(); if ((tick - old_tick) > interval) { if (is_finished == 0) { is_finished = 1; detachInterrupt(0); tone(pin_buzzer, 262, 2000); } } } void on_rising() { count = count + 1; } void display_integer(int value) { int d = value / 1000; display_number( 3, d, 0 ); value = value - d * 1000; d = value / 100; display_number( 2, d, 0 ); value = value - d * 100; d = value / 10; display_number( 1, d, 0 ); value = value - d * 10; display_number( 0, value, 0 ); } void display_number(byte no, byte value, byte set_dp_on) { unsigned int HC_DISP = 0; unsigned int HC_LEDCODE; unsigned int HC_LEDCODE_temp = 0; if (value > 15) value = 0; HC_LEDCODE = LED_BCD[value]; for (unsigned char i=0; i<8; ++i) { HC_LEDCODE_temp <<= 1; if (HC_LEDCODE&0x01) HC_LEDCODE_temp |= 0x01; HC_LEDCODE >>= 1; } if (set_dp_on) HC_LEDCODE_temp &= 0xfe; HC_DISP = HC_LEDCODE_temp; switch(no) { case 0: HC_DISP |= 0x8000; break; case 1: HC_DISP |= 0x4000; break; case 2: HC_DISP |= 0x2000; break; case 3: HC_DISP |= 0x1000; break; } write_74HC595( HC_DISP ); } void write_74HC595(unsigned int data_a) { digitalWrite( rck, LOW ); digitalWrite( sck, LOW ); for (byte look=0; look<16; ++look) { if (data_a&0x0001) digitalWrite( data, HIGH ); else digitalWrite( data, LOW ); digitalWrite( sck, HIGH ); digitalWrite( sck, LOW ); data_a >>= 1; } digitalWrite( rck, HIGH ); }
1-2: 라인과 67: 라인 아래는 제가 미리 준비해두었습니다. 4 bits LED 모듈을 이용하기 위한 함수들입니다.
20-22: LED 모듈의 핀 3개에 연결 할 핀들을 OUPUT으로 지정합니다.
24-25: 수은 스위치에 사용 할 핀은 INPUT으로 하고, 디바운싱을 위해 풀업 저항을 사용하기 위해 해당 핀을 HIGH로 지정합니다.
29- 35: 소리로 게임 시작을 알립니다.
37: 수은 스위치가 off 상태가 되면 on_rising 함수가 인터럽트에 의해서 실행됩니다. 0번 인터럽트를 사용하고 있기 때문에 핀은 2번 핀을 사용하게 됩니다. 수은 스위치의 핀 번호가 2번인 이유는 이것 때문입니다.
49: 현재의 count (수은 스위치가 off 된 횟수)를 LED 모듈에 표시합니다.
53-60: 30초 이후에는 더 이상 게임이 진행되지 않도록 합니다. 인터럽트를 멈추고, 부저 소리로 게임이 끝난 것을 알립니다.
배선
[그림 4] 배선
아두이노 - 쿼드콥터 제작 #1 (0) | 2015.05.18 |
---|---|
아두이노 - 찰리플렉싱 (Charlie Plexing) (0) | 2015.05.10 |
아두이노 - 금속 탐지기 (0) | 2015.04.25 |
아두이노 - 주사위 만들기 (0) | 2015.04.19 |
아두이노 - 뮤직박스 (0) | 2015.04.19 |