이번 프로젝트 목표는 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 제어
// 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);
}