[아두이노] 아두이노 신호등과 횡단보도신호등
[아두이노] 아두이노 신호등과 횡단보도신호등
- 온라인 가상시뮬레이터 : https://www.tinkercad.com
- 연계 참고 : [아두이노] 아두이노 신호등 만들기와 코딩
- 공개회로도 : https://www.tinkercad.com/things/7Oum4cYZ4CP
지난 시간에 간단히 아두이노 신호등을 만들어 실험했는데 여기에 횡단보도신호등을 추가하여 같이 제어하는 실험을 해볼까 합니다. 특정 도로 상황을 만들고 그 상황에서 차량신호등과 횡단보도신호등의 동작을 설정하고 그 부분만 회로도로 구성하고 상황에 맞게 동작하도록 코딩을 해보았습니다.
1. 도로의 신호등과 횡단보도신호등의 상황 설정
우선 아래와 같은 도로의 상황을 설정해 보았습니다.
위 그림에서 A, B 지점의 신호등과 횡단보드신호등을 아두이노로 표현하여 실험을 하겠습니다.
상황은 차량신호등은 4차선 도로의 주행이 우선 시 하겠죠. 그러면 2차선에서 바라보는 신호등은 "녹->황->적" 순서에서 적색등이 다른 등보다 더 긴 시간을 유지합니다. 도로의 신호등의 시간은 도로의 상태에 따라 시간이 다르기 때문에 삼거리 도로에서는 4차선 도로쪽 녹색등 시간이 적색등보다 길고 2차선의 적색등이 녹색등보다 더 긴 시간을 유지하게 됩니다. 즉, 2차선 적색등일 때 4차선은 녹색등이니깐 두 신호등의 관계를 잘 이해해 주세요.
횡당보도신호등은 2차선에서 바라 봤을 때 적색등일 때 횡단보도신호등이 작동하게 코딩을 할까 합니다. 대충 2차선으로 바라봤을 때 "녹->황->적"순으로 바뀌는데 적색등으로 바뀔 때 횡단보드신호등의 적색등이 녹색등으로 바뀌고 횡단보드의 7-Segment Display가 카운트를 하게 됩니다. 그리고 0이 되면은 다시 적색등으로 바뀌는 형태로 코딩했습니다.
좀 상황을 설정하고 코딩을 완성하고 보니 상황이 약간 이상하게 설정했더군요. 다시 코딩을 수정하기 귀찮아서 이상태로 실험을 마무리했는데 이부분을 감안하시고 실험 내용을 보시기 바랍니다.
2. 아두이노 신호등+횡단보도신호등 회로도
- 준비물 : 적색 LED 2개, 오렌지색 LED 1개, 녹색 LED 2개, 저항 220옴 6개, 7-Segment Display 1개, 74HC595칩 1개, 아두이노우노
- 내용 : 신호등 5,6,7번 핀을 LED 출력핀으로 연결하고 횡단보도신호등 11,12번 핀을 LED 출력핀으로 연결한다. 그리고 74HC595칩은 9,10,11번을 이용하고 7-Segment Display의 Vcc핀을 8번핀으로 사용합니다.
아래 회로도는 지난시간의 신호등 회로도에서 횡단보도신호등을 추가한 회로도 입니다. 두개의 횡단보드신호등을 만들 수 있었지만 너무 복잡하게 그려질 것 같아서 한쪽 횡단보드신호등만 표현했네요. 만약 두개를 만드신다면 횡단보드신호등의 연결된 선을 공유선으로 연결하시면 됩니다.
좀 복잡한 회로도인데 해당 표현은 아래 그림으로 대충 구분하시면 됩니다.
3. 코딩
7-Segment Display 부품을 사용하는데 그냥 아두이노우노 핀에 적접 연결해도 되지만 복습차원으로 74HC595칩을 이용하여 제어하도록 하겠습니다.
74HC595칩 제어 :
- latchPin, clockPin, dataPin을 pinMode( )로 선언
- digitalWrite(결쇠핀, 열림/잠금)으로 74HC595칩에 입력할때 열림/잠금을 제어
- shiftOut(데이터입력핀, 클럭핀, MSBFIRST, 전송값)으로 이걸 통해서 역순으로 데이터가 배치
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | const byte latchPin = 10 ; //ST_CP Pin const byte clockPin = 11 ; //SH_CP Pin const byte dataPin = 9 ; //DS Pin byte data[]={ 0B01000000, //0 0B01111001, //1 0B00100100, //2 0B00110000, //3 0B00011001, //4, 0B00010010, //5 0B00000010, //6 0B01111000, //7 0B00000000, //8 0B00010000 //9 }; |
위의 74HC595칩을 제어하는 3개의 ST_CP, SH_CP, DS Pin과 숫자는 1byte값안에 각 bit가 7-Segment Display의 각 핀에 해당됩니다. data[]배열변수에 숫자 패턴을 정의해 놓습니다. 0~9까지의 숫자 패턴을 만들어 놓았는데 실제로 0~3까지의 숫자만 사용됩니다.
그 값을 아래 3줄로 해서 출력하면 7-Segment Display의 숫자가 출력합니다.
1 2 3 | digitalWrite(latchPin, LOW); //열림 shiftOut(dataPin, clockPin, MSBFIRST, data[cnt]); //출력 digitalWrite(latchPin, HIGH); //닫힘 |
위 내용은 쉬프트레지스터(74HC595) 제어(아두이노) post에 가셔서 복습하시고 오셔야 이해가 되실 꺼에요. 이해가 안되시는 분들은 읽고 오시면 되겠습니다.
횡단보도신호등 동작 : 7-Segment Display가 "3-2-1-0"순서로 카운트하게 하려면 다음과 같습니다
1 2 3 4 5 6 7 | if (cnt> 0 && millis()-timeSeg>= 1000 ){ cnt--; digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST, data[cnt]); digitalWrite(latchPin, HIGH); timeSeg=millis(); } |
timeSeg변수는 7-Segment Display에 출력에 대한 이전시간값을 가지고 있습니다. ">=1000"으로 체크하면 1초 단위로 if문이 참이 됩니다. 여기서 cnt는 숫자패턴의 위치값이 됩니다. 즉, 1초 단위로 체크하는데 숫자패턴이 0보다 커야한다고 락을 걸어놓은 if문입니다. "cnt--"으로 현재 숫자패턴위치값을 하나 감소 하면서 출력된다고 생각하시면 됩니다.
횡단보도신호등의 "적색->녹색" 변환
1 2 | digitalWrite(TransversboardLight[ 1 ], LOW); //적색 LOW digitalWrite(TransversboardLight[ 0 ], HIGH); //녹색 HIGH |
횡단보도신호등의 "녹색->적색" 변환
1 2 | digitalWrite(TransversboardLight[ 0 ], LOW); //녹색 LOW digitalWrite(TransversboardLight[ 1 ], HIGH); //적색 HIGH |
위 두가지 횡단보도신호등 변환은 차량신호등이 적색이 되는 순간의 코딩 부분에 "적색->녹색"변환 코딩을 하고 7-Segment Display가 카운트 0이 되는 순간의 코딩 부분에 "녹색->적색"변환 코딩을 삽입하면 됩니다.
이제 위에서 이야기한 횡단보드신호등 코딩 부분을 지난시간에 만든 차량신호등에 합쳐 봅시다.
[신호등 기본소스]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | const byte trafficLight[ 3 ] = { 5 , 6 , 7 }; //신호등 핀 int lightTime[ 3 ] = { 5 , 2 , 3 }; //신호등 유지시간 unsigned long timeVal = 0 ; //이전시간 int indexVal = 0 ; //신호등 위치 void setup() { for ( int i= 0 ;i< 3 ;i++){ pinMode(trafficLight[i], OUTPUT); } //초기상태 digitalWrite(trafficLight[indexVal], HIGH); //녹색등 } void loop() { if (millis()-timeVal>=lightTime[indexVal]* 1000 ){ //신호등 동작 trafficLight[3]순서대로 digitalWrite(trafficLight[indexVal], LOW); //이전등 끄기 indexVal++; //신호등위치 증가 if (indexVal== 3 )indexVal= 0 ; // 신호등위치가 3이 되면 다시 0으로 처음위치로 돌아감 digitalWrite(trafficLight[indexVal], HIGH); //새로운등 켜기 timeVal=millis(); } } |
어디서 부터 접근해야 할까요. 위 loop()함수는 신호등 "녹색->오렌지색->적색"순서로 깜박입니다. 여기서 적색등이 되는 순간에 횡단보도신호등이 바뀐다고 했죠. 그러면 적색등일 때 "indexVal==2"일때의 횡단보도신호등의 조건문을 만들어 주면 됩니다.
1 2 3 4 5 6 | if (millis()-timeVal>=lightTime[indexVal]* 1000 ){ //신호등 동작 trafficLight[3]순서대로 신호등명령문; if (indexVal== 2 ){ //적색등일때 횡단보도신호등 초기상태; } } |
횡단보도신호등 초기상태는
1 2 3 4 5 6 7 8 9 10 | state= true ; timeSeg=millis(); //7-Segment Display 이전시간값 digitalWrite(TransversboardLight[ 1 ], LOW); //적색 LOW digitalWrite(TransversboardLight[ 0 ], HIGH); //녹색 HIGH digitalWrite(SegPower, HIGH); //7-Segment Display 전원 공급 //3 숫자 패턴 출력 digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST, data[cnt]); digitalWrite(latchPin, HIGH); |
대충 indexVal이 2일 때 적색으로 바뀌는 순간으로 그 때 횡단보도신호등의 초기상태를 위와 같이 코딩하게 됩니다. state은 다음 코딩의 체크문으로 사용하는 변수값입니다.
1 2 3 | if (state== true ){ 횡단보도신호등동작; } |
위와 같이 state문으로 횡단보도신호등을 동작시킬지 결정하는 if문입니다.
횡단보도신호등 동작은
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | if (cnt> 0 && millis()-timeSeg>= 1000 ){ //"2-1-0"출력함 3은 초기상태에서 출력했기 때문에 나머지 숫자 출력함 cnt--; digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST, data[cnt]); //숫자 출력 digitalWrite(latchPin, HIGH); timeSeg=millis(); //이전시간변수에 현재시간 저장 } if (cnt== 0 && millis()-timeSeg>= 1000 ){ //0을 출력하고 1초동안은 0인 상태를 유지하기 위함 cnt= 3 ; //숫자패턴 3으로 초기화 state = false ; //횡단보도신호등 동작 중단 digitalWrite(SegPower, LOW); //7-Segment Display 전원 공급 중단 digitalWrite(TransversboardLight[ 0 ], LOW); //녹색 LOW digitalWrite(TransversboardLight[ 1 ], HIGH); //적색 HIGH } |
횡단보도신호등의 7-Segment Display의 숫자를 카운트하고 카운트가 끝나면 다시 "녹색->적색" 등으로 바뀌게 됩니다. 횡단보도신호등이 끝나면 다시 처음 원위치 상태로 돌아가야 합니다.
종합해보면,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | byte data[]={ 0B01000000, //0 0B01111001, //1 0B00100100, //2 0B00110000, //3 0B00011001, //4, 0B00010010, //5 0B00000010, //6 0B01111000, //7 0B00000000, //8 0B00010000 //9 }; const byte latchPin = 10 ; //ST_CP Pin const byte clockPin = 11 ; //SH_CP Pin const byte dataPin = 9 ; //DS Pin const byte SegPower = 8 ; const byte TransversboardLight[ 2 ] = { 12 , 13 }; int cnt = 3 ; boolean state = false ; const byte trafficLight[ 3 ] = { 5 , 6 , 7 }; const byte lightTime[ 3 ] = { 5 , 2 , 7 }; unsigned long timeVal = 0 ; unsigned long timeSeg = 0 ; int indexVal = 0 ; void setup() { pinMode(latchPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT); pinMode(SegPower, OUTPUT); pinMode(TransversboardLight[ 0 ], OUTPUT); pinMode(TransversboardLight[ 1 ], OUTPUT); for ( int i= 0 ;i< 3 ;i++){ pinMode(trafficLight[i], OUTPUT); } digitalWrite(trafficLight[indexVal], HIGH); digitalWrite(TransversboardLight[ 1 ], HIGH); } void loop() { if (millis()-timeVal>=lightTime[indexVal]* 1000 ){ digitalWrite(trafficLight[indexVal], LOW); indexVal++; if (indexVal== 3 )indexVal= 0 ; digitalWrite(trafficLight[indexVal], HIGH); timeVal=millis(); if (indexVal== 2 ){ state= true ; timeSeg=millis(); digitalWrite(TransversboardLight[ 1 ], LOW); digitalWrite(TransversboardLight[ 0 ], HIGH); digitalWrite(SegPower, HIGH); digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST, data[cnt]); digitalWrite(latchPin, HIGH); } } if (state== true ){ if (cnt> 0 && millis()-timeSeg>= 1000 ){ cnt--; digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST, data[cnt]); digitalWrite(latchPin, HIGH); timeSeg=millis(); } if (cnt== 0 && millis()-timeSeg>= 1000 ){ cnt= 3 ; state = false ; digitalWrite(SegPower, LOW); digitalWrite(TransversboardLight[ 0 ], LOW); digitalWrite(TransversboardLight[ 1 ], HIGH); } } } |
4. 결과
실제로 제작해 해봤는데 배선이 좀 지져분하게 만들어 졌네요.
결과는 가상시뮬레이터에서 실험한 결과와 같은 동작으로 결과가 출력 되었네요.
마무리
기존의 신호등 코딩에서 횡단보도신호등을 추가했을 때 기존의 코딩에 대해서 신경 쓸 필요 없고 횡단보도신호등에 대한 코딩만 신경쓰면 됩니다. millis()함수를 이용하여 시간을 제어하면 차량신호등의 동작과 횡단보도신호등의 동작을 동시에 수행 할 수 있게 됩니다.
오늘 실험은 신호등과 횡단보드신호등에 상황을 만들고 두 상황을 동시에 처리를 하였습니다. 오늘 코딩한 스타일을 잘 기억해 주세요. 여러 상황을 동시에 처리하거나 또는 여러 부품을 동시에 제어할 때 millis()함수를 이용하여 시간을 제어하면 각 상황을 코딩하고 나서 다른 상황을 코딩할 때 시간에 대한 어려움을 쉽게 해결 합니다.
그리고, 오늘 post에서 2가지 상황을 설정하고 그 상황에 맞게 아두이노에서 동시에 처리하는 코딩을 하였습니다. 여러분들도 꼭 신호등이 아니더라도 여러가지 상황을 만들고 그 상황을 동시에 처리하는 코딩 연습을 많이 하셨으면 합니다. 하나의 부품을 제어하는 것은 무척 싶습니다. 하지만 둘 이상의 부품을 제어하는 것과 둘 이상의 상황을 제어하는 방법은 쉽지 않습니다. 둘 이상의 조건을 만족하기 위해서는 서로 충돌이 발생하지 않게 상상 코딩을 해야 하기 때문에 이 능력은 꾸준히 반복 학습을 통해서 터득 할 수 있습니다. 그렇기 때문에 오늘 제가 했던 방식으로 일상의 상황들을 하나씩 찾아서 적용하여 아두이노로 표현해 보세요.
'IOT > 아두이노' 카테고리의 다른 글
[아두이노] 구부림(flex) 센서와 관절 제어 (0) | 2019.07.26 |
---|---|
[아두이노] 아두이노 주차장 출입구 차량차단장치 (0) | 2019.07.25 |
[아두이노] 아두이노 신호등 만들기와 코딩 (0) | 2019.07.23 |
[아두이노] 아두이노 선풍기 만들기 (0) | 2019.07.22 |
[아두이노] Neopixel을 이용한 7-Segment Display (0) | 2019.07.18 |