前言:

感覺 Arduino 平台的崛起, 跟所選用微處理器有很大的關係. 新一代 Atmel 所開發的 ATmega 8位元微處理器, 豐富的 I/O 介面, 完善高階的開發環境, 真的是將垂垂老矣的 8051 遠遠地甩在身後. ATmega 蠻方便的就是已經內建三種重要的資料傳輸匯流介面: USART, I2C 及 SPI. 因為內建的, 所以不需要任何額外的電路, 就可以很方便的跟各種裝置溝通囉.

這篇就來做 SPI 傳輸介面的練習吧: 利用個8x8的 LED 陣列, 來做個迷你跑馬燈囉!

筆者在練習這個的時候, 剛好遇上 2018年4月10日, 是我們最愛的紐西蘭女高音歌手海莉的生日. 身為海莉的鐵竿粉絲, 往年都是送上小禮物例如親自畫的海莉畫像給女神慶祝生日的. 但是今年已經黔驢技窮, 不知道要送什麼了. 剛好利用這個迷你跑馬燈, 簡單地跑個慶祝的話語, 海莉妹妹, 生日快樂喲!

 

 

 

SPI (Serial Peripheral Interface) 介面:

先來簡單介紹一下硬體上很重要的 SPI 介面。 SPI介面的全名是 Serial Peripheral Interface (序列周邊介面),最早是由 Motorola 公司所推出的一種同步全雙工序列介面,它允許兩個裝置之間以同步,全雙工,序列的方式進行高速數據通信。且速度較其他兩個常用的 UART,I2C 介面的速度還要快,所以廣泛的被使用在各種重視傳輸速度的電子裝置上,例如 SD記憶卡,佳能 Canon 相機的 EF接環,數位/類比轉換IC,液晶顯示器,... etc.

SPI 通訊的主軸如下圖所示,其實關鍵是兩的環狀的頭尾相連的8位元位移暫存器,在一個時脈內,頭尾互相交換資料。總共需要四個通訊接腳,定義如下:

MOSI (Master Output Slave Input): 主機往周邊發送訊號的訊號線

MISO (Master Input Slave Output): 周邊往主機發送訊號的訊號線

SS (Slave Select): 周邊通訊選擇 (SPI 可以支援多重周邊通訊),用來指定要連線的週邊設備,邏輯假(Low) 代表選取,邏輯真(High) 代表未選。

SCK (Serial Clock): 主機跟周邊兩邊交換資料時兩邊的時脈基準

700px-SPI_single_slave.svg.png

SPI01.png

 

 

以上是單一周邊的連接方式,多周邊的連接方式如下 (這時候 Master 需要針對每個 Slave 都要有一個 SS 周邊選擇致能控制):

600px-SPI_three_slaves.svg.png

 

 

特點:

1. 透過主從的方式支援多重周邊通訊:一台主機可以跟多台周邊對談交換資料。主機藉由對不同周邊的 SS 周邊選擇訊號線的致能,選擇所欲交談的對象。

2. 採用同步的方式來傳輸交換數據:主機須於 SCK 訊號線提供兩周邊對談所需的同步時脈訊號。因為採用時脈來同步雙方數據交換,所以雙方通訊的速度由此時脈訊號的速度來決定,理論上最大傳輸速度沒有限制,實際上可以達到 20 Mbit/sec 的高資料傳輸速率。

3. 全雙工的方式主機跟周邊同時交換資料:在一個時脈週期內, MOSI/MISO 兩條線同時對周邊跟主機交換資料。

時脈極性 CPOL (Clock Polarity):定義idle時時脈訊號的電位基準,低電位 CPOL= 0, 高電位 CPOL= 1

時脈相位 CPHA (Clock Phase):定義資料是由時脈的前緣觸發還是後緣觸發。 CPHA=0 時前緣觸發,觸發時採樣。CPHA=1 時後緣觸發,觸發時採樣。

實際上有定義了四種資料模式:

SPI 模式
資料模式 時脈極性 CPOL 時脈相位 CPHA
MODE 01 0 0
MODE 02 0 1
MODE 03 1 0
MODE 04 1 1

 

Arduino 的 SPI 介面

Arduino 的 ATmega 微處理器內建 SPI 介面,接腳如下定義:

SS: Pin 10

MOSI : Pin 11

MISO: Pin 12

SCK: Pin 13

要控制多周邊的情況下, 假如 Arduino 是主機(Master),主機需要額外的 digital I/O 來做其他周邊的 SS (Slave Select) 選擇。

 

MAX7219 組裝 8x8 LED陣列:

我們這個迷你跑馬燈,主角是一個 8x8 的 LED 陣列。 這個 LED 陣列總共有 8x8 = 64 個數量龐大的 LED,要控制這麼多的 LED習慣上會採用專門設計的IC來控制。MAX7219 就是這樣的一個控制IC,被設計來控制驅動 8x8 的 LED陣列,或是8個七段顯示器。然後它採用 SPI 介面來跟外界溝通。

所以市面上很容易買到現成已經用 MAX7219 跟 8x8 LED 陣列製作好的模組,透過現成的模組,很方便就可以組成我們的迷你跑馬燈。而控制這種 8x8 LED陣列的主軸,自然轉向如何透過 SPI 通訊介面來跟 MAX7219 溝通!

 

MAX7219 的控制:

因爲筆者買到的已經是 MAX7219跟 8x8 LED 矩陣在一起的模組囉,所以細部電路就不管他囉!我們只要專心在如何跟 MAX7219 溝通跟控制就好。

MAX7219 內部一共有14個八位元的暫存器,一一解說如下

MAX7219 暫存器
暫存器名稱 位址 (16進位) 用途
Digit 0 0x1 LED矩陣第1行內容
Digit 1 0x2 LED矩陣第2行內容
Digit 2 0x3 LED矩陣第3行內容
Digit 3 0x4 LED矩陣第4行內容
Digit 4 0x5 LED矩陣第5行內容
Digit 5 0x6 LED矩陣第6行內容
Digit 6 0x7 LED矩陣第7行內容
Digit 7 0x8 LED矩陣第8行內容
No-Op 0x0 未使用
Decode Mode 0x9 是否啟用BCD解碼 (七段顯示器 only)
Intensity 0xA LED 顯示亮度
Scan Limit 0xB 可顯示的 LED 陣列或七段顯示器的數目
Shutdown 0xC 關閉所有LED,但仍可接收資料
Display Test 0xF 顯示器測試模式開啟(讓所有LED全亮,目視測試誰壞了)

 

MAX7219 的運作方式很簡單,它會不斷的檢視這14個暫存器的內容,根據內容採取對應的控制動作。所以我們只要透過 SPI 介面,根據我們的需求,不斷更新這14個暫存器的內容就可以囉。

 

MAX7219 SPI 協定:

MAX7219 的封包每次 16位元 (2 byte),前 8位元(低位元組)是資料,給暫存器用。後 4位元(高位元組)是暫存器位址,最後 4位元未使用(高位元組)。

真實傳送時,須從高位元組(暫存器位址)先傳送,再傳送低位元組(8位元資料)

 

Arduino 的好處是,底層的 SPI 驅動程式碼已經幫我們完成的差不多囉,我們只要把它們引用進來就可以囉。 SPI 的函式庫放在 SPI.h

#include <SPI.h>

 

所以透過這個函式庫,跟 MAX7219 通訊的核心程式碼如下

void SendTo7219(const byte reg, const byte data) {
  digitalWrite(SS, LOW);  Slave Select 設為Low, 準備傳送資料
  SPI.transfer(reg);      先送後八位元位址,指名暫存器的位址。

  SPI.transfer(data);     後送前八位元資料,給暫存器用。
  digitalWrite(SS, HIGH); Slave Select 設為High, 結束資料傳送

}

所以透過這個 SendTo7219,就可以自由的透過 SPI 介面,傳送控制 7219 的任一個暫存器的數值,進而控制我們 8x8 LED 矩陣迷你跑馬燈的行為!

 

MAX7219 的起始設定

底下為一開始設定的程式碼

void setup() {
  // put your setup code here, to run once:
  SPI.begin();                 SPI介面,開始通訊
  
  SendTo7219(DecodeMode,0);    DecodeMode=0, 不使用BCD解碼
  SendTo7219(Intensity,1);     Intensity=1, LED顯示亮度最暗(0-255)
  SendTo7219(ScanLimit,7);     ScanLimit=8, LED全部使用
  SendTo7219(DisplayTest,0);   DisplayTest=0, LED測試模式關閉
  SendTo7219(Shutdown,1);      Shutdown=1, 開啟所有LED顯示
  
  UpdateDisplay();
}

 

程式碼控制邏輯:

程式碼這邊重點是個 buf[8] 的一個 8 byte 的主矩陣,這個主矩陣上面每個 bit 是跟 8x8 LED 陣列相相呼應,它的資料也對應 7219 的暫存器 Digit 0 - Digit 7。

程式裡面每呼叫一次 UpdateDisplay(), 主矩陣 buf[8] 的資料,立即會跟 7219 裡 Digit 0 - 7 的矩陣資料同步,意即 LED圖形就會立即被更新囉!

void UpdateDisplay() {
      for (byte i=0; i<8; i++) {
      SendTo7219(i+1,buf[i]);
    }
}

 

再來是字型資料,既然是跑馬燈,就要有所有的英文字型資料。字型資料放在矩陣 font[128][8] 的一個二維矩陣。第一個索引是完全遵照 ASC code 的順序的,所以只要用字元的 ASC code,就可以索引到對應的8x8 共 8 bytes 所組成的英文字母字型資料囉。

const byte font[127][8] = {
  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x00
  { 0x7E, 0x81, 0x95, 0xB1, 0xB1, 0x95, 0x81, 0x7E }, // 0x01

    ...

 

最後是字型圖形的捲動

這裏介紹另外一個陣列 msg[], 這裏是來放你所想要顯示的訊息。

這裏的字型資料是有訣竅的,MAX7219 Digit 0 - 7 ,每個暫存器的一個byte 剛好是顯示一行 LED 的點,這裏這些字型資料的字是設計會跟每行LED垂直的。所以要讓字型捲動,只要很簡單的照順序的搬移主矩陣 buf[8] 裡每個 byte,空出來的位置放上下一個字的字型資料。等全部完成後,最後再 UpdateDisplay() 一下,讓它們顯示出來,就搞定囉!人眼也會覺得似乎圖形正從水平方向捲動中呢!

 

void ScrollChar(byte chr) {
  for (byte i=0; i<8; i++) {     掃過下一個字chr 的所有圖形資料
    for (byte j=0; j<7; j++) {
      buf[j] = buf[j+1];         搬移主矩陣的資料,往 index=0 移動
    }
    buf[7]=font[chr][i];         主矩陣 buf[7] 等於下一個字chr 的資料
    UpdateDisplay() ;            更新並顯示圖形
    delay(100);                  停個 0.1 秒
  }
}

 

 

8x8 LED 點矩陣模組 (已內建MAX7219):

正面照片

HipstamaticPhoto-560651276.409329.png

 

背面照片

HipstamaticPhoto-560651295.243959.png

 

 

迷你跑馬燈硬體接線

SPI02.png

 

 

整個外型圖

正面照片

IMG_2514.png

 

背面接腳照片

HipstamaticPhoto-560736298.385387.png

 

 

這裏,還要再次來推廣一下 Arduino 的空白 Shield 擴充卡

Arduino的空白 Shield,通常還有附一塊小麵包版,黏上去空白Shield之後,真的很方便。真的好像樂高積木一樣,只要透過杜邦接頭就可以很容易地連接跟組合,完全不需要動到焊槍就可以完成很多有趣的作品喲!

真的要好好的在 DIY Maker 界,讓我們這種業餘玩家好好的推廣把玩啦!

IMG_2495 (1).png

IMG_2502 (1).png

IMG_2510.png

 

 

 

最後,原始程式碼列表

 

//
// scrolling text example on LED matrix
//   SPI interface practice
//
//  Frank Lin  2018.9.30
//  

#include <SPI.h>


#define Intensity 0xA
#define DecodeMode 0x9
#define ScanLimit 0xB
#define DisplayTest 0xF
#define Shutdown 0xC


const byte font[127][8] = {
  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x00
  { 0x7E, 0x81, 0x95, 0xB1, 0xB1, 0x95, 0x81, 0x7E }, // 0x01
  { 0x7E, 0xFF, 0xEB, 0xCF, 0xCF, 0xEB, 0xFF, 0x7E }, // 0x02
  { 0x0E, 0x1F, 0x3F, 0x7E, 0x3F, 0x1F, 0x0E, 0x00 }, // 0x03
  { 0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x08, 0x00 }, // 0x04
  { 0x18, 0xBA, 0xFF, 0xFF, 0xFF, 0xBA, 0x18, 0x00 }, // 0x05
  { 0x10, 0xB8, 0xFC, 0xFF, 0xFC, 0xB8, 0x10, 0x00 }, // 0x06
  { 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00 }, // 0x07
  { 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF }, // 0x08
  { 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00 }, // 0x09
  { 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF }, // 0x0A
  { 0x70, 0xF8, 0x88, 0x88, 0xFD, 0x7F, 0x07, 0x0F }, // 0x0B
  { 0x00, 0x4E, 0x5F, 0xF1, 0xF1, 0x5F, 0x4E, 0x00 }, // 0x0C
  { 0xC0, 0xE0, 0xFF, 0x7F, 0x05, 0x05, 0x07, 0x07 }, // 0x0D
  { 0xC0, 0xFF, 0x7F, 0x05, 0x05, 0x65, 0x7F, 0x3F }, // 0x0E
  { 0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99 }, // 0x0F
  { 0x7F, 0x3E, 0x3E, 0x1C, 0x1C, 0x08, 0x08, 0x00 }, // 0x10
  { 0x08, 0x08, 0x1C, 0x1C, 0x3E, 0x3E, 0x7F, 0x00 }, // 0x11
  { 0x00, 0x24, 0x66, 0xFF, 0xFF, 0x66, 0x24, 0x00 }, // 0x12
  { 0x00, 0x5F, 0x5F, 0x00, 0x00, 0x5F, 0x5F, 0x00 }, // 0x13
  { 0x06, 0x0F, 0x09, 0x7F, 0x7F, 0x01, 0x7F, 0x7F }, // 0x14
  { 0x40, 0xDA, 0xBF, 0xA5, 0xFD, 0x59, 0x03, 0x02 }, // 0x15
  { 0x00, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x00 }, // 0x16
  { 0x80, 0x94, 0xB6, 0xFF, 0xFF, 0xB6, 0x94, 0x80 }, // 0x17
  { 0x00, 0x04, 0x06, 0x7F, 0x7F, 0x06, 0x04, 0x00 }, // 0x18
  { 0x00, 0x10, 0x30, 0x7F, 0x7F, 0x30, 0x10, 0x00 }, // 0x19
  { 0x08, 0x08, 0x08, 0x2A, 0x3E, 0x1C, 0x08, 0x00 }, // 0x1A
  { 0x08, 0x1C, 0x3E, 0x2A, 0x08, 0x08, 0x08, 0x00 }, // 0x1B
  { 0x3C, 0x3C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00 }, // 0x1C
  { 0x08, 0x1C, 0x3E, 0x08, 0x08, 0x3E, 0x1C, 0x08 }, // 0x1D
  { 0x30, 0x38, 0x3C, 0x3E, 0x3E, 0x3C, 0x38, 0x30 }, // 0x1E
  { 0x06, 0x0E, 0x1E, 0x3E, 0x3E, 0x1E, 0x0E, 0x06 }, // 0x1F
  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // ' '
  { 0x00, 0x06, 0x5F, 0x5F, 0x06, 0x00, 0x00, 0x00 }, // '!'
  { 0x00, 0x07, 0x07, 0x00, 0x07, 0x07, 0x00, 0x00 }, // '"'
  { 0x14, 0x7F, 0x7F, 0x14, 0x7F, 0x7F, 0x14, 0x00 }, // '#'
  { 0x24, 0x2E, 0x6B, 0x6B, 0x3A, 0x12, 0x00, 0x00 }, // '$'
  { 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, 0x00 }, // '%'
  { 0x30, 0x7A, 0x4F, 0x5D, 0x37, 0x7A, 0x48, 0x00 }, // '&'
  { 0x04, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, // '''
  { 0x00, 0x1C, 0x3E, 0x63, 0x41, 0x00, 0x00, 0x00 }, // '('
  { 0x00, 0x41, 0x63, 0x3E, 0x1C, 0x00, 0x00, 0x00 }, // ')'
  { 0x08, 0x2A, 0x3E, 0x1C, 0x1C, 0x3E, 0x2A, 0x08 }, // '*'
  { 0x08, 0x08, 0x3E, 0x3E, 0x08, 0x08, 0x00, 0x00 }, // '+'
  { 0x00, 0x80, 0xE0, 0x60, 0x00, 0x00, 0x00, 0x00 }, // ','
  { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00 }, // '-'
  { 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 }, // '.'
  { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00 }, // '/'
  { 0x3E, 0x7F, 0x71, 0x59, 0x4D, 0x7F, 0x3E, 0x00 }, // '0'
  { 0x40, 0x42, 0x7F, 0x7F, 0x40, 0x40, 0x00, 0x00 }, // '1'
  { 0x62, 0x73, 0x59, 0x49, 0x6F, 0x66, 0x00, 0x00 }, // '2'
  { 0x22, 0x63, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00 }, // '3'
  { 0x18, 0x1C, 0x16, 0x53, 0x7F, 0x7F, 0x50, 0x00 }, // '4'
  { 0x27, 0x67, 0x45, 0x45, 0x7D, 0x39, 0x00, 0x00 }, // '5'
  { 0x3C, 0x7E, 0x4B, 0x49, 0x79, 0x30, 0x00, 0x00 }, // '6'
  { 0x03, 0x03, 0x71, 0x79, 0x0F, 0x07, 0x00, 0x00 }, // '7'
  { 0x36, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00 }, // '8'
  { 0x06, 0x4F, 0x49, 0x69, 0x3F, 0x1E, 0x00, 0x00 }, // '9'
  { 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, // ':'
  { 0x00, 0x80, 0xE6, 0x66, 0x00, 0x00, 0x00, 0x00 }, // ';'
  { 0x08, 0x1C, 0x36, 0x63, 0x41, 0x00, 0x00, 0x00 }, // '<'
  { 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00 }, // '='
  { 0x00, 0x41, 0x63, 0x36, 0x1C, 0x08, 0x00, 0x00 }, // '>'
  { 0x02, 0x03, 0x51, 0x59, 0x0F, 0x06, 0x00, 0x00 }, // '?'
  { 0x3E, 0x7F, 0x41, 0x5D, 0x5D, 0x1F, 0x1E, 0x00 }, // '@'
  { 0x7C, 0x7E, 0x13, 0x13, 0x7E, 0x7C, 0x00, 0x00 }, // 'A'
  { 0x41, 0x7F, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00 }, // 'B'
  { 0x1C, 0x3E, 0x63, 0x41, 0x41, 0x63, 0x22, 0x00 }, // 'C'
  { 0x41, 0x7F, 0x7F, 0x41, 0x63, 0x3E, 0x1C, 0x00 }, // 'D'
  { 0x41, 0x7F, 0x7F, 0x49, 0x5D, 0x41, 0x63, 0x00 }, // 'E'
  { 0x41, 0x7F, 0x7F, 0x49, 0x1D, 0x01, 0x03, 0x00 }, // 'F'
  { 0x1C, 0x3E, 0x63, 0x41, 0x51, 0x73, 0x72, 0x00 }, // 'G'
  { 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00 }, // 'H'
  { 0x00, 0x41, 0x7F, 0x7F, 0x41, 0x00, 0x00, 0x00 }, // 'I'
  { 0x30, 0x70, 0x40, 0x41, 0x7F, 0x3F, 0x01, 0x00 }, // 'J'
  { 0x41, 0x7F, 0x7F, 0x08, 0x1C, 0x77, 0x63, 0x00 }, // 'K'
  { 0x41, 0x7F, 0x7F, 0x41, 0x40, 0x60, 0x70, 0x00 }, // 'L'
  { 0x7F, 0x7F, 0x0E, 0x1C, 0x0E, 0x7F, 0x7F, 0x00 }, // 'M'
  { 0x7F, 0x7F, 0x06, 0x0C, 0x18, 0x7F, 0x7F, 0x00 }, // 'N'
  { 0x1C, 0x3E, 0x63, 0x41, 0x63, 0x3E, 0x1C, 0x00 }, // 'O'
  { 0x41, 0x7F, 0x7F, 0x49, 0x09, 0x0F, 0x06, 0x00 }, // 'P'
  { 0x1E, 0x3F, 0x21, 0x71, 0x7F, 0x5E, 0x00, 0x00 }, // 'Q'
  { 0x41, 0x7F, 0x7F, 0x09, 0x19, 0x7F, 0x66, 0x00 }, // 'R'
  { 0x26, 0x6F, 0x4D, 0x59, 0x73, 0x32, 0x00, 0x00 }, // 'S'
  { 0x03, 0x41, 0x7F, 0x7F, 0x41, 0x03, 0x00, 0x00 }, // 'T'
  { 0x7F, 0x7F, 0x40, 0x40, 0x7F, 0x7F, 0x00, 0x00 }, // 'U'
  { 0x1F, 0x3F, 0x60, 0x60, 0x3F, 0x1F, 0x00, 0x00 }, // 'V'
  { 0x7F, 0x7F, 0x30, 0x18, 0x30, 0x7F, 0x7F, 0x00 }, // 'W'
  { 0x43, 0x67, 0x3C, 0x18, 0x3C, 0x67, 0x43, 0x00 }, // 'X'
  { 0x07, 0x4F, 0x78, 0x78, 0x4F, 0x07, 0x00, 0x00 }, // 'Y'
  { 0x47, 0x63, 0x71, 0x59, 0x4D, 0x67, 0x73, 0x00 }, // 'Z'
  { 0x00, 0x7F, 0x7F, 0x41, 0x41, 0x00, 0x00, 0x00 }, // '['
  { 0x01, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00 }, // backslash
  { 0x00, 0x41, 0x41, 0x7F, 0x7F, 0x00, 0x00, 0x00 }, // ']'
  { 0x08, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x08, 0x00 }, // '^'
  { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, // '_'
  { 0x00, 0x00, 0x03, 0x07, 0x04, 0x00, 0x00, 0x00 }, // '`'
  { 0x20, 0x74, 0x54, 0x54, 0x3C, 0x78, 0x40, 0x00 }, // 'a'
  { 0x41, 0x7F, 0x3F, 0x48, 0x48, 0x78, 0x30, 0x00 }, // 'b'
  { 0x38, 0x7C, 0x44, 0x44, 0x6C, 0x28, 0x00, 0x00 }, // 'c'
  { 0x30, 0x78, 0x48, 0x49, 0x3F, 0x7F, 0x40, 0x00 }, // 'd'
  { 0x38, 0x7C, 0x54, 0x54, 0x5C, 0x18, 0x00, 0x00 }, // 'e'
  { 0x48, 0x7E, 0x7F, 0x49, 0x03, 0x02, 0x00, 0x00 }, // 'f'
  { 0x98, 0xBC, 0xA4, 0xA4, 0xF8, 0x7C, 0x04, 0x00 }, // 'g'
  { 0x41, 0x7F, 0x7F, 0x08, 0x04, 0x7C, 0x78, 0x00 }, // 'h'
  { 0x00, 0x44, 0x7D, 0x7D, 0x40, 0x00, 0x00, 0x00 }, // 'i'
  { 0x60, 0xE0, 0x80, 0x80, 0xFD, 0x7D, 0x00, 0x00 }, // 'j'
  { 0x41, 0x7F, 0x7F, 0x10, 0x38, 0x6C, 0x44, 0x00 }, // 'k'
  { 0x00, 0x41, 0x7F, 0x7F, 0x40, 0x00, 0x00, 0x00 }, // 'l'
  { 0x7C, 0x7C, 0x18, 0x38, 0x1C, 0x7C, 0x78, 0x00 }, // 'm'
  { 0x7C, 0x7C, 0x04, 0x04, 0x7C, 0x78, 0x00, 0x00 }, // 'n'
  { 0x38, 0x7C, 0x44, 0x44, 0x7C, 0x38, 0x00, 0x00 }, // 'o'
  { 0x84, 0xFC, 0xF8, 0xA4, 0x24, 0x3C, 0x18, 0x00 }, // 'p'
  { 0x18, 0x3C, 0x24, 0xA4, 0xF8, 0xFC, 0x84, 0x00 }, // 'q'
  { 0x44, 0x7C, 0x78, 0x4C, 0x04, 0x1C, 0x18, 0x00 }, // 'r'
  { 0x48, 0x5C, 0x54, 0x54, 0x74, 0x24, 0x00, 0x00 }, // 's'
  { 0x00, 0x04, 0x3E, 0x7F, 0x44, 0x24, 0x00, 0x00 }, // 't'
  { 0x3C, 0x7C, 0x40, 0x40, 0x3C, 0x7C, 0x40, 0x00 }, // 'u'
  { 0x1C, 0x3C, 0x60, 0x60, 0x3C, 0x1C, 0x00, 0x00 }, // 'v'
  { 0x3C, 0x7C, 0x70, 0x38, 0x70, 0x7C, 0x3C, 0x00 }, // 'w'
  { 0x44, 0x6C, 0x38, 0x10, 0x38, 0x6C, 0x44, 0x00 }, // 'x'
  { 0x9C, 0xBC, 0xA0, 0xA0, 0xFC, 0x7C, 0x00, 0x00 }, // 'y'
  { 0x4C, 0x64, 0x74, 0x5C, 0x4C, 0x64, 0x00, 0x00 }, // 'z'
  { 0x08, 0x08, 0x3E, 0x77, 0x41, 0x41, 0x00, 0x00 }, // '{'
  { 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0x00 }, // '|'
  { 0x41, 0x41, 0x77, 0x3E, 0x08, 0x08, 0x00, 0x00 }, // '}'
  { 0x02, 0x03, 0x01, 0x03, 0x02, 0x03, 0x01, 0x00 }  // '~'
};


byte buf[8] = {0,0,0,0,0,0,0,0};
char msg[] = { 'H', 'a', 'p', 'p', 'y', ' ', 'B', 'i', 'r', 't', 'h', 'd', 'a', 'y', ' ', 'H', 'a', 'y', 'l', 'e', 'y', ' ', 'W', 'e', 's', 't', 'e', 'n', 'r', 'a', ' '};

void SendTo7219(const byte reg, const byte data) {
  digitalWrite(SS, LOW);
  SPI.transfer(reg);
  SPI.transfer(data);
  digitalWrite(SS, HIGH);

}

void UpdateDisplay() {
      for (byte i=0; i<8; i++) {
      SendTo7219(i+1,buf[i]);
    }
}

void ScrollChar(byte chr) {
  for (byte i=0; i<8; i++) {
    for (byte j=0; j<7; j++) {
      buf[j] = buf[j+1];
    }
    buf[7]=font[chr][i];
    UpdateDisplay() ;
    delay(100);
  }
}
void setup() {
  // put your setup code here, to run once:
  SPI.begin();
  
  SendTo7219(DecodeMode,0);
  SendTo7219(Intensity,1);
  SendTo7219(ScanLimit,7);
  SendTo7219(DisplayTest,0);
  SendTo7219(Shutdown,1);
  
  UpdateDisplay();
}

void loop() {
  for (int i=0; i<sizeof(msg); i++) {
    ScrollChar(msg[i]);
  }
}

 

 

xxx

arrow
arrow

    ohiyooo2 發表在 痞客邦 留言(1) 人氣()