🤖
LinkIt 7697 BlocklyDuino 使用指南
  • LinkIt 7697 BlocklyDuino 使用指南
    • 認識 LinkIt 7697
    • 認識 BlocklyDuino
    • BlocklyDuino v2 & v3 比較
    • 安裝開發環境 (v2)
      • 安裝 Arduino 編輯器
      • 安裝驅動並連接開發板
      • 安裝 BlocklyDuino 編輯器
      • 連結兩個編輯器並上傳程式
    • 安裝開發環境 (v3)
    • BlocklyDuino 基礎操作
    • 實作範例教學
      • A01. 內建 LED 閃爍
      • A02. 外接 LED 閃爍
      • A03. 外接 LED 呼吸燈
      • A04. RGB LED 顏色變化
      • A05. 外部按鈕控制開關
      • A06. 蜂鳴器播放聲音
      • A07 .可變電阻控制電壓輸出
      • A08. 伺服馬達控制
      • A21. DHT: 溫濕度感應器
      • A22. HTU21D: 溫溼度感應器
      • A23. PMSX003: PM2.5 感測器
      • A24. HC-SR04P: 超音波測距
      • A25. ADXL345: 加速規(動態)
      • A26. ADXL345: 加速規(手勢)
      • A27. 1602/2004: 液晶顯示模組
      • A28. WS2812: RGB 彩色燈條
      • A29. MFRC522: RFID
      • B00. Grove 相關基礎知識
      • B01. Grove 光感應器
      • B02. Grove 超音波測距感應器
      • B03. Grove 溫溼度感應器
      • B04. Grove 繼電器
      • B05. Grove LED 燈條
      • B06. Grove OLED 顯示器
      • C01. 雲端控制 LED 開關
      • C02. 上傳溫溼度到雲端
      • D01. 手機透過 BLE 讀寫裝置資料
      • E01. 遙控器: 按鈕控制 LED
    • 資源鏈結
  • LinkIt 7697 - Arduino IDE 開發指南
    • 環境設定
      • 設定 Arduino IDE
      • 將 LinkIt 7697 連接到電腦
        • 在 Windows 上安裝 CP2102N 驅動程式
        • 在 macOS 上安裝 CP2102N 驅動程式
      • 執行第一個程式
    • 開發指南
      • GPIO
      • UART
      • ADC
      • EINT (外部中斷 / External Interrupt)
      • I2C
      • SPI
      • EEPROM
      • Timer
      • Flash (索引式儲存空間)
      • RTC (Real-Time Clock)
      • Software Serial
      • 使用 Wi-Fi 函式庫
      • 使用 MCS 函式庫
        • 連接到 MCS
        • 連接到 MCSLite
          • 建立可透過 MCS Lite 控制的 Beacon
        • MCS 函式庫 API 使用手冊
          • MCSDevice
          • MCSLiteDeviceMCSLiteDevice
          • MCSDataChannel 相關類別
      • 使用 BLE 低功耗藍牙
        • 藍牙信標
        • 主控裝置
        • 周邊裝置
        • 已知限制
        • LBLE API 指南
          • LBLE
          • LBLECentral
          • LBLEPeripheral
          • LBLEAdvertisementData
          • LBLEService
          • LBLECharacteristic
          • LBLEAddress
          • LBLEUuid
          • LBLEClient
      • 使用 LinkIt Remote
        • LRemote API
        • LRemote 控制元件 API
      • LinkIt 7697 腳位的初始狀態
      • LinkIt 7697 供電說明
      • 更新 Bootloader 與韌體
      • Flash 燒錄工具
      • FOTA 更新
      • LinkIt 7697 的功能限制
      • 自行編譯 Arduino Package
      • 回報問題
    • 週邊元件連接教學
      • SMD 按鈕
      • RGB 三色 LED
      • 可變電阻
      • 九軸感應器 (MPU-9250)
      • 溫度與濕度感應器 (AM2302)
      • 超音波距離感應器
      • 光感應器 (LM358)
      • 0.96 吋 OLED 顯示模組 (SSD1308Z)
      • 長條型 LED 顯示模組 (MY9221)
      • 繼電器
      • 伺服馬達 (EMAX 9g ES08A Servo)
      • 使用 74HC595 驅動七段顯示器
      • 使用 MAX7219 驅動七段顯示器
      • 使用 MAX7219 驅動 8x8 矩陣式顯示器
      • 使用 OLED 模組 (如 SH1106 / SSD1306... 等模組)
      • 使用 PCF8574 / PCF8574A 驅動 1602 LCD
    • 開發套件與擴充板
      • Grove Starter Kit
      • Robot Shield
        • OTTO97
    • 下載
    • 資源連結
    • BSP 版本更新資訊
  • LinkIt 7697 - Development Guide for Arduino IDE
    • Environment Setup
      • Setup Arduino IDE
      • Connecting LinkIt 7697 to Computer
        • Install CP2102N Driver on Windows
        • Install CP2102N Driver on macOS
      • Run Your First Sketch
    • Developer Guide
      • GPIO
      • UART
      • ADC
      • External Interrupt
      • I2C
      • SPI
      • EEPROM
      • Timer
      • Flash (Key-Pair Storage)
      • RTC (Real-Time Clock)
      • Software Serial
      • Using the Wi-Fi Library
      • Using MCS Library
        • Connecting to MCS
        • Connecting to MCSLite
          • Build a Beacon controlled by MCS Lite
        • MCS Library API Reference
          • MCSDevice
          • MCSLiteDevice
          • MCSDataChannel Classes
      • Using Bluetooth
        • Beacons
        • Central Devices
        • Peripheral Devices
        • Limitations of LBLE library
        • LBLE Library API Guide
          • LBLE
          • LBLECentral
          • LBLEPeripheral
          • LBLEAdvertisementData
          • LBLEService
          • LBLECharacteristic
          • LBLEAddress
          • LBLEUuid
          • LBLEClient
      • Using LinkIt Remote
        • LRemote
        • LRemote Control Classes
      • Initial Pin State of LinkIt 7697
      • Powering the LinkIt 7697
      • Update Bootloader and Firmware
      • Flash Uploading Tool
      • FOTA Update
      • Limitations of LinkIt 7697
      • Source Code of Arduino Package
      • Issue Report
    • Tutorial
      • SMD Buttons
      • RGB LED
      • Potentiometer
      • IMU 9DOF v2.0 (MPU-9250)
      • Temperature and Humidity Sensor Pro (AM2302)
      • Grove Ultrasonic Ranger
      • Light Sensor (LM358)
      • Grove OLED Display 0.96" (SSD1308Z)
      • LED Bar v2.0 (MY9221)
      • Relay
      • Mini Servo (EMAX 9g ES08A Servo)
      • Driving 7-segment Displays with 74HC595
      • Driving 7-segment Displays with MAX7219
      • Driving 8x8 Dot Matrices with MAX7219
      • Using OLED module (SH1106 / SSD1306... etc.)
      • Driving 1602 LCD with PCF8574 / PCF8574A
    • Kits and Shields
      • Grove Starter Kit
      • Robot Shield
        • OTTO97
    • Download
    • Resources
    • BSP Release Notes
Powered by GitBook
On this page
  • Table of Contents
  • Mapping 7-segment Display to 8x8 Dot Matrix
  • Hardware Setup
  • 1-matrix Example
  • Chained-matrix Example
  • Scrolling-string Example
  • Summary
  1. LinkIt 7697 - Development Guide for Arduino IDE
  2. Tutorial

Driving 8x8 Dot Matrices with MAX7219

PreviousDriving 7-segment Displays with MAX7219NextUsing OLED module (SH1106 / SSD1306... etc.)

Last updated 3 years ago

Not only to , MAX7219 is also commonly used in driving 8x8 dot matrices. In this tutorial, we'll show how to use one MAX7219 to drive one 8x8 dot matrix and how to daisy-chain multiple MAX7219s to drive multiple 8x8 dot matrices. For ease of wiring, we use the (with MAX7219 built-in) as the component used in this article.

Table of Contents

Mapping 7-segment Display to 8x8 Dot Matrix

Although a 7-segment display and a 8x8 got matrix are quite different in form factor, they are actually with the same structure: a display module with a group of LEDs. One 7-segment display consists of 8 LEDs (7 LEDs for digit segments and one LED for the decimal point), and as mentioned in , one MAX7219 can drive up to 8 seven-segment displays. This means MAX7219 can drive up to 8x8 = 64 LEDs, which is exactly the number of LEDs on a 8x8 dot matrix. As a result, by using the non-decode (raw data) mode of MAX7219, it can be used to drive a 8x8 dot matrix. The next question is, how to map the LED position between a 7-segment display and a 8x8 dot matrix? Let's explain it with the following figure.

By using the non-decode display mode of MAX7219 (if you're not familiar with it, check the previous ), each column of the matrix is mapped to one digit control register. It means Digit 0 is mapped to Column 0, Digit 1 is mapped to Column 1 and so on. And each row of a column is mapped to different segments of a 7-segment display. Starting from the top dot, which is mapped to the LSB of the data fed to the Digit data register, the mapping goes down sequentially to the last row mapped to the MSB of the Digit register. Here we show an example to define the bitmap of "7" on the matrix.

According to the figure, the bitmap pattern of "7" is defined as:

const byte bitmap_7[] =
{
  // define the dot pattern from column 0 ~ column 7
  B00000000, B00000000, B01100001, B00010001, B00001001, B00000111, B00000000, B00000000
};

Hardware Setup

5 pins are needed from the LinkIt 7697:

  • 5V

  • GND

  • P15

  • P16

  • P17

And they are wiring to pins

  • VCC

  • GND

  • CLK

  • CS

  • DIN

of the display module, respectively.

By setting up the hardware wiring, next we give an example to show different bitmaps on the display.

1-matrix Example

Following the bitmap definition mentioned above, the first example in this tutorial uses one 8x8 dot matrix to display characters. This sketch code displays "Hello, LinkIt7697" repeatedly and the demo video is:

//
// Use multiple 8x8 dot matrix modules to display a marquee string
// http://www.icshop.com.tw/product_info.php/products_id/13181
//
// MAX7219 datasheet: https://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf
//

// the MAX7219 address map (datasheet table 2)
#define MAX7219_DECODE_REG      (0x09)
#define MAX7219_INTENSITY_REG   (0x0A)
#define MAX7219_SCANLIMIT_REG   (0x0B)
#define MAX7219_SHUTDOWN_REG    (0X0C)
#define MAX7219_DISPLAYTEST_REG (0x0F)
#define MAX7219_COLUMN_REG(pos) ((pos) + 1)

// shutdown mode (datasheet table 3)
#define MAX7219_OFF             (0x0)
#define MAX7219_ON              (0x1)

// pin 13 of MAX7219 (CLK)
const int clock_pin = 15;
// pin 12 of MAX7219 (LOAD)
const int data_latch_pin = 16;
// pin 1 of MAX7219 (DIN)
const int data_input_pin = 17;

// number of columns of the display matrx
#define NUM_OF_COLUMNS  (8)

// define the number of chained matrixes
#define NUM_OF_MATRIXES (5)

// matrix pattern for "Hello,LinkIt7697"
const byte char_pattern[] =
{
  B00000000, B00000000, B01111111, B00001000, B00001000, B01111111, // H
  B00000000, B00000000, B00111000, B01010100, B01010100, B00011000, // e
  B00000000, B00000000, B01000001, B01111111, B01000000, B00000000, // l
  B00000000, B00000000, B01000001, B01111111, B01000000, B00000000, // l
  B00000000, B00000000, B00111000, B01000100, B01000100, B00111000, // o
  B00000000, B00000000, B10110000, B01110000, B00000000, B00000000, // ,
  B00000000, B00000000, B01111111, B01000000, B01000000, B01000000, // L
  B00000000, B00000000, B01001000, B01111010, B01000000, B00000000, // i
  B00000000, B00000000, B01111100, B00000100, B00000100, B01111000, // n
  B00000000, B00000000, B01111111, B00010000, B00101000, B01000100, // k
  B00000000, B00000000, B01000001, B01111111, B01000001, B00000000, // I
  B00000000, B00000000, B00001000, B01111110, B01001000, B00000000, // t
  B00000000, B00000000, B01100001, B00010001, B00001001, B00000111, // 7
  B00000000, B00000000, B00111110, B01001001, B01001001, B00110000, // 6
  B00000000, B00000000, B00000110, B01001001, B01001001, B00111110, // 9
  B00000000, B00000000, B01100001, B00010001, B00001001, B00000111, // 7
  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000  // space
};

#define DISPLAY_COLUMN_LENGTH (sizeof(char_pattern))

// update a specific register value of all MAX7219s
void set_all_registers(byte address, byte value)
{
  digitalWrite(data_latch_pin, LOW);

  for (int i = 0; i < NUM_OF_MATRIXES; i++)
  {
    shiftOut(data_input_pin, clock_pin, MSBFIRST, address);
    shiftOut(data_input_pin, clock_pin, MSBFIRST, value);
  }
  
  digitalWrite(data_latch_pin, HIGH);
}

void clear_all_matrix()
{
  // clear the dot matrix
  for (int i = 0; i < NUM_OF_COLUMNS; i++)
  {
    set_all_registers(MAX7219_COLUMN_REG(i), B00000000);
  }
}

void init_all_max7219()
{
  // disable test mode. datasheet table 10
  set_all_registers(MAX7219_DISPLAYTEST_REG, MAX7219_OFF);
  // set medium intensity. datasheet table 7
  set_all_registers(MAX7219_INTENSITY_REG, 0x1);
  // turn off display. datasheet table 3
  set_all_registers(MAX7219_SHUTDOWN_REG, MAX7219_OFF);
  // drive 8 digits. datasheet table 8
  set_all_registers(MAX7219_SCANLIMIT_REG, 7);
  // no decode mode for all positions. datasheet table 4
  set_all_registers(MAX7219_DECODE_REG, B00000000);

  // clear matrix display
  clear_all_matrix();
}

void setup()  
{
  // init pin states
  pinMode(clock_pin, OUTPUT);
  pinMode(data_latch_pin, OUTPUT);    
  pinMode(data_input_pin, OUTPUT);

  // init MAX2719 states
  init_all_max7219();
}

unsigned int starting_column_index = 0;

void loop()  
{
  int i, j;
  int target_column;

  // turn off display first
  set_all_registers(MAX7219_SHUTDOWN_REG, MAX7219_OFF);
  
  // update all columns
  for (i = 0; i < NUM_OF_COLUMNS; i++)
  {
    digitalWrite(data_latch_pin, LOW);
    
    // update all matrixes
    for (j = NUM_OF_MATRIXES - 1; j >= 0; j--)
    {
      // jump to the correct column position for each matrix
      target_column = starting_column_index + NUM_OF_COLUMNS * j + i;
      //  make sure the target column is within the bitmap array
      target_column %= DISPLAY_COLUMN_LENGTH;
      
      shiftOut(data_input_pin, clock_pin, MSBFIRST, MAX7219_COLUMN_REG(i));
      shiftOut(data_input_pin, clock_pin, MSBFIRST, char_pattern[target_column]);
    }

    // latch the data pin to make the register data takes effect
    digitalWrite(data_latch_pin, HIGH);
  }
  
  // turn on display
  set_all_registers(MAX7219_SHUTDOWN_REG, MAX7219_ON);

  // step to the next column
  starting_column_index++;
  // go back to the first column of the string bitmap to be displayed
  if (starting_column_index >= DISPLAY_COLUMN_LENGTH)
  {
    starting_column_index = 0;
  }

  delay(200);
}

Explanation

When using MAX7219 with a dot matrix, the targets to be driven are columns, not digits. So we re-define the Digit data register to Column data register for better readability of the code:

#define MAX7219_COLUMN_REG(pos) MAX7219_DIGIT_REG(pos)

And some basic properties of the matrix and data to be displayed are defined:

// number of columns of the display matrx
#define NUM_OF_COLUMNS  (8)
// for each character bitmap, it consumes 4 bytes
#define BYTE_PER_MAP    (4)

// matrix pattern for "Hello,LinkIt7697"
const byte char_pattern[] =
{
  B01111111, B00001000, B00001000, B01111111,   // H
  B00111000, B01010100, B01010100, B00011000,   // e
  ...
  B00000000, B00000000, B00000000, B00000000    // space
};

#define DISPLAY_STR_LENGTH  (sizeof(char_pattern) / BYTE_PER_MAP)

Note

Because each character just occupies 4x8 dots, only those 4 columns are defined in the character bitmap pattern. For other columns of the 8x8 matrix, we simply leave it blank and not show contents on them.

To display a bitmap, MAX7219 needs to be set to non-decode (raw data) mode for all columns:

// no decode mode for all positions. datasheet table 4
set_register(MAX7219_DECODE_REG, B00000000);

and the code needs to update Column data registers for constructing a complete bitmap:

 // turn off display first
set_register(MAX7219_SHUTDOWN_REG, MAX7219_OFF);
 
// display one bitmap
for (i = 0; i < BYTE_PER_MAP; i++)
{
  // starting from column 2
  set_register(MAX7219_COLUMN_REG(2 + i), char_pattern[char_index * BYTE_PER_MAP + i]);
}
 
// turn on display
set_register(MAX7219_SHUTDOWN_REG, MAX7219_ON);

Due to a 4x8 bitmap is used on a 8x8 matrix, the code starts the updating position from column 2 to make the bitmap centered-aligned and updates data for BYTE_PER_MAP columns. Moreover, because 1 column consumes 1 byte data of the bitmap, when jumping to the next bitmap in the char_pattern array, the starting address of a different character would be a multiple of BYTE_PER_MAP.

Chained-matrix Example

MAX7219 supports to daisy-chain several MAX7219s to make one combined display. For chained MAX7219s, the data fed into the first IC would be output to the next IC after 16 cycles, which is the same cycle counts as the time consumed in sending one command. That's why it's called shift register: it takes 16 cycles to fill up the internal 16-bit data storage and starts to push bits out from the oldest bit in it when there are more data to be fed in. Therefore, for correctly sending commands to all chained MAX7219s, you need to send the command for the farthest node (from the main MCU) first and send the command for the nearest node last. Here is an illustrative animation for that:

In this video, 3 MAX7219s are used and it means total 16x3 = 48 cycles are needed to send commands to all MAX7219s. Initially, the LOAD pin is set to LOW and the command of node #2 (the farthest MAX7219) is sent in the first 16 cycles. For the next 16 cycles, the command of node #1 is sent and this makes the command of node #2 stored in node #0 pushed out and propagated to the next node. Finally, for the last 16 cycles, the command of node #0 is sent and the commands previously stored in node #0 and #1 are pushed to the final destination. After all commands are set to their correct position, the LOAD pin is set to HIGH and commands take effect for MAX7219 operations. This is the case where all MAX7219s need a new command and how the data flow is going. What if only one MAX7219 needs a new command and others don't need to change their states?

In the following chained-matrix example, we extend the previous 1-matrix example to a 5-matrix configuration. And use the No-Op command to display the same pattern on each 8x8 dot matrix sequentially as in the 1-matrix example:

Hardware Setup

The DOUT pin of each module is connected to the DIN pin on the next module. For rest of the pins, they are wiring to the counterpart on the next module.

Note

Make sure the power supply delivers sufficient 5V output when there are multiple display matrices chained together.

Based on the source of the 1-matrix example, some modifications are made to support the chained matrices. First, the No-Op command is defined:

#define MAX7219_NOOP_REG        (0x00)

And for updating commands to all chained MAX7219s, the set_register() API is extends to set_all_register() (all MAX7219 is set to the same command) and set_single_register() (only one MAX7219 receives a new command and others don't):

// update a specific register value of all MAX7219svoid set_all_registers(byte address, byte value){  digitalWrite(data_latch_pin, LOW);   for (int i = 0; i < NUM_OF_MATRIXES; i++)  {    shiftOut(data_input_pin, clock_pin, MSBFIRST, address);    shiftOut(data_input_pin, clock_pin, MSBFIRST, value);  }    digitalWrite(data_latch_pin, HIGH);} // only update the register in one MAX7219void set_single_register(int index, byte address, byte value){  // only process within valid index range  if (index >= 0 && index < NUM_OF_MATRIXES)  {    digitalWrite(data_latch_pin, LOW);     for (int i = NUM_OF_MATRIXES - 1; i >= 0; i--)    {      // for specified MAX7219, access the desired register      if (i == index)      {        shiftOut(data_input_pin, clock_pin, MSBFIRST, address);          }      else      {        // send No-Op operation to all other MAX7219s (the value is "don't-care" for No-Op command)        shiftOut(data_input_pin, clock_pin, MSBFIRST, MAX7219_NOOP_REG);      }            shiftOut(data_input_pin, clock_pin, MSBFIRST, value);    }      digitalWrite(data_latch_pin, HIGH);  }}

By using this 2 APIs to replace the set_register() API used in the 1-matrix example, the complete example is shown below:

//
// Use one MAX7219 to control 5 8x8 dot matrixes
// http://www.icshop.com.tw/product_info.php/products_id/13181
//
// MAX7219 datasheet: https://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf
//

// the MAX7219 address map (datasheet table 2)
#define MAX7219_DECODE_REG      (0x09)
#define MAX7219_INTENSITY_REG   (0x0A)
#define MAX7219_SCANLIMIT_REG   (0x0B)
#define MAX7219_SHUTDOWN_REG    (0X0C)
#define MAX7219_DISPLAYTEST_REG (0x0F)
#define MAX7219_DIGIT_REG(pos)  ((pos) + 1)
#define MAX7219_COLUMN_REG(pos) MAX7219_DIGIT_REG(pos)
#define MAX7219_NOOP_REG        (0x00)

// shutdown mode (datasheet table 3)
#define MAX7219_OFF             (0x0)
#define MAX7219_ON              (0x1)

// pin 13 of MAX7219 (CLK)
const int clock_pin = 15;
// pin 12 of MAX7219 (LOAD)
const int data_latch_pin = 16;
// pin 1 of MAX7219 (DIN)
const int data_input_pin = 17;

// number of columns of the display matrx
#define NUM_OF_COLUMNS  (8)
// for each character bitmap, it consumes 4 bytes
#define BYTE_PER_MAP    (4)
// define the number of chained matrixes
#define NUM_OF_MATRIXES (5)

// matrix pattern for "Hello,LinkIt7697"
const byte char_pattern[] =
{
  B01111111, B00001000, B00001000, B01111111,   // H
  B00111000, B01010100, B01010100, B00011000,   // e
  B01000001, B01111111, B01000000, B00000000,   // l
  B01000001, B01111111, B01000000, B00000000,   // l
  B00111000, B01000100, B01000100, B00111000,   // o
  B10110000, B01110000, B00000000, B00000000,   // ,
  B01111111, B01000000, B01000000, B01000000,   // L
  B01001000, B01111010, B01000000, B00000000,   // i
  B01111100, B00000100, B00000100, B01111000,   // n
  B01111111, B00010000, B00101000, B01000100,   // k
  B01000001, B01111111, B01000001, B00000000,   // I
  B00001000, B01111110, B01001000, B00000000,   // t
  B01100001, B00010001, B00001001, B00000111,   // 7
  B00111110, B01001001, B01001001, B00110000,   // 6
  B00000110, B01001001, B01001001, B00111110,   // 9
  B01100001, B00010001, B00001001, B00000111,   // 7
  B00000000, B00000000, B00000000, B00000000    // space
};

#define DISPLAY_STR_LENGTH  (sizeof(char_pattern) / BYTE_PER_MAP)

// update a specific register value of all MAX7219s
void set_all_registers(byte address, byte value)
{
  digitalWrite(data_latch_pin, LOW);

  for (int i = 0; i < NUM_OF_MATRIXES; i++)
  {
    shiftOut(data_input_pin, clock_pin, MSBFIRST, address);
    shiftOut(data_input_pin, clock_pin, MSBFIRST, value);
  }
  
  digitalWrite(data_latch_pin, HIGH);
}

// only update the register in one MAX7219
void set_single_register(int index, byte address, byte value)
{
  // only process for valid index range
  if (index >= 0 && index < NUM_OF_MATRIXES)
  {
    digitalWrite(data_latch_pin, LOW);

    for (int i = NUM_OF_MATRIXES - 1; i >= 0; i--)
    {
      // for specified MAX7219, access the desired register
      if (i == index)
      {
        shiftOut(data_input_pin, clock_pin, MSBFIRST, address);
    
      }
      else
      {
        // send No-Op operation to all other MAX7219s (the value is "don't-care" for No-Op command)
        shiftOut(data_input_pin, clock_pin, MSBFIRST, MAX7219_NOOP_REG);
      }
      
      shiftOut(data_input_pin, clock_pin, MSBFIRST, value);
    }
  
    digitalWrite(data_latch_pin, HIGH);
  }
}

void clear_matrix()
{
  // clear the dot matrix
  for (int i = 0; i < NUM_OF_COLUMNS; i++)
  {
    set_all_registers(MAX7219_COLUMN_REG(i), B00000000);
  }
}

void init_max7219()
{
  // disable test mode. datasheet table 10
  set_all_registers(MAX7219_DISPLAYTEST_REG, MAX7219_OFF);
  // set medium intensity. datasheet table 7
  set_all_registers(MAX7219_INTENSITY_REG, 0x1);
  // turn off display. datasheet table 3
  set_all_registers(MAX7219_SHUTDOWN_REG, MAX7219_OFF);
  // drive 8 digits. datasheet table 8
  set_all_registers(MAX7219_SCANLIMIT_REG, 7);
  // no decode mode for all positions. datasheet table 4
  set_all_registers(MAX7219_DECODE_REG, B00000000);

  // clear matrix display
  clear_matrix();
}

void setup()  
{
  // init pin states
  pinMode(clock_pin, OUTPUT);
  pinMode(data_latch_pin, OUTPUT);    
  pinMode(data_input_pin, OUTPUT);

  // init MAX2719 states
  init_max7219();
}

unsigned int char_index = 0;
unsigned int matrix_index = 0;

void loop()  
{
  int i;
  
  // turn off display first
  set_all_registers(MAX7219_SHUTDOWN_REG, MAX7219_OFF);

  // display one bitmap
  for (i = 0; i < BYTE_PER_MAP; i++)
  { 
    // starting from column 2
    set_single_register(matrix_index, MAX7219_COLUMN_REG(2 + i), char_pattern[char_index * BYTE_PER_MAP + i]);
  }

  // turn on display
  set_all_registers(MAX7219_SHUTDOWN_REG, MAX7219_ON);

  // step to the next character
  char_index++;
  // wrap around the character if needed
  if (char_index >= DISPLAY_STR_LENGTH)
  {
    char_index = 0;

    // move to the next matrix
    matrix_index++;

    if (matrix_index >= NUM_OF_MATRIXES)
    {
      clear_matrix();
      matrix_index = 0;
    }
  }
  
  delay(400);
}

This example uses 5-matrix configuration and you can use a different number of matrices to run this example by modifying the definition in Line 34:

// define the number of chained matrixes
#define NUM_OF_MATRIXES (5)

Recap

  • For commands applied to all MAX7219s, use the set_all_registers() API. Like the case in init_max7219() and clear_matrix().

  • For commands only applied to a specific MAX7219, use the set_single_register() API. It will keeps rest of the matrices un-touched.

Scrolling-string Example

With the basics mentioned above, the last example is further extended to give a demonstration about how to use 5 matrices to do a commonly-seen scrolling string effect:

The complete sketch codes of this example are:

//
// Use multiple 8x8 dot matrix modules to display a marquee string
// http://www.icshop.com.tw/product_info.php/products_id/13181
//
// MAX7219 datasheet: https://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf
//

// the MAX7219 address map (datasheet table 2)
#define MAX7219_DECODE_REG      (0x09)
#define MAX7219_INTENSITY_REG   (0x0A)
#define MAX7219_SCANLIMIT_REG   (0x0B)
#define MAX7219_SHUTDOWN_REG    (0X0C)
#define MAX7219_DISPLAYTEST_REG (0x0F)
#define MAX7219_COLUMN_REG(pos) ((pos) + 1)

// shutdown mode (datasheet table 3)
#define MAX7219_OFF             (0x0)
#define MAX7219_ON              (0x1)

// pin 13 of MAX7219 (CLK)
const int clock_pin = 15;
// pin 12 of MAX7219 (LOAD)
const int data_latch_pin = 16;
// pin 1 of MAX7219 (DIN)
const int data_input_pin = 17;

// number of columns of the display matrx
#define NUM_OF_COLUMNS  (8)

// define the number of chained matrixes
#define NUM_OF_MATRIXES (5)

// matrix pattern for "Hello,LinkIt7697"
const byte char_pattern[] =
{
  B00000000, B00000000, B01111111, B00001000, B00001000, B01111111, // H
  B00000000, B00000000, B00111000, B01010100, B01010100, B00011000, // e
  B00000000, B00000000, B01000001, B01111111, B01000000, B00000000, // l
  B00000000, B00000000, B01000001, B01111111, B01000000, B00000000, // l
  B00000000, B00000000, B00111000, B01000100, B01000100, B00111000, // o
  B00000000, B00000000, B10110000, B01110000, B00000000, B00000000, // ,
  B00000000, B00000000, B01111111, B01000000, B01000000, B01000000, // L
  B00000000, B00000000, B01001000, B01111010, B01000000, B00000000, // i
  B00000000, B00000000, B01111100, B00000100, B00000100, B01111000, // n
  B00000000, B00000000, B01111111, B00010000, B00101000, B01000100, // k
  B00000000, B00000000, B01000001, B01111111, B01000001, B00000000, // I
  B00000000, B00000000, B00001000, B01111110, B01001000, B00000000, // t
  B00000000, B00000000, B01100001, B00010001, B00001001, B00000111, // 7
  B00000000, B00000000, B00111110, B01001001, B01001001, B00110000, // 6
  B00000000, B00000000, B00000110, B01001001, B01001001, B00111110, // 9
  B00000000, B00000000, B01100001, B00010001, B00001001, B00000111, // 7
  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000  // space
};

#define DISPLAY_COLUMN_LENGTH (sizeof(char_pattern))

// update a specific register value of all MAX7219s
void set_all_registers(byte address, byte value)
{
  digitalWrite(data_latch_pin, LOW);

  for (int i = 0; i < NUM_OF_MATRIXES; i++)
  {
    shiftOut(data_input_pin, clock_pin, MSBFIRST, address);
    shiftOut(data_input_pin, clock_pin, MSBFIRST, value);
  }
  
  digitalWrite(data_latch_pin, HIGH);
}

void clear_all_matrix()
{
  // clear the dot matrix
  for (int i = 0; i < NUM_OF_COLUMNS; i++)
  {
    set_all_registers(MAX7219_COLUMN_REG(i), B00000000);
  }
}

void init_all_max7219()
{
  // disable test mode. datasheet table 10
  set_all_registers(MAX7219_DISPLAYTEST_REG, MAX7219_OFF);
  // set medium intensity. datasheet table 7
  set_all_registers(MAX7219_INTENSITY_REG, 0x1);
  // turn off display. datasheet table 3
  set_all_registers(MAX7219_SHUTDOWN_REG, MAX7219_OFF);
  // drive 8 digits. datasheet table 8
  set_all_registers(MAX7219_SCANLIMIT_REG, 7);
  // no decode mode for all positions. datasheet table 4
  set_all_registers(MAX7219_DECODE_REG, B00000000);

  // clear matrix display
  clear_all_matrix();
}

void setup()  
{
  // init pin states
  pinMode(clock_pin, OUTPUT);
  pinMode(data_latch_pin, OUTPUT);    
  pinMode(data_input_pin, OUTPUT);

  // init MAX2719 states
  init_all_max7219();
}

unsigned int starting_column_index = 0;

void loop()  
{
  int i, j;
  int target_column;

  // turn off display first
  set_all_registers(MAX7219_SHUTDOWN_REG, MAX7219_OFF);
  
  // update all columns
  for (i = 0; i < NUM_OF_COLUMNS; i++)
  {
    digitalWrite(data_latch_pin, LOW);
    
    // update all matrixes
    for (j = NUM_OF_MATRIXES - 1; j >= 0; j--)
    {
      // jump to the correct column position for each matrix
      target_column = starting_column_index + NUM_OF_COLUMNS * j + i;
      //  make sure the target column is within the bitmap array
      target_column %= DISPLAY_COLUMN_LENGTH;
      
      shiftOut(data_input_pin, clock_pin, MSBFIRST, MAX7219_COLUMN_REG(i));
      shiftOut(data_input_pin, clock_pin, MSBFIRST, char_pattern[target_column]);
    }

    // latch the data pin to make the register data takes effect
    digitalWrite(data_latch_pin, HIGH);
  }
  
  // turn on display
  set_all_registers(MAX7219_SHUTDOWN_REG, MAX7219_ON);

  // step to the next column
  starting_column_index++;
  // go back to the first column of the string bitmap to be displayed
  if (starting_column_index >= DISPLAY_COLUMN_LENGTH)
  {
    starting_column_index = 0;
  }

  delay(200);
}

Summary

The source codes are based on the and we modify it for working with the dot matrix:

There is a special register called No-Op register with address 0 (ref: table 2 in the ) is defined in MAX7219. When the LOAD pin is set to HIGH and MAX7219 receives a No-Op command, it will do nothing and its internal states won't be changed. Here we show another animation which deals with this case: only node #1 takes a new command and rest of the nodes on the chain keep un-touched.

Accompanying with the previous , this tutorial gives a complete view of different MAX7219 applications. Not only to dive 7-segment displays, the non-decode mode can also be used to drive multiple LEDs or a LED matrix. By using a shift register like MAX7219, the control and wiring complexities of building a LED display application can be greatly reduced.

previous tutorial of MAX7219
datasheet
7-segment display tutorial
drive 7-segment displays
8x8 dot matrix module
Mapping 7-segment Display to 8x8 Dot Matrix
Hardware Setup
1-matrix Example
Chained-matrix Example
Scrolling-string Example
Summary
the previous tutorial
MAX7219 tutorial