아두이노 우노로 정밀 반응 속도 테스터 만들기
부품 및 소모품
| 푸시 버튼 | 3개 |
| 5mm 적색 LED | 2개 |
| 수-수 점퍼 와이어 | 1세트 |
| 브레드보드 | 1개 |
| 아두이노 우노 | 1개 |
| USB A-B 케이블 | 1개 |
| 100Ω 저항 | 2개 |
| 10kΩ 저항 | 3개 |
앱 및 온라인 서비스
프로젝트 소개
운동선수, 저격수, 크리켓/야구 선수뿐 아니라 일반인 삶에도 반응 속도가 큰 영향을 미친다는 글을 읽고 내 반응 속도를 직접 측정해보고 싶어졌습니다. 예: 운전 중 반응 속도 느리면 대형 사고로 이어질 수 있죠.
1단계: 준비물
전자 취미가라면 다 굴러다니는 부품들입니다. 모르는 부품은 사진 참고하세요.
2단계: 시각 반응 속도 측정 절차
인체엔 청각/시각/촉각 반응 속도 등이 있지만 여기선 시각 반응 속도를 측정합니다.
- 시리얼 모니터에 "준비 버튼(버튼 3) 누르세요" 표시
- 준비 버튼 누르면 랜덤 대기 시간(2~5초) 후 두 LED 중 하나가 랜덤 점등
- 피험자는 점등된 LED에 대응하는 버튼(LED1→버튼1, LED2→버튼2)을 최대한 빨리 누름
- 아두이노가 LED 점등~버튼 눌림 사이 시간 차이(마이크로초) 측정
- 시리얼 모니터에 반응 시간 출력
3단계: 회로 구성
- 아두이노 5V, GND → 브레드보드 파워 레일
- LED 캐소드 → 100Ω 저항 → GND
- LED1 애노드 → D8, LED2 애노드 → D12
- 푸시 버튼 3개 장착 (눌리면 대각선 단자 연결됨)
- 10kΩ 풀다운 저항: 버튼 한 쪽 → 저항 → GND, 다른 쪽 → 5V
- 버튼 신호선 → D2(버튼2), D4(버튼1), D7(버튼3/준비)
※ 핀 번호는 취향껏 변경 가능
4단계: 코드 작성 포인트
- 버튼 디바운싱 처리 (마이크로초 단위)
- 반응 시간 측정 해상도 확보 (
micros() 사용)
- 시리얼 모니터로 디버깅 및 사용자 인터페이스
첨부 코드 다운로드해 바로 써도 되지만, 직접 짜보며 원리 이해하길 권장합니다. 헷갈리면 동영상 참고.
5단계: 테스트 & 게임
친구들과 대결! 평균 내기(아두이노가 자동으로 해줘도 좋음). 일반인 평균 시각 반응 속도 약 250ms. 음주 후 이 수치 넘으면 운전 절대 금물!
코드
아두이노 반응 속도 측정 코드
// 핀 번호 설정
const int buttonPin1 = 4; // LED1 대응 버튼
const int buttonPin2 = 2; // LED2 대응 버튼
const int buttonPin3 = 7; // 준비 버튼
const int ledPin1 = 8; // LED1
const int ledPin2 = 12; // LED2
// 상태 변수
int ledState1 = LOW, ledState2 = LOW;
int buttonState1, buttonState2, buttonState3;
int lastButtonState1 = LOW, lastButtonState2 = LOW, lastButtonState3 = LOW;
unsigned long lastDebounceTime = 0;
long debounceDelay = 20000; // 20ms 디바운스 (마이크로초)
unsigned long randNumber;
unsigned long minRandomNumber = 2000; // 2ms
unsigned long maxRandomNumber = 5000; // 5ms
unsigned long time1, time2;
int button3Pressed = LOW;
int printcount = 0;
int takeReading = LOW;
int reading1, reading2, reading3;
int oddNumber, evenNumber;
void setup() {
pinMode(buttonPin1, INPUT);
pinMode(buttonPin2, INPUT);
pinMode(buttonPin3, INPUT);
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
Serial.begin(115200);
digitalWrite(ledPin1, ledState1);
digitalWrite(ledPin2, ledState2);
randomSeed(analogRead(0)); // 노이즈로 시드 생성
}
void loop() {
if (printcount == 0) {
Serial.println("press button 3 when you are ready");
printcount = 1;
takeReading = LOW;
oddNumber = LOW;
evenNumber = LOW;
}
if (button3Pressed == HIGH) {
digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, LOW);
randNumber = random(minRandomNumber, maxRandomNumber);
delay(randNumber);
if (randNumber & 1 == 1) { // 홀수면 LED1
digitalWrite(ledPin1, HIGH);
digitalWrite(ledPin2, LOW);
time1 = micros();
oddNumber = HIGH;
} else { // 짝수면 LED2
digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, HIGH);
time1 = micros();
evenNumber = HIGH;
}
button3Pressed = LOW;
}
reading3 = digitalRead(buttonPin3);
if (takeReading == HIGH) {
if (oddNumber == HIGH) reading1 = digitalRead(buttonPin1);
if (evenNumber == HIGH) reading2 = digitalRead(buttonPin2);
}
// 디바운싱: 상태 변화 시 타이머 리셋
if (reading1 != lastButtonState1 || reading2 != lastButtonState2 || reading3 != lastButtonState3) {
lastDebounceTime = micros();
}
if ((micros() - lastDebounceTime) > debounceDelay) {
// 버튼 1 (LED1 대응)
if (reading1 != buttonState1) {
buttonState1 = reading1;
if (buttonState1 == HIGH) {
Serial.print("Your reaction time is: ");
Serial.print(lastDebounceTime - time1);
Serial.println("us");
Serial.println();
printcount = 0;
}
}
// 버튼 2 (LED2 대응)
if (reading2 != buttonState2) {
buttonState2 = reading2;
if (buttonState2 == HIGH) {
Serial.print("Your reaction time is: ");
Serial.print(lastDebounceTime - time1);
Serial.println("us");
Serial.println();
printcount = 0;
}
}
// 준비 버튼
if (reading3 != buttonState3) {
buttonState3 = reading3;
if (buttonState3 == HIGH) {
Serial.println("READY TO GO");
button3Pressed = HIGH;
takeReading = HIGH;
}
}
}
lastButtonState1 = reading1;
lastButtonState2 = reading2;
lastButtonState3 = reading3;
}
회로도