아두이노 엘리베이터 만들기

조홍기·2023년 9월 25일
1

arduino

목록 보기
3/3

최종 결과물 - https://www.tinkercad.com/things/0K3WCYYvSBF-copy-of-elevatorfinal2/editel?sharecode=dw_ECFCnfqurXCnMJ64mRlELmLRuyF2EXYveN7Q8W-0

목표

이번 프로젝트 목표는 Arduino의 loop에 익숙치가 않아서 다른 기능을 넣기보다는 엘리베이터 본연의 기능을 최대한 잘 구현하고, delay 없이도 문제 없도록 구현하는 것을 최우선으로 하였다.

사용법

1. 층은 1층에서 시작한다.
2. 원하는 층을 누르면 된다.
3. 버튼을 한 번 더 누르면 층 예약이 취소된다.

규칙

1. 이전에 올라가고 있었으면 입력된 층 중 가장 높은 층에 도달하기까지 방향을 바꾸지 않는다. 반대의 상황도 같다.
2. 지나가는 경로에 버튼을 누른 층이 있으면 모두 들렸다 간다. 만약 들리고 갈 경우 시간을 조금 더 소요한다.
3. 들리는 층에서도 승객들을 내리고 태우는 시간을 조금 고려한다.
4. 움직이는 도중에도 버튼 입력을 계속 받는다.
5. 버튼을 다시 누르면 취소가 가능하며 가던 진행 방향의 다음 층에서 멈춘다.

하면서 고려했던 사항들

1. 처음에 3층만 구현하였지만 층 수를 올릴 것을 고려하며 제작하였고 따라서 시프트 레지스터를 알게된 이후로는 쉽게 기능을 구현할 수 있었다.
2. delay 없이 구현하기 위하여 각종 flag를 쓰게될 것으로 예상했지만 flowchart에서는 우선 흐름만 잡았다.
3. 시프트 레지스터에 대해 찾다보니 다들 data핀을 서로 연결하여 LED를 같이 출력하였는데 나는 따로 써야하므로 data핀을 각각 연결해주었다.

시작 전 흐름도

최종 구현한 회로도

보완할 점

1. 전역 변수를 너무 남발했다.
2. 시프트 레지스터 기능을 급하게 구현하느라 아직 그 부분은 개념 보완이 필요하다.
3. 가독성을 위해 함수에 코드를 적당히 집어넣어야 할 것 같다.
4. now_floor이 변하는 타이밍이 적절치 않다.

참고자료

1. Parallel Shifting-Out with a 74HC595
2. 2개의 74HC595 (쉬프트 레지스터 IC) 이용하여 LED 제어

추가자료

1. 7 segment decoder - 7 세그먼트 디코더 | 작성자 엠에스리

코드

코드 보기
// C++ code
//

// const variables
const int TOTAL_FLOOR = 5;
const int START_BTN_PIN = 14;
const int START_BTN_LED_PIN = 4;
const int START_FLOOR_LED_PIN = 2;
const int START_BETWEEN_PIN = 3;
const int CLOCK_PIN = 8;
const int LATCH_PIN = 9;
const unsigned long MOVE_INTERVAL_TIME = 500;

// pin setup
int btn[TOTAL_FLOOR] = {0,};

// flags
//int move_flag = 0;
int prev_btn_state[TOTAL_FLOOR] = {0,};
int vector = 0;

// now_states
int now_floor, target_floor;
int btn_led_state[TOTAL_FLOOR] = {0,};

// times
unsigned long move_start_time = 0;

int tmp1, tmp2;
int pin;

// move_up
void move_up() {
  unsigned long gap = millis() - move_start_time;
//  vector = 1;

  digitalWrite(LATCH_PIN, 0);
  
  // first
  if (gap <= MOVE_INTERVAL_TIME) {
  	shiftOut(START_BETWEEN_PIN, CLOCK_PIN, 1 << (now_floor - 1) * 2);
  }

  // second
  else if (gap <= MOVE_INTERVAL_TIME * 2) {
    shiftOut(START_BETWEEN_PIN, CLOCK_PIN, 1 << ((now_floor - 1) * 2 + 1));
  }

  // if the next floor's led is on
  else if (btn_led_state[(now_floor - 1) + 1] && gap <= MOVE_INTERVAL_TIME * 5) {
    shiftOut(START_BETWEEN_PIN, CLOCK_PIN, 0);
    shiftOut(START_FLOOR_LED_PIN, CLOCK_PIN, 1 << ((now_floor - 1) + 1));
  }
  
  // if the next floor's led is off
  else if (gap <= MOVE_INTERVAL_TIME * 3) {
    shiftOut(START_BETWEEN_PIN, CLOCK_PIN, 0);
    shiftOut(START_FLOOR_LED_PIN, CLOCK_PIN, 1 << ((now_floor - 1) + 1));
  }

  // extra
  else {
    btn_led_state[(now_floor - 1) + 1] = 0;
    shiftOut(START_FLOOR_LED_PIN, CLOCK_PIN, 0);
    now_floor++;
    if (now_floor == target_floor) {
      vector = 0;
    }
    move_start_time = 0;
    Serial.println(now_floor);
  }

  digitalWrite(LATCH_PIN, 1);
  delay(1);
}


// move_down
void move_down() {
  unsigned long gap = millis() - move_start_time;
//  vector = -1;

  digitalWrite(LATCH_PIN, 0);
  
  // first
  if (gap <= MOVE_INTERVAL_TIME) {
    shiftOut(START_BETWEEN_PIN, CLOCK_PIN, 1 << ((now_floor - 1) * 2 - 1));
  }

  // second
  else if (gap <= MOVE_INTERVAL_TIME * 2) {
    shiftOut(START_BETWEEN_PIN, CLOCK_PIN, 1 << ((now_floor - 1) * 2 - 2));
  }

  // if the next floor's led is on
  else if (btn_led_state[(now_floor - 1) - 1] && gap <= MOVE_INTERVAL_TIME * 5) {
    shiftOut(START_BETWEEN_PIN, CLOCK_PIN, 0);
    shiftOut(START_FLOOR_LED_PIN, CLOCK_PIN, 1 << ((now_floor - 1) - 1));
  }
  
  // if the next floor's led is off
  else if (gap <= MOVE_INTERVAL_TIME * 3) {
    shiftOut(START_BETWEEN_PIN, CLOCK_PIN, 0);
    shiftOut(START_FLOOR_LED_PIN, CLOCK_PIN, 1 << ((now_floor - 1) - 1));
  }

  // extra
  else {
    btn_led_state[(now_floor - 1) - 1] = 0;
    shiftOut(START_FLOOR_LED_PIN, CLOCK_PIN, 0);
    now_floor--;
    if (now_floor == target_floor) {
      vector = 0;
    }
    move_start_time = 0;
    Serial.println(now_floor);
  }
  
  
  digitalWrite(LATCH_PIN, 1);
  delay(1);
}


// buttonPress
int buttonPress(int floor) {
  int press;
  int buttonState = digitalRead(btn[floor]);

  press = (buttonState && !prev_btn_state[floor]);
  prev_btn_state[floor] = buttonState;

  return press;
}


//
int max_floor() {
  int idx = -1;
  for (int i = 0; i < TOTAL_FLOOR; i++) {
    if (btn_led_state[i] == 1) {
      idx = i + 1;
    }
  }
  return idx;
}


//
int min_floor() {
  int idx = TOTAL_FLOOR;
  for (int i = TOTAL_FLOOR - 1; i >= 0; i--) {
    if (btn_led_state[i] == 1) {
      idx = i + 1;
    }
  }
  return idx;
}

// 
void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
  int i=0;
  int pinState;
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, OUTPUT);
  digitalWrite(myDataPin, 0);
  digitalWrite(myClockPin, 0);
  for (i=7; i>=0; i--)  {
    digitalWrite(myClockPin, 0);
    if ( myDataOut & (1<<i) ) {
      pinState= 1;
    }
    else {
      pinState= 0;
    }
    digitalWrite(myDataPin, pinState);
    digitalWrite(myClockPin, 1);
    digitalWrite(myDataPin, 0);
  }
  digitalWrite(myClockPin, 0);
}


// setup
void setup() {
  Serial.begin(9600);

  for (int i = 0; i < TOTAL_FLOOR; i++) {
    btn[i] = START_BTN_PIN + i;

    pinMode(btn[i], INPUT);
  }
  
  pinMode(LATCH_PIN, OUTPUT);

  now_floor = 1;
  target_floor = 1;
  digitalWrite(LATCH_PIN, 0);
  shiftOut(START_FLOOR_LED_PIN, CLOCK_PIN, 0);
  digitalWrite(LATCH_PIN, 1);
  delay(1);
}


// loop
void loop() {
  // sensing button press
  for (int i = 0; i < TOTAL_FLOOR; i++) {
    if (buttonPress(i)) {
      btn_led_state[i] ^= 1;
      
      // if elevator go up
      if (vector == 1) {
        tmp1 = max_floor();
        if (tmp1 == -1 || tmp1 < target_floor) {
          target_floor = now_floor + 1;
        }
        else {
          target_floor = tmp1;
        }
      }
      // if elevator go down
      else if (vector == -1) {
        tmp1 = min_floor();
        if (tmp1 == TOTAL_FLOOR || tmp1 > target_floor) {
          target_floor = now_floor - 1;
        }
        else {
          target_floor = tmp1;
        }
      }
    }
  }

  // when the elevator needs to move
  if (vector != 0) {
  	digitalWrite(LATCH_PIN, 0);
  	shiftOut(START_FLOOR_LED_PIN, CLOCK_PIN, 0);
  	digitalWrite(LATCH_PIN, 1);
  	delay(1);

    if (move_start_time <= 0) {
      move_start_time = millis();
    }

    if (vector == 1) {
      move_up();
    } else if (vector == -1) {
      move_down();
    }
  }

  // when the elevator reaches its destination
  else {
    // search new target
    tmp1 = max_floor();
    tmp2 = min_floor();
    if (tmp1 > now_floor && tmp1 <= TOTAL_FLOOR) {
      vector = 1;
      target_floor = tmp1;
    }
    else if (tmp2 < now_floor && tmp2 > 0) {
      vector = -1;
      target_floor = tmp2;
    }
    // target equals now_floor
    else {
      digitalWrite(LATCH_PIN, 0);
      shiftOut(START_FLOOR_LED_PIN, CLOCK_PIN, 1<<(now_floor-1));
      digitalWrite(LATCH_PIN, 1);
      btn_led_state[(now_floor-1)] = 0;
    }
  }

  // printing elevator button LED
  digitalWrite(LATCH_PIN, 0);
  pin = 0;
  for (int i = 0; i < TOTAL_FLOOR; i++) {
    if (btn_led_state[i]) {
      pin += 1<<i;
    }
  }
  shiftOut(START_BTN_LED_PIN, CLOCK_PIN, pin);
  digitalWrite(LATCH_PIN, 1);
  delay(1);
}
                  
profile
ROS, Python, Cpp 공부 중입니다.

0개의 댓글