Arduino 4-Digit FND CountArduino 4-Digit FND Count

Arduino Uno 4-Digit 7-Segment Timer Counter

지난 포스트에서 1자리 7세그먼트 사용법에 대해 소개하였습니다. 이번 포스트에서는

4자리 FND를 소개하고, 0.01초 간격으로 시간을 카운트

하는 예제를 소개합니다.

1자리 FND의 동작 예제는 하단의 관련포스트를 참조해주세요.


4Digit 7Segment

본 예제에서 사용하는 4자리 7세그먼트는 공통 캐소드 타입으로, 내부의 회로는 아래 그림과 같이 구성되어있습니다. 총 12개의 핀으로 구성되며 4개의 자리 수 선택 핀(Digit 1 ~ 4) 와 8개의 세그먼트 핀(A~G, DP)으로 구성됩니다. 

4자리 7세그먼트 공통 캐소드 타입4자리 7세그먼트 공통 캐소드 타입

4자리 FND는 아래 그림과 같이 Digit1~4 를 빠른 속도로 순차적으로 켜서 4자리 모두 불이 들어와 있는 것처럼 보이도록 코드가 작성되어야 합니다. 

4-DIgit FND 동작 방법4-DIgit FND 동작 방법

Hardware

준비물

본 예제의 구성품은 아래와 같습니다.

  • Arduino Uno x 1EA
  • 4-Digit 7-Segment x 1EA (본 예제에서는 HS410561K-32)
  • DIP Type Resistor x 12EA (2.2kΩ)
  • Bread Board x 1EA
  • Jumper WIres


회로도 및 연결

아두이노 4자리 FND 연결아두이노 4자리 FND 연결

예제에 사용된 회로는 4자리 FND를 테스트하기 위한 회로로 세그먼트마다 2.2kΩ 의 저항을 직렬로 연결 하였습니다. 회로도의 핀맵은 실제 구성에 편리한대로 수정이 가능합니다. 본 회로도와 연결이 다를 경우 아래 코드의 헤더 부분에서 수정하여 적용이 가능합니다.

코드 : 0.00s ~ 99.99s 카운트

타이머 인터럽트로 10ms 마다 인터럽트 서비스 루틴 호출하여 카운트한 값을 4-Digit 7-Segment 에 출력 하는 코드 입니다.

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <MsTimer2.h>
 
#define segA 12  // 'a' 세그먼트 연결 핀 번호
#define segB 2  // 'b' 세그먼트 연결 핀 번호
#define segC 7  // 'c' 세그먼트 연결 핀 번호
#define segD 9  // 'd' 세그먼트 연결 핀 번호
#define segE 10  // 'e' 세그먼트 연결 핀 번호
#define segF 11  // 'f' 세그먼트 연결 핀 번호
#define segG 6  // 'g' 세그먼트 연결 핀 번호
#define segDP 8 // 'dp' 세그먼트 연결 핀 번호
#define digit1 13 // 1st digit 연결 핀번호
#define digit2 4 // 2nd digit 연결 핀번호
#define digit3 3 // 3rd digit 연결 핀번호
#define digit4 5 // 4th digit 연결 핀번호3r
 
// main 함수에서 처리 편하게 하기 위해 핀번호 배열을 생성
int fndDigit[4= {digit1, digit2, digit3, digit4};
int fndPort[8= {segA, segB, segC, segD, segE, segF, segG, segDP};
// index 0-9 -> 숫자 1~9
// index 10 -> Blank
int fndData[11][8= {
                    { 00000011 }, // 0
                    { 10011111 }, // 1
                    { 00100101 }, // 2
                    { 00001101 }, // 3
                    { 10011001 }, // 4
                    { 01001001 }, // 5
                    { 01000001 }, // 6
                    { 00011011 }, // 7
                    { 00000001 }, // 8
                    { 00001001 }, // 9
                    { 11111111 }, // 10 - blank
                };   
// 초기값 10 -> Blank
int iflag = 0;
 
void setup(){
    // 1000ms 간격으로 myTimer() 함수를 호출합니다.
    MsTimer2::set(10, myTimer);
    MsTimer2::start();
    // 7 Segment 연결된 포트 모두 출력으로 설정
    for(int i = 0 ; i < 4 ; i++)
    {
        pinMode(fndDigit[i], OUTPUT);
        digitalWrite(fndDigit[i], LOW);
    }
    for(int i = 0 ; i < 8 ; i++)
    {
        pinMode(fndPort[i],OUTPUT);
        digitalWrite(fndPort[i],HIGH);
    }
}
 
void loop(){
    static int iCount = 0;
 
    // 타이머 인터럽트가 발생 (iflag=1) 되면 iCount 를 1씩 증가, iCount 값이 10000일 경우 0으로 전환
    if (iflag == 1)
    {
        if (iCount == 10000) {
            iCount = 0;
        }
        else {
            iCount++;
        }
        iflag = 0;
    }
 
    // 4자리수에 각각 입력 될 숫자 입력
    int digit1st = iCount / 1000;
    int digit2nd = iCount % 1000 / 100;
    int digit3rd = iCount % 100 / 10;
    int digit4th = iCount % 10;
    // for 문을 돌리기 위해 배열을 사용
    int digitData[4= {digit1st, digit2nd, digit3rd, digit4th};
 
    for(int i = 0 ; i < 4 ; i++)
    {
        // 모든 Digit 1~4 핀 Off
        digitalWrite(digit1,LOW);
        digitalWrite(digit2,LOW);
        digitalWrite(digit3,LOW);
        digitalWrite(digit4,LOW);
 
        // 각 Digit 에 맞는 fnd 숫자의 값 입력
        for(int j= 0 ;j<8;j++)
        {
            digitalWrite(fndPort[j], fndData[digitData[i]][j]); 
            // 소수점 구분 점 찍기
            if(i==1digitalWrite(fndPort[7], 0);
        }
 
        // 해당 Digit On
        digitalWrite(fndDigit[i],HIGH);
        // 밝기 조절을 위해 2ms LED ON 시간 조절
        delay(2);
    }
}
 
// 10ms 간격 타이머 인터럽트
void myTimer(){
    iflag = 1;
}
cs

코드 설명

  • 3~14줄 : 회로도 연결이 다른 경우 선언부에서 수정이 가능합니다.
  • 17~18 줄 : FND 처리를 편하게 하기 위해 핀 번호를 배열로 처리합니다.
  • 21줄 : FND숫자 데이터 입니다. 인덱스와 표시되는 데이터가 일치되도록 배열을 구성하였습니다.
  • 37~52줄 void setup()
    • 39~40줄 : 10ms 간격으로 타이머 인터럽트를 호출 하도록 설정합니다.
    • 42~51줄 : FND에 사용되는 모든 핀은 출력포트로 설정하고, Digit 핀은 LOW, Seg 핀은 HIGH로 초기화합니다.
  • 54~98줄 void loop()
    • 58~67줄 if문 : 10ms 간격으로 iCount 변수를 1씩 증가하고, iCount 가 10000이 되면 0으로 초기화 합니다.
    • 70~73줄 : 4Digit 의 자리수에 출력할 데이터를 결정합니다. 
      • Digit.1 : 10ms 단위
      • Digit.2 : 100ms 단위
      • Digit.3 : 1s 단위
      • Digit.4 : 10s 단위
    • 77~97줄 for문 : iCount의 데이터를 FND 에 실제 출력하는 코드입니다.
  • 101~103줄 : 10ms 간격으로 호출되는 인터럽트 서비스 루틴 함수입니다.

실행 결과

코드의 실행 결과는 아래 영상과 같습니다. 


마무리

본 포스트에서 아두이노에서 제공되는

타이머 인터럽트 라이브러리를 사용하여 FND에 타이머 카운트를 출력하는 예제

를 소개하였습니다. 문의 사항이 있으시면 댓글로 부탁드립니다.

끝까지 읽어 주셔서 감사합니다.^^

관련포스트

👉 아두이노 FND 관련글 목록 보기

👉 아두이노 디스플레이 장치 관련글 목록 보기

👉 아두이노 인터럽트 관련글 목록 보기

👉 아두이노 관련글 전체 목록 보기


댓글
  • 태수키 2020.10.14 08:50 수정/삭제 댓글쓰기
    반대로 100에서 ~ 0으로 가는 카운트다운을 하려면 어떻게해야하나요?
  • 코드의 55번라인부터 ~ 67번까지 라인을 아래와 같이 수정하면 될 것 같습니다.

    iCount 의 초기 값을 10000으로 설정하고, 타이머 인터럽트가 발생할 때 마다 -1씩 감소하는 방식입니다. iCount가 0이 되면 10000으로 초기화 합니다.
    iCount가 10000일때 '0000'으로 표시 됩니다.

    static int iCount = 10000;

    // 타이머 인터럽트가 발생 (iflag=1) 되면 iCount 를 1씩 증가, iCount 값이 10000일 경우 0으로 전환
    if (iflag == 1)
    {
    if (iCount == 0) {
    iCount = 10000;
    }
    else {
    iCount--;
    }
    iflag = 0;
    }

    코드를 검증하고 댓글을 달지는 않아서 오류가 있을 수 있습니다. 위의 설명을 참고해주세요.
  • 태수키 2020.10.14 09:07 수정/삭제 댓글쓰기
    감사합니따! 라면타이머 미션주셔서 어제부터 골머리 앓고있었는데 해결했습니다ㅠㅠ
  • 네~ 해결되었다니 다행이네요ㅎ 좋은하루되세요ㅎ
  • 태수키 2020.10.14 09:11 수정/삭제 댓글쓰기
    넵 좋은하루되십셔
  • 태수키 2020.10.14 18:08 수정/삭제 댓글쓰기
    귀찮게 해서 죄송하지만 혹시 버튼을 이용해서 타이머를 start stop하려면 어디쪽 코드를 수정해야할까요..ㅜㅜ
  • 스위치를 사용하는 방법은 용도에 따라 다양하고, 원하는 기능을 구현하는 방법도 다양한데, 아래의 포스트를 참고해보시면 힌트가 될 것 같습니다.
    핵심은 스위치가 눌려 질때 마다 flag를 True/False 로 토글에서 flag 가 True일때는 카운트를 멈추고, False 일때는 카운트를 계속 진행하는 방식으로 진행하시면 될 것 같습니다.

    아두이노 스위치 입력 인터럽트
    https://juahnpop.tistory.com/31

    좀더 완성도 있는 코드를 원하시면 스위치 디바운싱 관련 포스트도 참고해주세요.
    https://juahnpop.tistory.com/39
  • 태수키 2020.10.15 08:33 수정/삭제 댓글쓰기
    넵 팁주셔서 감사합니다
  • 태수키 2020.10.20 17:34 수정/삭제 댓글쓰기
    오랜만에 죄송하지만 물어볼곳이 없네요 ㅠㅠ.. SW를 추가하면 자꾸 mytimer 가 선언되지않았다고 에러가떠서요.
  • 본문코드의 1번,39번,40번 줄 코드가 적용되있나요~?
  • 태수키 2020.10.20 18:49 수정/삭제 댓글쓰기
    대답해주셔서 감사합니다! 101,102번코드가 너무밑에있어서 적용이안되었습니다
  • 네~ 또 놀러오세요ㅎ
  • 태수키 2020.10.20 18:58 수정/삭제 댓글쓰기
    그렇게 말해주시니 죄송함을 무릅쓰고 하나만 더 여쭙겠습니다
    #include <MsTimer2.h>
    #include "pitches.h"
    #define segA 12 // 'a' 세그먼트 연결 핀 번호
    #define segB 2 // 'b' 세그먼트 연결 핀 번호
    #define segC 7 // 'c' 세그먼트 연결 핀 번호
    #define segD 9 // 'd' 세그먼트 연결 핀 번호
    #define segE 10 // 'e' 세그먼트 연결 핀 번호
    #define segF 11 // 'f' 세그먼트 연결 핀 번호
    #define segG 6 // 'g' 세그먼트 연결 핀 번호
    #define digit1 13 // 1st digit 연결 핀번호
    #define digit2 4 // 2nd digit 연결 핀번호
    #define digit3 3 // 3rd digit 연결 핀번호





    // main 함수에서 처리 편하게 하기 위해 핀번호 배열을 생성
    int fndDigit[3] = {digit1, digit2, digit3};
    int fndPort[7] = {segA, segB, segC, segD, segE, segF, segG};
    int switchPin = 8;
    const char BUZZER = 5;
    // index 0-9 -> 숫자 1~9
    // index 10 -> Blank
    volatile boolean bFlag = false;
    int fndData[11][8] = {
    { 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, 0, 1, 1 }, // 7
    { 0, 0, 0, 0, 0, 0, 0, 1 }, // 8
    { 0, 0, 0, 0, 1, 0, 0, 1 }, // 9
    { 1, 1, 1, 1, 1, 1, 1, 1 }, // 10 - blank
    };
    // 초기값 10 -> Blank
    int iflag = 0;

    // 10ms 간격 타이머 인터럽트
    void myTimer()
    {
    iflag = 1;
    }

    void setup()
    {
    // 1000ms 간격으로 myTimer() 함수를 호출합니다.
    MsTimer2::set(10,myTimer);
    MsTimer2::start();

    // 7 Segment 연결된 포트 모두 출력으로 설정
    for(int i = 0 ; i < 4 ; i++)

    {
    pinMode(switchPin, INPUT_PULLUP);
    pinMode(fndDigit[i], OUTPUT);
    pinMode(BUZZER, OUTPUT);
    digitalWrite(fndDigit[i], LOW);
    }
    for(int i = 0 ; i < 8 ; i++)
    {
    pinMode(switchPin, INPUT_PULLUP);
    pinMode(fndPort[i],OUTPUT);
    pinMode(BUZZER, OUTPUT);
    digitalWrite(fndPort[i],HIGH);
    }
    }

    void loop()
    {
    static int iCount = 18000;

    // 타이머 인터럽트가 발생 (iflag=1) 되면 iCount 를 1씩 증가, iCount 값이 10000일 경우 0으로 전환
    if (iflag == 1)
    {
    if (iCount == 0) {
    iCount = 18000;
    digitalWrite(BUZZER, HIGH);
    delay(50);

    }
    else {
    iCount--;
    }
    iflag = 0;

    }
    if(bFlag == true){ // bFlag 가 True 인 경우 실행
    bFlag = false;
    }
    }


    // 4자리수에 각각 입력 될 숫자 입력
    int digit1st = iCount / 10000;
    int digit2nd = iCount % 10000 / 1000;
    int digit3rd = iCount % 1000 / 100;
    // for 문을 돌리기 위해 배열을 사용
    int digitData[3] = {digit1st, digit2nd, digit3rd};


    for(int i = 0 ; i < 3 ; i++)
    {
    // 모든 Digit 1~4 핀 Off
    digitalWrite(digit1,LOW);
    digitalWrite(digit2,LOW);
    digitalWrite(digit3,LOW);

    // 각 Digit 에 맞는 fnd 숫자의 값 입력
    for(int j= 0 ;j<8;j++)
    {
    digitalWrite(fndPort[j], fndData[digitData[i]][j]);
    // 소수점 구분 점 찍기
    if(i==1) digitalWrite(fndPort[7], 0);
    }

    // 해당 Digit On
    digitalWrite(fndDigit[i],HIGH);
    // 밝기 조절을 위해 2ms LED ON 시간 조절
    delay(2);
    }
    }
    현재 스위치누르면 180 -> 0으로 카운트되고 멈춘뒤 다시 스위치누르면 리셋되어 180부터 0이되는 타이머를
    만드는중인데 짜집기열심히해도 너무어려워서 며칠째 고전중이네요 조언 조금만해주시면 감사하겠습니다 ㅠ
  • 스위치가 Tact 스위치 같은 타입이면 아래 링크의 EXTI를 사용하는 법을 한번 고려해보세요.

    전역 변수로 스위치 상태에 따른 플래그 변수(switchFlag)를 하나 선언하고, 스위치가 눌러지면 상황에 따라 이 플래그를 아래의 예시와 같이 상황에 맞게 입력 한 후에
    0 : Count 진행
    1 : Count 멈춤
    2 : Count 초기화

    loop() 문에서 switchFlag 의 값에 따라 Count를 180 -> 0, 멈춤, 초기화 하는 방식으로 해도 괜찮을 것 같습니다.
  • 태수키 2020.10.21 13:34 수정/삭제 댓글쓰기
    팁주셔서 감사합니다!
  • 태수키 2020.10.28 14:57 수정/삭제 댓글쓰기
    아직도해결을못했네요...ㅜ 스위치를 추가하려고해도 인터럽트가 우선순위라서 무시하고 그냥 카운트되는데 해결방법이있는지 도와주실수있나요..
  • juahnpop@naver.com 으로 코드 한번 보내주세요. 제가 도움 줄 수 있는 부분이 있으면 알려드릴께요.ㅎ
댓글쓰기 폼