フォト
2025年3月
            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 31          
無料ブログはココログ

« 2016年4月 | トップページ | 2016年6月 »

2016年5月の11件の記事

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);
}


2016年5月29日 (日)

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

以前やった16x16LEDマトリックスの制御の再挑戦です。

今回はaitendo製のM1571616Cを使ってみました。

LEDドットマトリクス [M1571616C]
LEDマトリックス


実際の製品

Dscn5244

16x16 LEDマトリックスって意外と販売されていなくて、私の知る限り秋月電子と
aitendoしかないです。秋月電子のはブレッドボードに乗せたれない変なピン配置でしたが
aitendoのはストレートで使いやすいですね。

動作確認

Dscn5267

側面にRが明記されている方のPIN並びが1~16のようです(裏面ピン番号16,32が記載)。

下記が製品ページに公開されているピン割り付けです。

02

動作確認すると何か変です。
ブレッドボード上で1ピンを5V、17ピンにGND接続したらCOL1、ROW1が点灯しました。
アノードとカソードが逆っぽい。上の図は間違っているみたいです。
このあたりは、aitendoクォリティだから仕方ない。と諦めます^^

これで、ピンの割り付けが把握出来ました。

次にダイナミック駆動にて制御してみます。
以前作成したのもを修正しました。

ブレッドボード上に実装した様子
Dscn5255

上の写真の16x16LEDマトリックス、左側がピン1~ピン16、右側がピン17~ピン32となります。
また、黒いICがTB62706です。ピンピッチ変換の基板を利用しています。

動いている様子


全点の点灯チェック、パターン表示、向き確認するための漢字表示の動作テストです。
問題なしです(実際は、文字の鏡表示が発覚して配線を逆にしました)。

回路図

※回路図ではR1の抵抗、4.7kとなっていますが2.2kが正しいです。

03_2

利用部品
・TB62706   16ビットLEDドライバ
   シフトレジスタ兼LEDドライバみたいなやつです。抵抗1本で定電流量指定出来ます。
   ダイナミック駆動でカラム選択として利用しています(1ポートのみがセレクトされる)。
   また、シングとして定電流制御を行っています。

   このIC、DIP版が無くてSDIP(1.778mmピッチ)です。
   ピッチ変換基板を使ってブレッドボード上に乗せました。

・74HC595   8ビットシフトレジスタ
   おなじみのシフトレジスタです。連結して16ビット長で利用しています。
   表示パターンデータを流し込みます。
   1ピン当たり35mA、全体で75mA流せます。
   今回は各ICにつき同時に8ポート点灯(電流を流す)ので、1ポート当たり、
            75mA÷8 = 9.475mA 以下
   にする必要があります。取りあえず1ピン当たり8mAと決めます。

・2.2kΩ抵抗
   TB62706用の定電流制御に利用します。
   1つのLEDに流す電流を指定しています。
   TB62706の定電流制御で抵抗値の決定は下記の式を使います。
      IOUT = ( 1.26 / REXT) x 14.7

   今回はLEDに8mA(IOUT)流したいので、抵抗REXTはこの式より約2.2kΩとなります。

  TB62706、74HC595は同じインタフェースのシフトレジスタであるため、
  連結して利用しています。Arduinoからは4本の線で32ビットのデータを流し込んでいます。

スケッチ

Arduino IDE 1.6.9 を利用して作成しました。

MsTime2ライブラリによるタイマ割り込みを使ってLEDのダイナミック駆動を行っています。

  04

 バックグラウンド処理(タイマー割り込み)で表示用データ(uint16_t fbuf[16])の内容を
表示しています。10msec間隔で割り込みを発生し、そのタイミングで16x16ドットの
パターンを表示しています。割り込み処理中のみ、LEDを表示し割り込みを抜けると
LEDを消しています。

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

どちらでも人間の目の残像を利用して全画面表示しているように見えます。

(1)の場合は、1回の割り込み当たりの処理は少ない分、(2)より16倍早い周期で
割り込みを行う必要があります。また常に1ライン点灯出来るため(2)より明るいです。
(実際やってみると明るい。しかし1msec間隔で割り込みしないとチラつきました)

(2)の場合は、1回の割り込み当たりの処理が多い分、遅い周期で済みます。
1画面分16ライン表示後、全画面を消す必要があります。
(消さないと最後のラインだけが長い時間の点灯となり均等な点灯でなくなります)。
そのため、(1)より若干暗くなります。

どちらとも試して問題なく動作しましたが、今回は(2)の1回の割り込みで1画面分
表示することにしました。単位時間当たりの割り込み回数が少ない分、オーバーヘッド
にかかる処理が少なくなると考えました。

今後、他の割り込み処理やSPI、I2C通信との併用した場合、どちらが良いか
再度検討したいと思います(この文書いている途中で、(1)の方が良い気がしてきた.. OTZ)。

フォアグランド処理では、配列のパターンデータを表示用データに突っ込んでいます。

2016/05/30 追記
  やはり、1回の割り込みで1ライン描画の方が表示が良好です。
  ただし、1msec間隔での割り込みが必要で処理が追い付いていない感じです。

スケッチ: ダウンロード sample.zip (2.3K)

//
// aitendo 16x16LEDドットマトリックスの制御サンプル
// 2016/05/29 たま吉さん
//
#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へ

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 }
};

//
// 行の指定
//
void selectRow(byte no) {
    uint16_t val = _BV(15-no);

    // ビット列データの出力
    for( byte i = 0; i < 16; i++ ){
      digitalWrite(DATAPIN, val & _BV(i) ? 1:0);			
      digitalWrite(CLOCKPIN, HIGH);
      digitalWrite(CLOCKPIN, LOW);
    }
}

//
// 行フォントパターンの送信
//
void dataOut(uint16_t val ) {       
	for( uint8_t i = 0; i <16; i++ ){					
    digitalWrite(DATAPIN, val & _BV(i) ? 1:0);      
		digitalWrite(CLOCKPIN, HIGH);
		digitalWrite(CLOCKPIN, LOW);
	}
}

//
// バッファ内データを表示する
//
void fontout() {
    // 点灯LEDが移動するパターン
    digitalWrite(ENABLEPIN,LOW);            // OUTを有効にする
    for( byte i = 0; i < 16; i++ ) {
       digitalWrite(LATCHPIN, LOW);		//送信開始        
       selectRow(i);            
       dataOut(fbuf[i]);
       digitalWrite(LATCHPIN, HIGH);		//送信開始        
     }
    digitalWrite(ENABLEPIN,HIGH);            // OUTを無効にする
}

//
// バッファにフォントパターンをセット
//
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]); // フォントバッファに初期パターン設定 
     
     // 割り込み開始
     MsTimer2::set(10, fontout); // 1/60秒程度で1文字を表示 
     MsTimer2::start();
     setdot(0,0,1);
}

void loop(){
  testdotset();  // ドット単位アクセス表示
  test02() ;     // スクロールテスト

  // 配列格納文字パターンを順番に表示する
  for (byte i =0; i < 11; i++)
    setfontscl(fnt[i],40);
}


以前よりも、あっさりと回路が簡略化出来ました。 以前の回路、縦横変えれば
トランジスタアレイは不要でしたね。なんておバカさんなことをしていたのでしょう。

消費電力の検証

消費電力の測定のためArduinoから表示部に流れ込む電流を測定してみました。

Dscn5272_2

最大で14.4mAでした。電圧は5Vなので消費電力は72mWとなります。
256点点灯の割には意外と少ないですね。
(最初 「瞬間的に最大16個点灯だから、8mA x 16 = 128mAのはずでは?おかしい!」と
おバカな勘違いをしていました。定電流制御でシンク1ライン8mAを流しているのに.. OTZ)

その2に続きます...

2016年5月24日 (火)

グラフィック液晶 Nokia5110(PCD8544)で日本語フォント表示

「漢字フォントライブラリSDカード版」の動作確認に使ってた
グラフィック液晶 Nokia5110(コントローラ用ICはPCD8544)、意外と使いやすいです。
値段もAliexpressで送料込みで$1.8で購入出来ます。

03

表示解像度はモノクロ 84x48ドット (504バイト)と低いですが、その分リソース消費も
少なくてすみ、Arduino(Atmega328)あたりで使うにはちょうどよいです。
また小型でデータ通信は4本(GND、RESET含む)で済むのでお手軽に使えます。

動作の様子

デモ動画では部分スクロール表示の都度、全画面分の表示データをグラフィック液晶側に
転送(SPI接続)しているのですが、実用レベルで表示出来ています。

ただし、SDライブラリと表示用のフレームバッファ(504バイト)の利用でかなりSRAMを
消費します。のこり500バイト弱しかないです。

フレームバッファ(504バイト)無しでも表示は出来るのですが、文字の行間詰めたり
出来ない等ちょっと不便です。


プログラムスケッチを置いておきます。
  ダウンロード lcdtest5.zip (5.1K)

スケッチのコンパイルには別途 「漢字フォントライブラリSDカード版」が必要です。

開発環境

Arduino IDE 1.6.9を利用しています。
(バージョンが上がる毎にコンパイル時間が遅くなっている気がします..)

02

簡単な接続構成

01

グラフィック液晶、SDカードモジュールともSPI接続となります。

当初はSPI通信ではなく、shiftOut()でやっていたのですが遅くて
  ・ shiftOut() の高速化(高速版に置き換え)
  ・ digitalWrite()の高速化(高速版に置き換え)
をやりそこそこ使えるようになりました。

更に、shiftOut()をSPI通信に変えてもSDカードと競合しないと分かり置き換えたところ
各段に処理速度が向上しました。

これくらいの速度が出せるならもうちょっと面白いことが出来そうです。

2016年5月21日 (土)

GitHubはじめました

GitHubをはじめました。今後は作成したプログラム等の公開はGitHubを使っていこうと思います。

私のサイトはこちらです。
  https://github.com/Tamakichi

全然使い慣れていなくて、現在勉強中です。
(GitHubのアカウントはだいぶ前に取っていたのですが、放置していました)

今まで、製作物(ソース)の公開を本ブログで行っていたのですが、ココログでは
1Mバイト以上ファイルをアップロード出来ないので分割する必要があり、不便でした。

また、記事毎にファイルが分散して、自分でもどの記事で公開しているのか等、管理が
面倒になってきました。

過去の公開プログラムを含めてGitHubのサイトを整備していきたいと思います。

追記

GitHubの機能の一つ、gistを使うとソースリストをブログに組み込んで表示出来るみたいです。
試しにIchigoJamのソースを掲載してみました。

この機能はいいですね。

2016年5月20日 (金)

arduino用漢字フォントライブラリSDカード版の製作(2)

前回からの続きです。

Dscn5228

いくつかのグラフィック液晶にてフォント表示を試してみると、表示するには面倒な処理が
必要と判明しました。

モノクログラフィック液晶では、表示用のメモリが下図のようになっており1バイトが縦の
ドットに対応した形が一般的のようです。

  グラフィック液晶Nokia5110のメモリ構造 (1バイトが横1ドット 縦8ドットに対応する)
05

この形式で正しく文字を表示するには、ドット単位で文字の回転をさせてからメモリに書き込む
必要があります。16x16ドットだと256ドット分の座標変換となります。

具体的には下記のフォントの形式を

      フォントデータのデータ並び

   02

次のような形式に変換します。

      グラフィック液晶用に変換したフォントデータのデータ並び

03



赤い数字がバイト並びの順番です。MSBが上位ビット、LSBが下位ビットです。
この処置は1ビットづつ取り出して、再配置という無駄に処理を要します。

表示の都度、変換しても良いのですが、SDカードの大容量を生かし、
あらかじめフォントを作成して用意することにしました。

フォントライブラリの利用時に、切り替えて利用出来るようにしました。

  08

これにより、表示がちょっと早くなりました。また、プログラムも短くなりました。
ただし、SDカードからの読み取りなのでやはり遅いです。

ライブラリはもう少し、動作確認をしてから公開したいと思います。
この処理はSPIフラッシュメモリ版のライブラリにも反映したいと思います。

2016/05/21 追記

現時点のライブラリをGitHubにて公開します。
  ・ライブラリ公開ページ Arduino-KanjiFont-Library-SD
    https://github.com/Tamakichi/Arduino-KanjiFont-Library-SD

  ・ダウンロード直リンク
    https://github.com/Tamakichi/Arduino-KanjiFont-Library-SD/archive/master.zip

2016年5月13日 (金)

arduino用漢字フォントライブラリSDカード版の製作(1)

最近、ArduinoでSDカードをいじっているのでこの機会に以前作成した漢字フォントROM
SDカードに移植することにしました。

実際にやってみると、SPIフラッシュメモリからの読み込み部の関数の差し換え程度で
簡単に移植出来ました。SPIフラッシュメモリの代わりにmicroSDカードにフォントデータ
ファイルを入れ、そのファイルからデータを取得します。

動作確認はSainSmart製Arduino UNO互換機を利用
3.3Vでの稼働が可能で、オスとメスのジャンパワイヤーが利用出来て便利です。

Dscn5217

Arduino IDEでの移植作業
SDカードライブラリを使うとフラッシュメモリ、SRAMの消費量が多くなります。
ダイエット作業がちょっと必要です。

現状だと、「Arduino - TV出力(TVoutLibrary使用)で漢字表示」でやった処理を
SDカード版に置き換えることは出来そうにないです。

02

7種類(8,10,12,14,16,20,24ドット)のフォントデータの取得動作チェック
文字列(UTF-8)に該当するフォントデータを取得し、そのパータンをコンソール出力しています。

画像は24ドットのフォントを表示していることろ

01

何となく問題なく動作しています。あとは表示速度やエラー処理、メモリ消費量を
押させる等の見直しをやっていきます。

取りあえずは、手持ちの液晶ディスプレイに日本語文章を表示して使い物になるかを
評価したいと思います。


2016/05/15 追記


テーブル等の領域をプログラム領域(フラッシュメモリ上)に配置することでRAMの使用が
259バイト少なくすることが出来ました。ただし速度的に若干低下する可能性があります。

03

2016/05/16 追記

手持ちの液晶ディスプレイ Nokia5110によるフォント表示テスト

Dscn5222

この液晶ディスプレイは表示は見やすいですが、ビットデータの並びが縦方向なので
表示のために、フォントデータを回転させる必要ります。

SPIフラッシュメモリに比べるとやはりちょっと遅いですね。
まあ実用レベルです。

この表示テストでいくつかの不具合を発見しました。移植前の不具合もありました。
また、使いにくところを改善(おもにメモリ消費を抑える)しました。

8ドットフォント

Dscn5219

16ドットフォント

Dscn5220

24ドットフォント

Dscn5221

この液晶ディスプレイで8の倍数以外のフォントを表示する場合ちょっと処理が面倒です。
縦に詰める際、一旦表示中のデータを読んで合成して再度書き込む必要があります。

この液晶ディスプレイでは表示内容の参照は出来ないようで、ちゃんとやるには
書込み用のバッファを用意してく必要があります。
それは面倒なのでやりません。結果、現状では8、16、24ドット以外は行間に隙間が空きます。

2016年5月11日 (水)

ArduinoによるI2C EEPROMのエミュレーション (5)

前回からの続きです。

ユニバーサル基板に実装してIchigoJam用シールドにしてみました。

Dscn5206

シールドにはIchigoJam用のピンソケットとArduino用のピンソケットを設けています。
Atmega328にはaitendoのラベルを貼ってみました。

Dscn5205

長い端子でIchigoJamに装着します。この端子はaitendoのピンソケット(2.54) [PS254S-H8.5]
の14ピンを使っています。
IchigoJamとの接続はVCC、GND、SDA、SCLの4線です。

Dscn5201

当初、動作が不安定でしたが10μFの電解コンデンサをVCC・GND間(写真に見えるやつ)
を入れたところ安定しました。

ただし、SDカードの抜き差し時にIchigoJamにリセットがかかってしまいます。
さらに100μの電解コンデンサを入れたら抜き差し時のリセットが発生しなくなりました。

Dscn5200

う~ん、ブレッドボード時の実装ではパスコン0.1μFだけで問題なかったのですが..
良く考えたら、利用しているIchigoJamがブレッドボード時で使っていたものと違いますね。

試しに、純正版IchigoJam(旧版)で試してみました。

Dscn5210

やはり、全然問題なしです。100μFコンデンサさは不要です。
多分、10μFコンデンサも不要でしょう。
(旧版はピン幅が異なるため上に乗せられませんのでワイヤー接続です)

かき集めた部品で作った作ったIchigoJamにちょっと問題ありのようです。
電源部の三端子レギュレータは50mAでは足りないのか、または安定した電流が取れて
いない可能性があります。

利用しているキーボードも別のものを使っており、キーボードの消費電流等も影響している
可能性もありますね。

シールド自体は問題無しです。
上の乗っかっているのはArduinoなのでArduino IDEによるプログラムの作成が出来ます。
EEPROMエミューレションの他に色々と別のことが出来そうです。

2016年5月 8日 (日)

Ichigojam Uの製作

基板のみ購入したIchigoJam U

Dscn4719

手持ちの部品で組み立てました。

02

後ろ側に圧電スピーカーを取り付けました。

Dscn5185

PS/2コネクタの代わりにUSBコネクタを取り付けたために、ちょっと修正入れています。

03

オリジナルと比べると、ちょっと不格好ですが利用上は問題なしです。
ラベルはEXCELで作成して印刷しました。良く使うI2C(SDA、SCL)も明記しました。

IchigoJam Uは、初代と比べると一回り大きいです。
ピンソケットの幅が初代より5mmくらい広くなっています。
初代は水晶振動子は無しでしたが、IchigoJam Uでは標準装備となっています。

Dscn5192

キーボードもUSB接続でPS/2キーボードとして動作しました。
ただし、キーボードに関しては相性があります。手持ちのキーボードでは
動かないものがありました。

2016年5月 7日 (土)

ArduinoによるI2C EEPROMのエミュレーション (4)

前回からの続きです。

見た目が既に純正のArduinoからずれている感がありますが、
一応中身(Atmage328Pの中身)はArduinoで、Arduino IDE環境にて開発しているので
このタイトルで行きます。

Arduino Unoだと5V=>3.3Vレベル変換が必要ですが
Arduino Pro Mini 328 3.3V 8MHz ならそのまま利用できると思います。

リセットボタンを追加しました。
また、一時的にmicroSDカードモジュールを手持ちの
秋月電子の 「マイクロSDカードスロットDIP化キット」に置き換えました。

    マイクロSDカードスロットDIP化キット AE-MICRO-SD-DIP
   03

Aliexpressで購入したモジュールは、コンデンサ・抵抗等が付加されており、
たまたま正常動作した可能性があるため動作確認しました。
よく使われるパーツ利用の動作チェックです。動作としては特に問題無しでした。

Dscn5177


ブレッドボード上の実装図

01

3.3.V、GND、SCL、SDA の4本はIchigojamに接続します。
その右のGND、DTR、RXD、TXDはUSB-UARTモジュール経由でパソコンに接続し、
Arduino IDEによるスケッチ書のき込み、デバッグ用シリアル通信に使用します。

回路図
02

秋月電子のマイクロSDカードスロットの接続において、SPI接続には10kΩ程度の
プルアップ抵抗を入れるのが良いようですが今回は入れていません。
ビットが化けたりする場合入れておくことにします。
(前回使っていたモジュールには組み込み済みで問題無しです)

クロックは内部クロックの8MHzにて稼働させています。
内部クロックの場合、最大10%のずれがあるのでシリアル通信に問題が発生する
恐れがあります。また個体差もあるようです。

私の使っているATmage328Pでは良く使う115200bpsでも問題なく通信出来ました。


スケッチ


「Arduino(あちゃんでいいの)によるI2C EEPROMのエミュレーション (2)」
からの変更はありません。

スケッチの書き込みは、ブートローダ経由でやっていますが稀にエラーとなる場合が
あります。内部クロック利用のためい通信エラーが発生するようです。
ただし、リトライにより書き込みは完了してくれます。

2016年5月 5日 (木)

ArduinoによるI2C EEPROMのエミュレーション (3)

部品数を抑える&基板実装の試行中。前回からの続きです。

内部クロック(8 MHz internal clock)で動くかどうか試したところ、問題なく動作しました。
aitendoの「あちゃんでいいの」は不要となりました。

08

更に、I2C(Wire)のソースを見ると、SDA・SCLともプルアップ抵抗ありの設定となってました。
プルアップ抵抗も不要と分かり取りました。

Eeprom

内部クロック(8 MHz internal clock)動作の設定は、下記のサイトを参考にしました。

1) Qiita - ATmega328P に 8MHz 版のブートローダーを書き込む
2) From Arduino to a Microcontroller on a Breadboard
3) Running Atmega 328P without external quartz

上記 3)の記事によると 3.3V 内部クロック 8MHz駆動は、5V 16MHz稼働に比べ消費電力
が抑えられるみたいですね。

試しにIcigoJamからの電源供給にしてみても問題なく動作しました。
後で消費電力等は計測してみます。

2016/05/06 追記
消費電力を測定しました。

Dscn5169

Dscn5172

流れる電流は 最大で23.4mA 、消費電力は77.22mW(23.4x3.3V) でした。

次にIchigoJamを含めた全体の消費電力(電流)を測定してみました。
測定はIchigoJamのVCCに直接3.3Vを供給、キーボードはつなげたままの状態で行いました。

流れる電流は最大で最大で42.1mA、消費電力は138.93mW(42.1x3.3V)でした。

Dscn5175

IchigoJamの三端子レギュレータは3.3V 50mAのタイプが使われています。
(2016/05/06 補足 IchigoJam Uは150mAのです)

データシートを見ると 5Vから3.3V変換の場合、実際には最小で75mA流せるみたいなので、
随時接続の利用でも問題なさそうです。

Arduino(あちゃんでいいの)によるI2C EEPROMのエミュレーション (2)

前回の続きです。

保存先をmicroSDカードにしました。これによりIchigoJamで利用出来るEEPROMと同等の
容量(128kバイト 128本のプログラム保存)となりました。
エミュレションのターゲットは Microchip社の24LC1025(容量 128kバイト)です。

開発はArduino(あちゃんでいいの)を使い Arduino IDE 1.6.8を利用しました。

関連記事
  Arduino(あちゃんでいいの)でmicroSDカード利用の動作確認
  Arduino1台で複数のI2Cスレーブを実装する

実験中の画像
Dscn5138

ブロック図的なもの

01

機能としては、EEPROMと同様に、
IchigoJamの標準コマンド LOADSAVEFILESLRUNでプログラムの保存、読込、
実行が可能です。保存したmicroSDカードはもちろんパソコンでも利用出来ます。

05

SDカードに保存するファイルの形式は2つのタイプをサポートしました。
  1)バイナリ形式(IchigoJamメモリー形式)
  2)テキスト形式

1)はIchigoJamのメモリー上、またはEEPROM保存形式です。テキストエディタで編集する
ことが出来ません。2)はテキストエディタで編集可能な形式です。

バイナリ形式は、プログラム領域(1kバイト)の未使用部にデータを埋め込で利用する
IchigoJam的プログラミング・テクニックが存在するのでサポートは必須ですね。
ただし、この形式だとパソコン上での編集が面倒です。
そこで、テキスト形式もサポートすることにしました。

実際のmicroSDカードの中身
02

保存するテキストファイル名はIchigoJamのプログラム番号に対応しています。
IchigoJamではEEPROM上のプログラムは100~227の番号で指定しますが、その番号を
ファイル名にしています。

拡張子はバイナリ形式がDAT、テキスト形式がTXTです。
新規保存の場合はXXX.DATのバイナリ形式で保存されます。
(デフォルトはバイナリ形式としています)

テキスト形式で保存を行う場合、microSDカードにあらかじめXXX.TXTファイルを
作成しておく必要があります。
(保存時に拡張子をチェックし、TXTであればテキスト形式で保存している)

テキスト形式の場合、未使用領域へのデータ埋め込みは出来ません。
保存時に消えてしまいます。

ファイルの日付は現時点では"2016/05/01"固定です。

スケッチ(プログラムソース)
   
ソースを公開します(注意: まだまだ動作確認不十分です^^ )
   ダウンロード Ichigoepprom3.zip (6.4K)

   
実行にはSDカードモジュール、I2C接続、Arduono 3.3V稼働環境が必要となります。


プログラムの実装について

SDカードの利用はArduino IDE 1.6.8の付随するSDライブりを利用しています。
I2C通信については、Arduino IDE 1.6.8の付随するWireライブラリを修正して利用してます。

今回の実装でIchigoJamがI2Cマスター、ArduinoがI2Cスレーブの構成です。
ArduinoのI2C(Wire)ライブラリは、 "受信データがMAX 32バイト、スレーブとして利用する
場合、スレーブアドレスを同時に複数もてない"
制約があります。

この部分を修正し、受信データ MAX 64バイト、スレーブアドレス複数対応しました。
(修正については大したことはやっていません)

ちなみに、Wireライブラリはハードウェア依存のためか、次のディレクトリに入っています。
(インストール先 先頭フォルダ名は各自の環境により異なります)
  \Arduino 1.6.8\hardware\arduino\avr\libraries\Wire 

せっかくなので改良版ライブラリを置いておきます(上記フォルダに入れ替えで利用)
        改良版 Wireライブラリ: ダウンロード Wire.zip (16.6K)      

        既存のライブラリと置き換えても問題は発生しないと思いますが、
        修正部分を無効化できるよう、ライブラリフォルダ内の"WIRE_EXPANSION.h"
        にて設定出来るようにしました。

        03

        WIRE_EXPANSION.h の WIRE_EXPANSION を 0 にすると無効になります。

        04

  この修正版を使ってスレーブアドレス複数対応を利用する場合は、次のような記述をします。

#include <Wire.h>
extern "C" {
#include <utility/twi.h>
}

#define DEVICE_ADDRESS 0x50  // 24LC1025 I2Cデバイスアドレス 

// I2Cマスタからのデータ受信ハンドラ
void receiveEvent(int len) {
   uint16_t slaveAdr;                 // マスター要求スレーブアドレス
   slaveAdr = twi_get_address();      // ターゲットスレーブアドレス
   ・・・
}

void setup() {
    Wire.begin(DEVICE_ADDRESS) ;        // I2Cの初期化、自アドレスをA0とする
    twi_set_addressMask(B00001000);     // 複数アドレス対応 DEVICE_ADDRESS+0x04 も許可)
    Wire.onRequest(requestEvent) ;      // I2Cコマンド要求割込み関数の登録
    Wire.onReceive(receiveEvent) ;      // I2Cデータ受信割込み関数の登録
    ・・・
}

void loop() {
    ・・・  
}

具体的にはsetup()のWire.begin(DEVICE_ADDRESS)の直後に
    twi_set_addressMask(B00001000);
でアドレス一致チェックで無視するビットをセットします。

7ビットアドレス(下位ビット未使用)なので、0x50(DEVICE_ADDRESS)の他に0x54も
利用したい場合は、0x04<<1 ( = B00001000 )  を引数に指定します。

複数のアドレスの判定は、 データ受信時のハンドラ receiveEvent(int len) 内で
  twi_get_address()
を使って実際のターゲットとなるスレーブアドレスを取得することが出来ます。

« 2016年4月 | トップページ | 2016年6月 »