> For the complete documentation index, see [llms.txt](https://cavedu.gitbook.io/linkit-7697/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cavedu.gitbook.io/linkit-7697/linkit-7697-arduinoide/zhou-bian-yuan-jian-lian-jie-jiao-xue/shi-yong-max7219-qu-dong-qi-duan-xian-shi-qi.md).

# 使用 MAX7219 驅動七段顯示器

在前一篇教學裡，介紹了如何利用 74HC595 shift register 驅動七段顯示器的基本概念。在接下來的文章中，將會說明如何使用另一顆 LED 驅動 IC：MAX7219，來驅動七段顯示器 (最高支援八個七段顯示器；換句話說，相當於同時驅動 64 顆 LED)。藉由修改 74HC595 教學範例的程式，使 LinkIt 7697 得以使用[八位數七段顯示器模組](https://robotkingdom.com.tw/product/%e5%85%ab%e4%bd%8d%e6%95%b8%e4%b8%83%e6%ae%b5%e9%a1%af%e7%a4%ba%e5%99%a8-595%e9%a9%85%e5%8b%95/) (內建 MAX7219)，並透過這個過程讓開發者了解 MAX7219 的主要功能及運作機制。

### 目錄 <a href="#driving7segmentdisplayswithmax7219-mu-lu" id="driving7segmentdisplayswithmax7219-mu-lu"></a>

* 目錄
* 指令格式
* 硬體接線
* 暫存器定義
  * Decode Mode (0x09)
  * Digit 0 \~ Digit 7 data (0x01 \~ 0x08)
  * Intensity (0x0A)
  * Scan Limit (0x0B)
  * Shutdown (0x0C)
  * Display Test (0x0F)
* 範例：顯示遞增數值
* 結論

### 指令格式 <a href="#driving7segmentdisplayswithmax7219-zhi-ling-ge-shi" id="driving7segmentdisplayswithmax7219-zhi-ling-ge-shi"></a>

在深入解析 MAX7219 前，第一步要先了解如何與 MAX7219 溝通。執行任何一項 MAX7219 的功能時，都需要對它發出指令，待 MAX7219 收到指令後，它會依指令更新其內部暫存器的值、進而觸發動作。指令格式為固定 16-bit 長度的「暫存器位址 / 資料數值」組合，各個位元的定義如下 (X 表示可為任意值)：

![](/files/56mrt7NZ0BdWBY2MqbZv)

發送指令的方式為：拉低 **LOAD** 訊號、在 **CLK** 訊號打 16 個時脈的過程中，透過 **DIN** 腳位依序把 16-bit 的指令送進 MAX7219，送完後拉高 **LOAD** 訊號即完成一筆指令的傳輸。對應的時序圖示意為：

![](/files/cEafGAzVrXIYxeqciDGZ)

透過使用 [shiftOut()](https://www.arduino.cc/en/Reference/ShiftOut) API 產生時脈訊號及傳送資料，在 Arduino 裡的實作如下：

```
// define pins used on LinkIt 7697
// 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;
 
// update the register value of MAX7219
void set_register(byte address, byte value)  
{
  digitalWrite(data_latch_pin, LOW);
  shiftOut(data_input_pin, clock_pin, MSBFIRST, address);
  shiftOut(data_input_pin, clock_pin, MSBFIRST, value);
  digitalWrite(data_latch_pin, HIGH);
}
```

### 硬體接線 <a href="#driving7segmentdisplayswithmax7219-ying-ti-jie-xian" id="driving7segmentdisplayswithmax7219-ying-ti-jie-xian"></a>

LinkIt 7697 透過下列腳位與八位數顯示器模組相連：

* 5V
* GND
* P15
* P16
* P17

該五隻腳位分別接到顯示模組上的：

* VCC
* GND
* CLK
* CS (即 MAX7219 的 LOAD 腳位)
* DIN

接線示意圖為：

![](/files/mnycnSY6opFMfOferEW0)

{% hint style="danger" %}
顯示模組需使用 5V 電源輸入，若僅供給 3.3V 則顯示器亮度會受到影響。
{% endhint %}

### 暫存器定義 <a href="#driving7segmentdisplayswithmax7219-zan-cun-qi-ding-yi" id="driving7segmentdisplayswithmax7219-zan-cun-qi-ding-yi"></a>

要順利驅動 MAX7219，需正確設定對應的暫存器。在此範例中，開發者需要設定下列六類型的暫存器：

| 暫存器名稱                   | 位址           | 說明                         |
| ----------------------- | ------------ | -------------------------- |
| Decode Mode             | 0x09         | 開啟 / 關閉 decode 模式          |
| Intensity               | 0x0A         | 調整顯示器亮度                    |
| Scan Limit              | 0x0B         | 設定欲啟動的顯示器數目                |
| Shutdown                | 0x0C         | 開啟 / 關閉顯示模組                |
| Display Test            | 0x0F         | 開啟 / 關閉測試模式 (顯示器的所有筆畫皆會亮起) |
| Digit 0 \~ Digit 7 data | 0x01 \~ 0x08 | 控制位數 0 到位數 7 的顯示資料         |

在 Arduino 範例程式裡將它們定義為：

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

針對各個暫存器，對應的操作說明及範例如下：

#### Decode Mode (0x09) <a href="#driving7-segmentdisplayswithmax7219-decodemode-0x09" id="driving7-segmentdisplayswithmax7219-decodemode-0x09"></a>

MAX7219 針對每個顯示器，皆分別支援兩種資料顯示模式：1) 原始資料模式 2) BCD 碼模式。例如：

```
set_register(MAX7219_DECODE_REG, B00011010);
```

此例中，位元 1、3、4 被設為 **1**，因此表示位數 1、位數 3、位數 4 被設定為 **BCD 碼 decode 模式**。而剩下的位數 0 / 2 / 5 / 6 / 7 則為**原始資料模式**。

#### Digit 0 \~ Digit 7 data (0x01 \~ 0x08) <a href="#driving7-segmentdisplayswithmax7219-digit0-digit7data-0x01-0x08" id="driving7-segmentdisplayswithmax7219-digit0-digit7data-0x01-0x08"></a>

在**原始資料模式**中，開發者需自行指定七段顯示器中每個筆畫的明滅資訊，就如同 74HC595 教學中提及的一樣。

![](/files/QSYqZqZe56S94BAYzja2)

舉例來說，若開發者想在位數 **3** 顯示數字 "7"，表示七段顯示器的筆畫 "A"、"B"、"C" (參考上圖) 需要被開啟；對應到暫存器的值，即 Digit 3 暫存器的第 4、5、6 個位元 (上圖表格) 需設定為 1：

```
set_register(MAX7219_DIGIT_REG(3), B01110000);
```

雖然在原始資料模式中指定筆畫的方式較為複雜，但它提供了開發者顯示各種圖形組合的彈性：

![](/files/2jzrRbWeZpWNztZ3Drcg)

除了原始資料模式外，MAX7219 還提供了另一種叫做 **BCD 碼 decode 模式**的操作方法。在 **decode 模**式下，每個字的筆畫構成已被事先定義、並依照 BCD 碼 B 區 (見下表) 的規範儲存在 MAX7219 當中。因此要顯示這些字時，僅需提供每個字所對應的索引編號即可。

&#x20;![](/files/VW9ogG44ClPkwmT0M0Iu)

**\*不論在原始資料模式或是 decode 模式中，若要顯示小數點，都需自行將 Digit 暫存器的第 7 位元 (D7) 設成 1。**

也就是說，若開發者要顯示數字 "0" 到 "9"、"-"、"E"、"H"、"L"、"P" 及 " " (空格) 這十六種字元，在 decode 模式下，不需自行傳送筆畫定義資訊給 MAX7219、直接給 MAX7219 字元的索引值即可。例如，要使用 decode 模式在位數 5 顯示子母 "E"，則需把 Decode Mode 暫存器的 D5 設成 1，接著把 Digit 5 data 暫存器設為 11 (也就是二進位的 B1011，見上表定義)，就可以讓顯示器顯示出字母 "E"。對應的程式碼如下：

```
// Make Digit 5 is under BCD Code B decode mode
set_register(MAX7219_DECODE_REG, B00100000);
// Make it display character "E"
set_register(MAX7219_DIGIT_REG(5), 11);
```

#### Intensity (0x0A) <a href="#driving7-segmentdisplayswithmax7219-intensity-0x0a" id="driving7-segmentdisplayswithmax7219-intensity-0x0a"></a>

調整 LED 顯示器的亮度。值域範圍為 0x0 (最暗) 到 0xF (最亮)。

```
// Dimmest
set_register(MAX7219_INTENSITY_REG, 0x0);
// Brightest
set_register(MAX7219_INTENSITY_REG, 0xF);
```

#### Scan Limit (0x0B) <a href="#driving7-segmentdisplayswithmax7219-scanlimit-0x0b" id="driving7-segmentdisplayswithmax7219-scanlimit-0x0b"></a>

設定模組上要開啟的顯示器個數 (即顯示位數)。下面分別為開啟一個位數、五個位數、以及八位數全開的範例：

```
// Only Digit 0 are turned on
set_register(MAX7219_SCANLIMIT_REG, 0);
// Only Digit 0 ~ Digit 4 are turned on
set_register(MAX7219_SCANLIMIT_REG, 4);
// All digits (Digit 0 ~ Digit 7) are turned on
set_register(MAX7219_SCANLIMIT_REG, 7);
```

#### Shutdown (0x0C) <a href="#driving7-segmentdisplayswithmax7219-shutdown-0x0c" id="driving7-segmentdisplayswithmax7219-shutdown-0x0c"></a>

開啟 / 關閉顯示器模組。

```
#define MAX7219_OFF (0x0)
#define MAX7219_ON  (0x1)

// Turn off the display
set_register(MAX7219_SHUTDOWN_REG, MAX7219_OFF);
// Turn on the display
set_register(MAX7219_SHUTDOWN_REG, MAX7219_ON);
```

#### Display Test (0x0F) <a href="#driving7-segmentdisplayswithmax7219-displaytest-0x0f" id="driving7-segmentdisplayswithmax7219-displaytest-0x0f"></a>

開啟 / 關閉測試模式。開啟此模式時，顯示器的所有筆畫都會亮起。

```
// Enter test mode. No matter what data bytes of each digit register are, all display segments are on
set_register(MAX7219_DISPLAYTEST_REG, MAX7219_ON);
// Non-test mode. Display segments according to the data byte and decode mode for each digit
set_register(MAX7219_DISPLAYTEST_REG, MAX7219_OFF);
```

### 範例：顯示遞增數值 <a href="#driving7segmentdisplayswithmax7219-fan-li-xian-shi-di-zeng-shu-zhi" id="driving7segmentdisplayswithmax7219-fan-li-xian-shi-di-zeng-shu-zhi"></a>

結合上述的暫存器說明並修改之前的 74HC595 範例，下列的 Arduino sketch 展示了如何在八位數七段顯示器模組上顯示遞增數值 (及小數點移動) 的效果。

{% embed url="<https://youtu.be/-LImaR1HjwU>" %}

```
//
// Use one MAX7219 to control 8-digit seven-segment display
// the display module: http://www.icshop.com.tw/product_info.php/products_id/20686
//
// 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)

// 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;

// digit pattern for a 7-segment display. datasheet table 5
const byte digit_pattern[16] =
{
  B01111110,  // 0
  B00110000,  // 1
  B01101101,  // 2
  B01111001,  // 3
  B00110011,  // 4
  B01011011,  // 5
  B01011111,  // 6
  B01110000,  // 7
  B01111111,  // 8
  B01111011,  // 9
  B01110111,  // A
  B00011111,  // b
  B01001110,  // C
  B00111101,  // d
  B01001111,  // E
  B01000111   // F
};

#define DP_FLAG       (B10000000)
#define NUM_OF_DIGITS (8)

unsigned int counter = 0;
unsigned int digit_base = 16;

// update the register value of MAX7219
void set_register(byte address, byte value)  
{
  digitalWrite(data_latch_pin, LOW);
  shiftOut(data_input_pin, clock_pin, MSBFIRST, address);
  shiftOut(data_input_pin, clock_pin, MSBFIRST, value);
  digitalWrite(data_latch_pin, HIGH);
}

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

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

  // init MAX2719 states
  init_max7219();
}

void loop()  
{
  int i;
  unsigned int number;
  unsigned int digit_value;
  byte byte_data;
  
  number = counter++;
  
  // turn off display first
  set_register(MAX7219_SHUTDOWN_REG, MAX7219_OFF);

  // get every values in each position of those 8 digits based on "digit_base"
  //
  // digit_base should be <= 16
  //
  // for example, if digit_base := 2, binary values will be shown. If digit_base := 16, hexidecimal values will be shown
  //
  for (i = 0; i < NUM_OF_DIGITS; i++)
  {
    digit_value = number % digit_base;
    number /= digit_base;

    byte_data = digit_pattern[digit_value];

    if (counter % NUM_OF_DIGITS == i)
    {
      byte_data |= DP_FLAG;
    }

    set_register(MAX7219_DIGIT_REG(i), byte_data);
  }

  // turn on display
  set_register(MAX7219_SHUTDOWN_REG, MAX7219_ON);
  
  delay(50);
}
```

此範例的基本配置如下：

* 以十六進位遞增數值。
* 使用**原始資料模式**定義字元筆畫，
* 使用中等顯示亮度。

可透過一些修改進行顯示效果的改變。例如，要從原本的 16 進位數值變為 10 進位 / 8 進位 / 2 進位模式時，可修改**第 52 行**的 *digit\_base* 將之設定為 10、8 或是 2。下面的程式碼為修改成 10 進位的範例：

```
// change the counting mode to decimal mode
unsigned int digit_base = 10;
```

若要將資料解讀模式從**原始資料模式**改為 **BCD 碼 decode 模式**，則需要修改兩個地方。首先在**第 74 行**將八個顯示器都設定為 decode 模式：

```
// enable decode mode for all positions. datasheet table 4
set_register(MAX7219_DECODE_REG, B11111111);
```

接著在**第 111 行**，將送進 MAX7219 的資料從筆畫資訊改為索引索引值：

```
digit_value = number % digit_base;
number /= digit_base;
// no need to get the raw segment patterns. use the value directly to index the BCD code
byte_data = digit_value; // byte_data = digit_pattern[digit_value];
```

### 結論 <a href="#driving7segmentdisplayswithmax7219-jie-lun" id="driving7segmentdisplayswithmax7219-jie-lun"></a>

透過本教學的內容，開發者可了解 MAX7219 的使用方法。雖然 MAX7219 的主要功能為驅動七段顯示器，但它也可用於其他的 LED 驅動場景。例如 [8x8 矩陣式顯示器](https://robotkingdom.com.tw/product/max7219dotmatrix/)就是另一種常見的 MAX7219 應用：利用**原始資料模式**的設定方法來控制矩陣式顯示器。詳細的原理及做法，將會在下一篇教學裡進行詳細介紹。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://cavedu.gitbook.io/linkit-7697/linkit-7697-arduinoide/zhou-bian-yuan-jian-lian-jie-jiao-xue/shi-yong-max7219-qu-dong-qi-duan-xian-shi-qi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
