使用 MAX7219 驅動 8x8 矩陣式顯示器
Last updated
Last updated
除了用於驅動七段顯示器,MAX7219 另一種常見的應用為驅動 8x8 矩陣式 LED 顯示器。此教學文章將介紹如何使用單顆 MAX7219 驅動 8x8 矩陣式顯示器,以及如何串聯 (daisy-chain) 數個 MAX7219 以驅動多個 8x8 顯示矩陣。為了降低電路複雜度,本文使用 8x8 矩陣式顯示模組 (內建 MAX7219) 作為範例使用元件。
目錄
七段顯示器與矩陣顯示器的對應關係
硬體接線
範例一:使用單個顯示器
範例二:串連多個顯示器
範例三:字串跑馬燈
結論
雖然七段顯示器與 8x8 矩陣式顯示器在外型上有極大的差異,但本質上兩者是相同的東西:皆為內含多顆 LED 的顯示裝置。一個七段顯示器含有 8 顆 LED (筆畫部分使用 7 顆 LED、小數點使用 1 顆 LED),而且根據之前的教學,得知 MAX7219 可同時驅動 8 組七段顯示器,也就是說,MAX7219 最多可驅動 8x8 = 64 顆 LED,而這個數字,正好就是 8x8 矩陣式顯示器內所具有的 LED 數目。因此,讓 MAX7219 以原始資料模式運作,即可用於驅動 8x8 矩陣顯示器。所以,如何將七段顯示器對應至矩陣顯示器?接下來的文章將以實際範例搭配對應程式碼進行說明。
上圖為矩陣顯示器的示意圖。當使用 MAX7219 的原始資料模式時 (若不熟悉 MAX7219 運作模式,可參考之前的教學範例),矩陣顯示器的每個欄位可對應到一個 Digit 暫存器,也就是說,第 0 欄對應到 Digit 0、第 1 欄對應到 Digit 1... 以此類推。而矩陣的每一列則對應到七段顯示器中的不同筆畫,從顯示器最上方開始,第 0 列對應到 Digit 暫存器資料的第 0 個位元 (LSB)、第 1 列對應到 Digit 暫存器的第 1 個位元... 依序下去,直到第 7 列對應到 Digit 暫存器的 MSB (第 7 位元)。以實際範例說明,例如要在矩陣顯示器上顯示數字 "7" 的圖像:
根據圖上的位元資訊,可知 "7" 的點陣圖樣可被表示為:
const byte bitmap_7[] =
{
// define the dot pattern from column 0 ~ column 7
B00000000, B00000000, B01100001, B00010001, B00001001, B00000111, B00000000, B00000000
};
而這些資訊就是後續會送進 Digit 暫存器作為顯示用的原始資料。
硬體接線
需使用 LinkIt 7697 的下列五隻腳位:
5V
GND
P15
P16
P17
分別將它們連接至顯示模組上的:
VCC
GND
CLK
CS
DIN
接線示意圖如下:
第一個範例將依照前面章節介紹的點陣圖定義方式,在單個 8x8 矩陣式顯示器上顯示不同字元。下面的 sketch 程式碼會驅動顯示器顯示 "Hello, LinkIt7697" 字樣,並呈現如同影片中的效果:
這段程式碼是以之前七段顯示器教學的 sketch 為基礎,修改為驅動矩陣顯示器的版本:
//
// Use one MAX7219 to control a 8x8 dot matrix
// 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)
// 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)
// 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 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 clear_matrix()
{
// clear the dot matrix
for (int i = 0; i < NUM_OF_COLUMNS; i++)
{
set_register(MAX7219_COLUMN_REG(i), B00000000);
}
}
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, 0x1);
// 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);
// 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;
void loop()
{
int i;
// 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);
// step to the next character
char_index++;
// wrap around the character if needed
if (char_index >= DISPLAY_STR_LENGTH)
{
char_index = 0;
}
delay(666);
}
不同於七段顯示器,當使用 MAX7219 驅動矩陣式顯示器時,程式所要控制的是每個「欄位」的內容、而非每個「數字」的內容。所以為了增加可讀性,程式中將 Digit 暫存器的名稱改為 Column 暫存器:
#define MAX7219_COLUMN_REG(pos) MAX7219_DIGIT_REG(pos)
並定義顯示器及圖形等相關基本參數:
// 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)
注意
由於每個字元只使用 4x8 個像素,所以定義點陣圖資訊時,只定義了其中 4 個欄位,其他欄位則保持空白、不顯示任何東西。
為了顯示自訂的點陣圖,MAX7219 需將每個 Column 暫存器皆設定為以原始資料模式運作:
// no decode mode for all positions. datasheet table 4set_register(MAX7219_DECODE_REG, B00000000);
接著依序將點陣圖資訊送進各個 Column 暫存器,進而組成欲顯示的圖形:
// turn off display firstset_register(MAX7219_SHUTDOWN_REG, MAX7219_OFF); // display one bitmapfor (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 displayset_register(MAX7219_SHUTDOWN_REG, MAX7219_ON);
由於只使用 8x8 矩陣中的 4x8 點陣範圍 (並置中顯示),所以程式碼從顯示器的第 2 欄開始更新暫存器資訊,並且一共更新 BYTE_PER_MAP 個欄位。此外,由於顯示器「每一欄」的內容對應到點陣圖資料的「一個 byte」,因此 char_pattern 陣列中每張點陣圖的起始位置,都會是以 BYTE_PER_MAP 為倍數間隔開來。
MAX7219 支援以串連模式 (daisy-chain) 連接數個 MAX7219 以驅動多個顯示器。當多個 MAX7219 IC 串連在一起時,送進第一顆 IC 的資料會在 16 個時脈訊號 (cycle) 後輸出至下一顆 IC;這個數字剛好與 MAX7219 收取一筆指令所花費的時間相同,因此這也是為何 MAX7219 被稱作為 shift register 的原因:當 IC 本身花 16 個時脈訊號的時間、將資料收進內部的 16-bit 儲存空間後,若還有更多的資料持續送進來,則 IC 會依「先進先出」的順序,開始將內部的 16-bit 資料以 bit 為單位往外輸出。所以,當欲傳送指令給串連在一起的 MAX7219 時,開發者需依「從遠到近」的順序發出給各個 MAX7219 的指令,才能正確地讓指令到達其所對應的 MAX7219。以下用動畫說明此傳輸過程:
此動畫中有三個 MAX7219 串聯在一起,所以若要傳送指令到所有的 MAX7219,則需要 16x3 = 48 個時脈訊號的時間。傳送流程一開始 LOAD 訊號被拉低,使 MAX7219 進入等待指令更新的狀態;在前 16 個時脈訊號中,開發板送出給 MAX7219 #2 (接線上離開發板最遠的 MAX7219) 的指令進入首個節點,接下來的 16 個時脈訊號,再送出給 MAX7219 #1 的指令。此時原本存在首個節點中的指令會被往後推出進到下一個節點。在最後一組的 16 個時脈訊號裡,開發板送出給 MAX7219 #0 的指令,並觸發原本存在首兩個節點中的指令繼續向後推進至最終的目的地。當所有指令都到達正確位置後,將 LOAD 訊號拉高,讓 MAX7219 依收到的指令進行動作。此流程即說明了當串聯在一起的 MAX7219 需接收新指令時,資料傳遞的順序及運作機制。但如果串連在一起的 MAX7219 中,只有單個 MAX7219 需要更新指令、其他的不需新指令,又該如何進行呢?
MAX7219 裡有一個特殊的暫存器,稱為 No-Op 暫存器 (位址為 0,請參閱 datasheet 中的 Table 2)。當 MAX7219 在 LOAD 訊號為 HIGH 時看到 No-Op 指令,將不會進行任何動作、狀態也不會改變。下面的動畫展示「只有 MAX7219 #1 需收取新指令、其他節點皆不改變狀態」的狀況:
在接下來的多個矩陣顯示器串連範例中,會將前一個範例擴充為五個顯示器的組態,並透過使用 No-Op 指令,讓每個顯示器單獨顯示與上例相同的圖像:
硬體接線
將每個顯示模組的 DOUT 腳位接至下個顯示模組的 DIN 腳,而其他腳位則直接連接到下個模組的相同腳位即可。
注意
當串連多個矩陣顯示器時,請確保 5V 供電源能提供足夠的電流輸出,以免顯示模組因供電不足而無法正常運作。
以驅動單個顯示器的程式碼為基礎,將之修改為可驅動串連顯示器的版本。首先,先定義 No-Op 指令:
#define MAX7219_NOOP_REG (0x00)
接著將 set_register() 擴充為 set_all_registers() 以及 set_single_register(),分別用來對串連在一起的 MAX7219 下指令。set_all_registers() 的作用為對所有 MAX7219 皆發出相同的指令,而 set_single_register() 則是針對單一 MAX7219 進行指令更新 (其他的 MAX7219 則不改變狀態):
// 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); }}
綜合上述改動,並利用這兩個 API 取代原本驅動單個顯示器範例中的 set_register() API 後,完整的程式範例如下:
//
// 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);
}
此例使用了 5 個顯示器模組,若要更改模組數目,可直接修改第 34 行的定義:
// define the number of chained matrixes
#define NUM_OF_MATRIXES (5)
若要對所有的 MAX7219 下同樣的指令,請使用 set_all_registers() API,就如同 init_max7219() 以及 clear_matrix() 皆為相同的概念。
若只要對特定的 MAX7219 下指令,請使用 set_single_register() API,即可讓其他 MAX7219 不受影響。
結合前面所述的概念,最後一個範例將展示如何進一步使用 5 個矩陣顯示器產生常見的跑馬燈效果:
完整的範例程式碼如下:
//
// 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);
}
接續前篇的七段顯示器教學,本文完整地介紹了另一種 MAX7219 應用:不只用於驅動七段顯示器,利用原始資料模式的操作,MAX7219 也可用於驅動多個 LED、或是驅動矩陣式 LED。藉由使用 shift register,可大幅簡化建置 LED 顯示應用時的佈線及控制複雜度。
完成硬體線路連接後,接下來的文章將示範如何在顯示器上顯示圖案。