在前一篇教學裡,介紹了如何利用 74HC595 shift register 驅動七段顯示器的基本概念。在接下來的文章中,將會說明如何使用另一顆 LED 驅動 IC:MAX7219,來驅動七段顯示器 (最高支援八個七段顯示器;換句話說,相當於同時驅動 64 顆 LED)。藉由修改 74HC595 教學範例的程式,使 LinkIt 7697 得以使用八位數七段顯示器模組 (內建 MAX7219),並透過這個過程讓開發者了解 MAX7219 的主要功能及運作機制。
目錄
暫存器定義
Digit 0 ~ Digit 7 data (0x01 ~ 0x08)
指令格式
在深入解析 MAX7219 前,第一步要先了解如何與 MAX7219 溝通。執行任何一項 MAX7219 的功能時,都需要對它發出指令,待 MAX7219 收到指令後,它會依指令更新其內部暫存器的值、進而觸發動作。指令格式為固定 16-bit 長度的「暫存器位址 / 資料數值」組合,各個位元的定義如下 (X 表示可為任意值):
發送指令的方式為:拉低 LOAD 訊號、在 CLK 訊號打 16 個時脈的過程中,透過 DIN 腳位依序把 16-bit 的指令送進 MAX7219,送完後拉高 LOAD 訊號即完成一筆指令的傳輸。對應的時序圖示意為:
透過使用 shiftOut() API 產生時脈訊號及傳送資料,在 Arduino 裡的實作如下:
Copy // 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);
}
硬體接線
LinkIt 7697 透過下列腳位與八位數顯示器模組相連:
該五隻腳位分別接到顯示模組上的:
接線示意圖為:
顯示模組需使用 5V 電源輸入,若僅供給 3.3V 則顯示器亮度會受到影響。
暫存器定義
要順利驅動 MAX7219,需正確設定對應的暫存器。在此範例中,開發者需要設定下列六類型的暫存器:
開啟 / 關閉測試模式 (顯示器的所有筆畫皆會亮起)
在 Arduino 範例程式裡將它們定義為:
Copy // 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)
MAX7219 針對每個顯示器,皆分別支援兩種資料顯示模式:1) 原始資料模式 2) BCD 碼模式。例如:
Copy 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)
在原始資料模式 中,開發者需自行指定七段顯示器中每個筆畫的明滅資訊,就如同 74HC595 教學中提及的一樣。
舉例來說,若開發者想在位數 3 顯示數字 "7",表示七段顯示器的筆畫 "A"、"B"、"C" (參考上圖) 需要被開啟;對應到暫存器的值,即 Digit 3 暫存器的第 4、5、6 個位元 (上圖表格) 需設定為 1:
Copy set_register(MAX7219_DIGIT_REG(3), B01110000);
雖然在原始資料模式中指定筆畫的方式較為複雜,但它提供了開發者顯示各種圖形組合的彈性:
除了原始資料模式外,MAX7219 還提供了另一種叫做 BCD 碼 decode 模式 的操作方法。在 decode 模 式下,每個字的筆畫構成已被事先定義、並依照 BCD 碼 B 區 (見下表) 的規範儲存在 MAX7219 當中。因此要顯示這些字時,僅需提供每個字所對應的索引編號即可。
*不論在原始資料模式或是 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"。對應的程式碼如下:
Copy // 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)
調整 LED 顯示器的亮度。值域範圍為 0x0 (最暗) 到 0xF (最亮)。
Copy // Dimmest
set_register(MAX7219_INTENSITY_REG, 0x0);
// Brightest
set_register(MAX7219_INTENSITY_REG, 0xF);
Scan Limit (0x0B)
設定模組上要開啟的顯示器個數 (即顯示位數)。下面分別為開啟一個位數、五個位數、以及八位數全開的範例:
Copy // 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)
開啟 / 關閉顯示器模組。
Copy #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)
開啟 / 關閉測試模式。開啟此模式時,顯示器的所有筆畫都會亮起。
Copy // 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);
範例:顯示遞增數值
結合上述的暫存器說明並修改之前的 74HC595 範例,下列的 Arduino sketch 展示了如何在八位數七段顯示器模組上顯示遞增數值 (及小數點移動) 的效果。
Copy //
// 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 進位的範例:
Copy // change the counting mode to decimal mode
unsigned int digit_base = 10;
若要將資料解讀模式從原始資料模式 改為 BCD 碼 decode 模式 ,則需要修改兩個地方。首先在第 74 行 將八個顯示器都設定為 decode 模式:
Copy // enable decode mode for all positions. datasheet table 4
set_register(MAX7219_DECODE_REG, B11111111);
接著在第 111 行 ,將送進 MAX7219 的資料從筆畫資訊改為索引索引值:
Copy 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];
結論
透過本教學的內容,開發者可了解 MAX7219 的使用方法。雖然 MAX7219 的主要功能為驅動七段顯示器,但它也可用於其他的 LED 驅動場景。例如 8x8 矩陣式顯示器 就是另一種常見的 MAX7219 應用:利用原始資料模式 的設定方法來控制矩陣式顯示器。詳細的原理及做法,將會在下一篇教學裡進行詳細介紹。