아두이노 #55 MAX7219 32x8 LED 매트릭스 스크롤 원리와 라이브러리 없이 구현 예시
Lucy Archive
Lucy 2023
2020. 12. 3. 23:35

Arduino : 32x8 LED Matrix Scrolling

지난 포스트에서 MAX7219 32x8 LED Matrix 기초 사용법에 대해 소개하였습니다. 이번 포스트는

아두이노 우노 보드로 LED Matrix에 문자를 스크롤하는 원리와 코드를 소개

합니다. 

문자열 스크롤 기본 원리

LED Matrix에 문자열을 스크롤 하기 위한 방법 용도에 따라 다양한 방법으로 구현 가능합니다. 이 포스트에서 소개한 방법은 많은 방법 중 하나임을 참고해주세요.

디스플레이 버퍼

LED Matrix, LCD 와 같은 디스플레이 장치는 대부분 디스플레이 버퍼를 사용합니다. 디스플레이 버퍼는 화면에 표시할 데이터를 저장하는 데이터 배열입니다. 아래와 같이 32x8 픽셀의 LED Matrix와 320 x 240 LCD 가 있는 경우 아래와 같은 데이터 사이즈 버퍼를 사용합니다. 용도에 따라 다른 다양한 방식으로 사용 가능합니다. 

디스플레이 버퍼 예시

  • 32 x 8 LED Matrix : char[4][8]
  • 320 x 240 LED Matrix : int[320][240]

(왼) 32x8 LED Matrix, (우) 320 x 240 LED Matrix

위의 디스플레이 버퍼를 사용하면 디스플레이 장치를 아래 그림과 같은 방법으로 동작 가능합니다. 일단 컨트롤러 내부의 사정과 관련 없이 Display Buffer에서 디스플레이 장치로 주기적으로 데이터를 전송하는 기능을 만듭니다. 표시할 화면이 변경되는 경우 컨트롤러 내부에서 Display Buffer의 데이터만 변경합니다. 크게 이런 원리로 디지털 디스플레이 장치를 제어 가능합니다.

LED Matrix의 스크롤

32X8 LED Matrix에서 문자열을 스크롤하기 위해 2개의 데이터 버퍼를 사용하였습니다. 제가 작명에는 소질이 없어서 적절한지 모르겠지만, 출력할 텍스트가 모두 저장되는 stringBuff와 표시할 화면의 데이터를 저장하는 displayBuff 두 개를 만들었습니다. 

8x8 Font를 사용하는 경우 32x8 LED Matrix에는 4글자만 표현이 가능합니다. "Hello World!"와 같은 12 문자를 표시하기 위해 12글자와 문자열 앞뒤 여백을 stringBuff에 저장합니다. 이후에 스크롤 속도에 따라 displayBuff에 저장될 데이터를 변경합니다. 아래 그림은 이해를 돕기 위한 그림입니다. 붉은색은 stringBuff이고 빨간색은 displayBuff입니다.

LED Matrix 스크롤 원리

LED 매트릭스 스크롤 하기

준비물

본 예제에 사용된 부품은 아래와 같습니다.

  • Arduino Uno x 1EA
  • MAX7219 32x8 LED 매트릭스 x 1EA
  • 점퍼 와이어

하드웨어 연결

Arduino Uno와 LED Matrix는 아래의 회로도와 같이 연결하였습니다. Arduino Uno 보드의 13, 11, 10번 핀을 각각 LED 매트릭스 모듈의 SCK, DIN, CS 핀에 연결하였습니다.

Arduino Uno와 LED Matrix 연결 회로도

코드 작성

아래 코드를 실행시키기 위한 옵션은 아래와 같습니다.

  • #define TEXTBUFFERLENGTH 40 : stringBuff의 크기 설정
  • #define MODULESIZE 4 : MAX7219 LED Matrix 모듈 개수
  • #define SCROLLSPEED 70 : 스크롤 스피드 조정하는 숫자(오차는 있지만 ms 단위로 생각)
    • 60 이하로 설정 시 잔상효과 있을 수 있음
  • #define STRING "Hello World!" : LED 매트릭스에 표시할 문자열
    • 문자열 4자리 이하 : 경우 고정된 문자 출력
    • 문자열 4자리 초과 : 문자열 스크롤
#define SCK 13
#define DIN 11
#define LATCH 10

#define TEXTBUFFERLENGTH 40
#define MODULESIZE 4 /* Module Number */
#define SCROLLSPEED 70
#define STRING "Test"

String string = STRING; /* Input String to Display */
int stringLength; /* string 의 문자열 길이를 저장하는 변수 */

uint8_t stringBuff[TEXTBUFFERLENGTH][8]; /* String Dot Data Buffer*/
uint8_t displayBuff[MODULESIZE][8]; /* Display Data Buffer */

boolean scrollFlag = false; /* string 변수가 5글자 이상일 경우 인지 판단하는 flag */
int scrollTIme = SCROLLSPEED; /* 스크롤 속도 조정 */

/* Reference : https://github.com/dhepper/font8x8/blob/master/font8x8_basic.h */
const uint8_t font[128][8] PROGMEM = {
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0000 (nul)
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0001
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0002
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0003
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0004
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0005
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0006
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0007
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0008
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0009
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000A
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000B
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000C
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000D
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000E
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+000F
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0010
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0011
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0012
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0013
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0014
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0015
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0016
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0017
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0018
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0019
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001A
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001B
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001C
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001D
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001E
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+001F
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0020 (space)
    { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00},   // U+0021 (!)
    { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0022 (")
    { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00},   // U+0023 (#)
    { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00},   // U+0024 ($)
    { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00},   // U+0025 (%)
    { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00},   // U+0026 (&)
    { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0027 (')
    { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00},   // U+0028 (()
    { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00},   // U+0029 ())
    { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00},   // U+002A (*)
    { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00},   // U+002B (+)
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06},   // U+002C (,)
    { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00},   // U+002D (-)
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00},   // U+002E (.)
    { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00},   // U+002F (/)
    { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00},   // U+0030 (0)
    { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00},   // U+0031 (1)
    { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00},   // U+0032 (2)
    { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00},   // U+0033 (3)
    { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00},   // U+0034 (4)
    { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00},   // U+0035 (5)
    { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00},   // U+0036 (6)
    { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00},   // U+0037 (7)
    { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00},   // U+0038 (8)
    { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00},   // U+0039 (9)
    { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00},   // U+003A (:)
    { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06},   // U+003B (//)
    { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00},   // U+003C (<)
    { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00},   // U+003D (=)
    { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00},   // U+003E (>)
    { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00},   // U+003F (?)
    { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00},   // U+0040 (@)
    { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00},   // U+0041 (A)
    { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00},   // U+0042 (B)
    { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00},   // U+0043 (C)
    { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00},   // U+0044 (D)
    { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00},   // U+0045 (E)
    { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00},   // U+0046 (F)
    { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00},   // U+0047 (G)
    { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00},   // U+0048 (H)
    { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+0049 (I)
    { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00},   // U+004A (J)
    { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00},   // U+004B (K)
    { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00},   // U+004C (L)
    { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00},   // U+004D (M)
    { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00},   // U+004E (N)
    { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00},   // U+004F (O)
    { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00},   // U+0050 (P)
    { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00},   // U+0051 (Q)
    { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00},   // U+0052 (R)
    { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00},   // U+0053 (S)
    { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+0054 (T)
    { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00},   // U+0055 (U)
    { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00},   // U+0056 (V)
    { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00},   // U+0057 (W)
    { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00},   // U+0058 (X)
    { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00},   // U+0059 (Y)
    { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00},   // U+005A (Z)
    { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00},   // U+005B ([)
    { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00},   // U+005C (\)
    { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00},   // U+005D (])
    { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00},   // U+005E (^)
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF},   // U+005F (_)
    { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0060 (`)
    { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00},   // U+0061 (a)
    { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00},   // U+0062 (b)
    { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00},   // U+0063 (c)
    { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00},   // U+0064 (d)
    { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00},   // U+0065 (e)
    { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00},   // U+0066 (f)
    { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F},   // U+0067 (g)
    { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00},   // U+0068 (h)
    { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+0069 (i)
    { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E},   // U+006A (j)
    { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00},   // U+006B (k)
    { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00},   // U+006C (l)
    { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00},   // U+006D (m)
    { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00},   // U+006E (n)
    { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00},   // U+006F (o)
    { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F},   // U+0070 (p)
    { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78},   // U+0071 (q)
    { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00},   // U+0072 (r)
    { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00},   // U+0073 (s)
    { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00},   // U+0074 (t)
    { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00},   // U+0075 (u)
    { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00},   // U+0076 (v)
    { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00},   // U+0077 (w)
    { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00},   // U+0078 (x)
    { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F},   // U+0079 (y)
    { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00},   // U+007A (z)
    { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00},   // U+007B ({)
    { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00},   // U+007C (|)
    { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00},   // U+007D (})
    { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+007E (~)
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}    // U+007F
};

void setup(){
    pinMode(SCK, OUTPUT);
    pinMode(DIN, OUTPUT);
    pinMode(LATCH, OUTPUT);

    write_Max7219(0x09, 0x00); // Decode Mode - No decode for digits
    write_Max7219(0x0a, 0x01); // Intensity - 1/32
    write_Max7219(0x0b, 0x07); // Scan Limit - All Output Port Enable
    write_Max7219(0x0c, 0x01); // Shutdown - Normal Operation
    write_Max7219(0x0f, 0x00); // Display Test

    delay(50);

    reset_StringBuff(); // string에 저장된 문자열을 stringBuff에 저장
}

void loop(){
    unsigned long now = millis();
    static unsigned long pastTime;

    if(now-pastTime >= scrollTIme){ // 설정된 스크롤 간격으로 동작하는 if문
        if(scrollFlag){
            pastTime = now;
            static int index;
            static int shiftCount;
            for(int i = 0 ; i < MODULESIZE ; i++){
                for(int j = 0 ; j < 8 ; j++){
                    displayBuff[i][j] = (stringBuff[index+i][j] >> shiftCount) | stringBuff[index+i+1][j] << 8 - shiftCount;
                }
            }
            shiftCount++;
            if(shiftCount == 8){
                shiftCount = 0;
                index++;
            }
            if(index > stringLength + 5){
                index = 0;
            }
            display_Max7219();
        }
    }
}

void write_Max7219(uint8_t address, uint8_t data){
    digitalWrite(LATCH,LOW);
    for(int i = 0 ; i < MODULESIZE ; i++){
        shiftOut(DIN, SCK, MSBFIRST, address);
        shiftOut(DIN, SCK, MSBFIRST, data);
    }
    digitalWrite(LATCH,HIGH);
}

void display_Max7219(){
    for( int rowNumber = 1 ; rowNumber < 9 ; rowNumber++){
        digitalWrite(LATCH,LOW);
        for( int columnData = 0 ; columnData < MODULESIZE ; columnData++){
            shiftOut(DIN, SCK, MSBFIRST, rowNumber);
            shiftOut(DIN, SCK, LSBFIRST, displayBuff[columnData][rowNumber - 1]);
        }
        digitalWrite(LATCH,HIGH);
    }
}

void reset_StringBuff(){ // stringBuff에 데이터 세팅하는 함수
    stringLength = string.length();
    for(int i = 0 ; i < TEXTBUFFERLENGTH ; i++){
        for(int j = 0 ; j < 8 ; j++){
            stringBuff[i][j] = 0b00;
        }
    }
    if(stringLength > 4){
        scrollFlag = true;
        for(int i = 5 ; i < stringLength + 5 ; i++){
            for(int j = 0 ; j < 8 ; j++){
                stringBuff[i][j] = pgm_read_byte(&(font[string.charAt(i-5)][j]));
            }
        }
    }
    else{
        scrollFlag = false;
        for(int i = 0 ; i < stringLength ; i++){
            for(int j = 0 ; j < 8 ; j++){
                displayBuff[i][j] = pgm_read_byte(&(font[string.charAt(i)][j]));
            }
        }
        display_Max7219();
    }
}

 

주요 코드 설명

void loop() 내의 아래 if문 코드는 선언문에서 #define으로 정의된 SCROLLSPEED 속도에 따라 displayBuff의 데이터를 설정하는 코드입니다.

if(now-pastTime >= scrollTIme){ // 설정된 스크롤 간격으로 동작하는 if문
    if(scrollFlag){
        pastTime = now;
        static int index;
        static int shiftCount;
        for(int i = 0 ; i < MODULESIZE ; i++){
            for(int j = 0 ; j < 8 ; j++){
                displayBuff[i][j] = (stringBuff[index+i][j] >> shiftCount) | stringBuff[index+i+1][j] << 8 - shiftCount;
            }
        }
        shiftCount++;
        if(shiftCount == 8){
            shiftCount = 0;
            index++;
        }
        if(index > stringLength + 5){
            index = 0;
        }
        display_Max7219();
    }
}

void reset_StringBuff() 함수는 string 변수에 저장된 문자열의 길이가 4를 초과하는지 판단하여 4를 초과하는 경우 stringBuff에 문자열 도트 데이터를 저장하고, 4이하면 displayBuff에 문자열 도트데이터를 바로 저장 후 MAX7219에 데이터를 송신합니다.

void reset_StringBuff(){ // stringBuff에 데이터 세팅하는 함수
    stringLength = string.length();
    for(int i = 0 ; i < TEXTBUFFERLENGTH ; i++){
        for(int j = 0 ; j < 8 ; j++){
            stringBuff[i][j] = 0b00;
        }
    }
    if(stringLength > 4){
        scrollFlag = true;
        for(int i = 5 ; i < stringLength + 5 ; i++){
            for(int j = 0 ; j < 8 ; j++){
                stringBuff[i][j] = pgm_read_byte(&(font[string.charAt(i-5)][j]));
            }
        }
    }
    else{
        scrollFlag = false;
        for(int i = 0 ; i < stringLength ; i++){
            for(int j = 0 ; j < 8 ; j++){
                displayBuff[i][j] = pgm_read_byte(&(font[string.charAt(i)][j]));
            }
        }
        display_Max7219();
    }
}

실행 결과

위 코드에서 선언문 #define STRING "TEST" 4글자를 입력한 경우 아래 그림과 같은 정지 화면이 정상적으로 출력됩니다.

4글자 이하 출력시 고정 텍스트 출력

위 코드에서 #define STRING "Hello World!" 와 같이 4 글자를 초과하는 문자열을 입력하면 아래 영상과 같이 스크롤이 되는 것을 확인할 수 있습니다.

표시 문자열 4글자 초과시 스크롤 출력

마무리

이번 포스트에서는 LED Matrix를 사용하여 텍스트 스크롤하는 원리와 동작 코드 예시를 소개하였습니다. 코드에서 사용한 폰트는 8x8 사이즈인데, 5x7의 텍스트를 사용해서 촘촘하게 데이터를 만들면 한결 보기 좋고, 부드러운 문자열을 출력할 수 있을 것이라 예상합니다. 

관련포스트

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

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

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