フォト
2025年4月
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30      
無料ブログはココログ

« aitendo 16x16LEDマトリックスの制御 (1) | トップページ | aitendo 16x16LEDマトリックスの制御 (3) »

2016年5月31日 (火)

aitendo 16x16LEDマトリックスの制御 (2)

前回から続きです。スケッチ(プログラム)を修正しました。

Dscn5280

前回はダイナミック駆動(ダイナミック点灯)について、2つの方法を検討し、
  (1)1回の割り込みで1ライン表示し16回の割り込みで1画面分表示する方法
  (2)1回の割り込みで1画面(16ライン分)表示を行う方法

(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()を高速版に置き換えて実装しました。
下記のサイトを参考にしました。
   ・akira345/EasyMP3_For_Arduino
   ・Arduino処理速度とメモリー使用改善の策 | ポート直接制御によるスリム化
動かしてみると、前回よりも文字のスクロールが早くなりました。
割り込み処理に時間がかかっていて、フォアグランドの処理に遅くなっていたようです。

修正版スケッチを掲載します。スケッチ内の #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);
}


« aitendo 16x16LEDマトリックスの制御 (1) | トップページ | aitendo 16x16LEDマトリックスの制御 (3) »

arduino」カテゴリの記事

表示器制御関連」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック


この記事へのトラックバック一覧です: aitendo 16x16LEDマトリックスの制御 (2):

« aitendo 16x16LEDマトリックスの制御 (1) | トップページ | aitendo 16x16LEDマトリックスの制御 (3) »