程式碼下載

使用硬體元件

  • 麵包板
  • Arduino Nano
  • MAX7219數碼管顯示模組
  • 杜邦線

元件介紹

本次使用的顯示器數碼組是由MAX7219 晶片與 8 個七段式數碼顯示管所組合的模組
由於 MAX7219 採用 SPI 的序列介面, 透過該介面, 只需使用三條控制線串接 Arduino, 即可同時驅動8個七段顯示器(或點陣式LED), 故使用該晶片可大幅減化連接數碼管顯示的硬體線路, 提昇使用效率

SPI 介面

SPI介面的全名是 Serial Peripheral Interface(序列周邊介面),廣泛用於各種電子裝置,像SD記憶卡、數位/類比轉換IC、LED控制晶片...等。
SPI 採用四條線連接主機和周邊設備,這四條連線的名稱和用途如下:
  • SS:周邊選擇線(Slave Select),指定要連線的周邊設備。此線輸入0,代表選取,1代表未選。這條線也稱為CS (Chip Select,晶片選擇線)
  • MOSI:從主機往周邊傳送的資料線(Master Output, Slave Input)
  • MISO:從周邊往主機傳送的資料線(Master Input, Slave Output)
  • SCK:序列時脈線(Serial Clock)

Arduino 的 SPI介面

Arduino UNO 及 NANO 主板上的 SPI 介面, 其腳編號分別為 10(SS), 11(MOSI), 12(MISO), 13(SCK), 等四個腳位, 由於每個 SPI 周邊都需要單獨連接 SS 線, 所以 SS 線也可選用 10-13 以外的任何接腳當做「周邊選擇」線。

完成後效果

透過第三方程式庫, 展現 MAX7219 晶片驅動 8 個七段式數碼管的能力

建置步驟

步驟 1 : 連接硬體線路

接線示意圖(由於 MAX7219 僅接收 Nano 所傳送的資料, 無須傳送資料給 Nano, 故除電源線外, 只需三條控制線即可, 其中 DIN 及 CLK 必須接 D11 與 D13, 而 CS 則可更換為其他接腳)
將 Nano 及 MAX7219 數碼顯示模組插入麵包板
依序將 MAX7219 數碼顯示模組的接腳連接到 Nano 相對應的接腳上
VCC ==> 3V3(or 5V)
GND ==> GND
DIN ==> D11
CS ==> D7
CLK ==> D13

步驟 2 : 撰寫程式

第三方程式庫
使用第三方程式庫, 可有效簡化程式編碼, 本方案使用 [DigitLedDispaly] 的程式庫, 其安裝方式如下
1. 開啟 [程式庫管理員] 並搜尋 [7219] 字串, 可顯示與 MAX7219 相關的 的程式庫, 請找到 [DigitLedDispaly] 程式庫, 並完成該程式庫的安裝
2. 程式庫安裝完成後, 可於 >本機>文件>Arduino>libraries 目錄下產生 [DigitLedDispaly] 的目錄, 該目錄內可找到相對應的程式庫及範例檔案
3. 於 Arduino 整合開發環境(IDE)工具下, 也可直接開啟 [DigitLedDispaly] 範例程式, 進行測試

程式庫重要函式說明

DigitLedDisplay()
// 建構函數, 用於建立 DigitLedDisplay 物件, 後續動作直接針對該物件操作
DigitLedDisplay(int dinPin, int csPin, int clkPin);
// 建立物件時需傳入三個參數分別為 Arduino 連接 MAX7219 之 DIN(資料輸入), 
   CS(晶片選擇線 Chip Select), CLK(序列時脈線 Serial Clock), 
   等三個接腳的編號
註: 相對於 Arduino UNN 及 NANO 板子上的 SPI 介面位置, 
    其 DIN 必須連接 11 接腳, CLK必須連接 13 接腳, 
    而 CS 則可連接11~13 以外的任何接腳
EX :
DigitLedDisplay ld = DigitLedDisplay(11, 7, 13);

setBright()
// 設定亮度函數, 其值介於 1~15
void setBright(int brightness);
EX:
  /* Set the brightness min:1, max:15 */
  ld.setBright(10); 

setDigitLimit()
// 設定控制數字LED的數量
void setDigitLimit(int limit);
EX:
  /* Set the digit count */
  ld.setDigitLimit(8); 

printDigit()
// 數值顯示函數, 用於直接顯示數值
// 參數 1 為要顯示的數值
// 參數 2 為顯示數值的啟始位置(由最左邊開始起算, 預設值為 0, 由 0 起算 )
void printDigit(long number, byte startDigit = 0);
EX:
  ld.printDigit(12345678);   // 直接顯示數值(最左邊開始起算, 起算值為 0)
  ld.printDigit(123, 4);   // 直接顯示數值, 但由第 5個 LED 開始顯示
注意事項 : printDigit() 函式只會更新顯示數值所對應的 LED,
           無對應顯示位置的 LED, 將保持原有狀態
EX:
執行 printDigit(123456);  MAX7219 模組顯示  123456
接著再執行 printDigit(888);  則 MAX7219 模組顯示  123888 
(只更新 888 三個位置的 LED) 

write()
// 特定 LED 顯示函數, 用於直接於指定特定的 LED 進行顯示
// 參數 1 為指定特定的 LED 位置(由最左邊開始起算, 起算值為 1 )
// 參數 2 為要顯示的內容, 該內容以二進位編碼的數值表示, 
          其數值分別對應到單一 LED 的七段數碼管及小數點位置, 
          故可控制個別 LED 燈管的亮滅, 如下圖所示			
void write(byte address, byte data);
EX:
ld.write(5, B00011101);   // 於 第 5 個 LED 的下方顯示 o

範例程式內容
運用 #include 將函式庫引入, 並定義 DIN, CS, CLK 連接 Arduino 的腳位
/* Include DigitLedDisplay Library */
#include "DigitLedDisplay.h"
#define DIN  11
#define CS   7
#define CLK  13
定義七段顯示器部份字元顯示的二進位碼, 該二進位分別代表 HELO. 及空白等字元, 提供程式內直接引用
#define SHOW_H  B00110111
#define SHOW_E  B01001111 
#define SHOW_L  B00001110
#define SHOW_O  B01111110
#define SHOW_POINT  B10000000
#define SHOW_BLANK  B00000000	
建立 DigitLedDisplay 物件(ld), 後續動作直接針對該物件操作, 並於 setup() 函式內設定顯示亮度及數字 LED 的個數
DigitLedDisplay ld = DigitLedDisplay(DIN, CS, CLK);
void setup() {
  /* Set the brightness min:1, max:15 */
  ld.setBright(10);
  /* Set the digit count */
  ld.setDigitLimit(8);
}
撰寫測試函式
測試函式 1 : testPrintDigit01()
先顯示 1~8 的數字, 並依序向右移動一格
void testPrintDigit01() {
  // 由1~8的數字依序右移一格顯示
  long number = 12345678; // 必須使用長整數 
  for(int i=0; i < 8; i++){
    ld.printDigit(number);
    delay(500);
    ld.clear();
    number = number / 10L;
  } 
  delay(500); 
  ld.clear();
}
測試函式 2 : testPrintDigit02()
分兩組分別顯示 0~99的數值
void testPrintDigit02() {
  // 分兩組分別顯示 0~99
  for (int i = 0; i < 100; i++) {
    ld.printDigit(i);
    /* Start From Digit 4 */
    ld.printDigit(i, 4);
    delay(50);
  }
  delay(500);   
  ld.clear();
}
測試函式 3 : testWrite()
顯示 HELLO. 的跑馬燈
在撰寫函式前, 需先定義跑馬燈顯示字元的陣列 show_word[]
byte show_word[] = { 
  SHOW_H, SHOW_E, SHOW_L, SHOW_L,
  SHOW_O, SHOW_POINT, SHOW_BLANK, SHOW_BLANK
};
testWrite() 的函式內容
void testWrite() {
  // HELLO. 的跑馬燈
  for (int i = 6; i < 40; i++) {
    ld.write(8, show_word[(i+6)%8]);
    ld.write(7, show_word[(i+7)%8]);
    ld.write(6, show_word[i%8]);
    ld.write(5, show_word[(i+1)%8]);
    ld.write(4, show_word[(i+2)%8]);
    ld.write(3, show_word[(i+3)%8]);
    ld.write(2, show_word[(i+4)%8]);
    ld.write(1, show_word[(i+5)%8]);
    delay(300);
  } 
}
測試函式 4 : testOnOff()
利用 on(), off() 函數產生閃爍效果
void testOnOff() {
  // 利用 on(), off() 函數產生閃爍效果
  // 顯示 HELLO.
  ld.write(8, SHOW_BLANK);  // 空白
  ld.write(7, SHOW_BLANK);  // 空白
  ld.write(6, SHOW_H);  // H
  ld.write(5, SHOW_E);  // E
  ld.write(4, SHOW_L);  // L
  ld.write(3, SHOW_L);  // L
  ld.write(2, SHOW_O);  // O
  ld.write(1, SHOW_POINT);  // .
  // 閃爍 10 次
  for (int i = 0; i <= 10; i++) {
    /* Display off */
    ld.off();
    delay(150);

    /* Display on */
    ld.on();
    delay(150);
  }
  delay(500);
}
最後再撰寫 loop() 函式, 於 loop 函式內分別呼叫前述所定義的測試函式
void loop() {
  // 第 1 段測試
  ld.printDigit(11111111);
  delay(1000);
  testPrintDigit01();
  
  // 第 2 段測試
  ld.printDigit(22222222);
  delay(1000);
  ld.clear();  
  testPrintDigit02();
  
  // 第 3 段測試
  ld.printDigit(33333333);
  delay(1000);
  testWrite();
  
  // 第 4 段測試
  ld.printDigit(44444444);
  delay(1000);
  testOnOff();
}

上傳與執行

完成程式撰寫後, 即可將電腦連接 Nano 並上傳程式及查看執行效果

範例實作 Youtube 影片