본문 바로가기

IT

4. 신호등 구현하기 (LED와 스위치)

반응형

이번에는 LED와 스위치를 사용한 간단한 신호등 시스템을 구현해보겠습니다.


차가 보는 신호등과 사람이 보는 신호등으로 나눌 수 있고, 시간에 따라서 차량이 운행 가능하게 변경하고, 사람이 길을 건널 수 있도록 신호가 자동으로 바뀌도록 구현해야 하며, 추가로 사람이 사용하는 신호등에는 건너는 사람이 원할 때 스위치를 작동하여 잠시 후 보행자 신호로 변경하는 신호등을 구현해야 합니다.


1. 하드웨어 설계

차가 보는 신호등은 (빨강, 노랑, 녹색)으로 총 3개의 LED를 사용하여 구현하면 됩니다.

사람이 보는 신호등은 (빨강, 녹색)으로 구현하며, 보행자 신호로 바꾸기 위한 스위치가 추가로 하나 필요합니다.

LED는 0, 1의 디지털 신호만 사용하므로 디지털 출력(OUTPUT)을 사용하도록 하고,

스위치도 마찬가지로 0, 1의 디지털 신호만 사용하게 되므로 디지털 입력(INPUT)을 사용하겠습니다.


하드웨어 설계는 아래와 같이 Fritzing을 사용하여 이미지로 올립니다.


** 주의 : LED를 사용하는 경우 회로에 저항을 꼭 220옴 저항을 추가하도록 한다.


좀 더 논리적으로 표현된 스케메틱 이미지 입니다.




2. 소프트웨어 설계


/** 자동차신호등에서 사용하는 LED 핀위치 */
#define pinCarG 13
#define pinCarY 12
#define pinCarR 11

/** 사람이 사용하는 LED 핀위치 */
#define pinHumanG 10
#define pinHumanR 9
/** 사람이 사용하는 스위치 핀위치 */
#define pinHumanSw 8

// 신호등 녹색등이 점등되는 시간
#define TIME_USE_HUMAN 2 // sec
// 신호등이 녹색이 점멸되는 시간 (초)
#define BLINK_COUNT 5

unsigned long prevTime;

void setup() {
  // 디버깅이 필요한 경우 시리얼로 데이터를 전달
  // Serial.begin(9600);
  
  pinMode(pinCarG, OUTPUT);
  pinMode(pinCarY, OUTPUT);
  pinMode(pinCarR, OUTPUT);

  pinMode(pinHumanG, OUTPUT);
  pinMode(pinHumanR, OUTPUT);
  pinMode(pinHumanSw, INPUT_PULLUP);

  // Serial.println("Start Traffic Sign System.");

  initLED();
}

void loop() {
  int sw = digitalRead(pinHumanSw);

  if (sw == 0 && digitalRead(pinCarG) == 1) {
    /*
     * 사람이 누르는 스위치는 자동차신호등이 녹색인 상태에서만
     * 작동하도록 구현함
     */
    changeLED();
  } else {
    unsigned long currentTime = millis();
    if (currentTime > prevTime + 10 * 1000) {
      /*
       * 스위치를 작동하지 않아도 차 신호등이 10초간 유지되면
       * 보행자 신호로 자동 변환하도록 설계함
       */
      changeLED();
    }
  }

}

void changeLED() {
  // 버튼클릭후 1초 대기
  // Serial.println("Press Switch. wait 3 sec.");
  delay(1000);

  // 차량 신호등에 노란색 점등
  // Serial.println("Turn on car yellow led during 3 sec.");
  digitalWrite(pinCarG, LOW);
  digitalWrite(pinCarY, HIGH);
  delay(2000);

  // 자동차 신호등을 빨강으로 전환
  digitalWrite(pinCarY, LOW);
  digitalWrite(pinCarR, HIGH);
  // 사람용 신호등도 변경한다.
  digitalWrite(pinHumanR, LOW);
  digitalWrite(pinHumanG, HIGH);

  // 2초간 횡단보도사용
  delay(TIME_USE_HUMAN * 1000);

  // 5초동안 점멸
  // Serial.println("Remain 5 sec using cross line.");
  for(int i = 0; i < BLINK_COUNT; i++) {
    digitalWrite(pinHumanG, LOW);
    delay(500);
    digitalWrite(pinHumanG, HIGH);
    delay(500);
  }

  // Serial.println("Reset traffic sign");
  // 신호등을 원래 상태로 전환한다.
  initLED();
}

void initLED() {
  digitalWrite(pinCarG, HIGH);
  digitalWrite(pinCarY, LOW);
  digitalWrite(pinCarR, LOW);

  digitalWrite(pinHumanG, LOW);
  digitalWrite(pinHumanR, HIGH);

  prevTime = millis();
}


소스에서 하나 눈여겨볼 점은

int sw = digitalRead(pinHumanSw);
이부분이다. sw == 0 인 경우가 스위치가 눌린 것이다. 이유는 인풋에서 풀업으로 설정한 것이기 때문이고, 풀업, 풀다운에 대해서는 별도의 웹사이트들의 도움을 받도록 하자, 하여간 여기서는 풀업 스위치로 작동하는 것으로 스위치를 누르지 않을 경우 1의 값이, 누른경우 0의 값이 입력됨을 사용한다는 것을 인지하도록 한다.

(사실, 스위치도 위에 구현한 것같이 단순히 스위치만 사용하면 안된다. 정확한 구현을 위해서는 저항을 이용하여 풀업, 풀다운을 정확하게 구현해주어야 한다.)



스위치 부분에 보면 10K옴의 저항이 적용된 것을 볼 수 있을 것이다. 이런 경우에는 스위치는 풀다운 스위치로 작동하게 되고, 소스에서도 핀모드를 설정할 때 INPUT_PULLUP에서 INPUT으로 설정하여야 한다.

이렇게 설정하는 이유는 인풋에서 스위치가 눌리지 않아서 회로가 끊겨있는 경우 잔여전류나 주변 기기의 작동에 대하여 간혹 스위치가 작동하는 것처럼 작동하는 것을 방지할 수 있다. 위와 같이 구현하는 경우 스위치가 눌린 경우 1이 입력되고, 스위치가 눌리지 않은 경우 0으로 작동하게 된다. PULLUP과는 반대로 작동한다. 저항이 들어간 풀업 스위치를 구현하는 방법은 간단하다. 저항과 스위치의 위치만 서로 반대로 위치를 바꾸면 거꾸로 스위치가 눌렸을 때 0, 스위치가 눌리지 않은 경우 1로 입력되게 된다. (전기의 흐름을 잘 생각해보아야 한다.)


위와 같이 작성한 소스를 사용하면 간단히 차량, 보행자 신호등을 구현할 수 있다. 삼거리, 사거리 신호등 시스템은 이보다 복잡하지만, 보행자 신호등을 위한 신호등은 위와 같이 간단히 구현할 수 있다.


끝.

반응형