[아두이노] 4-Digit 7-Segment Display 시계 리모콘 제어

IOT/아두이노|2019. 6. 20. 10:38

[아두이노] 4-Digit 7-Segment Display 시계 리모콘 제어



지난 시간에 6-Digit 7-Segment Display 아두이노 시계에서 리모콘 시간 입력을 가상시뮬레이터로 실험을 하였습니다. 오늘은 다행히 IR Sensor(수신부) 부품을 찾아서 실제 리모콘으로 제어하는 실험을 할 수 있게 되었네요. 참고로 4-Digit 7-Segment Display 부품이라서 4개의 숫자 밖에 출력을 못합니다. 그래서 시/분을 리모콘으로 제어할 것인지 분/초를 제어할지 고민하다가 분/초를 리모콘으로 제어하고 제어된 결과가 정상적으로 동작하는지 살펴보는게 나을 것 같아서 분/초 시계를 만들어 보았습니다.


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


  • 준비물 : 4-Digit 7-Segment Display 1개, IR Sensor 1개, IR remote 1개, 아두이노우노
  • 내용 : 7-Segment Display 부품의 핀 번호 순서에 맞게 아두이노우노에 연결하고, IR Sensor 핀을 2번핀에 연결하시오.

IR Sensor(수신부)는 핀 위치가 다를 수 있습니다. fritzing에 제공되는 핀위치에 따라 연결했기 때문에 연결하실 때 해당 수신부 부품이 어떤 부품이냐에 따라 주의해서 연결해 주세요.


아래 IR Sensor(수신부) 부품이면 핀 번호를 보시고 연결하시면 됩니다.


2. 코딩



사전학습 post의 소개한 소스를 실제 코딩에도 그대로 적용됩니다. 사전학습 종합소스와 아래 수정 할 부분을 같이 보고 어느 부분을 수정되었는지 같이 보시면서 읽어주세요. 아니면 아래 수정한 종합소스를 보면서 수정한 부분의 위치가 어느 위치이고 수정됐는지 같이 보면서 이해하시기 바랍니다. 그 이유는 그냥 아래 수정 할 부분에 이부분을 수정합니다라고 이야기 하기 때문에 말하는 부분이 정확이 어느 부분인지 혼동할 수 있기 때문에 꼭 종합소스를 같이 봐주세요.

수정 할 부분은 리모콘 키값부분입니다.


사용할 버턴은 위 사진에서 보는 버턴들을 이용 합니다. 이 부분의 키값을 알려면 리모콘 키값 조회 공개회로도 보시고 맞게 코딩을 수정한 뒤에 키 값을 알아내고 그 키값을 아래와 같이 수정하변 됩니다.

#define STATE 16736925 // ch버턴
#define SELECT_TIME 16748655 // EQ버턴
#define TIME_UP 16754775 // +버턴
#define TIME_DOWN 16769055 // -버턴

다음으로 4-Digit 7-Segment Display 핀 번호에 대해서 변수 수정을 해야 합니다.

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 위치 핀

다음 수정부분은

     if(output==true){
       if(results.value==SELECT_TIME){
         selectVal++;
         if(selectVal==3)selectVal=0;
       }

이 부분으로 원래는 시/분/초 3개의 시간위치가 기존 소스에 있었지만 두개를 분/초를 이용하기 때문에 분/초 위치만 왔다 갔다 하여야 하기 때문에 다음과 같이 수정이 됩니다.

if(selectVal==2)selectVal=0;

만약, 시/분만 왔다 갔다 해야 한다면

if(selectVal==3)selectVal=1;

어떻게 변경해야 할지 아시겠지요.

나머지도 수정해야 하는데 그대로 뒀습니다. 그냥 둬도 동작에는 영향이 없습니다.

출력부분에서 4개의 숫자만 출력되기 때문에 다음 부분을 수정해야 합니다.

void loop() {
  IRremoteRead(); //리모콘 읽기

  if(output==false){ //시간 출력
    readTime = millis()/1000;
    if(millis()>=86400000){
       timer0_millis=0;
    }
    sec = readTime%60;
    min = (readTime/60)%60;
    hour = (readTime/(60*60))%24; 

    segOutput(3,sec%10,0); //sec 1의 자리
    segOutput(2,sec/10,0); //sec 10의 자리
    segOutput(1,min%10,1); //min 1의 자리
    segOutput(0,min/10,0); //min 10의 자리
 //  segOutput(1,hour%10,1); //hour 1의 자리
 //  segOutput(0,hour/10,0); //hour 10의 자리      
  }
  else{ //시간 조정     
    segOutput(3,clockVal[0]%10,0); //sec 1의 자리
    segOutput(2,clockVal[0]/10,0); //sec 10의 자리
    segOutput(1,clockVal[1]%10,1); //min 1의 자리
    segOutput(0,clockVal[1]/10,0); //min 10의 자리
//    segOutput(1,clockVal[2]%10,1); //hour 1의 자리
//    segOutput(0,clockVal[2]/10,0); //hour 10의 자리      
  }
}

분/초를 출력하기 때문에 시 부분을 주석 처리하시면 됩니다. 만약에 시/분을 출력하고 싶다면 초 부분을 주석처리하면 됩니다.

참고로,

** segOutput(segment display 위치,시간값,dp핀값)**

4개의 segment display으로 {0,1,2,3} 순서로대로 위치값을 갖기 때문에 출력 시간값의 위치는 정확히 지정해주시고 코딩해주세요.

수정한 부분을 종합 완성하면,

#include <IRremote.h>

#define STATE 16736925 // ch버턴
#define SELECT_TIME 16748655 // EQ버턴
#define TIME_UP 16754775 // +버턴
#define TIME_DOWN 16769055 // -버턴
  
const byte IRpin = 2;  
IRrecv irrecv(IRpin);
decode_results results;

//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 위치 핀

boolean output = false;//시간 출력형식 지정
byte selectVal = 0;
int clockVal[3]={0,0,0};


extern volatile unsigned long timer0_millis; //타이머변수
unsigned long readTime; //현재타이머시간
int hour, min, sec;

void setup() {
  Serial.begin(9600);  
  irrecv.enableIRIn(); // 리모콘 시작
 
  for(int i=0;i<10;i++){
    pinMode(segPin[i], OUTPUT);
  }
  for(int j=0;j<6;j++){
    pinMode(digitPin[j], OUTPUT);    
    digitalWrite(digitPin[j], HIGH); 
  }  
}

void loop() {
  IRremoteRead(); //리모콘 읽기
   
  if(output==false){ //시간 출력
    readTime = millis()/1000;
    if(millis()>=86400000){
       timer0_millis=0;
    }
    sec = readTime%60;
    min = (readTime/60)%60;
    hour = (readTime/(60*60))%24; 

    segOutput(3,sec%10,0); //sec 1의 자리
    segOutput(2,sec/10,0); //sec 10의 자리
    segOutput(1,min%10,1); //min 1의 자리
    segOutput(0,min/10,0); //min 10의 자리
 //  segOutput(1,hour%10,1); //hour 1의 자리
 //  segOutput(0,hour/10,0); //hour 10의 자리      
  }
  else{ //시간 조정     
    segOutput(3,clockVal[0]%10,0); //sec 1의 자리
    segOutput(2,clockVal[0]/10,0); //sec 10의 자리
    segOutput(1,clockVal[1]%10,1); //min 1의 자리
    segOutput(0,clockVal[1]/10,0); //min 10의 자리
//    segOutput(1,clockVal[2]%10,1); //hour 1의 자리
//    segOutput(0,clockVal[2]/10,0); //hour 10의 자리      
  }
}

void IRremoteRead(){
   if (irrecv.decode(&results)) //리모콘 누른값이 없다면 패스
    {
     if(results.value==STATE){
       output=!output;       
       if(output==false){
         hour = clockVal[2];
         min = clockVal[1];
         sec = clockVal[0];
         timer0_millis = ((long)hour*3600+min*60+sec)*1000;         
       }
       else{
         selectVal=0;
         for(int i=0;i<3;i++){
           clockVal[i]=0;
         }         
       }       
     }
     
     if(output==true){
       if(results.value==SELECT_TIME){
         selectVal++;
         if(selectVal==2)selectVal=0;
       }
         
       if(results.value==TIME_UP)clockVal[selectVal]++;
       else if(results.value==TIME_DOWN) clockVal[selectVal]--;
       

       if(selectVal==2){                  
         if(clockVal[selectVal]==24)clockVal[selectVal]=0;
         else if(clockVal[selectVal]==-1)clockVal[selectVal]=23;
       }
       else{
         if(clockVal[selectVal]==60)clockVal[selectVal]=0;
         else if(clockVal[selectVal]==-1)clockVal[selectVal]=59;         
       }

     }
    //Serial.println(results.value); //key value
     irrecv.resume(); // 다음값
    }
}

//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. 결과


  • CH => 시간입력 ON/OFF
  • EQ => 시간 입력 제어 위치
  • +/-=> 숫자 증감/감소

CH 버턴을 누르면 시간을 입력 할 준비 상태가 됩니다. +/- 바로 누르면 sec가 움직입니다. EQ를 누르면 min 위치로 이동하고 다시 +/-를 누르면 min이 움직입니다. 입력 할 시간 세팅이 끝나면 CH 버턴을 누르면 입력된 시간이 타이머변수에 세팅이 되고 그때부터 시간이 흘러가고 4-Digit 7-Segment Display에 현재 분/초를 출력하게 됩니다.


마무리


오늘은 Digit 7-Segment Display 부품에 분/초가 출력되는데 여기에 리모콘을 누르면 분/초를 조정할 수 있게 됩니다. 참고로 실험에서는 시 부분은 0시로 무조건 초기 세팅이 되고 분/초가 제어가 이루어지기 때문에 위 소스로만 제작한다면 약간 아두이노 시계라고 보기 어렵습니다. 수정하셔서 시/분으로 제작하시고 60초를 버리고 시/분을 입력하여 초는 무조건 0초부터 시작하게 수정하시면 진자 아두이노 시계 느낌으로 제작이 완료 됩니다. 이 부분은 위 코딩 수정부분을 보시면 어디를 수정하면 원하는 결과가 나올지는 찾을 수 있을거라 생각됩니다. 한번 수정해 보세요.

여기서 직접 리모콘까지 아두이노로 만들어 보았으면 좋은데 송신부 부품이 없어서 아깝게 아두이노 리모콘 제작은 못 보여드리네요. 혹시 관심이 있으시면 아두이노 리모콘 만들기를 구글 검색하시면 간단한 에제 소스를 보실 수 있으니깐 만들어 보실분들은 한번 도전해 보세요. 아두이노 리모콘을 만드시면 나중에 가정 전자제품의 리모콘의 키값을 아두이노로 IR Sensor(수신부)로 읽을 수 있으면 아두이노 리모콘에 그 키값을 저장했다가 실제 가정 전자제품을 직접 만든 아두이노 리모콘으로 제어할 수 있습니다. 여러개의 리모콘 값을 아두이노 리모콘으로 통합시키면 하나의 리모콘으로 모든 가전제품을 제어할 수 있게 되니깐 호기심이 있는 분들은 꼭 실험해 보세요.


댓글()

[아두이노] 6-Digit 7-Segment Display 시계 리모콘 제어

IOT/아두이노|2019. 6. 19. 09:00

[아두이노] 6-Digit 7-Segment Display 시계 리모콘 제어



6-Digit 7-Segment Display 지난 시간에 아두이노 시계를 제작하여 가상 실험을 하였습니다. 그런데 아두이노 시계의 초기값을 PC 시리얼모니터에서 시간을 입력하는게 좀 불편해 보여서 다른 외부 장치로 시간을 입력하는 방법이 없을까 고민하다가 무선으로 시간값을 입력하는 방법을 상상하다가 몇가지 상상한 방법 중에 리모콘으로 시간을 입력해볼까 하는 호기심이 생겨서 좋은 학습 자료가 될 것 같아서 리모콘으로 아두이노 시간값을 입력하는 실험하게 되었네요. 리모콘으로 시간을 입력하는데 그 입력된 시간을 리모콘이 누를때 숫자가 변경되고 그 값이 6-Digit 7-Segment Display 부품에 출력되게 해야 하는데 6개의 7-Segment Display을 각각 개별적으로 6개의 숫자를 갱신하게 할지 아니면 시/분/초 단위로 3개의 숫자로 리모콘으로 제어해서 3개의 숫자값을 출력해야 할지 아니면 다른 방법으로 시간 숫자를 제어할지 여러개를 고민하고 실험해 보았습니다. 그중 하나를 선택하여 post로 소개 합니다.

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


  • 준비물 : 7-Segment Display 6개, IR Sensor 1개, IR remote 1개, 아두이노우노
  • 내용 : 7-Segment Display 부품의 핀 번호 순서에 맞게 아두이노우노에 연결하고, IR Sensor 핀을 2번핀에 연결하시오.

지난 시간의 회로도에서 스위치버턴핀으로 사용한 2번핀을 IR Sensor핀으로 사용했습니다. 수정 부분은 IR Sensor 핀만 변경해주시면 됩니다.


2. 코딩



리모콘 제어를 간단히 복습을 해 볼까요.


[IRemote]

  • 선언 :
#include <IRremote.h>
 
int IRpin = 2;  // IR Sensor Pin
IRrecv irrecv(IRpin);
decode_results results;
  • 초기세팅 : 리모콘 시작
void setup(){
  irrecv.enableIRIn(); // 리모콘 시작
}
  • 리모콘 읽기 : results.value으로 리모콘이 읽은 키 값이 저장되어 있음
void loop(){
  if (irrecv.decode(&results)){ //리모콘 누른값이 없다면 패스
      //results.value 로 리모콘이 눌린 값이 들어 있음.
        
        irrecv.resume(); // 다음값
  }
}

몇달 전 post의 내용인데 오랫만의 리모콘을 아두이노 시계에 적용합니다. 참고로 IRremote 라이브러리 설치는 사전학습에 가시면 나와 있으니깐 보시고 설치한 다음 사용하세요. 혹시 위와 같이 코딩했는데 작동을 안하면 라이브러리를 확인하시고 설치하시면 됩니다.

1) 리모콘 키값 찾기



위 그림의 리모콘의 버턴 4개를 사용할 예정입니다.

  • FUNC/STOP => 시간입력 ON/OFF
  • ST/REPT => 시간 입력 제어 위치
  • 세모 위/아래 => 숫자 증감/감소

가상시뮬레이터로 사전학습의 회로도와 키값 확인 소스를 누르시면 해당 results.value을 확인 할 수 있습니다.

위 코딩에서

Serial.println(results.value);

이렇게 해서 리모콘의 해당 키값을 시리얼모니터로 확인 한 다음 기록해 주세요.

#define STATE 16597183  //FUNC/STOP
#define SELECT_TIME 16609423 //ST/REPT
#define TIME_UP 16601263 //세모 UP
#define TIME_DOWN 16584943 //세모 DOWN

참고로, 실제로 실험하실 때는 리모콘 키값을 직접 누르시고 해당 키 값을 메모장에 기록했다가 위처럼 표현하시면 됩니다. 리모콘 종류에 따라 키 값이 다를 수 있음으로 꼭 사전에 키값을 확인하시고 코딩해 주세요.

2) 시간 입력 리모콘 제어


  • FUNC/STOP => 시간입력 ON/OFF

시간을 입력받을지 결정해야 합니다. 상태변수를 하나 만들어서 아래와 같이 IF 조건문을 만들면 됩니다.

if (irrecv.decode(&results)) //리모콘 누른값이 없다면 패스
    {
     if(results.value==STATE){
           output=!output;
     }
}

FUNC/STOP 리모콘 버턴을 누르면 output가 true or false 교대로 상태값을 갖게 됩니다. output가 true면 시간 입력이고 false면 입력된 시간이 흘러가게 하는 코딩을 하겠습니다.

if(리모콘키값==STATE){
  output=!output; 
  if(output==false){
    timer0_millis 시간 설정;
  }
  else{
    시간 전 입력 초기화;    
  } 
}
if(output==true){        
   시간 입력;
}

코딩을 하면,

 if (irrecv.decode(&results)) //리모콘 누른값이 없다면 패스
    {
     if(results.value==STATE){ //시간 입력 결정
       output=!output;       
       if(output==false){  //리모콘으로 시/분/초 입력한 값을 타이머변수에 저장;
         hour = clockVal[2];
         min = clockVal[1];
         sec = clockVal[0];
         timer0_millis = ((long)hour*3600+min*60+sec)*1000;         
       }
       else{  //시간 입력 전 입력 변수을 초기화
         selectVal=0;
         for(int i=0;i<3;i++){
           clockVal[i]=0;
         }         
       }       
     }
     if(output==true){ //시간 입력 제어
        시간입력;        
     }       
     irrecv.resume(); // 다음값
    }
}

clockVal[3]은 hour, min, sec의 값을 저장하게 됩니다. 그리고 selectVal은 시/분/초의 위치를 나타냅니다.

if(results.value==SELECT_TIME){ //시/분/초 위치 선택
  selectVal++;
  if(selectVal==3)selectVal=0;
}

ST/REPT를 누를 때 시/분/초가 selectVal이 0이면 sec이고, 1이면 min, 2이면 hour를 가리킵니다. selectVal가 3이 되면 다시 0으로 초기화됩니다. 해당 리모콘의 키 버턴을 통해 시/분/초 위치값을 지정할 수 있게 됩니다.

이제 세모 UP/DOWN 버턴을 통해서 시간값을 증감/감소를 제어를 해 볼까요.

if(results.value==TIME_UP) clockVal[selectVal]++;  //시간값 증가
else if(results.value==TIME_DOWN) clockVal[selectVal]--;  //시간값 감소

"clockVal[selectVal]++" or "clockVal[selectVal]--"로 시/분/초 값을 증가/감소를 시키게 됩니다. 여기서, 시간은 24시, 분은 60분, 초는 60초가 max 값입니다. 그래서 증가할 때 숫자는 시간은 24시를 넘지 말아야 하고 분/초는 60을 넘지 말아야 합니다.

그 부분을 IF문으로 표현을 하면 다음과 같습니다.

if(selectVal==2){ //hour 일때              
  if(clockVal[selectVal]==24)clockVal[selectVal]=0;
  else if(clockVal[selectVal]==-1)clockVal[selectVal]=23;
}
else{ //min, sec 일때
  if(clockVal[selectVal]==60)clockVal[selectVal]=0;
  else if(clockVal[selectVal]==-1)clockVal[selectVal]=59;         
}

selectVal가 2이면 시간이니깐 IF문에서 24가 되면 clockVal[selectVal]으로 0으로 만들고 감소할 때 -1이 되면 23으로 만들어 주면 0~23시간 조절하면 됩니다

그리고 그외 0~1이면 분/초로 60이 max이니깐 IF문으로 60이면 clockVal[selectVal]으로 0으로 만들고 감소할 때 -1이 되면 59으로 만들어 주면 0~59분/초를 조절하면 됩니다

3) 출력


  if(output==false){ //시간 출력
    readTime = millis()/1000;
    if(millis()>=86400000){
       timer0_millis=0;
    }
    sec = readTime%60;
    min = (readTime/60)%60;
    hour = (readTime/(60*60))%24; 

    segOutput(5,sec%10,0); //sec 1의 자리
    segOutput(4,sec/10,0); //sec 10의 자리
    segOutput(3,min%10,1); //min 1의 자리
    segOutput(2,min/10,0); //min 10의 자리
    segOutput(1,hour%10,1); //hour 1의 자리
    segOutput(0,hour/10,0); //hour 10의 자리      
  }
  else{ //시간 조정     
    segOutput(5,clockVal[0]%10,0); //sec 1의 자리
    segOutput(4,clockVal[0]/10,0); //sec 10의 자리
    segOutput(3,clockVal[1]%10,1); //min 1의 자리
    segOutput(2,clockVal[1]/10,0); //min 10의 자리
    segOutput(1,clockVal[2]%10,1); //hour 1의 자리
    segOutput(0,clockVal[2]/10,0); //hour 10의 자리      
  }

output가 false이면 시간을 출력하니깐 타이머변수를 세팅하면 millis()함수 현재 시간을 구하여 출력하면 됩니다. 지난시간의 출력 부분하고 같기 때문에 그대로 적용합니다. 하지만 시간을 입력할 때도 6-Digit 7-Segment Display 출력해야 하기 때문에 output가 true일때는 입력상황이니깐 그 입력에 대한 출력부분도 코딩해야 합니다. 입력시간은 clockVal[3] 배열변수에 저장되기 때문에 10의 자리와 1의 자리를 쪼개서 각 숫자를 해당 위치에 맞게 출력시키면 됩니다.

위의 표현한 코딩을 지난시간의 아두이노 시계에 합쳐 보도록 하겠습니다.

4) 종합 소스


#include <IRremote.h>

#define STATE 16597183
#define SELECT_TIME 16609423
#define TIME_UP 16601263
#define TIME_DOWN 16584943
  
const byte IRpin = 2;  
IRrecv irrecv(IRpin);
decode_results results;


//a,b,c,d,e,f,g 상태값
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]={3,4,5,6,7,8,9,10}; //사용핀{a,b,c,d,e,f,g,dp} 순서대로임
const byte digitPin[6] = {A0,A1,A2,A3,A4,A5}; //segment 위치 핀

boolean output = false;//시간 출력형식 지정
byte selectVal = 0;
int clockVal[3]={0,0,0};

extern volatile unsigned long timer0_millis; //타이머변수
unsigned long readTime; //현재타이머시간
int hour, min, sec;


void setup() {
  Serial.begin(9600);  
  irrecv.enableIRIn(); // 리모콘 시작
 
  for(int i=0;i<10;i++){
    pinMode(segPin[i], OUTPUT);
  }
  for(int j=0;j<6;j++){
    pinMode(digitPin[j], OUTPUT);    
    digitalWrite(digitPin[j], HIGH); 
  }  
}

void loop() {
  IRremoteRead(); //리모콘 읽기
   
  if(output==false){ //시간 출력
    readTime = millis()/1000;
    if(millis()>=86400000){
         timer0_millis=0;
    }
    sec = readTime%60;
    min = (readTime/60)%60;
    hour = (readTime/(60*60))%24; 

    segOutput(5,sec%10,0); //sec 1의 자리
    segOutput(4,sec/10,0); //sec 10의 자리
    segOutput(3,min%10,1); //min 1의 자리
    segOutput(2,min/10,0); //min 10의 자리
    segOutput(1,hour%10,1); //hour 1의 자리
    segOutput(0,hour/10,0); //hour 10의 자리      
  }
  else{ //시간 조정     
    segOutput(5,clockVal[0]%10,0); //sec 1의 자리
    segOutput(4,clockVal[0]/10,0); //sec 10의 자리
    segOutput(3,clockVal[1]%10,1); //min 1의 자리
    segOutput(2,clockVal[1]/10,0); //min 10의 자리
    segOutput(1,clockVal[2]%10,1); //hour 1의 자리
    segOutput(0,clockVal[2]/10,0); //hour 10의 자리      
  }
}

void IRremoteRead(){
   if (irrecv.decode(&results)) //리모콘 누른값이 없다면 패스
    {
     if(results.value==STATE){ //시간 입력 결정
       output=!output;       
       if(output==false){ //리모콘으로 시/분/초 입력한 값을 타이머변수에 저장;
         hour = clockVal[2];
         min = clockVal[1];
         sec = clockVal[0];
         timer0_millis = ((long)hour*3600+min*60+sec)*1000;         
       }
       else{  //시간 입력 전 입력 변수을 초기화
         selectVal=0;
         for(int i=0;i<3;i++){
           clockVal[i]=0;
         }         
       }       
     }
     
     if(output==true){ //시간 입력 제어
       if(results.value==SELECT_TIME){ //시/분/초 위치 선택
         selectVal++;
         if(selectVal==3)selectVal=0;
       }
             
       if(results.value==TIME_UP)clockVal[selectVal]++; //시간값 증가
       else if(results.value==TIME_DOWN) clockVal[selectVal]--; //시간값 감소
 
       if(selectVal==2){ //hour 일때                 
         if(clockVal[selectVal]==24)clockVal[selectVal]=0;
         else if(clockVal[selectVal]==-1)clockVal[selectVal]=23;
       }
       else{ //min, sec 일때
         if(clockVal[selectVal]==60)clockVal[selectVal]=0;
         else if(clockVal[selectVal]==-1)clockVal[selectVal]=59;         
       }

     }   
     irrecv.resume(); // 다음값
    }
}

//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); 
}

지난시간의 아두이노 시계 소스를 이해 하셔야 오늘 리모콘 제어 부분을 이해할 수 있습니다. 단편적으로 설명하다 보니 아두이노시계 소스를 모른 상태에서 이해하시기가 좀 어려울 수 있겠네요. 사전학습을 미리 하시고 post를 읽어 주시기 바랍니다.

3. 결과


  • FUNC/STOP => 시간입력 ON/OFF
  • ST/REPT => 시간 입력 제어 위치
  • 세모 위/아래 => 숫자 증감/감소

FUNC/STOP 버턴을 누르면 시간을 입력 할 준비 상태가 됩니다. 세모 위/아래 바로 누르면 sec가 움직입니다. ST/REPT를 누르면 min 위치로 이동하고 다시 세모 위/아래를 누르면 min이 움직입니다. 또, ST/REPT를 누르면 hour 위치로 이동하고 다시 세모 위/아래를 누르면 hour이 움직입니다. 입력 할 시간 세팅이 끝나면 FUNC/STOP 버턴을 누르면 입력된 시간이 타이머변수에 세팅이 되고 그때부터 시간이 흘러가고 6-Digit 7-Segment Display에 현재 시간을 출력하게 됩니다.

한번 위의 순서대로 시간을 입력해 보세요.

아래 동영상은 회로도가 복잡해서 가상시뮬레이터를 실행하면 지연 렉이 발생합니다. 그래서 1초가 움직이는데 좀 오래 걸리는데 이게 잘못된 코딩은 아니고 지연 렉이니깐 감안하시고 보세요.


마무리


오늘은 가상시뮬레이터에서 가상으로 아두이노 시계를 만들었는데 거기에다가 리모콘을 연결하여 시간 입력을 실험 하였습니다. 약간 시간을 입력하는 로직이 좀 복잡할 수 있습니다. 혹시 위 post 이해가 안가지면 if문 단위로 가상 데이터를 넣어서 어떤 동작을 하는지 체크하시면서 테스트 해보시기 바랍니다.

참고로, 실제 구현 한것도 post에 올릴려고 했는데 IR Sensor를 찾지 못해서 실제로는 구현을 못해 봤네요. 만약 찾게 되면은 4-Digit 7-Segment Display 부품에 IR Sensor를 연결하여 실제로 실험한 post를 올리겠습니다.


댓글()

[아두이노] 4-Digit 7-Segment Display 가상시뮬레이터 실험

IOT/아두이노|2019. 6. 18. 09:00

[아두이노] 4-Digit 7-Segment Display 가상시뮬레이터 실험



4-Digit 7-Segment Display 지난 시간에 실험했던 것을 가상시뮬레이터로 회로도을 만들어 보았습니다. 시계 회로도에서 추가로 6-Digit 7-Segment Display 형식으로 아두이노 시계를 만들어 보았으니깐 가상시뮬레이터로 한번 체험해보시고 수정할 코딩이 있으면 추가 코딩을 해보시기 바랍니다.

1. 4-Digit 7-Segment Display


1) 숫자 카운트 (0~9999)


  • 준비물 : 7-Segment Display 4개, 아두이노우노
  • 내용 : 7-Segment Display 부품의 핀 번호 순서에 맞게 아두이노우노에 연결하시오.


2-Digit 7-Segment Display 회로도에서 2개를 더 추가해서 4-Digit 7-Segment Display 회로도를 완성 했네요.



참조 링크 post에서 숫자 카운트 (0~9999) 소스를 실험하시면 됩니다. 주의할 점은 아두이노 핀 번호에 대한 변수지정은 수정해야 합니다.

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 segPin[8]={2,3,4,5,6,7,8,9}; //사용핀{a,b,c,d,e,f,g,dp} 순서대로임
const byte digitPin[4] = {A0,A1,A2,A3}; //segment 위치 핀

결과


0.01초 단위로 카운트를 하는 결과입니다.


2) 시간 출력


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


스위치 버턴이 추가 된 회로도 입니다. 지난시간의 실제 4-Digit 7-Segment Display 부품으로 생각하시면 됩니다.



참조 링크 post에서 아두이노 시계 소스를 실험하시면 됩니다. 여기에서 주의 할 점은 아두이노 핀 번호에 대한 변수지정입니다. 그 부분은 방금 했던 방식으로 그대로 변경하시면 됩니다.

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 segPin[8]={2,3,4,5,6,7,8,9}; //사용핀{a,b,c,d,e,f,g,dp} 순서대로임
const byte digitPin[4] = {A0,A1,A2,A3}; //segment 위치 핀

결과


시리얼 모니터로 입력하면 시/분이 가상시뮬레이터의 7-Segment Display 부품에 출력됩니다. 참고로, 가상시뮬레이터가 회로도 복잡해서 실행 시 지연이 발생해서 1초 단위의 움직임이 발생하지 않습니다. "23:59:57"시간을 입력해서 3초 후 "00:00:00"이 되어야 하는데 움짤에 몇십초가 걸렸네요. 감안하시고 결과를 보시기 바랍니다. 그리고 스위치버턴을 누르면 12시 기준으로 시간 표시와 아니면 24시 기준으로 시간 표시로 변경할 수 있는 기능을 추가했습니다.


2. 6-Digit 7-Segment Display 회로도


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


위에서 만든 회로도에서 2개의 7-Segment Display을 추가 연결했네요.



참조 링크 post에서 아두이노 시계 소스를 실험하시면 됩니다. 시/분 출력을 시/분/초까지 출력시키면 됩니다. 마무리 부분이니 이부분은 지난 시간의 소스를 가져와서 수정된 부분을 보도록 할까요.

[종합소스]

//a,b,c,d,e,f,g 상태값
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]={3,4,5,6,7,8,9,10}; //사용핀{a,b,c,d,e,f,g,dp} 순서대로임
const byte digitPin[6] = {A0,A1,A2,A3,A4,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<6;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;   
  } 
  readTime = millis()/1000;
  if(millis()>=86400000){
     timer0_millis=0;
  }
  sec = readTime%60;
  min = (readTime/60)%60;
  hour = (readTime/(60*60))%24; 

  if(state==true){ //12시 or 24시 출력모드
    hour = hour%12;
  } 
  segOutput(5,sec%10,0); //sec 1의 자리
  segOutput(4,sec/10,0); //sec 10의 자리
  segOutput(3,min%10,1); //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); 
}

결과


"23:59:57" 시간을 입력하지만 이 역시 회로도가 복잡하게 디자인 되어 지연 렉이 발생하네요. 3초가 꽤 길게 걸리네요. 코딩에 문제가 있는게 아니라 지연 렉이니깐 감안하시고 동영상을 보시기 바랍니다.


시계 결과가 너무 흐리게 나왔네요. 위에 링크 된 6-Digit 7-Segment Display 공개 회로도에 가셔서 테스트를 해 보시기 바랍니다.

마무리


오늘은 가상시뮬레이터로 3개의 회로도를 만들고 간단히 실험을 해 보았습니다. 실제로 제작해서 실험을 해보시는 것도 괜찮ㅅ브니다. 가상 시뮬레이터로 여러분들도 간접 체험을 할 수 있게 회로도를 개별적으로 만들어 놓았습니다. 위에 공개회로도를 링크 걸어놓은 곳에 가셔서 한번 테스트 해보세요. 그리고 따로 상상하는 부분이 있으면 가상시뮬레이터를 복사하셔서 직접 수정해 보세요.


댓글()

[아두이노] 4-Digit 7-Segment Display 시계 만들기

IOT/아두이노|2019. 6. 15. 09:00

[아두이노] 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으로 올릴지 결정할께요. 될 수 있으면 가상시뮬레이터로 한번 제작해서 보여드리는 방향으로 할께요.


댓글()

[아두이노] 4-Digit 7-Segment Display 제어

IOT/아두이노|2019. 6. 14. 09:00

[아두이노] 4-Digit 7-Segment Display 제어



지난시간에 2-Digit 7-Segment Display(애노드형)을 가상시뮬레이터에서 실험 했었습니다. 오늘은 실제로 4-Digit 7-Segment Display로 숫자를 출력해보는 실험을 해보겠습니다. 4-Digit 7-Segment Display 부품은 캐소드형이고 지난시간에 일부 변수값과 상태값은 전부 반전된 형태로 표현해야 하기 때문에 회로도를 만들고나서 코딩을 할 때 혼동하지 말고 주의해서 코딩하시기 바랍니다.


1. 4-Digit 7-Segment Display(캐소드형)


4-Digit 7-Segment Display 부품은 아래 이미지와 같습니다. 대충 그렸는데 썩 마음에 들지 않네요.


내부 회로도를 살펴보면 지난 시간에 애노드형 2-Digit 7-Segment Display 회로도를 보셨을 꺼에요. 오늘은 실제 사용되는 4-Digit 7-Segment Display 부품은 캐소드형으로 아래와 같은 회로도로 구성되어 있습니다.


4개의 7-Segment가 a,b,c,d,e,f,g,dp 핀을 공유하고 제어는 D1, D2, D3, D4로 각 D핀을 개방함으로써 해당 7-Segment에 숫자나 문자를 출력하게 됩니다.

캐소드형이기 때문에 D1, D2, D3, D4 핀은 LOW가 될때 a,b,c,d,e,f,g,dp 핀이 HIGH일 때 해당 LED에 불이 들어오게 됩니다. 지난시간의 애노드형 2-Digit 7-Segment Display 반대입니다.

2. 4-Digit 7-Segment Display 핀 번호



위 표를 꼭 기억해 주세요. 4-Digit 7-Segment Display 부품의 위의 부품이미지처럼 순서대로 1~12번까지 있는데 각 핀에 해당된 값을 기억해 주세요. 세개의 표가 있는데 양쪽 표는 여러분들이 보기 편한 것을 참조해 주시고요. 가운데 표는 아두이노와 연결했을 때의 표입니다. 아두이노 핀은 여러분들이 실제 4-Digit 7-Segment Display 부품의 핀을 아두이노에 어떤식으로 연결하느냐에 따라서 아두이노핀 번호는 달라집니다. 가운데 표는 여러분들이 실제 구현을 할 때 표로 직접 작성해주세요. 그리고 나서 코딩을 할 때 해당 4-Digit 7-Segment Display 핀의 값을 기준으로 변수를 선언하실 수 있습니다.

즉, 위 표와 같이 연결을 한다면,

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

이런식으로 pin번호를 순서대로 4-Digit 7-Segment Display 핀값에 매칭되는 아두이노 핀번호를 선언해주면 됩니다. 위 배열 변수에 저장된 값은 4-Digit 7-Segment Display부품과 아두이노에 어떻게 연결했느냐에 따라서 값이 달라집니다.

여러분들이 편한 방식으로 마음대로 연결하시고 코딩할 때만 핀변수값을 정확히 선언하시면 부품을 제어하는데 어려움은 없을 거라 생각됩니다.

참고로, 선 연결 할 때 a,b,d,c,e,f,g,dp핀을 한쪽으로 뭉쳐서 순서대로 아두이노에 연결하고 나머지 4개의 핀은 d1,d2,d3,d4에 순서대로 연결하셔도 됩니다. 하지만 이경우는 4-Digit 7-Segment Display 부품의 핀 위치값을 정확히 알고 있을 때 선을 연결하는 방법인데 좀 지져분하게 선이 연결 됩니다. 그리고, 선 연결 할 때 실수 할 가능성이 가장 큽니다. 별로 추천드리지 않습니다.

쉽게, 4-Digit 7-Segment Display 부품 핀번호 1~12번을 아두이노 2~12번으로 순서대로 매칭시켜서 선을 연결하거나 아니면 아두이노의 아날로그와 디지털핀을 이용하여 4-Digit 7-Segment Display 부품 핀 번호 1~6번은 아두이노 A0~A5에 연결하고 나머지 7~12번은 아두이노 2~7번으로 위아래 순서대로 선을 연결하셔도 됩니다. 그냥 순서대로 핀을 보기 좋게 연결하시고 코딩에서 해당핀에 대한 변수만 제대로 선언하시면 제어하는데 어려움이 없을 꺼에요

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


준비물 : 4-Digit 7-Segment Display 1개, 아두이노우노
내용 : 4-Digit 7-Segment Display 부품의 핀 번호 순서에 맞게 아두이노우노에 연결 하시오.



위 회로도는 4-Digit 7-Segment Display 핀번호 1~6번은 아날로그 핀 A0~A5에 순서대로 연결하고 7~12번은 순서대로 2~7번으로 연결하려다가 따로 스위치버턴을 인터럽트 핀을 이용할 까 고민중이라 인터럽트핀이 2,3 번 핀 중에 우선 2번핀 하나정도는 남겨 두기 위해서 3~8번으로 순서대로 핀을 연결했네요.

핀 연결은 여러분들이 편하신 방법으로 연결하시면 됩니다. 규칙도 없고 그냥 여러분이 원하는 스타일로 연결만 해주세요. 연결하시고 나서 코딩을 할 때 해당핀에 대한 변수를 선언할 때 정확히 지정만 해주면 됩니다.

2. 코딩


1)LED 숫자 패턴


[애노드형]

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

캐소드형 회로도이기 때문에 아래와 같이 1은 0으로 0은 1로 변경만 시키면 됩니다.

//a,b,c,d,e,f,g 상태값
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  
};

2) 숫자 카운트 (0~9999)


아래와 같이 millis()함수는 실시간으로 현재 타이머시간값을 읽어옵니다 그 값을 기준으로 각 자릿숫자를 d1,d2,d3,d4에 저장됩니다.

readTime = millis()/1000;
d1 = readTime%10; //1의 자리
d2 = (readTime/10)%10; //10의 자리
d3 = (readTime/100)%10; //100의 자리
d4 = (readTime/1000)%10; //1000의 자리

2-Digit 7-Segment Display 에서 100의 자리, 1000의 자리가 추가 되었을 뿐 따로 코딩에는 변동이 없습니다.

2) 숫자 카운트 출력(0~9999)

segOutput(3,d1,0); //1의 자리
if(readTime>=10) segOutput(2,d2,0); //10의 자리  
if(readTime>=100) segOutput(1,d3,0); //100의 자리  
if(readTime>=1000) segOutput(0,d4,0); //1000의 자리  

출력되 100의 자리, 1000의 자리로 segOutput()함수 인자만 맞게 넣어주시면 4자리 숫자가 카운트 되어 출력됩니다.

3) 종합소스


//a,b,c,d,e,f,g 상태값
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  
};

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

unsigned long readTime=0; //현재시간
int d1 = 0; //1의 자리
int d2 = 0; //10의 자리
int d3 = 0; //100의 자리
int d4 = 0; //1000의 자리

void setup() {
  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() {   
  readTime = millis()/1000;
  d1 = readTime%10; //1의 자리
  d2 = (readTime/10)%10; //10의 자리
  d3 = (readTime/100)%10; //100의 자리
  d4 = (readTime/1000)%10; //1000의 자리
  
  segOutput(3,d1,0); //1의 자리
  if(readTime>=10) segOutput(2,d2,0); //10의 자리  
  if(readTime>=100) segOutput(1,d3,0); //10의 자리  
  if(readTime>=1000) segOutput(0,d4,0); //10의 자리  
}
//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개의 7-Segment의 숫자가 정확히 출력되는지 확인하기 위해서는 1000초가 걸립니다. 즉, 16분 40초를 기다려야 합니다. 그래서 0.01초로 카운트를 한 영상입니다.

<
readTime = millis()/10; //0.01초 단위






4. 입터럽트 스위치 버턴으로 타이머 리셋


스위치버턴을 입터럽트 이벤트를 발생시킬 예정입니다. 스톱워치처럼 스위치를 누르면 타이머가 누른 시점에서 리셋되어 돌아가고 다시 스위치를 누르면 정지되고 타이머가 돌다가 멈춘 시간값을 보여주게 됩니다. 그리고 다시 스위치를 누르면 처음부터 다시 타이머가 돌게하는 실험을 할 예정입니다.

1) 회로도


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

2번핀은 인터럽트 핀으로 스위치 버턴을 2번핀에 연결했습니다.


2) 코딩



인터럽트스위치 버턴을 사용하니깐 아래와 같이 코딩합니다 사전학습에 있던 내용이깐 가셔서 읽고 오세요.

const byte interruptPin = 2;//인터럽트핀
void setup() {
  pinMode(interruptPin, INPUT_PULLUP); 
  attachInterrupt(digitalPinToInterrupt(interruptPin), switchFn, FALLING);
}
void loop() {   
  if(state==true){ //스위치 상태가 true일때 카운트
        스위치눌러질때 동작명령;
    }
}
void switchFn(){
  state=!state;
  if(state==true){
    timer0_millis=0; //타이머변수 리셋  
  }
}

여기서, switchFn() 함수를 약간 수정했는데 그것은 state의 값이 true일 때만 timer0_millis을 0으로 초기화 했습니다. 즉, 스위치눌러 타이버가 동작할 때 그 시점에 timer0_millis=0으로 초기화 한다는 의미입니다.

위에서 타이머 동작 기본 소스에서 인터럽트 스위치 버턴 코딩을 합치면 아래와 같은 전체 소스가 완성 됩니다.

//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;//인터럽트핀
extern volatile unsigned long timer0_millis; //타이머변수

boolean state = false;//타이머 동작 제어

unsigned long readTime=0; //현재시간
int d1 = 0; //1의 자리
int d2 = 0; //10의 자리
int d3 = 0; //100의 자리
int d4 = 0; //1000의 자리

void setup() {
  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(state==true){ //스위치 상태가 true일때 카운트
    readTime = millis()/1000;
    d1 = readTime%10; //1의 자리
    d2 = (readTime/10)%10; //10의 자리
    d3 = (readTime/100)%10; //100의 자리
    d4 = (readTime/1000)%10; //1000의 자리 
  }
  if(readTime>=0)segOutput(3,d1,0); //1의 자리
  if(readTime>=10) segOutput(2,d2,0); //10의 자리  
  if(readTime>=100) segOutput(1,d3,0); //10의 자리  
  if(readTime>=1000) segOutput(0,d4,0); //10의 자리 
}
//스위치버턴 이벤트
void switchFn(){
  state=!state;
  if(state==true){
    timer0_millis=0; //타이머변수 리셋  
  }
}
//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) 결과


스위치가 눌러지면 state=true가 되고 1초 단위로 카운트 하게 됩니다. 참고로 다시 누르면 state=false로 정지됩니다. 다시 누르면 state=true가 되고 timer0_millis=0으로 초기화 되고 처음부터 다시 1초 단위로 카운트를 하게 됩니다.


마무리


오늘은 실제 4-Digit 7-Segment Display 부품에 카운트 결과를 출력해 보았습니다. 지난 시간에 시리얼모니터로 결과를 출력했던 것과 다르게 좀 복잡해 보였을 꺼에요. 하나하나 뜯어보면 어렵지 않는 내용이니깐 분리해서 하나씩 살펴보시기 바랍니다.

다음 시간에는 아두이노 시계로 4-Digit 7-Segment Display에 현재 시간을 만들고 그 시간을 기준으로 시간이 흘러가는 것을 실험해 보겠습니다.

댓글()

[아두이노] 2-Digit 7-Segment Display

IOT/아두이노|2019. 6. 13. 09:00

[아두이노] 2-Digit 7-Segment Display



지난 시간까지 해서 시간에 대해서 여러가지 원리에 대해서 살펴 보았습니다. 오늘은 7-Segment Display을 이용하여 지난 시간에 공부했던 코딩 결과를 출력해보는 시간을 갖도록 하죠. 원래는 4-Digit 7-Segment Display를 회로도를 만들어서 실험한 결과를 보여드릴려고 했는데 회로도를 너무 복잡하고 지져분하게 표현하면 가독성이 떨어지기 때문에 간단히 2개로 2-Digit 7-Segment Display로 구성하고 출력 원리만 설명하면 될 것 같아서 회로도를 최소화 했습니다. 실제 실험을 하신다면 이 원리를 기반으로 4-Digit 7-Segment Display로 실험하셔도 됩니다.


1. 7-Segment 복습



너무 오래전에 이야기 했던 거라 간단히 복습차원으로 설명할께요. 각 post 연계를 하면서도 해당 post는 독립적인 내용을 담고 있어야 해서 어쩔 수 없이 중복된 복습 내용을 간단히 소개하도록 하게 합니다.


위 그림처럼 a,b,c,d,e,f,g,dp 핀과 com1,2핀으로 기본 구성되어 있습니다.


  • 애노드 : com1,2 중 하나에 Vcc가 공급되고 나머지 a,b,c,d,e,f,g,dp에 0V(gnd)상태가 되면 LED에 불이 들어옴
  • 캐소드 : com1,2 중 하나에 Gnd에 연결되면 나미저 a,b,c,d,e,f,g,dp에 5V(Vcc)상태가 되면 LED에 불이 들어옴

이 두 개념만 가지고 있으면 됩니다. LED은 +,-가 연결되어 불이 들어오기 때문에 7-Segment도 한쪽이 +면 반대쪽이 -가 되어야 불이 들어옵니다. 어떤 원리인지 아시겠지요.

참고로, 실험은 애노드 2-Digit 7-Segment Display 회로도로 구성했습니다. 실제로 4-Digit 7-Segment Display를 구매 하시면 캐소드 부품으로 실험 하실 꺼에요. 혹시, 자신이 쓰는 부품이 다를 수 있으니 부품에 대한 데이터시트를 꼭 확인하시고 실험하세요. 왜! 불이 안들어오지 하는 이유가 대부분 핀 연결을 반대로 하는 경우가 대부분입니다. 그리고, 왜! 숫자가 정상적으로 안나오지 하면 애노드와 캐소드는 a,b,c,d,e,f,g,dp 핀 값이 반대 값을 갖기 때문에 반대 LED에 불이 들어오는 경우입니다. 꼭! 제대로 확인하시고 실험하시기 바랍니다.

2. 2-Digit 7-Segment Display 원리(애노드형)


2-Digit 7-Segment Display or 4-Digit 7-Segment Display 의 원리는 동일합니다. 같은 a,b,c,d,e,f,g,dp핀을 공유하고 Vcc핀은 각각의 7-Segment의 전원을 공급하는 별도 핀으로 나눠주면 2개든 4개든 상관없이 동시에 제어가 가능합니다.


위 그림처럼 각각 D1의 7-Segment와 D2의 7-Segment에 HIGH 되면 a,b,c,d,e,f,g,dp핀이 LOW가 되면 LED에 불이 들어오는데 D1, D2가 동시에 HIGH되면 2개의 7-Segment에는 동일한 문자가 출력됩니다. 2개의 7-Segment에 서로 다른 문자가 출력되게 할려면 각 D1, D2의 전원 공급의 시간차를 두고 a,b,c,d,e,f,g,dp핀을 제어하면 됩니다. 즉, 전류 공급에 의한 일시적 잔상효과를 이용한 방법이지요.

두개의 7-Segment에 시간차 전원 공급으로 문자를 출력하게 함으로서 서로 다른 문자를 출력할 수 있게 됩니다. 여기서, 주의할 점은 시간차의 값이 크면 동시에 출력되는 효과를 볼 수 없으며 시간차를 최소화 하여 잔상효과로 동시에 2개의 7-Segment에 문자가 출력되는 듯한 착시효과가 나타나게 시간차를 잘 조절하셔야 합니다.

//D1 출력
digitalWrite(D1, HIGH); 
for(int i=0;i<7;i++){
   digitalWrite(segPin[i], D1문자LED값);        
}
digitalWrite(segPin[7], dp);
delayMicroseconds(1000);
digitalWrite(D1, LOW); 

//D2 출력
digitalWrite(D2, HIGH); 
for(int i=0;i<7;i++){
   digitalWrite(segPin[i], D2문자LED값);        
}
digitalWrite(segPin[7], dp);
delayMicroseconds(1000);
digitalWrite(D2, LOW); 

이렇게 delayMicroseconds(1000)의 시간만큼 D1, D2 LED에 전원을 공급하게 됩니다. 이 명령문이 교대로 loop()함수로 반복하면 D1과 D2가 동시에 문자를 출력하는 효과가 발생합니다. (1초는 100만 마이크로 초)

참고로, 짧은 시간차를 이용하기 위해서 delay()함수 대신 delayMicroseconds()함수를 사용했네요.

같은 a,b,c,d,e,f,g,dp핀을 공유하면서 D1, D2의 전원 공급의 시간차로 서로 다른 문자를 출력할 수 있게 됩니다. 만약에 4-Digit 7-Segment Display 이면 D1, D2, D3, D4로 각각 시간차를 두고 전원을 공급한다면 4개의 문자가 동시에 출력되는 듯한 착시효과로 동시에 4개의 서로다른 문자를 출력하는 것 같은 결과를 얻게 됩니다.

3. 2-Digit 7-Segment Display 회로도


  • 준비물 : 7-Segment 2개, 330옴 2개, 아두이노우노
  • 내용 : 애노드형 방식으로 핀은 연결하는데 a,b,c,d,e,f,g,dp은 원하는 디지털핀에 연결하시오.


혹시, 위 그림이 복잡해 보이시면 사전학습 Post [아두이노] 7 Segment LED 제어 의 글을 보시면 애노드형으로 한개짜리 7-Segment로 구성된 회로도가 있을 꺼에요. 그걸 보시고 한개 더 중복해서 연결하시면 됩니다.

4. 숫자 카운트 코딩(0~99)


위의 2-Digit 7-Segment Display 원리의 코딩을 기반으로 숫자를 카운트 해 볼까요.

1) LED 숫자 패턴 만들기


//a,b,c,d,e,f,g
byte segValue[10][7] = { //애노드형
   {0,0,0,0,0,0,1}, //0
   {1,0,0,1,1,1,1}, //1
   {0,0,1,0,0,1,0}, //2
   {0,0,0,0,1,1,0}, //3
   {1,0,0,1,1,0,0}, //4
   {0,1,0,0,1,0,0}, //5
   {0,1,0,0,0,0,0}, //6
   {0,0,0,1,1,1,1}, //7
   {0,0,0,0,0,0,0}, //8
   {0,0,0,0,1,0,0}  //9  
};

D1의 숫자를 만든다면 D1이 Vcc면 a,b,c,d,e,f,g의 핀이 0일때 불이 들어옵니다

0의 숫자를 만들려면 LED에 불은 g핀을 제외한 나머지가 다 0이 되어야 합니다.

0 => 0,0,0,0,0,0,1

나머지 숫자도 이런식으로 만들면 됩니다, 참고로 저장변수공간을 줄일려면 아예 7개의 값을 byte형으로 만드셔도 됩니다.

0 => 0,0,0,0,0,0,1 =>OB00000010

이렇게 해서 10개의 byte 배열변수로 만들면 저장공간을 대폭 줄일 수 있습니다. 이해를 돕기 위해서 그냥 개별적으로 저장공간에 하나의 상태값만 저장되게 코딩하겠습니다. 'OB00000010'으로 표현하면 bitRead()함수로 각각 해당 위치의 값을 읽어와서 해당 LED에 불이 들어오게 제어하는 코딩을 하면 되는데 이 부분은 여러분들에게 숙제로 남겨두겠습니다.

2) millis()함수로 시간값 쪼개기


시간 함수에 대해서 지난 시간에 꽤 오래 동안 몇일에 걸쳐 이야기를 했기 때문에 생략하고 간단히 코딩으로 소개하는 수준으로 넘어가겠습니다.

readTime = millis()/1000; //초단위로 만듬
d1 = readTime%10; //1의 자리
d2 = (readTime/10)%10; //10의 자리

millis()함수로 읽은 타이머 시간값을 1000으로 나눠서 초단위로 시간값으로 readTime변수에 저장합니다. 이 초 값을 지난시간에 배웠던 방식으로 1의 자리와 10의 자리로 분리해 내서 d1, d2의 해당 숫자를 저장합니다.

3) 숫자 출력


위 2-Digit 7-Segment Display 원리에서 Segment의 숫자를 출력하기 위해서 코딩부분을 따로 외부 사용자정의 함수로 빼서 아래와 같이 segOutput()함수로 만들었습니다. d은 digit 위치이고, Number은 출력되는 숫자, dp은 Segment의 왼쪽 사이드에 있는 dot LED의 상태값입니다.

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

코딩에 보시면 segClear()함수가 있는데 이것 역시 사용자 정의 함수로 제가 만든 함수입니다. 함수단어명을 유심히 보면 Segment를 뭔가 Clear한다는 의미를 담고 있는 걸 보실 수 있을거에요. 즉, LED를 초기화 상태로 되돌리는 함수를 하나 더 만들었습니다.

그 이유는, 연속으로 각 Segment에 숫자를 출력하면 한쪽 Segment의 값이 유지된 상태에서 다른 Segment에 LED에 불이 들어오게 할때 기존에 남아 있는 a,b,c,d,e,f,g,dp핀의 상태값이 유지된 상태에서 전류가 일시적으로 공급되어 양쪽 Segment에 일부 핀에 전류가 동시 공급되는 현상이 발생합니다. 그래서 잔상으로 두 Segment의 일부 LED에 불이 겹쳐서 나오게 됩니다. 그렇기 때문에 각 Segment에 불이 들어오게 하기전에 초기화 작업을 해줘야 겹치는 LED의 문제를 해결 할 수 있습니다.

void segClear(){
  for(int i=0;i<8;i++){
    digitalWrite(segPin[i], HIGH);        
  }
}

이렇게 간단하게 a,b,c,d,e,f,g,dp핀 HIGH 상태로 초기화 하시면 됩니다.

4) 전체소스

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

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

unsigned long readTime=0; //현재시간
int d1 = 0; //1의 자리
int d2 = 0; //10의 자리

void setup() {
  for(int i=0;i<10;i++){
    pinMode(segPin[i], OUTPUT);
  }
  pinMode(digitPin[0], OUTPUT);
  pinMode(digitPin[1], OUTPUT);    
  digitalWrite(digitPin[0], LOW); 
  digitalWrite(digitPin[1], LOW);      
}

void loop() {  
  //시간 갱신
  readTime = millis()/1000;
  d1 = readTime%10; //1의 자리
  d2 = (readTime/10)%10; //10의 자리
  
  segOutput(1,d1,1); //1의 자리
  if(readTime>=10) segOutput(0,d2,1); //10의 자리  
}
//LED 초기화
void segClear(){ 
  for(int i=0;i<8;i++){
    digitalWrite(segPin[i], HIGH);        
  }
}
//LED 출력
void segOutput(int d, int Number, int dp){ 
  segClear();
  digitalWrite(digitPin[d], HIGH); 
  for(int i=0;i<7;i++){
     digitalWrite(segPin[i], segValue[Number][i]);        
  }
  digitalWrite(segPin[7], dp);
  delayMicroseconds(1000);
  digitalWrite(digitPin[d], LOW); 
}

5. 결과



마무리


2-Digit 7-Segment Display를 만들어 보았습니다. 방식은 애노드형으로 회로도를 구성해 보았는데 지끔까지 아두이오 post에서 한번이상은 거론했던 내용들이라서 이전 post를 보셨던 분들은 복습의 시간이 되었을 듯 싶네요.

오늘의 핵심은,

digitalWrite(digitPin[d], HIGH); 
  for(int i=0;i<7;i++){
     digitalWrite(segPin[i], segValue[Number][i]);        
  }
  digitalWrite(segPin[7], dp);
  delayMicroseconds(1000);
digitalWrite(digitPin[d], LOW); 

위 코딩은 2-Digit 7-Segment Display에 숫자를 출력하기 위한 핵심 코딩입니다. 이부분만 이해하신다면 어떤 숫자나 문자든 쉽게 2-Digit 7-Segment Display에 출력할 수 있게 됩니다.

다시 보시면,

digitalWrite(digitPin[d], HIGH); 
숫자 LED 출력;
delayMicroseconds(1000);
digitalWrite(digitPin[d], LOW); 

이 로직으로 애노드형이기 때문에 digitPin[d]은 특정 위치의 7-Segment이고 전원을 공급 HIGH로 시작합니다. 전원이 공급될 때 출력 LED의 상태 LOW가 결정되고 그 상태를 delayMicroseconds(1000)의 딜레이시간동안 유지합니다. 즉, 해당 숫자가 딜레이시간만큼 전원이 공급된다는 의미이지요. 그리고 나서 digitPin[d] 전원공급 해체 LOW로 하나의 숫자를 7-Segment에 출력시키는 최소 시간의 로직이 됩니다.

이걸 기반으로 여러개의 7-Segment에 숫자들을 출력하여 동시에 출력되는 듯한 착시효과를 부여하게 됩니다. 몇줄 안되는 이 로직을 꼭 기억해 주세요. 이걸 이해하시게 되면 나중에 스톱워치, 시계, 온도계 등 과 같은 여러 숫자값을 출력하는 장치로 활용할 수 있습니다. 지난 시간에 시간에 관한 여러가지 원리를 배웠는데 그 결과를 7-Segment에 출력할 수 있습니다.

한번 오늘 배운 회로도를 가지고 지난 시간에 배웠던 것들을 한번 적용해 보셨으면 합니다. 저도 몇가지 가상과 실제로 실험하여 post를 할 예정입니다. 어떤 값을 출력할지는 아직 결정되지 않았고 아마도 시간 관련해서 출력하는 장치로 실험을 할 것 같습니다. 여러분들도 한번 오늘 배운 내용을 토대로 어떤 부품의 출력장치로 사용할지 상상의 나래를 펼쳐 보세요.


댓글()

[아두이노] 7 Segment Decoder(CD4511) 제어

IOT/아두이노|2019. 2. 16. 14:57

[아두이노] 7 Segment Decoder(CD4511) 제어



이번에도 새로운 칩을 소개 합니다. 7-segment Decoder(CD4511)은 7 Segment LED를 제어하는데 효율적인 칩입니다. 다른곳에서 원리만 이해하셨다면 사용 가능합니다. 이 칩은 4가지 값에 의해서 7개의 출력값을 만들어 낼 수 있습니다. 이 칩도 제 블로그에서 소개했던 내용인데 7 Segment LED를 포스팅 할때 한번에 소개하는게 나을 것 같아서 가상시뮬레이터에서도 제공되는 칩으로 이번에는 CD4511 칩을 이용해 실험하고자 합니다.

1. 7 segment Decoder(CD4511)



위 그림에서 보는것 처럼 입력 A,B,C,D 핀으로 아두이노에서 4개의 핀의 출력값을 CD4511 칩에 입력으로 받게 됩니다. CD4511 칩의 연결은 다음 과 같습니다.

  • Vcc핀 과 Gnd핀은 아두이노에 5V와 Gnd 핀에 연결
  • LT핀와 BI핀은 Vcc로 연결
  • LE핀은 Gnd로 연결
  • 입력 A,B,C,D핀은 아두이노 디지털핀 4개 연결(실험에서는 2,3,4,5핀 사용)
  • 출력 a,b,c,d,e,f,g핀은 7 Segment LED의 DP핀을 제외한 나머지 순차적으로 A,B,C,D,E,F,G핀에 연결

여기서 회로도 설계할때에 선 연결이 노가다 작업으로 좀 힘들지만 그래도 한번 이해하면 나중에 쉽게 사용이 가능해 집니다. CD4511 칩에 선들을 어떻게 연결하는지가 숙지하시면 됩니다.

2. 회로도 구성


  • 준비물 : CD4511 칩 1개, 7 Segment LED 1개(캐소드형임), 저항 330옴 1개, 저항 10k옴 4개, 아두이노우노, 뻥판
  • 내용 : CD4511 칩을 이용해서 7 Segment LED에 숫자를 출력하게 하자. 참고로 7 Segment LED(캐소드형)


CD4511 칩에 입력을 바로 아두이노의 출력값 5V를 보내지 않고 10K옴의 저항을 붙여줍니다. 스위치 버턴을 연상하시면 됩니다. 어짜피 상태값만 보내주면 되기 때문인거죠. 정확히 CD4511 칩의 허용 전압이 기억이 안나서 안전하게 저항을 붙였습니다. 데이터시트를 인터넷에서 찾아보셔서 허용 전압을 참고하시면 되겠습니다. 위에서 설명한 CD4511 칩의 핀들이 어디에 연결하는지 설명한대로 실제 선을 연결하시면 됩니다. 그리고 주의할 것은 7 Segment LED은 캐소드형 입니다.

처음에만 복잡해 보일뿐 익숙해지면 단순합니다. 핀에 마우스를 대면 핀 이름이 나오고 해당된 부품과 연결하시면 됩니다.

3. 코딩


  • 사용함수 : pinMode(출력핀, 모드), digitalWrite(출력핀, 상태값)
  • 내용 : 아두이노에서 4개의 출력 상태를 값을 CD4511 칩을 제어하여 7 Segment LED에 숫자를 0~9까지 순차적으로 출력해보자.(7 Segment LED은 캐소드형으로 이 기준으로 코딩함)

  • CD4511 제어 :
    • digitalWrite(출력핀, 상태값)으로 CD4511 칩의 출력값을 결정

참쉽죠. LED 제어할대 배운 PinMode()와 digitalWrite()함수만 사용하시면 됩니다.

설계

(1) 숫자 패턴만들기

CD4511 4개의 입력값을 받습니다. 그러면 4개의 상태를 8421 BCD 코드표를 참조하시면 좋습니다. 캐소드형 7 Segment LED를 하면 정확히 아두이노 핀의 역순으로 코딩하면 일치하게 됩니다. 그래서 이번 실험은 이해하기 쉽게 캐소드형 코딩을 선택했습니다.

0000 => 0
0001 => 1
0010 => 2
...

0은 0000 => 출력값은 1111110 됩니다.
0은 A[4] = {0,0,0,0}
그러면 0~9까지 10개의 패턴이니깐 2차배열변수로 만들면은 아래와 같이 만들어 지겠죠.

int data[10][4]={
   {0,0,0,0}, //0
   {0,0,0,1}, //1
   {0,0,1,0}, //2
   {0,0,1,1}, //3
   {0,1,0,0}, //4
   {0,1,0,1}, //5
   {0,1,1,0}, //6
   {0,1,1,1}, //7
   {1,0,0,0}, //8
   {1,0,0,1}  //9
};

(2) 숫자 출력

0은 A[4] = {0,0,0,0} 이고,
datapin은 datatpin[4] = { 5,4,3,2} 하면

 for(int j=0;j<4;j++){
    digitalWrite(datapin[j],A[j]);
 }

이렇게 됩니다. 하지만 10개의 패턴과 각 패턴의 상태값 4개를 2차 배열 위의 date[10][4]로 만들면 2차 for문을 사용하면

  for(int i=0;i<10;i++){
     for(int j=0;j<4;j++){
       digitalWrite(datapin[j],data[i][j]);
     }
     delay(1000);
  }     

여기서 delay(1000)을 두어 1초 단위로 0~9까지 7 Segment LED에 출력되게 됩니다.

코딩을 하면

int data[10][4]={
   {0,0,0,0}, //0
   {0,0,0,1}, //1
   {0,0,1,0}, //2
   {0,0,1,1}, //3
   {0,1,0,0}, //4
   {0,1,0,1}, //5
   {0,1,1,0}, //6
   {0,1,1,1}, //7
   {1,0,0,0}, //8
   {1,0,0,1}  //9
};
int datapin[4] ={5,4,3,2};

void setup(){
  for(int i=0;i<4;i++){
    pinMode(datapin[i],OUTPUT);
  }
}
void loop(){
   for(int i=0;i<10;i++){
     for(int j=0;j<4;j++){
       digitalWrite(datapin[j],data[i][j]);
     }
     delay(1000);
  } 
} 

4. 결과


결과 동영상을 보면 다이렉트로 전 과정을 동영상 촬영을 했는데 회로도를 만드는 과정에서 Vcc 선을 Gnd로 잘못 연결해서 가상시뮬레이터 처음 실행에서 CD4511 칩이 망가졌습니다. 가상시뮬레이터라서 실제로 CD4511 칩이 망가지는 것이 아니기 때문에 그렇게 큰 의미는 없지만 이걸 실제로 선을 잘못 연결한다면 칩에 문제가 생기겠지요. 다시 동영상으로 촬영할려다가 선 연결의 중요성과 이런 점에서 가상시뮬레이터를 사용의 장점이 될 것 같아서 그냥 올립니다.(실제로 다시 촬영하기 귀찮음!)

마무리


74HC595 칩은 3핀을 사용했지만 CD4511 칩은 4핀을 사용합니다. 그러면 이전 시간에 배운 74HC595 칩으로 하는게 좋을 것 같다는 생각을 하실 수 있습니다. CD4511 칩을 제어는 무지 간단 합니다. 아두이노 없이도 이 칩을 이용해서 7 Segment LED를 제어가 가능합니다.

그리고 74HC595+CD4511으로 7 Segment LED를 제어를 한번 해보세요. 이 두 칩을 배우고 나서 이걸 합쳐서 실험해보고 싶어져서 7 Segment LED를 제어 해보았어요. 이 내용은 다음 포스팅에 쓰도록 할께요. 한번 두 칩에 동작 원리를 생각하고 회로도를 구성하고 코딩해보세요.

한번 74HC595칩과 CD4511을 결합을 하면 어떻게 회로도가 표현 되는지 상상의 나래를 펼쳐보세요.


댓글()

[아두이노] 74HC595+ 7 Segment LED 실제 실험

IOT/아두이노|2019. 2. 15. 09:26

[아두이노] 74HC595+ 7 Segment LED 실제 실험



가상시뮬레이터에서 아두이노우노를 다루면서 실제 현실에서도 동일하게 작동을 하는지 궁금하신 분들이 있을꺼에요. 그래서 귀찮니즘을 안고 실제로 실험을 하였습니다. 예전에 74HC595 칩을 뻥판에 꼽을 개고생 했는데 뻥판이 싼거라 핀이 잘 안들어가서 핀 부분이 약간 오그라졌는데 이번에도 역시나 꼽을 때 오그라지고 뽑을 때 오그라져서 나오더군요. 몇번 실험하고 나면 74HC595 칩이 망가질것 같네요.

1. 회로도 구성



[아두이노] 쉬프트레지스터(74HC595) 제어 편에서 실제로 7 Segment LED도 뻥판에 배치를 해야하기 때문에 약간 배치하는 위치를 수정했네요.


좀 더 깔끔해진 회로도 모습이지요.

지난시간에 가상시뮬레이터로 설계한 모습에서 다시 가상시뮬레이터의 뻥판에 재배치한 모습입니다. 그런데 실제로 같은 위치에 배치하면 이런 모습이 아니라 지져분한 모습입니다. 가상시뮬레이터에서 회로도를 배치한대로 실제로 동일하게 배치했습니다. 참고로 저항은 220옴뿐이 없어서 이걸로 했습니다. 저항은 LED에 필요한 허용치 저항을 연결하면 되니깐 제 경우는 저항 220옴으로 실험했네요.


위 사진은 뻥판 연결된 모습인데 실험 중의 한 컷인데요. 선만 봐도 엄청 지져분하죠. 74HC595 칩을 뻥판에 꼽을 때 개고생 했네요. 핀 위치는 대충 가상시뮬레이터에서 연습 몇번해서 그런지 선 연결은 지져분할 뿐 간단했네요. 가상시뮬레이터에 연습없이 바로 실제로 실험한다면 선 연결할 때 실수하는 경우가 많겠죠.

2. 코딩


코딩은 지난시간에 숫자를 순차적으로 출력하는 로직을 그대로 집어 넣었습니다.

byte data[]={
0B10000001,  
0B11110010,
0B01001001,
0B01100000,
0B00110011,
0B00100100,
0B00000101,
0B11110000,
0B00000001,
0B00100000
};
int latchPin = 11; //ST_CP Pin
int clockPin = 12; //SH_CP Pin
int dataPin = 9; //DS Pin

void setup(){
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
void loop(){
 for(int i=0;i<10;i++){
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, data[i]);
    digitalWrite(latchPin, HIGH);       
    delay(1000);
  }  
}

3. RaspberryPi3 에서 아두이노우노로 프로그램 이식


PC에서 RaspberryPi3를 원격 제어를 통해 아두이노 IDE를 띄워고 위 코딩을 복사한 뒤에 실제 아두이노우노에 프로그램 이식을 수행했습니다.
PC에 아두이노 IDE를 설치했다면 바로 PC에서 아두이노우노에 프로그램을 이식하면 됩니다.


4. 결과


아래 13초짜리 동영상은 실제 프로그램이 이식된 아두이노우노가 74HC595 칩에 숫자 패턴 데이터값을 전송하여 7 Segment LED에 숫자가 가상시뮬레이터에서 나왔던 결과와 동일하게 출력되는지 테스트한 결과입니다.


마무리


실제 아두이노우노로 실험을 해 보았습니다. 가상시뮬레터의 결과와 동일하게 나오는 것을 보실 수 있었을 겁니다. 이처럼 실제로 키트를 사서 실험을 하실 수 있지만 실제로 실험하면 가상으로 한것보다 시간도 많이 걸리고 손으로 일일히 노가다 작업을 많이 해야 합니다. 편하게 마우스로 선을 연결할 수 있는 것을 실제로 뻥판에 억지로 꼽고 하는게 쉽지가 않죠. 그리고 부품이 작어서 아무 지식도 없는 상태에서 보고 따라서 꼽을려고 하면 그것도 만만치 않습니다.

특히, 74HC595 칩의 경우는 작고 핀들의 네임들을 외우지 않는 이상 햇갈릴 수 있습니다. 하지만 가상에서는 마우스을 대면 핀 네임들을 쉽게 확인이 가능합니다. 가상시뮬레이터로 여러번 반복 실험을 하다보면은 실제 실험에서도 어렵지 않게 핀 연결을 할 수 있게 됩니다.

제가 아두이노우노를 실험할 때 실제 아두이노우노 키트가 있지만 가상시뮬레이터에서 하는 이유는 실제 아두이노키트를 사용해서 실험하는 것보다 가상시뮬레이터에서 더 쉽게 실험할 수 있기 때문입니다.

막연히 아두이노우노 키트를 사서 하는것보다 가상시뮬레이터로 충분히 즐긴 후 좀 더 다양한 실험을 하고 싶을때
아두이노 시리즈 중 원하는 싱글보드를 구매하셔서 실험하시면 됩니다.


댓글()

[아두이노] 7 Segment LED 제어

IOT/아두이노|2019. 2. 12. 13:23

[아두이노] 7 Segment LED 제어



오늘은 LED 제어의 연장선상으로 7 Segment LED를 제어해 보도록 하겠습니다. 사용될 함수는 LED 제어때 사용한 pinMode( ), digitalWrite( )만 이해하시면 쉽게 제어를 할 수 있습니다.

1. 7 Segment LED


A,B,C,D,E,F,G,DP 핀으로 총 8개의 핀으로 구성되어 있습니다. 각 핀은 위 그림에서 보는것 같지 해당 위치의 LED에 불을 제어하는 핀으로 생각하시면 됩니다. 실제로 구매하시면 애노드형과 캐소드형이 있는데 위아래핀이 애노드 7 Segment LED이고 좌우고 캐소드였나 암튼 가상시뮬레이터에서 사용하는게 애노드형 초기 기본으로 되어 있는데 속성창에서 캐소드형으로 바꿔서 실험할 수 있습니다.

애소드와 캐소드 차이

7 Segment LED핀들이 가상시뮬레이터에서는 핀에서 COM1, COM2 핀이 있는데 아무핀이나 하나에 5V(+)핀이면 애노드형이고 Gnd(-)핀이면 캐소드형이 됩니다.

  1. 애노드 : A~G,DP핀이 0V이고 COM1 or COM2가 5V이면 해당 핀 LED에 불이 들어옵니다.
  2. 캐소드 : A~G,DP핀이 5V이고 COM1 or COM2가 Gnd이면 해당 핀 LED에 불이 들어옵니다.

쉽게 말해서 서로 반대라고 생각하시면 됩니다. 애노드형은 출력핀이 0일때 LED에 불이 들어오고 캐소드형은 출력핀이 1일때 LED에 불이 들어온다는 것만 이해하시면 됩니다. 참고로 7 Segment LED를 구매하실때 제품이 애노드형인지 캐소드형인지 확실히 확인하시고 구매하세요. 그래야 햇갈리는 핀연결과 코딩을 하지 않습니다.

2. 회로도 구성


  • 준비물 : 7 Segment LED 1개, 저항 330옴 1개, 아두이노우노
  • 내용 : 알파벳과 숫자를 출력해보자.

애노드형모델캐소드형모델



대충 붉은선이 5V에 연결되어 있고 검은선이 Gnd에 연결된 모습을 보면 대충 알겠죠.

##3. 코딩

  • 사용함수 : pinMode( ), digitalWrite( )
  • 내용 : 애노드형모델 기반으로 알파벳과 숫자를 순차적으로 출력하는 코딩을 해보자.

  • 7 Segment LED의 각 led 제어 :
    pinMode(핀, 모드)으로 전류를 출력할 핀들을 출력모드(OUTPUT) 사용하겠다고 선언
    digitalWrite(핀, 상태)은 HIGH(5V) or LOW(0V)로 전류를 출력할지 말지를 결정(여기서, 1은 5V, 0은 0V)

7 Segment LED도 내부에 LED들을 제어하기 때문에 LED 제어할때랑 동일합니다. 애노드형이기 때문에 0일때 불이 들어고 1일때 불이 꺼진다는 것만 생각하시고 코딩에 들어가세요. LED 제어의 복습차원이라고 생각하시면 됩니다. 참고로 알파벳과 숫자를 만드는 수작업인 노가다가 필요합니다.

설계

(1) 알파벳(A,B,C,D,E,F)과 숫자(0,1,2,3,4,5,6,7,8,9) 만들기



A글자 만들려면 LED D핀이 꺼지고 나머지 핀들이 켜져야 겠죠.(켜기=0, 꺼지기=1)

00010000

배열로 A[8]={0,0,0,1,0,0,0,0} 이 된다. 이건 하나의 A글자의 패턴입니다. 그러면 각 글자와 숫자의 패턴을 배열변수로 만들어야겠죠. 참고로, 앞에 7개는 글자나 숫자를 만드는 핀이고 마지막 8번째는 DP핀으로 점 LED 입니다. 0을 설정한 이유는 그냥 점 LED를 켜지는 것을 테스트 목적인것이지 의미는 없다는 점 참고하세요. 점 LED 빼고 싶다면 00010001 이러면 되겠죠.
아래 2차배열로 표현할때 점 LED은 글자가 출력할때 그냥 같이 켜지게 했고 숫자가 출력할때에 그냥 꺼지게 했어요. 원래 여러개 연결한다면 소숫점으로 사용하면 좋겠는데 한개 7 Segment LED라서 그냥 테스트로 켜지는지 보기위한 실험으로 의미는 없습니다.

int segValue[16][8] = {
   {0,0,0,1,0,0,0,0}, //A
   {1,1,0,0,0,0,0,0}, //B
   {1,1,1,0,0,1,0,0}, //C
   {1,0,0,0,0,1,0,0}, //D
   {0,1,1,0,0,0,0,0}, //E
   {0,1,1,1,0,0,0,0}, //F
   {0,0,0,0,0,0,1,1}, //0
   {1,0,0,1,1,1,1,1}, //1
   {0,0,1,0,0,1,0,1}, //2
   {0,0,0,0,1,1,0,1}, //3
   {1,0,0,1,1,0,0,1}, //4
   {0,1,0,0,1,0,0,1}, //5
   {0,1,0,0,0,0,0,1}, //6
   {0,0,0,1,1,1,1,1}, //7
   {0,0,0,0,0,0,0,1}, //8
   {0,0,0,0,1,0,0,1}  //9  
};

(2) 알파벳과 숫자를 만들었다면 실제 출력해야겠죠.

  • 핀배열 변수 선언 :
int segPin[8]={2,3,4,5,6,7,8,9}; 
  • 출력핀모드 선언 :
for(int i=0;i<9;i++){
    pinMode(segPin[i], OUTPUT);
  }
  • 출력 : 이부분이 실제 코딩 로직의 전부입니다. 각 패턴를 for문으로 루프 도는게 전부임
for(int i=0;i<16;i++){ //16패턴
  for(int j=0;j<8;j++){ //패턴값
   digitalWrite(segPin[j], segValue[i][j]);        
}
  delay(1000);
}  

애노드형모델 코딩을 실제 하면은

int segValue[16][8] = {
   {0,0,0,1,0,0,0,0}, //A
   {1,1,0,0,0,0,0,0}, //B
   {1,1,1,0,0,1,0,0}, //C
   {1,0,0,0,0,1,0,0}, //D
   {0,1,1,0,0,0,0,0}, //E
   {0,1,1,1,0,0,0,0}, //F
   {0,0,0,0,0,0,1,1}, //0
   {1,0,0,1,1,1,1,1}, //1
   {0,0,1,0,0,1,0,1}, //2
   {0,0,0,0,1,1,0,1}, //3
   {1,0,0,1,1,0,0,1}, //4
   {0,1,0,0,1,0,0,1}, //5
   {0,1,0,0,0,0,0,1}, //6
   {0,0,0,1,1,1,1,1}, //7
   {0,0,0,0,0,0,0,1}, //8
   {0,0,0,0,1,0,0,1}  //9  
};
int segPin[8]={2,3,4,5,6,7,8,9}; //사용핀{a,b,c,d,e,f,g,dp} 순서대로임

void setup() {

  for(int i=0;i<9;i++){
    pinMode(segPin[i], OUTPUT);
  }
}
void loop() {
  for(int i=0;i<16;i++){
    for(int j=0;j<8;j++){
     digitalWrite(segPin[j], segValue[i][j]);        
  }
    delay(1000);
  }  
}

for문에 대해서 저번에 설명을 했으며 for문을 이해해야만 왜 이렇게 코딩이 되었는지 이해가 되실꺼에요.
혹시 이해가 안되시는 분들은 LED 제어(아두이노)를 다시 한번 보시고 간단히 소개된 for문을 보시고 대충 어떤 느낌인지 살펴보세요.

여기서 캐소드형 경우는

패턴배열변수값들을 반대로 하시면 됩니다.

int segValue[16][8] = {
   {1,1,1,0,1,1,1,1}, //A
   {0,0,1,1,1,1,1,1}, //B
   {0,0,0,1,1,0,1,1}, //C
   {0,1,1,1,1,0,1,1}, //D
   {1,0,0,1,1,1,1,1}, //E
   {1,0,0,0,1,1,1,1}, //F
   {1,1,1,1,1,1,0,0}, //0
   {0,1,1,0,0,0,0,0}, //1
   {1,1,0,1,1,0,1,0}, //2
   {1,1,1,1,0,0,1,0}, //3
   {0,1,1,0,0,1,1,0}, //4
   {1,0,1,1,0,1,1,0}, //5
   {1,0,1,1,1,1,1,0}, //6
   {1,1,1,0,0,0,0,0}, //7
   {1,1,1,1,1,1,1,0}, //8
   {1,1,1,1,0,1,1,0}  //9  
};

코딩에서는 for문을 사용해서 led 출력핀들의 모드와 출력상태를 표현하는 것과 2차배열로 7 Segment LED패턴을 표현하는 것 두개뿐이 없습니다. 패턴을 2차배열로 표현하는 노가다 작업만 있을 뿐이죠.

4. 결과



애노드형 모델을 실험 동영상입니다.



마무리


LED 제어의 연장선상의 7 Segment LED제어를 해 보았습니다. 한개짜리지만 실제 4개짜리로 묶여진 부품도 있어서 좀 더 다양한 표현을 할 수 있습니다. 글자나 숫자를 출력할 수 있으면 이걸로 많은걸 표현이 가능합니다.

실생활에서 보면 시계를 떠오르시는분들이 많겠죠. 또는 거리에 나가면 가장 가깝게 신호등에 숫자가 출력되는걸 보실 수 있을꺼에요. 그러면 아두이노로 신호등을 만들고 7 Segment LED로 신호등의 타이머로 현실과 비슷하게 표현을 가능하겠죠. 이걸 대충요 종이로 신호등을 만들어서 제어하면 아이들에게 재밌는 교통 교육용이 될 수 있겠죠.

오늘 배운 패턴 배열변수는 무척 중요합니다. 꽤 많이 사용하는 2차배열변수인데요. 다음에 LED CUBE나 8x8 도트매트릭스를 소개할지 모르겠지만 계속해서 사용합니다. 배열변수를 혹시 모르시겠다면 관련글들을 검색해서 꼭 공부해주세요.


댓글()