라즈베리파이, 아두이노

[간단한 아두이노 코딩] 8. 세븐 세그먼트 + 디코더 사용하기

포도알77 2020. 11. 24. 10:12

세븐 세그먼트 + 디코더 사용하기

 

1. 세븐 세그먼트 디코더

 디코더란, n개의 데이터라인으로 2^n의 출력을 뽑아내는 장치이다. 쉽게 말해서 7세그먼트에는 총 7개의 LED가 있고, 숫자는 0-9까지 총 10개이다. 이때 숫자를 2진법으로 표현한다면 4개의 데이터 선만 있으면 가능하고, 이를 7개의 LED에 연결하여 출력할 수 있게 된다.

 

 이처럼 디코더를 이용하면 더 적은 수의 GPIO를 이용하여 많은 값을 출력할 수 있다. 이와 반대로 동작하는 것을 인코더라고 한다.

 

 7 세그먼트는 한 자리 숫자를 출력하기 위해서 총 7개의 GPIO를 이용하기 때문에 디지털 시계와 같이 4개의 7 세그먼트를 출력하기 위해서는 총 32개의 GPIO가 필요하게 된다. 이를 4개의 디코더를 이용하여 16개의 GPIO로 줄일 수 있고, 칩 셀렉터를 이용하면 6개까지 줄일 수 있게 된다. 

 

 아무튼 이번 포스팅에서는 BCD 디코더와 clock을 사용하는 시프트 레지스터를 이용하여 1개의 7 Segment를 출력해 볼 것이다.

 


2. BCD to 7-Segment 디코더

 시중에 이미 다수의 BCD 7 세그먼트 디코더들이 있다. 앞선 7 세그먼트 포스팅에서 언급된 바와 같이, 7세그먼트와 디코더가 항상 같은 CC, CA 타입인지 확인하고 구매하자.

 

 BCD란, Binary Coded Decimal로 10진수를 2진법으로 표현한 것을 의미한다.

 

그리고 10진수를 다시 7세그먼트로 표현한다면 아래와 같다.

 

 

 이제 이 두개의 표를 하나로 나타내면 아래와 같다.

 

 이렇게 바이너리를 세그먼트의 출력으로 변환하는 것을 BCD 7 세그먼트 디코더라고 부르며, 실제 위의 동작에 필요한 로직 서킷은 카르노맵을 이용하여 구할 수 있으며, 이는 아두이노 수준과는 거리가 멀어 담지 않는다.

 

 아무튼 우리는 위와 같은 동작을 수행하는 디코더 칩을 구매해서 연결하여 쓰면된다. 대표적인 칩으로는 74LS48(CC타입)과 74LS47(CA타입)이 있다. 

 

74LS48(CC) 구매링크

74LS48(CC) 74LS47(CA)

 

 


 

3. BCD 7 세그먼트 디코더 회로도, 소스코드

 74LS48(CC)이나 기타 동일한 BCD 7세그먼트 디코더이면 대부분 동일하기 때문에 핀 레이아웃만 잘 확인하고 꽂으면 된다. 74LS48 레이아웃은 다음과 같다.

 핀 이름 위에 줄이 그어져 있으면, 토글로 0일때 동작하는 것을 뜻한다. LT는 램프 테스트로 아래의 표를 보면 항상 HIGH이어야 되며, RBO는 리플 블랭크 아웃풋이고, RBI는 리플 블랭크 인풋이다. 이 또한 HIGH로 되어있어야 하므로, LT, RBI, RBO는 Vcc와 같이 연결하면 된다.

 

// 세그먼트 디지털핀 A,B,C,D
int segment[4] = {2,3,4,5};

void setup() {
  // 핀모드 OUTPUT 설정
  for(int i=0; i<4; i++)
    pinMode(segmen[i], OUTPUT);
}

void loop() {
  // i : 0~9까지 숫자
   for(int i = 0; i < 10; i++){
      // j : 0~3, A,B,C,D 핀
      for(int j = 0; j < 4; j++){
        // A핀 0번째 비트
        // B핀 1번째 비트
        // C핀 2번째 비트
        // D핀 3번째 비트
        // 0x8은 1000(2) 이진수로 3번째 비트만 켜진 상태
        // X >> Y 연산은 숫자 X를 오른쪽으로 Y번 비트 시프트
        // ex) 8 >> 3은 이진수 1000이 3번 비트 시프트 0001으로 출력
        // j == 0, (0x1 << 0) == 0x1 (1)
        // j == 1, (0x1 << 1) == 0x2 (2)
        // j == 2, (0x1 << 2) == 0x4 (4)
        // j == 3, (0x1 << 3) == 0x8 (8)
        // i는 이진법으로 저장되어 있으므로 
        // 위의 shift 결과와 and 연산을 통해 1,0 여부를 확인
        digitalWrite(segmen[j], i&(0x1<<j));
      }
      delay(1000);
   }
}

 


 

4. Clock 기반의 시프트 레지스터

 GPIO 4개를 이용하지 않고, 1개의 데이터 선과 클럭 그리고 Data in Enable 선을 이용하여 전송하는 시프트 레지스터도 있다. 특히 아두이노 스타터킷에 포함된 SN74HC595N과 같은 IC인데, 이를 이용하는 회로도와 소스코드도 아래에 첨부한다.

 

 시프트 레지스터는 클럭에 맞춰서 비트를 입력하는 IC로 앞에서 Shift 연산을 통해서 10진수를 넣은 것과 달리 8개의 비트를 시프트로 넣어서 Qa~h까지 출력되도록 한다. 이때 SRCLK가 클럭이고, SER이 입력, RCLK는 출력 Refresh, SRCLR는 출력 초기화, 그리고 OE는 출력 Enable이다. 정상 출력을 위해서 OE와 SRCLR에는 GND인가하면 된다.

 

 우리는 Vcc, GND, 7개의 Qa~g 그리고 SER(데이터 입력), RCLK(출력 Refresh), SRCLK(클럭)을 사용한다.

RCLK를 0으로 맞추고 SRCLK에 0과 1의 값을 반복하면서 SER에 데이터를 입력하고, 다시 RCLK를 1으로 세팅하면 된다.

 

 

// 핀 설정
#define SER_PIN 2
#define RCLK_PIN 3
#define SRCLK_PIN 4

// 7세그먼트 출력 정보 0~9
int num[10][7] = {
  {1,1,1,1,1,1,0},
  {0,1,1,0,0,0,0},
  {1,1,0,1,1,0,1},
  {1,1,1,1,0,0,1},
  {0,1,1,0,0,1,1},
  {1,0,1,1,0,1,1},
  {1,0,1,1,1,1,1},
  {1,1,1,0,0,0,0},
  {1,1,1,1,1,1,1},
  {1,1,1,0,0,1,1}
};

void setup(){
  //핀 모드 설정
  pinMode(SER_PIN, OUTPUT);
  pinMode(RCLK_PIN, OUTPUT);
  pinMode(SRCLK_PIN, OUTPUT);
}

void loop(){
  // i : 0~9
  for(int i = 0; i < 10; i++){
    // 아웃풋 리프레시 핀 LOW
    digitalWrite(RCLK_PIN, LOW);
    
    int val = 0;
    // 7세그먼트 출력 정보를 담는 과정이다.
    // j : 0~6이며 각각 a~g핀에 해당
    for(int j= 0 ; j< 7; j++)
      // j번 왼쪽으로 시프트해서 저장
      val |= (num[i][j] << j);
    // 클럭과 동기화해서 데이터를 보내는 함수로
    // MSB는 가장 큰 값이 가장 높은 비트부터 저장됨을 뜻한다.
    // 우리가 이진수를 표현할 때 8을 1000(2)으로 표현하는 것은 MSB 표현법
    // 위의 루프에서 val의 이진수 값이 gfedcba(2)으로 담겼고
    // MSBFIRST를 통해서 g부터 a까지 전달된다.
    shiftOut(SER_PIN, SRCLK_PIN, MSBFIRST, val);
    // 아웃풋 리프레시 핀 HIGH (Qa~h 핀에 값 출력)
    digitalWrite(RCLK_PIN, HIGH);
    delay(1000);
  }
}

 


 

5. 정리

 너무 복잡하게 보이는 것 같은데, 이것만 기억하면 된다.

컴퓨터는 숫자를 이진법으로 저장한다. 세그먼트는 2진법으로 표현할 수 없다. 따라서 2진법으로 표현된 값을 바로 세그먼트 출력으로 바꾸는 장치가 필요하다 --> 디코더

 

 

* 파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음 (위 쿠팡 광고 배너)

페이스북으로 공유카카오톡으로 공유카카오스토리로 공유트위터로 공유URL 복사