4-Digit 7-Segment Display 시계 만들기(아두이노)

in #kr-arduino6 years ago

4-Digit 7-Segment Display 시계 만들기(아두이노)



지난 시간에 4-Digit 7-Segment Display을 사용하는 방법을 실험 하였습니다. 오늘은 지난시간에 만든 회로도와 기본소스를 기반으로 아두이노 시계를 실제 만들어 보겠습니다.

1. 4-Digit 7-Segment Display 회로도


  • 준비물 : 4-Digit 7-Segment Display 1개, 스위치버턴 1개, 아두이노우노
  • 내용 : 4-Digit 7-Segment Display 부품의 핀 번호 순서에 맞게 아두이노우노에 연결하고, 스위치 버턴은 2번핀에 연결하시오.
  • 참조 : 4-Digit 7-Segment Display 제어(아두이노)

지난 시간의 회로도와 동일합니다.

2. 시계 코딩



시간을 참조 Post에 가셔서 사전 학습 해주세요.

1) 시간 구하기


시간은 시리얼통신으로 입력을 받을 경우를 가정해서 시간을 구해 볼까요.

if(Serial.available()){
  String inString = Serial.readStringUntil('\n');    
}

inString에 시간 문자열을 읽습니다.

int index1 = inString.indexOf(':'); 
int index2 = inString.indexOf(':',index1+1);   
int index3 = inString.length();
    
hour = inString.substring(0, index1).toInt();
min = inString.substring(index1+1,index2).toInt();
sec = inString.substring(index2+1,index3).toInt(); 

위와 같이 코딩해서 hour, min, sec 구하게 됩니다. 지난시간에 설명을 다했기 때문에 간단히 넘어 갑니다.

timer0_millis = ((long)hour*3600+min*60+sec)*1000;   

hour, min, sec 값을 초로 변환하여 timer0_millis 변수에 저장하면 타이머는 입력된 시간을 기준으로 돌아가게 됩니다. 즉, 입력된 시간에서 타이머 시간이 흐른다고 보시면 됩니다.

readTime = millis()/1000;

sec = readTime%60;
min = (readTime/60)%60;
hour = (readTime/(60*60))%24; 

readTime 변수에는 millis()함수에서 읽은 타이머 시간값을 1000으로 나눈 몫 값을 저장하기 때문에 입력된 시간을 기준으로 1초 단위로 값이 변화가 일어 나겠죠. 입력시간을 기준으로 흐르는 시간값을 hour, min, sec값으로 다시 구하면 현재 시간을 구할 수 있게 됩니다.

이 값을 4-Digit 7-Segment Display로 출력하면 실제 아두이노 시계가 완성 됩니다.

2) 시간 타이머리셋 지정


24시간을 기준으로 시간을 리셋 시킬 예정입니다. 그러면 어떻게 코딩해야 할까요.

if(millis()>=86400000){ //타이머 리셋
     timer0_millis=0;
}

if문으로 1day는 24시간이고 이 시간은 "60x60x24" 가 됩니다. 여기에 1초(1000)을 곱해주면 86400000의 타이머 시간값이 만들어 집니다. 이 시간이 되면 timer0_millis=0으로 리셋 시키면 24시간 단위로 타이머는 처음부터 다시 돌게 됩니다.

3) 인터럽트 스위치버턴 활용


지난시간에 인터럽트 스위치버턴을 추가했는데 그러면 이 스위치버턴을 그냥 두기가 아쉬워서 어떤 기능을 넣을까 고민하다가 시간 표시를 제어하는 스위치버턴으로 변경해 보았습니다.

void switchFn(){
  state=!state;
}

스위치 버턴이 눌러지면 state 변수가 반전이 일어나게 했습니다.

if(state==true){ //12시 or 24시 출력모드
  hour = hour%12;
}   

이렇게 수정했습니다. 현재 시간 hour를 12시 기준으로 출력할 것인지 24시 기준으로 출력할 건지를 스위치버턴으로 제어하는 기능을 추가 했네요.

4) 종합소스


이제 지난시간의 소스에다가 위 설계 코딩을 삽입하면 아래와 같이 완성 됩니다.

//a,b,c,d,e,f,g 상태값
const byte segValue[10][7] = {
   {1,1,1,1,1,1,0}, //0
   {0,1,1,0,0,0,0}, //1
   {1,1,0,1,1,0,1}, //2
   {1,1,1,1,0,0,1}, //3
   {0,1,1,0,0,1,1}, //4
   {1,0,1,1,0,1,1}, //5
   {1,0,1,1,1,1,1}, //6
   {1,1,1,0,0,0,0}, //7
   {1,1,1,1,1,1,1}, //8
   {1,1,1,1,0,1,1}  //9  
};

const byte segPin[8]={7,3,A3,A1,A0,6,A4,A2}; //사용핀{a,b,c,d,e,f,g,dp} 순서대로임
const byte digitPin[4] = {8,5,4,A5}; //segment 위치 핀

const byte interruptPin = 2;//인터럽트핀

boolean state = false;//시간 출력형식 지정
extern volatile unsigned long timer0_millis; //타이머변수
unsigned long readTime; //현재타이머시간
int hour, min, sec;

void setup() {
  Serial.begin(9600);  
  
  pinMode(interruptPin, INPUT_PULLUP); 
  attachInterrupt(digitalPinToInterrupt(interruptPin), switchFn, FALLING);
  
  for(int i=0;i<10;i++){
    pinMode(segPin[i], OUTPUT);
  }
  for(int j=0;j<4;j++){
    pinMode(digitPin[j], OUTPUT);    
    digitalWrite(digitPin[j], HIGH); 
  }  
}

void loop() {   
  if(Serial.available()){ //입력시간 읽기
    String inString = Serial.readStringUntil('\n');    
    int index1 = inString.indexOf(':'); 
    int index2 = inString.indexOf(':',index1+1);   
    int index3 = inString.length();
    
    hour = inString.substring(0, index1).toInt();
    min = inString.substring(index1+1,index2).toInt();
    sec = inString.substring(index2+1,index3).toInt(); 
    
    timer0_millis = ((long)hour*3600+min*60+sec)*1000;   //입력시간 초변환
  } 
    
  if(millis()>=86400000){ //타이머 리셋
     timer0_millis=0;
  }
  readTime = millis()/1000; //현재시간 읽기
  sec = readTime%60;
  min = (readTime/60)%60;
  hour = (readTime/(60*60))%24; 

  if(state==true){ //12시 or 24시 출력모드
    hour = hour%12;
  } 
  segOutput(3,min%10,0); //min 1의 자리
  segOutput(2,min/10,0); //min 10의 자리
  segOutput(1,hour%10,1); //hour 1의 자리
  segOutput(0,hour/10,0); //hour 10의 자리    
}

//12시 or 24시 출력 변경
void switchFn(){
  state=!state;
}

//LED 초기화
void segClear(){ 
  for(int i=0;i<8;i++){
    digitalWrite(segPin[i], LOW);        
  }
}
//LED 출력
void segOutput(int d, int Number, int dp){ 
  segClear();
  digitalWrite(digitPin[d], LOW); 
  for(int i=0;i<7;i++){
     digitalWrite(segPin[i], segValue[Number][i]);        
  }
  digitalWrite(segPin[7], dp);
  delayMicroseconds(1000);
  digitalWrite(digitPin[d], HIGH); 
}

3. 결과


1) 분/초 출력


숫자를 4개 뿐이 출력을 못하기 때문에 간단히 시간이 흐르는 것을 확인 할 수 있게 출력 숫자는 분/초로 세팅했습니다.

  segOutput(3,sec%10,0); //min 1의 자리
  segOutput(2,sec/10,0); //min 10의 자리
  segOutput(1,min%10,1); //min 1의 자리
  segOutput(0,min/10,0); //min 10의 자리    

입력은 정상적으로 시간 "23:59:50"을 입력할 때는 내부적으로 시간은 정확하게 흘러갑니다. 여기서, 출력은 분/초만 표시될 뿐이죠

분/초만 아래와 같이 출력되어 정상적으로 시간이 흘러가네요.

2) 시/분 출력


종합 소스에 시/분 코딩을 그대로 실험한 결과입니다. 출력은 시/분만 출력됩니다.

  segOutput(3,min%10,0); //min 1의 자리
  segOutput(2,min/10,0); //min 10의 자리
  segOutput(1,hour%10,1); //hour 1의 자리
  segOutput(0,hour/10,0); //hour 10의 자리    

입력은 시간 "23:59:10"을 입력했습니다.

결과는 아래의 동영상에 보시면 "23:59"만 출력됩니다. 내부적으로 초는 계속 흘러가고 있습니다. 인터럽트 스위치버턴을 누르면 12시 기준으로 시간을 표시되고 다시 누르면 23시 기준으로 시간이 표시 되는 실험 결과를 보실 수 있을 꺼에요. 그리고 24시가 되면은 "00:00"으로 리셋되는 것 까지 보실 수 있을 꺼에요.

마무리


4-Digit 7-Segment Display 부품 밖에 없어서 안타깝게 6자리 시간 표시를 못했네요. 그러다보니 분/초 아니면 시/분으로 표시할 수 밖에 없었고 결과 동영상으로는 표현의 한계가 있었네요.

개별 7-Segment가 2개 있으면 추가로 연결해서 표시 할 수 있었겠지만 한개뿐이라 연결을 포기 했습니다. 아무튼 이런식으로 아두이노 시계를 만들 수 있다는 것을 보여드리는 걸로 정리를 할까 합니다. Stepper Motor로 시계를 표시하고 싶은데 4-Digit 7-Segment Display가 post 주제에서 나중에 응용편으로 기회가 된다면 그때 보여드릴게요. 주제에 맞게 post를 하기 위해서 그 실험은 생략하도록 하겠습니다.

가상시뮬레이터에서 6개 7-Segment를 이용해서 확실히 시계를 만들어서 보여드릴까 고민 좀 해보겠습니다. 여러분들은 실제 제작을 안하더라고 가상시뮬레이터에서 동일한 실험이 체험할 수 있게 귀찮은 회로선 연결을 해야하지만 한번 생각해보고 다음 post으로 올릴지 결정할께요. 될 수 있으면 가상시뮬레이터로 한번 제작해서 보여드리는 방향으로 할께요.

Sort:  

7세그먼트 몰라서 숫자써서 하나하나 찾아낸 노가다의 추억ㅋㅋㅋ

한가지 재밌는 사실은 4-Digit 7-Segment Display이 3x3x3 led cube, 키패드 등의 부품과 동일한 원리로 동작해요.
하나의 원리를 깨우치면 나중에 다른 부품들을 응용할 때 꽤 유용하게 활용할 수 있는 것 같아요.

아 그렇군요. 4.7 은 같은 줄 알았는데 다른 것들도 같은 원리라니 신기합니다. ^^ 하핳핳핳. 다음에 또 기회 있을 때 재밌는 거 만들어봐야겠네요. codingman 님 감사합니다. 멋진 걸 배웠네요.ㅎㅎㅎㅎ

여기에, 74hc595 칩을 이용하여 8개 핀을 3핀으로 줄일 수 있고요. 12 or 16 출력 신호를 만들어내는 칩을 이용하면 이름이 막 떠오르지 않지만 이용하면 더 재밌는 것을 만들 수 있어요.
나중에 도전해 보세요.

칩이 달라지면 그런 것도 할 수 있군요. 3핀으로 줄일 수 있는지는 몰랐는데요. 음. ㅇ_ㅇ 12, 16출력이라 오호. 신기해요.

대개 LED를 다량 연결할 때 칩들을 많이 이용하는 것 같아요. 저도 칩네임이 잘 기억 안나지만 칩 몇개만 연결해서 표현하면 수십개의 LED를 제어할 수 있어서 효율적인 면에서 칩을 많이 사용하더군요.
유튜브 같은 LED로 표현한 작품들을 보시면 아마 많이 보실 수 있을꺼에요.

Congratulations @codingman! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

Award for the number of upvotes received

Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word STOP

To support your work, I also upvoted your post!

Do not miss the last post from @steemitboard!


Participate in the SteemitBoard World Cup Contest!
Collect World Cup badges and win free SBD
Support the Gold Sponsors of the contest: @good-karma and @lukestokes


Do you like SteemitBoard's project? Then Vote for its witness and get one more award!

(jjangjjangman 태그 사용시 댓글을 남깁니다.)
호출에 감사드립니다! 즐거운 스티밋하세요!

짱짱맨! 방문에 감사합니다.

C compiler는 어떤걸 사용하시나요?

아두이노 통합개발환경(IDE)를 이용해서 프로그램을 이식하네요.

Coin Marketplace

STEEM 0.28
TRX 0.12
JST 0.034
BTC 63914.94
ETH 3312.82
USDT 1.00
SBD 3.92