아이가 런닝맨을 좋아해서 런닝맨에 가끔 나오는 만보기 게임기를 만들었습니다. 포스트를 작성하는 동안에도 주머니에 넣고 온 집을 뛰어다니고 있습니다 ㅋㅋ 아래는 손으로 흔들기 데모입니다. 부저가 울리면 시작되고, 부저가 다시 울리면 흔들어도 숫자가 더 이상 늘어나지 않습니다. (어린이 날은 집에서 아두이노를 ㅡ.ㅡ)
작동 원리
수은 스위치가 기울어지거나 흔들릴 때마다 숫자를 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 |