SparkFun 8x8 LED 矩陣控制板 |
在以下的影片中,會展示以水平捲動方式顯示8X8英文字型以及垂直捲動顯示16X16中文字型等兩種效果。
『EV3 8x16 LED顯示看板』示範影片:
重要技術資訊
在Sparkfun官網文件中『RGB Matrix – Serial Backpack User Guide』,提供了許多重要的技術資訊,另外在產品頁面中也還有許多應用範例值得參考。
- Arduino透過SPI介面傳送64個bytes的資料序列給LED矩陣,藉以控制每一個LED的顏色顯示, 而資料byte的顏色值格式如以下圖示,最多可顯示255種顏色:
- 在Daisy Chain模式下,SPI bus的clock speed不能超過125KHz,設定SPI時脈的Arduino程式碼如下:
void setup() { Serial.begin(9600); pinMode (CS_pin, OUTPUT); pinMode (MOSI_pin, OUTPUT); pinMode (SCLK_pin, OUTPUT); SPI.begin(); SPI.setClockDivider(SPI_CLOCK_DIV128); // Daisy-chain should set this speed setDaisyChain(true); }
- 設定Daisy Chain模式的指令為:'%' + n, n表示串接的LED矩陣數量,以下的程式碼是將串接數量設定為2。同時因為 '%' 字符是指令前置碼,所以由SPI介面傳送的資料序列中,應避免包含 '%' 字符(Ascii值0x25),否則會造成不正常的顯示結果。
/* ************************************************************ * Enable Daisay-chain mode * ************************************************************ */ void setDaisyChain(boolean setChain) { //Send the command mode character digitalWrite(CS_pin, LOW); delay(1); SPI.transfer('%'); digitalWrite(CS_pin, HIGH); delay(100); //Configure the correct number of boards digitalWrite(CS_pin, LOW); delay(1); if(setChain) SPI.transfer(2); else SPI.transfer(1); digitalWrite(CS_pin, HIGH); delay(100); }
在下面的圖示中,所表示的是SPI buffer中128個bytes的資料序列對應每一個LED實際位置的順序關係,而兩者間的關係式為:bufferIndex = ledRow * 8 + ledColumn + (ledColumn > 7 ? 56: 0);
LED 位置對應SPI Buffer資料序列順序關係
/* ************************************************************ * SPI write to RGB Matrix * ************************************************************ */ void transferRGBMatrix(char* dotMatrixBuffer, int delayMillis) { digitalWrite(CS_pin, LOW); delay(1); for(int xi=0; xi<128; xi++) SPI.transfer(dotMatrixBuffer[xi]); digitalWrite(CS_pin, HIGH); delay(1); delay (delayMillis); }
實作英數字型顯示
- 以LED矩陣顯示英數字符,需要有字符的8x8 bitmap字型資料,可以預先以陣列方式將大小寫英文字母(A~Z,a~z)、數字(0~9)以及一些常用符號的bitmap資料建立在Arduino程式中,這樣就可以透過呼叫函式傳入英數字符作為引數方式讀取對應的bitmap資料。
/* ************************************************************ * Get font buffer extended function * char displayChar : Ascii value of the character in the string to be displayed * int cidx : The index of this character in the string * char* fontBuffer : The font pattern buffer of this character * ************************************************************ */ void getFontEX(char displayChar, int cidx, char* fontBuffer) { int fidx=cidx*FONT_HEIGHT; if((displayChar >= 'A') && (displayChar <= 'Z')) for(int idx=0; idx<FONT_HEIGHT; idx++) fontBuffer[fidx+idx] = captialFont[(displayChar-'A')*FONT_HEIGHT+idx]; else if((displayChar >= 'a') && (displayChar <= 'z')) for(int idx=0; idx<FONT_HEIGHT; idx++) fontBuffer[fidx+idx] = lowerFont[(displayChar-'a')*FONT_HEIGHT+idx]; else if((displayChar >= '0') && (displayChar <= '9')) for(int idx=0; idx<FONT_HEIGHT; idx++) fontBuffer[fidx+idx] = numberFont[(displayChar-'0')*FONT_HEIGHT+idx]; else { switch (displayChar) { case '.': for(int idx=0; idx<FONT_HEIGHT; idx++) fontBuffer[fidx+idx] = dotFont[idx]; break; case ',': for(int idx=0; idx<FONT_HEIGHT; idx++) fontBuffer[fidx+idx] = commaFont[idx]; break; case '!': for(int idx=0; idx<FONT_HEIGHT; idx++) fontBuffer[fidx+idx] = exclamFont[idx]; break; default: for(int idx=0; idx<FONT_HEIGHT; idx++) fontBuffer[fidx+idx] = 0x00; } } }
- 依據LED矩陣Data Byte顏色值格式,將Bitmap資料中每一個bit值轉換成顏色值資料,轉換的方式為:當bit為ON時設定為前景顏色值,OFF則為背景顏色值。
- 轉換後的LED顏色值資料依據前面提到的LED位置對應SPI buffer資料序列關係,存放至SPI buffer中,再以SPI介面傳送給LED矩陣就能夠正確的顯示出字符。
Bitmap轉換SPI buffer資料序列示意圖
實作英數字串水平捲動效果
水平捲動8X8英數字串的方式與動畫原理相似,依序將連續的畫格(Frame)傳送給LED矩陣,製作出捲動的視覺效果:- 首先將所有字符的bitmap資料依序結合成一個新的bitmap資料,因為bitmap是圖像的數位表示方式,這樣就如同接合每個字符的 8 x 8 正方形圖像成為一張水平方位的矩形圖像。
而矩形圖像的尺寸為:寬 x 長 = 8 x (8 x N) 個 bits,N是字符的數目,每一個bit資料可以視為是一個像素(Pixel) 。8 x 32 英數字串bitmap - 接著以 8 x 16的LED矩陣作為畫布(Canvas),自矩形圖像資料中,由左往右依序漸次增加讀取 8 x 1個像素作為劃格(Frame),將畫格內的bitmap資料轉換成LED顏色值再傳送至畫布中顯現出來,這樣就可以呈現出以水平方式往左捲動的視覺效果。
實作中文字串垂直捲動顯示
- 中文無法如同英數字可在程式中預先建立每個字符的bitmap資料,而是需將所要顯示的中文訊息字串的bitmap資料製作成header file,再由程式中以include方式引用。
Header file的bitmap圖像尺寸會是:寬 x 長 = (16 x N) x 16 bits,N是中文字符的數目。
如右圖示為 32 x 16 bits的圖像。
- 製作向上垂直捲動效果的原理同水平捲動的處理方式,差別在於改成由上往下依序漸次增加讀取 1 x 16 個像素作為劃格(Frame),同樣將 bit 值轉換成LED顏色值之後再傳送至LED矩陣,就可以顯示出垂直捲動的視覺效果。
※ 水平捲動英數字型程式碼
/* ************************************************************
* display font with marguee effect extended function
* ************************************************************ */
void displayFontMarqueeEX(int strLen, char* fontBuffer, char fontColor, char backColor, int delayMillis)
{
char dotMatrixBuffer[128];
short ledidx=0;
for(int cidx=0; cidx<strLen; cidx++) { // Each character
for(int fidx=FONT_WIDTH-1; fidx>=0; fidx--) { // From MSB to LSB
for(int xrow=0; xrow<8; xrow++) { // Each row
for(int xcol=15, fcnt=fidx; xcol>=0; xcol--, fcnt++) { // Each column
ledidx = xrow*8 + (xcol>=8? xcol+56: xcol);
dotMatrixBuffer[ledidx] = backColor;
if(fcnt<=FONT_WIDTH-1) { // if fcnt = 0-7, move current char pattern to led buffer
if(bitRead(fontBuffer[cidx*FONT_HEIGHT+xrow], fcnt))
dotMatrixBuffer[ledidx] = fontColor;
} // if fcnt = 0-7, move current char pattern to led buffer
else {
if(fcnt<=FONT_WIDTH*2-1) { // if fcnt = 8-15, move last char pattern to led buffer
if(cidx>0) {
if(bitRead(fontBuffer[(cidx-1)*FONT_HEIGHT+xrow], fcnt-FONT_WIDTH))
dotMatrixBuffer[ledidx] = fontColor;
}
} // if fcnt = 8-15, move last char pattern to led buffer
else { // if fcnt = 16-23, move last+1 char pattern to led buffer
if(cidx>1) {
if(bitRead(fontBuffer[(cidx-2)*FONT_HEIGHT+xrow], fcnt-FONT_WIDTH*2))
dotMatrixBuffer[ledidx] = fontColor;
}
} // if fcnt = 16-23, move last+1 char pattern to led buffer
}
} // Each column
} // Each row
transferRGBMatrix(dotMatrixBuffer, delayMillis);
} // From MSB to LSB
} // Each character
}
※ 垂直捲動中文字型程式碼
/* ************************************************************
* display 16*16 bitmap font with marguee effect extended function
* ************************************************************ */
void displayBigFontMarqueeEX(byte* fontBuffer, char fontColor, char backColor, int delayMillis)
{
char dotMatrixBuffer[128];
short ledidx=0;
for(int fidx=0; fidx<font_height; fidx++) {
for(int yidx=7, ridx=fidx; yidx>=0; yidx--, ridx++) {
for(int bidx=7; bidx>=0; bidx--) {
ledidx = yidx*8+(7-bidx);
dotMatrixBuffer[ledidx] = backColor;
dotMatrixBuffer[ledidx+64] = backColor;
if(ridx<font_height) {
if(bitRead(fontBuffer[ridx*2], bidx)) dotMatrixBuffer[ledidx] = fontColor;
if(bitRead(fontBuffer[ridx*2+1], bidx)) dotMatrixBuffer[ledidx+64] = fontColor;
}
}
}
transferRGBMatrix(dotMatrixBuffer, delayMillis);
}
}
沒有留言:
張貼留言