산구루|국토종주 자전거길 가이드
  • 홈
  • 종주 공통
    • 자전거길 종주 인증에 대하여
    • 국토종주 거리 계산기
    • 자전거길 종주 데이터
    • 인사 말씀
    • 처음 오신 분
    • 블로그 이용법
    • 닫기
  • 국토종주
    • 한강 구간
      • 아라
      • 한강(서울)
      • 남한강
    • 새재
    • 낙동강 구간
      • 낙동강 중류
      • 낙동강 하류
    • 닫기
  • 4대강종주
    • 한강종주
      • 한강(서울)
      • 남한강종주
    • 낙동강종주
      • 낙동강 상류(안동)
      • 낙동강 중류
      • 낙동강 하류
    • 금강종주
    • 영산강종주
    • 닫기
  • 나머지 종주
    • 동해안종주
    • 제주환상종주
    • 섬진강종주
    • 북한강종주
    • 오천종주
    • 닫기
  • 지리산
    • 지리산둘레길3(인월-금계)
    • 지리산둘레길11(하동호-삼화실)
    • 닫기
  • 로그인
  • 내정보
    • 등록(블로그 가입)
    • 프로필 보기/수정
    • 비밀번호 찾기
    • 닫기
  • 검색
    • 닫기

[아두이노005] 7세그먼트 74HC595 튜브 사용법

2018년 1월 11일 | {산구루}작성 | Leave a Comment |

이글은 2018.1.11에 있었던 오프라인 강의 노트입니다.

아두이노에서 가장 흔하게 사용하는 출력 장치는 7세그먼트 LED를 이용한 디스플레이입니다. LED를 사용하는 방법과 핀을 확장하기 위한 MUX (multiplexer)의 한 종류인 74HC595 사용법을 알아봅시다.

다이오드에 대하여 다이오드에 대하여

다이오드(diode)는 한 방향으로만 전류를 흐르게 하는 반도체 소자입니다.그중에서 전류를 흘리면 빛을 발하는 다이오드를 LED (발광 다이오드, Light Editting Diode)라고 합니다.

다이오드설명

다이오드는 극성이 있습니다.다리가 긴 쪽이 + 방향이며 아노드라고 하고,그 반대쪽이 캐소드입니다.

▲모두 닫기  |  {끝:다이오드에 대하여}
7세그먼트 튜브에 대하여 7세그먼트 튜브에 대하여

LED를 7개 모아서 글자를 구성하는 부품이 ‘7세그먼트 튜브’입니다.실용적으로는 소숫점을 포함하여 8개의 LED로 숫자 하나를 표현합니다.숫자 하나를 표시하기 위하여 8개의 핀이 필요합니다.

7세그먼트설명2

7세그먼트 튜브는 공통 단자를 아노드(+) 또는 캐소드(-)로 만듭니다. 공통 단자와 반대 극성의 전압이 걸리는 세그먼트 낱개가 켜지게 됩니다. 시중에 판매되는 제품에는 공통 아노드가 더 많습니다.

만약 4자리 숫자를 표현하려면 몇개의 핀이 필요할까요? 아두이노 우노의 핀이 20개인데 튜브에 40개의 핀을 사용할 수는 없는 노릇입니다.

4자리세그먼트

여러 자리를 표시하는 경우는 자리 번호를 공통 아노드나 공통 개소드로 하고,자리수를 번갈아 가면서 표시하는 ‘다이나믹 표시’ 기법을 사용합니다.위와 같이 4자리를 표시할 때도 12개의 핀만 있으면 됩니다.

이 경우 특정 시점에는 하나의 숫자만 켜지게 되는데 아주 빠르게 반복되므로 마치 동시에 켜져 있는 듯 보입니다. 빠르게 반복되게 프로그램 로직을 구성해야 합니다. 이런 상황에서는 타이머 인터럽트를 이용하면 편합니다.

▲모두 닫기  |  {끝:7세그먼트 튜브에 대하여}
74HC595에 대하여 74HC595에 대하여
그러나 튜브에 12개의 핀을 할당하기도 부담스러우므로, 2개의 MUX(74HC595)를 이용하면 단 3개의 핀으로 4자리 7세그먼트르 제어할 수 있습니다. 하나의 74HC595에는8개의 세그먼트 낱개를 연결하고, 또 하나의 74HC595에는 4개의 자릿수 표시 공통 단자를 연결하면 됩니다.(이 때 공통 단자 연결 74HC595의 4핀은 남습니다) 다음에 이 두 소자를 직렬로 연결하면 한꺼번에 제어할 수가 있습니다.

74HC595와7세그먼트

74HC595 소자에는 데이터를 받아들이는데 사용되는 핀이 3개 있고,받아들인 데이터를 동시에 출력하는 핀이 8개 있습니다. 이 소자에는 8비트의 레지스터가 있는데 각 비트의 값에 따라 해당 핀에 5V(1)나 0V(0)가 출력됩니다. LATCH핀에 0V를 걸면 레지스터에 값을 보낼 수 있습니다. CLK핀이 0V에서 5V로 바뀔 때 DATA핀에 5V가 걸리면 비트 1, 0V가 걸리면 비트 0이 전송됩니다. shiftOut() 함수는 8비트를 레지스터에 보내는데 사용합니다. 소자는 여러 개를 직렬로 연결할 수도 있습니다.이론적으로는 여러 개의 74HC595를 단 3개의 핀으로 제어할 수가 있습니다.

다음은 각 세그멘트별 값을 나타낸 표입니다. 특정 숫자를 표현할 때는 각 세그멘트를 |(OR)로 연결해서 만든 값을 사용할 수도 있고, 미리 완성된 값을 지정할 수도 있습니다.

세그먼트
이진수
10진수
SEG_A
B0000 0001
1
SEG_B
B0000 0010
2
SEG_C
B0000 0100
4
SEG_D
B0000 1000
8
SEG_E
B0001 0000
16
SEG_F
B0010 0000
32
SEG_G
B0100 0000
64
SEG_DP
B1000 0000
128
숫자 '2'
B0101 1011
91
SEG_A |
SEG_B |
SEG_D |
SEG_E |
SEG_G
1+
2+
8+
16+
64=
91

다음은 공통 아노드 4 자리 튜브를 두 개의 74HC595로 제어하는 예입니다. LATCH,CLK,DATA핀은 각각 4,7,8번 핀에 연결되어 있습니다. 첫 번째 자리에 숫자 ‘2’를 표시하는 경우를 도식화한 것입니다.

74HC595설명

배선를 살펴보면 두 소자의 LATCH와 CLK핀은 아두이노와 연결되어 있습니다. 자릿수 소자의 DATA핀은 아두이노와 연결되어 있고 세그먼트 소자의 DATA핀은 자릿수 소자의 핀에 연결되어 있습니다. 두 개의 74HC595는 순차적으로 연결되어 있어서 shiftOut()을 한 번 수행하면 자릿수 레지스터에 8비트가 옮겨지고,두 번째 shiftOut()를 수행하면 새롭게 8비트가 자릿수 레지스터에 들어가면서 기존에 있던 8비트는 세그먼트 레지스터로 밀려서 옮겨갑니다.
공통 아노드 튜브의 경우 세그먼트 낱개에 연결되는 핀이 LOW가 되어야 ON 상태가 됩니다. 그림의 ‘2’를 표시하는 패턴은 사람이 이해하기 쉽게 핀이 HIGH가 되어야 ON 상태가 되도록 표시되어 있으므로 shiftOut()하기 전에 ~기호를 이용해서 반전시킵니다.
위 경우를 나타낸 스케치 일부입니다.

1
2
3
4
5
6
7
8
const byte latchPin = 4;
const byte clkPin = 7;
const byte dataPin = 8;
//
digitalWrite(latchPin,LOW);
shiftOut(dataPin, clkPin, MSBFIRST, ~B010111011);
shiftOut(dataPin, clkPin, MSBFIRST, B00000001);
digitalWrite(latchPin,HIGH);  

비트 연산자 비트 연산자
비트연산자
의미
설명
&
비트 AND둘다 1 일때 1
|
비트 OR둘중 하나만 1이면 1
^
비트 XOR둘중 하나만 1이면 1
둘다 1이면 0
~
비트 반전0 -> 1
1 -> 0
<<
왼쪽으로 비트 이동자릿수 만큼 이동
넘치면 없어짐
<<
오른쪽으로 비트 이동자릿수 만큼 이동
넘치면 없어짐
▲모두 닫기  |  {끝:74HC595에 대하여}
7세그먼트 패턴 표시용 기초 스케치 7세그먼트 패턴 표시용 기초 스케치
숫자와 문자 패턴을 출력하는 초보적인 스케치입니다. 두 개의 74HC595 소자와 연결된 공통 아노드 4 자리 튜브를 사용한 경우입니다. 복잡한 스케치에 사용하기에는 제약이 있지만 개념만 이해하면 되겠습니다.

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
// 74HC595에 사용되는 핀
#define LATCH_PIN 4
#define CLK_PIN 7
#define DATA_PIN 8
// 숫자(0~9)표현하는 비트 패턴
//const byte num[] = {63, 6, 91, 79, 102, 109, 125, 7, 127, 111};
const byte num[] = {
  B00111111,  // 0
  B00000110,  // 1
  B01011011,  // 2
  B01001111,  // 3
  B01100110,  // 4
  B01101101,  // 5
  B01111101,  // 6
  B00000111,  // 7
  B01111111,  // 8
  B01101111   // 9
};
const byte segA = B00000001;
const byte segB = B00000010;
const byte segC = B00000100;
const byte segD = B00001000;
const byte segE = B00010000;
const byte segF = B00100000;
const byte segG = B01000000;
const byte segDP= B10000000;
const byte segBlank = B00000000;
// 자릿수(1~4)를 표현하는 비트 값
const byte segmentDigit[] = {0x01,0x02,0x04,0x08};
void setup () {
  pinMode(LATCH_PIN,OUTPUT);
  pinMode(CLK_PIN,OUTPUT);
  pinMode(DATA_PIN,OUTPUT);
}
void loop() {
  // 25.7c 표시
  writePattern(0 , num[2]);
  writePattern(1 , num[5] | segDP); // 소숫점 표시
  writePattern(2 , num[7]);
  writePattern(3 , segD | segE| segG);        // c
}
void writePattern(byte digit, byte pattern) {
  // LATCH핀이 LOW가 되면 74HC595의 레지스터에 비트를 받아들일 준비가 됩니다.
  digitalWrite(LATCH_PIN,LOW);
  // 공통 아노드 튜브의 경우 segment 낱개에 연결되는 핀이 LOW가 되어야 ON 상태가 됩니다.
  // 위 num[]은 사람이 이해하기 쉽게 핀이 HIGH가 되어야 ON 상태가 되도록 표시되어 있으므로
  // shiftOut()하기 전에 ~기호를 이용해서 반전시킵니다.
  shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, ~pattern);
  shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, segmentDigit[digit] );
  digitalWrite(LATCH_PIN,HIGH);
  // LATCH핀이 HIGH가 되면 74HC595의 레지스터에 있는 비트 값에 따라 해당 핀에 5V(1)나 0V(0)를 동시에 출력합니다.
}

▲모두 닫기  |  {끝:7세그먼트 패턴 표시용 기초 스케치}
7세그먼트 표시용 기초 클래스 7세그먼트 표시용 기초 클래스
앞에서 나온 기초 스케치를 클래스로 만들어 봤습니다. 두 개의 74HC595 소자와 연결된 공통 아노드 4 자리 튜브를 사용한 경우입니다. 프리미티브한 기능만 있지만 작은 사이즈이고 원하는대로 응용이 가능한 클래스입니다. 기능이 풍부한 범용 클래스는 다음에 나옵니다.

SanguruSegmentBasic.h ▼

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
// 74HC595에 사용되는 핀
#define LATCH_PIN 4
#define CLK_PIN 7
#define DATA_PIN 8
 
// 주기적으로 튜브에 update하기 위하여 Timer1을 이용합니다.
#include <TimerOne.h>
 
// 7세그먼트용 기초 클래스입니다.
#include <SanguruSegmentBasic.h>
SanguruSegmentBasic seg(LATCH_PIN,CLK_PIN,DATA_PIN);
  
void setup () {
  // 250 microSec 마다 수행합니다.
  Timer1.initialize(250);
  // 7세그먼트 update용 ISR(Interrupt Service Rountine)을 지정합니다.
  Timer1.attachInterrupt(segUpdate);  
  seg.setBrightness(5); // 밝기 단계 1~7, 높을수록 밝다.
  //seg.setDigitOrderHigh(); // common digit 배선이 역순일 때 사용
  //seg.setCommonCathode();  // common cathode 일 때 사용
}
void loop() {  
  // 25.7c 표시
  seg.writePattern(0 , seg.num[2]);
  seg.writePattern(1 , seg.num[5] | seg.DP); // 소숫점 표시
  seg.writePattern(2 , seg.num[7]);
  seg.writePattern(3 , seg.D | seg.E | seg.G); // c
}
void segUpdate() {
  seg.update();
}

SanguruSegmentBasic.h SanguruSegmentBasic.h

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
#ifndef SANGURU_SEGMENT_BASIC_H_
#define SANGURU_SEGMENT_BASIC_H_
#include "Arduino.h"
 
class SanguruSegmentBasic {
  public:
 
  // constructor 에는 void 조차도 없다.
  SanguruSegmentBasic(byte inLatchPin, byte inClkPin, byte inDataPin);
  void writePattern(byte digit, byte pattern);
  void write(int number);
  void write(float number, byte decimalPlaces);
  // ISR에 이 메쏘드를 넣어야 한다.
  void update();
 
  // common digit 배선이 역순으로 되어 있을 때 사용
  void setDigitOrderHigh();
 
  // common cathode 일 때 사용
  void setCommonCathode();
 
  // 밝기를 1~7단계로 표시. 높을 수록 밝다. 기초값 5
  void setBrightness(byte bright);
 
  //const bytenum[] = {63, 6, 91, 79, 102, 109, 125, 7, 127, 111};
  const byte num[10] = {
   B00111111,  // 0
   B00000110,  // 1
   B01011011,  // 2
   B01001111,  // 3
   B01100110,  // 4
   B01101101,  // 5
   B01111101,  // 6
   B00000111,  // 7
   B01111111,  // 8
   B01101111   // 9
  };
  const byte A = B00000001;
  const byte B = B00000010;
  const byte C = B00000100;
  const byte D = B00001000;
  const byte E = B00010000;
  const byte F = B00100000;
  const byte G = B01000000;
  const byte DP= B10000000;
  const byte Blank = B00000000;
 
  volatile byte buffer[4];
 
  private:
  byte latchPin,clkPin,dataPin;
  byte digitOrderLowOrHigh = LOW;
  byte bright = 5;
  bool commonAnode = true;    
 
  const byte digit[4] = {0x01,0x02,0x04,0x08};
  // ISR에서 수정되거나 사용되는 변수는 volatile을 지정해야 값이 안전하게 전달된다.
  
  volatile byte digitLoop = 0;
  volatile int eachDigitLoop[4];
};
//↑ class 뒤에는 ;가 있어야 한다.
#endif

SanguruSegmentBasic.cpp SanguruSegmentBasic.cpp

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
#include "SanguruSegmentBasic.h"
#include "Arduino.h"
 
// constructor 앞에는 void 조차도 없다.
SanguruSegmentBasic::SanguruSegmentBasic(byte inLatchPin, byte inClkPin, byte inDataPin) {
  latchPin = inLatchPin;
  clkPin = inClkPin;
  dataPin = inDataPin;  
 
  pinMode(latchPin,OUTPUT);
  pinMode(clkPin,OUTPUT);
  pinMode(dataPin,OUTPUT);
}
void SanguruSegmentBasic::writePattern(byte digit, byte pattern) {
  buffer[digit] = pattern;  
}
void SanguruSegmentBasic::write(int number) {
  write((float)number,0);
}
 
void SanguruSegmentBasic::write(float number, byte decimalPlaces) {
  int expo[4] = {1,10,100,1000};
  byte buffer[4] = {0,0,0,0};
  bool sign = false;
  
  if (decimalPlaces > 3 || decimalPlaces < 0) return; int val = number * expo[decimalPlaces]; if (val > 9999 || val < -999) {
    writePattern(3,121); // 121=E
    return;
  }    
    
  if (val < 0 ) { val = 0 - val; sign = true; } int i; for (i = 3; i >= 0 && val != 0; val /= 10, i--) {
    buffer[i] = num[val % 10];
  }
  if (sign == true) {
      buffer[i] = 64; // minus(-)
  }
  if (decimalPlaces > 0) {
    buffer[3-decimalPlaces] += 128;   // decimal point
  }
  for (int i = 0; i <= 3; i++) { writePattern(i,buffer[i]); } } void SanguruSegmentBasic::update() { // 한 자릿수씩 번갈이 가면서 표시한다. digitLoop++; if (digitLoop > 3)
    digitLoop = 0;
 
  // common digit의 배선 순서가 역순인 경우 대비
  byte newDigitLoop;
  if (digitOrderLowOrHigh == LOW)
   newDigitLoop = digitLoop;
  else
    newDigitLoop = 3 - digitLoop;
  
  // 공통 아노드 튜브의 경우 segment 낱개에 연결되는 핀이 LOW가 되어야 ON 상태가 된다.
  // 위 num[]은 사람이 이해하기 쉽게 핀이 HIGH가 되어야 ON 상태가 되도록 표시되어 있으므로
  // shiftOut()하기 전에 buffer[]를 ~기호를 이용해서 반전시킨다.
  byte newDigit,newBuffer;
  if (commonAnode == true) {
   newBuffer = ~buffer[newDigitLoop];
   newDigit = digit[digitLoop];
  }
  else {
   newBuffer = buffer[newDigitLoop];
   newDigit = ~digit[digitLoop];
  }
 
  // 밝기를 1~7 단계로 조절
  eachDigitLoop[digitLoop]++;
 
  if ( (bright == 1 && (eachDigitLoop[digitLoop] % 20 !=0)) ||
       (bright == 2 && (eachDigitLoop[digitLoop] % 13 !=0)) ||
       (bright == 3 && (eachDigitLoop[digitLoop] % 10 !=0)) ||
       (bright == 4 && (eachDigitLoop[digitLoop] % 6 !=0)) ||
       (bright == 5 && (eachDigitLoop[digitLoop] % 3 !=0)) ||
       (bright == 6 && (eachDigitLoop[digitLoop] % 2 !=0)) ) {
   newBuffer = B00000000;
   newDigit  = B00000000;
  }
  
  // LATCH핀이 LOW가 되면 74HC595의 레지스터에 비트를 받아들일 준비가 된다.
  digitalWrite(latchPin,LOW);
  shiftOut(dataPin, clkPin, MSBFIRST, newBuffer);
  shiftOut(dataPin, clkPin, MSBFIRST, newDigit );
  digitalWrite(latchPin,HIGH);
  // LATCH핀이 HIGH가 되면 74HC595의 레지스터에 있는 비트 값에 따라 해당 핀에 5V(1)나 0V(0)를 동시에 출력한다.
}
void SanguruSegmentBasic::setDigitOrderHigh() {
  digitOrderLowOrHigh = HIGH;
}
void SanguruSegmentBasic::setCommonCathode() {
  commonAnode = false;
}
void SanguruSegmentBasic::setBrightness(byte inBright) {
  if (inBright > 7)
   inBright = 7;
  else if (inBright < 1)
   inBright = 1;
  bright = inBright;
}

클래스 확장하여 사용하기 클래스 확장하여 사용하기
이미 존재하는 클래스를 확장하여 사용할 때는 객체의 포인터를 이용하면 됩니다. ‘->’를 이용하면 객체 포인터의 메쏘드에 접근할 수 있습니다.
위 클래스를 확장하여 정수를 표현하는 write() 함수를 (교육 목적으로) 만들어 보았습니다.
(실제로는 SanguruSegmentBasic.h에는 write()메쏘드가 포함되어 있으므로 별도로 함수를 만들 필요는 없습니다.)

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
// 사용할 때
write(&seg,-234);
write(&seg,25.8,1);
//
void write(SanguruSegmentBasic *seg,int number) {
  write(seg,(float)number,0);
}
 
void write(SanguruSegmentBasic *seg,float number, byte decimalPlaces) {
  int expo[4] = {1,10,100,1000};
  byte buffer[4] = {0,0,0,0};
  bool sign = false;
  
  if (decimalPlaces > 3 || decimalPlaces < 0) return; int val = number * expo[decimalPlaces]; if (val > 9999 || val < -999) { seg->writePattern(3,121); // 121=E
    return;
  }    
    
  if (val < 0 ) { val = 0 - val; sign = true; } int i; for (i = 3; i >= 0 && val != 0; val /= 10, i--) {
      buffer[i] = seg->num[val % 10];
  }
  if (sign == true) {
      buffer[i] = 64; // minus(-)
  }
  if (decimalPlaces > 0) {
      buffer[3-decimalPlaces] += 128;   // decimal point
  }
  for (int i = 0; i <= 3; i++) { seg->writePattern(i,buffer[i]);
  }
}

▲모두 닫기  |  {끝:7세그먼트 표시용 기초 클래스}
7세그먼트 범용 클래스 7세그먼트 범용 클래스

다음은 두 개의 74HC595 소자를 사용하는 4 자리 LED 튜브를 제어할 수 있는 SanguruSegment.h의 사용 예입니다.
시리얼로 입력된 명령어에 따라 다양한 방식으로 표시할 수 있습니다. 소스를 보면 그 사용 예를 익힐 수 있습니다.

SanguruSegment.h ▼

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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
// SanguruSegment.h 사용시 필요
#include <TimerOne.h>
 
// SanguruSegment.h 클라스
#include <SanguruSegment.h>
SanguruSegment segment;
 
// 74HC595 핀 설정
#define LATCH_PIN 4    // RCLK_PIN
#define CLK_PIN 7      // SCLK_PIN
#define DATA_PIN 8     // QB_PIN,DIO_PIN
 
void setup ()
{
  // 값을 250에서 1000 사이의 값을 사용하면 된다.
  int microSec = 250;
  Timer1.initialize(microSec);
  
  // 반복적으로 update할 때 사용할 ISR을 정의한다.
  // ISR안에는 segment.update()가 있어야 한다.
  Timer1.attachInterrupt(segment_update);
  
  // 글자가 역순으로 나타나면 LOW와 HIGH를 서로 바꾸면 된다.
  // LOW: LOW to HIGH, HIGH: HIGH to LOW
  byte digitOrder = LOW;  
  
  segment.init(LATCH_PIN,CLK_PIN,DATA_PIN,digitOrder,microSec);  
  
  Serial.begin(9600);
  Serial.println("Started..." );
  printHelp();
 
  // 초기치로 '1234'를 표시해 둔다.
  segment.write(1234);
}
 
void loop() {
 
  // Serial로 입력된 'key value'에 따라 다양하게 표현한다.
  if (Serial.available()) {
    readAndDisplay();  
  }  
}
 
// ISR
void segment_update(){
  segment.update();
}
 
// 클라스 SanguruSegment.h의 사용 예를 알 수 있다.
void readAndDisplay() {
  
    char c = Serial.read();
    // 정수 표시
    if ( c == 'i' ) {
      int i = Serial.parseInt();
      Serial.print("i ");
      Serial.println(i);
      segment.write(i);    
    }
    
    // 앞에 0을 채운 정수
    else if ( c == 'I' ) {
      int i = Serial.parseInt();
      Serial.print("I ");
      Serial.println(i);
      segment.write(i,'0');
    }
 
    // 소숫점 표시
    else if ( c == 'f' ) {
      float f = Serial.parseFloat();
      Serial.print("f ");
      Serial.println(f,1);
      segment.write(f,1);    
    }
    
    // 앞에 0을 채운 소숫점 표시
    else if ( c == 'F' ) {
      float f = Serial.parseFloat();
      Serial.print("F ");
      Serial.println(f,1);
      segment.write(f,1,'0');      
    }
 
    // 윈도우 시작설정. 초기값은 0
    else if ( c == 'w' ) {
      int val = Serial.parseInt();
      segment.setWindow(val,segment.windowLen);
      Serial.print("windowFrom ");
      Serial.println( segment.windowFrom);
    }
    // 윈도우 길이 설절, 초기값은 4
    else if ( c == 'l' ) {
      int val = Serial.parseInt();
      segment.setWindow(segment.windowFrom,val);
      Serial.print("windowLen ");
      Serial.println( segment.windowLen);
    }
 
    // 첫 자리에 패턴값을 표시한다.
    else if ( c == 'a' ) {
      segment.patternBuffer[0] = Serial.parseInt();
      Serial.print("a --> patternBuffer[0] ");
      Serial.println( segment.patternBuffer[0]);    
    }
 
    // 둘째 자리에 패턴값을 표시한다.
    else if ( c == 'b' ) {
      segment.patternBuffer[1] = Serial.parseInt();
      Serial.print("b --> patternBuffer[1] ");
      Serial.println( segment.patternBuffer[1]);
    }
 
    //  세째 자리에 패턴값을 표시한다.
    else if ( c == 'c' ) {
      segment.patternBuffer[2] = Serial.parseInt();
      Serial.print("c --> patternBuffer[2] ");
      Serial.println(segment.patternBuffer[2]);
    }
 
    // 네째 자리에 패턴값을 표시한다.
    else if ( c == 'd' ) {
      segment.patternBuffer[3] = Serial.parseInt();
      Serial.print("d --> patternBuffer[3] ");
      Serial.println( segment.patternBuffer[3]);
    }
 
    // Timer1 주기를 microSec 단위로 다시 지정한다.
    else if ( c == 'y' ) {
      unsigned long titmer1InitVal = Serial.parseInt();
      Serial.print("y --> timer1InitVal ");
      Serial.println( titmer1InitVal);
      Timer1.initialize(titmer1InitVal);
    }
 
    // 문자 스트링를 출력한다. 문자 끝에는 #로 표시한다.
    else if ( c == 'q' ) {
      char buf[20]= {0};
      Serial.readBytesUntil('#',buf,19);
      Serial.print("q --> [");
      Serial.print(buf);
      Serial.println("]");
      String strBuf = String(buf);
      strBuf.trim();
      Serial.print("q(~#String) --> [");
      Serial.print(strBuf);
      Serial.println("]");
      segment.write(buf);  
    }
 
    // 설정된 윈도우를 깜빡거린다.
    else if ( c == 'k' ) {
      int val = Serial.parseInt();
      Serial.print("k(blink) --> [");
      Serial.print(val);
      Serial.println("]");
      segment.blink(val);  
    }
 
    // 콜론을 on(1) off(0)한다.
    else if ( c == 'n' ) {
      int val = Serial.parseInt();
      Serial.print("n(colon) --> [");
      Serial.print(val);
      Serial.println("]");
      segment.colon(val);  
    }
 
    // 윗쪽  점을 on(1) off(0)한다.
    else if ( c == 'u' ) {
      int val = Serial.parseInt();
      Serial.print("u(upperDot) --> [");
      Serial.print(val);
      Serial.println("]");
      segment.upperDot(val);  
    }
 
    // 콜론 깜빡거림을 on(1) off(0)한다.
    else if ( c == 'o' ) {
      int val = Serial.parseInt();
      Serial.print("o(blinkColon) --> [");
      Serial.print(val);
      Serial.println("]");
      segment.blinkColon(val);  
    }
 
    // 윗쪽 점 깜빡거림을 on(1) off(0)한다.
    else if ( c == 'p' ) {
      int val = Serial.parseInt();
      Serial.print("p(blinkUpperDot) --> [");
      Serial.print(val);
      Serial.println("]");
      segment.blinkUpperDot(val);  
    }
 
    // 소숫점 깜빡거림을 on(1) off(0)한다.
    else if ( c == 'z' ) {
      int val = Serial.parseInt();
      Serial.print("z(blinkDot) --> [");
      Serial.print(val);
      Serial.println("]");
      segment.blinkDot(val);  
    }
 
    // 모든 표시를 지운다.
    else if ( c == 'x' ) {
      int val = Serial.parseInt();
      Serial.print("x(clear) --> [");
      Serial.print(val);
      Serial.println("]");
      segment.clear();  
    }
 
   // 표시 순서를 바꾼다. 0: LOW to HIGH, 1:HIGH to LOW
    else if ( c == 'r' ) {
      int val = Serial.parseInt();
      Serial.print("r(digitOrder) --> [");
      Serial.print(val);
      Serial.println("]");
      segment.setDigitOrder(val);  
    }
 
    // 왼쪽에 붙여서 표시한다. 숫자인 경우 기초값은 오른쪽 붙임이다.
    else if ( c == 'j' ) {
      int val = Serial.parseInt();
      Serial.print("j(leftJustify) --> [");
      Serial.print(val);
      Serial.println("]");
      segment.setLeftJustify();  
    }
 
    // 오른쪽에 붙여서 표시한다. 숫자인 경우 기초값은 오른쪽 붙임이다.
    else if ( c == 'J' ) {
      int val = Serial.parseInt();
      Serial.print("J(rightJustify) --> [");
      Serial.print(val);
      Serial.println("]");
      segment.setRightJustify();  
    }
 
    // 밝기를 1~7단계로 표시한다. 기초값은 5이다. 큰 숫자가 밝게 표시된다.
    // 글자가 깜빡거려 보이면 Timer1.initialize() 값을 낮추면된다.(250 정도)
    else if ( c == 't' ) {
      int val = Serial.parseInt();
      Serial.print("t(bright) --> [");
      Serial.print(val);
      Serial.println("]");
      segment.setBrightness(val);  
    }
 
    // help 표시
    else if ( c == 'h' ) {
      printHelp();
    }
}
 
void printHelp(){
  Serial.println("commands");
  Serial.println("h display help");
  Serial.println("x clear");
  Serial.println("i integer with leading blank");
  Serial.println("I integer with leading zero");
  Serial.println("f float with leading blank");
  Serial.println("F float with leading zero");
  Serial.println("w set window from");
  Serial.println("l set window len");
  Serial.println("a set patternBuffer[0]");
  Serial.println("b set patternBuffer[1]");
  Serial.println("c set patternBuffer[2]");
  Serial.println("d set patternBuffer[3]");
  Serial.println("y Timer1 interval in microSec");
  Serial.println("q readBytesUntil #");  
  Serial.println("n colon 1/0");
  Serial.println("u upperDot 1/0");
  Serial.println("k blink 1/0");
  Serial.println("z blinkDot 1/0");
  Serial.println("o blinkColon 1/0");
  Serial.println("p blinkUpperDot 1/0");
  Serial.println("r digitOreder 0/1");
  Serial.println("j leftJustify");
  Serial.println("J rightJustify");
  Serial.println("t bright(1~7");
}
▲모두 닫기  |  {끝:7세그먼트 범용 클래스}

관련

Filed Under: 사물인터넷, 아두이노, 아두이노강좌, 정보기술

댓글 남기기 응답 취소

Copyright © 2025 · Waytips Theme ·