aitendo 16x16LEDマトリックスの制御 (2)
前回から続きです。スケッチ(プログラム)を修正しました。
(2)を選択したのですが、双方を比較して(1)の方が表示が明るくて見やすいようなので
(1)の方法に変更しました。
ダイナミック駆動による表示では、人間の目で見たチラつきを無くすには1/60秒以上の
間隔で1画面分(16x16LEDマトリックス)を更新させる必要があります。
(1)の場合、1回の割り込みで1ラインですので16回の割り込みを1/60秒で行う必要があり、
その1ライン毎の割り込み間隔は
1/60秒÷16 = 1/960秒 ≒ 1/1000秒 (1msec)
となります。
今回使っているタイマー割り込みライブラリ MsTimer2では最小間隔1msecですので、
取りあえずこの割り込みは実装出来ます。
ところが、 ArduinoのdigitalWrite()は低速で多用により1msec間隔で1ラインの出力が
間に合っていない(1msec以上かかる)感じで、shiftOut()に切り替えたました。
しかしそのshiftOut()も遅いです。
そこで、shiftOut()、digitalWrite()を高速版に置き換えて実装しました。
下記のサイトを参考にしました。
修正版スケッチを掲載します。スケッチ内の #define DRAWMODE 2 にて
上記方式(1)、(2)を切り替えることが出来ます。デフォルトで(1)の方式を設定しています。
スケッチ ダウンロード sample2.zip (2.7K)
// sample2.ino // aitendo 16x16LEDドットマトリックスの制御サンプル // 2016/05/30 たま吉さん // #include <arduino.h> #include <MsTimer2.h> #include <string.h> #define DATAPIN (7) // TB62706のSERIAL-INへ #define LATCHPIN (9) // TB62706のLATCHへ #define CLOCKPIN (8) // TB62706のCLOCKへ #define ENABLEPIN (6) // TB62706のENABLEへ #define DRAWMODE 2 // 割り込み時描画モード 1:全画面/1回 2(1以外):1ライン/1回 uint16_t fbuf[16]; // 表示パターンバッファデータ // 文字データ "こんにちは埼玉県" uint16_t fnt[11][16]= { {// "" 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff }, {// こ 0x0000,0x0000,0x1ff8,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x2000,0x3000,0x1c00,0x07fc,0x0000,0x0000 }, {// ん 0x0200,0x0200,0x0600,0x0400,0x0c00,0x0800,0x0800,0x1b80, 0x1440,0x1840,0x3040,0x2042,0x2046,0x604c,0x4038,0x0000 }, {// に 0x0000,0x1000,0x1000,0x31fc,0x2000,0x2000,0x2000,0x2000, 0x2000,0x2000,0x2200,0x2200,0x2b00,0x31fe,0x1000,0x0000 }, {// ち 0x0100,0x0100,0x0100,0x7ffc,0x0200,0x0600,0x0400,0x0ff0, 0x1808,0x3004,0x0004,0x0004,0x000c,0x0038,0x07e0,0x0000 }, {// は 0x0000,0x2020,0x2020,0x6020,0x47fe,0x4020,0x4020,0x4020, 0x4020,0x4020,0x43e0,0x4438,0x542c,0x6466,0x23c0,0x0000 }, {// 埼 0x2020,0x2020,0x23fe,0x2050,0xf8d8,0x218c,0x2000,0x27ff, 0x2004,0x21e4,0x3924,0x6124,0xc124,0x01e4,0x0004,0x001c}, {// 玉 0x0000,0x7ffe,0x0100,0x0100,0x0100,0x0100,0x0100,0x3ffc, 0x0100,0x0100,0x0118,0x010c,0x0104,0x0100,0xffff,0x0000 }, {// 県 0x07f8,0x2408,0x2408,0x27f8,0x2408,0x2408,0x27f8,0x2408, 0x2408,0x27f8,0x2000,0x3fff,0x0888,0x188c,0x7087,0x0080 }, {// ブランク 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, {// 格子 0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555, 0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555 } }; // // shiftOut高速化版 // void new_shiftOut(uint8_t dataPin,uint8_t clockPin,uint8_t bitOrder,byte val) { uint8_t i; uint8_t bit_data = digitalPinToBitMask(dataPin); uint8_t bit_clock = digitalPinToBitMask(clockPin); volatile uint8_t *out_data = portOutputRegister(digitalPinToPort(dataPin)); volatile uint8_t *out_clock = portOutputRegister(digitalPinToPort(clockPin)); for (i = 0; i < 8; i++) { if (bitOrder == LSBFIRST) { if(val & (1 << i)) { *out_data |= bit_data; } else { *out_data &= ~bit_data; } } else { if(val & (1 << (7 - i))) { *out_data |= bit_data; } else { *out_data &= ~bit_data; } } *out_clock |= bit_clock; *out_clock &= ~bit_clock; } } // // digitalWrite高速化版 // inline void new_digitalWrite(uint8_t pin, uint8_t val) { uint8_t bit = digitalPinToBitMask(pin); volatile uint8_t *out = portOutputRegister(digitalPinToPort(pin)); if (val == LOW) *out &= ~bit; else *out |= bit; } // // バッファ内データを表示する(一括1画面表示) // void fontout() { // 点灯LEDが移動するパターン new_digitalWrite(ENABLEPIN,LOW); // OUTを有効にする for( byte i = 0; i < 16; i++ ) { new_digitalWrite(LATCHPIN, LOW); //送信開始 // 行選択 uint16_t val = _BV(15-i); new_shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, val); new_shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, val>>8); // 行フォントパターンの送信 new_shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, fbuf[i]); new_shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, fbuf[i]>>8); new_digitalWrite(LATCHPIN, HIGH); //送信終了 } new_digitalWrite(ENABLEPIN,HIGH); // OUTを無効にする } // // バッファ内データを表示する(1ライン分割表示) // void fontout2() { static uint8_t _line = 0; // 点灯LEDが移動するパターン new_digitalWrite(ENABLEPIN,LOW); // OUTを有効にする new_digitalWrite(LATCHPIN, LOW); //送信開始 // 行選択 uint16_t val = _BV(15-_line); new_shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, val); new_shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, val>>8); // 行フォントパターンの送信 new_shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, fbuf[_line]); new_shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, fbuf[_line]>>8); new_digitalWrite(LATCHPIN, HIGH); //送信終了 _line++; if (_line == 16) _line = 0; } // // バッファにフォントパターンをセット // void setfont(uint16_t* fptr) { memcpy(fbuf, fptr, 32); } // // バッファ内の指定座標に点をセット // void setdot(uint8_t x, uint8_t y, byte dot) { fbuf[y] = dot ? fbuf[y]| (0x8000>>x): fbuf[y] & ~(0x8000>>x); } void testdotset() { for (byte y=0; y<16; y++) { for (byte x=0; x<16; x++) { setdot(x,y,1); delay(10); } } for (byte y=0; y<16; y++) { for (byte x=0; x<16; x++) { setdot(x,y,0); delay(10); } } } // // 指定座標にフォントパターンをセット // void setfontat(uint16_t* fptr, uint8_t x, uint8_t y) { uint16_t w; if (x>15 || y >15) return; for (byte j=y,i=0; j < 16; j++,i++) fbuf[j] = (fbuf[j]>>(16-x))<<(16-x) | fptr[i]>>x; } void test01() { for (byte i=0; i <11; i++) { for (byte x=15; x > 0; x--) { setfontat(fnt[i],0,x); delay(20); } } } // // ドット表示チェック(デバッグ用) // void dottest() { for (byte y=10; y < 11;y++) for (byte x=0;x <16;x++) { fbuf[y]= 0x8000>>x; delay(50); fbuf[y]= 0; } } // // バッファーデータのスクロール // h_mode : 0 なし,1 左 ,2 右 // v_mode : 0 なし,1 上, 2 下 // void scroll(uint8_t h_mode, uint8_t v_mode) { if (h_mode ==1) for (byte i = 0; i < 16; i++) fbuf[i] = fbuf[i]<<1; if (h_mode ==2) for (byte i = 0; i < 16; i++) fbuf[i] = fbuf[i]>>1; if (v_mode ==1) { for (byte i = 0; i < 15; i++) fbuf[i]= fbuf[i+1]; fbuf[15]=0; } if (v_mode == 2) { for (byte i = 15; i >0; i--) fbuf[i]= fbuf[i-1]; fbuf[0] = 0; } } // スクロールテスト void test02() { byte i; setfont(fnt[6]); for (i=0; i<16;i++) { scroll(1,0); delay(50); } delay(200); setfont(fnt[6]); for (i=0; i<16;i++) { scroll(2,0); delay(50); } delay(200); setfont(fnt[6]); for (i=0; i<16;i++) { scroll(0,1); delay(50); } delay(200); setfont(fnt[6]); for (i=0; i<16;i++) { scroll(0,2); delay(50); } delay(200); setfont(fnt[6]); for (i=0; i<16;i++) { scroll(1,1); delay(50); } delay(200); setfont(fnt[6]); for (i=0; i<16;i++) { scroll(2,2); delay(50); } delay(200); } // // スクロールしながらパターンを表示 // void setfontscl(uint16_t* fptr, uint16_t dly) { for (byte i=0; i<16; i++) { scroll(1, 0); setfontat(fptr, 15-i, 0) ; delay(dly); } } void setup() { pinMode(ENABLEPIN,OUTPUT); pinMode(DATAPIN, OUTPUT); pinMode(LATCHPIN, OUTPUT); pinMode(CLOCKPIN, OUTPUT); digitalWrite(ENABLEPIN,HIGH); digitalWrite(CLOCKPIN, LOW); digitalWrite(LATCHPIN, HIGH); digitalWrite(ENABLEPIN,LOW); // OUTを有効にする digitalWrite(ENABLEPIN,HIGH); // OUTを無効にする setfont(fnt[9]); // フォントバッファに初期パターン設定 // 割り込み開始 #if DRAWMODE == 1 MsTimer2::set(10, fontout); // 16ライン描画/1回 版 #else MsTimer2::set(1, fontout2); // 1ライン描画/1回 版 #endif MsTimer2::start(); setdot(0,0,1); } void loop(){ testdotset(); // ドット単位アクセス表示 test02() ; // スクロールテスト // 配列格納文字パターンを順番に表示する for (byte i =0; i < 11; i++) setfontscl(fnt[i],40); }
最近のコメント