フォト
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年5月 | トップページ | 2016年7月 »

2016年6月の9件の記事

2016年6月28日 (火)

ESP-WROOM-02を始めました(3) SPIFFSの利用

2016/07/02 追記更新

前回はSDカードに漢字フォントとビットマップファイルをを載せていたのですが、
そのデータを標準搭載のフラッシュメモリ上に置けることが分かりました。

ということで、実際にフラッシュメモリ上に漢字フォントをおいて動かしてみました。
取りあえず、動作しました。

03

だだし若干、表示にチラつきが出ます。
フラッシュメモリにアクセスする時にダイナミック駆動に利用しているタイマー割り込みが
中断させられるのかもしれません。

今後、WiFi通信等の利用も考えると、1msecの割り込みのダイナミック駆動はちょっと
負担が大きそうです。

フラッシュメモリの具体的な利用方法

ESP-WROOM-02には4MバイトのSPI接続フラッシュメモリが搭載されており、
そのうち、1M or 3Mバイトをデータ用のファイルシステムとして利用出来ます。

この領域は、専用に確保されておりスケッチを書き換えても影響を受けません。

  Flash layout

  ※公式サイトのリファレンスマニュアル ESP8266 Arduino Core /  File System /  より引用
    http://esp8266.github.io/Arduino/versions/2.3.0/doc/filesystem.html

ファイルシステムに利用する領域はArduino IDEにて選択が出来ます。

フラッシュサイズが4MバイトのESP-WROOM-02は1M or 3Mバイトが選択出来ます。

Arduino IDEから任意のファイルを配置出来る

やり方は、公式サイトのリファレンスマニュアル
  ESP8266 Arduino Core /  File System / Uploading files to file system
     http://esp8266.github.io/Arduino/versions/2.3.0/doc/filesystem.html#uploading-files-to-file-system
に記載されています。

ブラグインをダウンロードして、Arduino IDEに組み込み、Arduino IDEを再起動、
これで、ツールメニューに「EPS8266 Sketch data upload」というメニューが追加されます。

現在開いているスケッチが置いてあるフォルダにフォルダ data を作成してその中に
データファイルを置いておきます。

そんでもって、メニュー 「EPS8266 Sketch data upload」 をクリックしてアップロードします。

実際に漢字フォントとビットマップファイルの約1.75Mバイトをアップロードしてみると
数分かかりましたが、エラーなく完了出来ました。

プログラムからのファイルアクセス

ヘッダーファイル fs.h をインクルドします。これにより、File system object (SPIFFS)が
利用出来ます。

ファイルシステムの操作はSPIFFSオブジェクトを使って行います。
SDライブラリのSDオブジェクトとほとんど同じ感覚で利用出来ます。

SDオブジェクトからSPIFFSオブジェクトへの移行は関数がほぼ1対1でかつ、
パラメタも類似しているためすんなりと行えました。

ただ、どうもSDライブラリとの相性が悪いのかSD.hも別途インクルドするFileクラス関連の
コンパイルエラーが発生しました(これは要調査です)。
まあ、今回は、併用しないのでSD.hのインクルドを止めました。

プログラム(スケッチ)

現時点のバージョンを置いておきます。
     ダウンロード sample5v2_esp.zip (14.1K)   

ココログでは、1Mバイト以上のファイルを置けないので、フォントデータは下記より
ダウンロードして下さい。
     https://github.com/Tamakichi/Arduino-KanjiFont-Library-SD/archive/master.zip

フォントの著作権は私ではなくフォント作成者にあります。
解凍し、README.TXTのライセンス等に関する記載内容を確認の上お使い下さい。

解凍したフォルダのfontbin内のFONT.BINが利用するフォントデータとなります。
このフォントデータをスケッチ配置フォルダ下のdataフォルダに入れて、ESP-WROOM-02
にアップロードして利用します。

最後に

最終的にはESP-WROOM-02用の漢字フォントライブラリを整備したいと思います。

2016/07/02 追記

ライブラリ化し、下記にて公開しました。
  ・ESP8266用漢字フォントライブラリ SPIFFS版 ESP8266-KanjiFont-Library-SPIFFS
    https://github.com/Tamakichi/ESP8266-KanjiFont-Library-SPIFFS

2016年6月26日 (日)

ESP-WROOM-02を始めました(2)

前回からの続きです。
ESP8266搭載のESP-WROOM-02の調査中です。

Arduinoとしてどれくらい利用可能かを確認するため、
Arduino UNO(Atmega328)用のaitendo 16x16LEDマトリックス制御プログラムを移植
してみました。

Dscn5336

動作の様子



意外とライブラリの互換性レベルが高く、
I/Oピンの割り付け変更とタイマー割り込みの設定の変更程度で動きました。
(直接レジスタをいじっている高速版digitalWrite()、shiftOut()はさすがに動かないので、
正規版に戻しました)。

行儀のよいArduino UNO用スケッチなら少々の修正で利用出来ると思います。
実際に自作のビットマップファイルロードライブラリ、フォントライブラリが利用出来ました。
(この動作確認にて、自作のフォントライブラリの不具合を見つけました)

SPI、SDライブラリは割り付けピンを変えるだけで利用出来ました。

プログラム領域にデータを置いて参照利用するpgm_read_byte()利用出来ました。

タイマー割り込みに使っていたMsTimer2ライブラリは動かないので、ESP8266用に
用意されているTickerを利用しました。利用はとても簡単です。

ヘッダーファイル Ticker.hをインクルードして、グローバル変数を宣言して、
  #include <Ticker.h>
  Ticker ticker ;


タイマー割り込み設定の
  MsTimer2::set(1, fontout);
  MsTimer2::start();
  ticker.attach_ms(1, fontout);
と変更するだけです。

「いろは歌」はSDカード上のフォントを利用して表示しています。
「ねこにこんばんわ」はビットマップファイルを読み込んで表示していま。

タイマ割り込みTickerは、MsTimer2に比べると若干、精度が悪い感じです。
ダイナミック駆動のLED表示に若干ムラが生じます。

ピン割り付けがちょっと悩みましたが、下記のサイトの情報が大変参考になりました。

・Qiita - ESP-WROOM-02 Arduino互換ボードのGPIOはこうやって使う
   http://qiita.com/umi_kappa/items/ac3d37db44a2dcfe71fd

スケッチ  ダウンロード sample5_esp.zip (4.6K)

  ※コンパイルには下記のライブラリが別途必要です。
   sdfonts   : Arduino用漢字フォントライブラリ SDカード版
   sdbitmap : Arduino用Bitmap画像ロードライブラリ

// sample5_esp.ino
// aitendo 16x16LEDドットマトリックスの制御サンプル 漢字フォントライブラリ利用バージョン
// 2016/06/16 ESP-WROOM-02(ESP8266)用に移植 by たま吉さん
// 2016/06/29 コメント追記、定数の定義追加 by たま吉さん
//

#include <sdfonts.h>
#include <string.h>
#include <sdbitmap.h>
#include <Ticker.h>

// ビットマップ操作関数宣言
void scrollBitmap(uint8_t *bmp, uint16_t w, uint16_t h, uint8_t mode);
void clearBitmapAt(uint8_t* bmp, uint16_t w, uint16_t h, int16_t x, int16_t y, uint8_t cw, uint8_t ch);
void setBitmapAt(uint8_t *dstbmp, uint16_t dstw, uint16_t dsth, int16_t dstx, int16_t dsty,uint8_t *srcbmp, uint16_t srcw, uint16_t srch);

//ESP-WROOM-02 接続ピン設定
#define DATAPIN   (5)     // TB62706のSERIAL-INへ接続
#define LATCHPIN  (2)     // TB62706のLATCHへ接続
#define CLOCKPIN  (4)     // TB62706のCLOCKへ接続
#define ENABLEPIN (16)    // TB62706のENABLEへ接続

#define MOSI_SD   (13)    // SDカードのMOISへ接続
#define MISO_SD   (12)    // SDカードのMISOへ接続
#define CLK_SD    (14)    // SDカードのCLKへ接続
#define CS_SD     (15)    // SDカードモジュールCSへ接続

//LEDドットマトリックス用定義
#define FBUFSIZE     32   // ドットマトリックスフレームバッファサイズ
#define MWIDTH       16   // ドットマトリックス幅
#define MHIGTHT      16   // ドットマトリックス高さ

// タイマー割り込み
Ticker ticker;

// 表示用バッファ
uint8_t fbuf[FBUFSIZE];   // 表示パターンバッファデータ
uint8_t buf[MAXFONTLEN];  // フォントデータ格納アドレス(最大24x24/8 = 72バイト)

// バッファ内データを表示する(1ライン分割表示)
void fontout() {
  static uint8_t _line = 0;      // 表示対象行
  // 点灯LEDが移動するパターン
  digitalWrite(ENABLEPIN,LOW);   // OUTを有効にする
  digitalWrite(LATCHPIN, LOW);   //送信開始        
 
  // 表示対象行選択
  uint16_t val = _BV(15-_line);
  shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, val);
  shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, val>>8);       
     
  // 表示対象行のフォントパターン送信
  shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, fbuf[(_line<<1)+1]);
  shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, fbuf[_line<<1]);

  digitalWrite(LATCHPIN, HIGH);  //送信終了

  // 表示対象行を次行に設定
  _line++;
  if (_line == MHIGTHT )
    _line = 0;
}

// バッファクリア
void clearBuf() {
   memset(fbuf, 0, FBUFSIZE);
}

// いろは歌デモ
void test_iroha() {
  char* str="色はにほへど散りぬるを我が世たれぞ常ならむ有為の奥山今日越えて浅き夢見じ酔ひもせず";
  uint8_t fn;
  uint8_t tmpbuf[FBUFSIZE];        // 表示パターン2次バッファデータ
  memset(tmpbuf,0,FBUFSIZE);       // 2次バッファクリア
  SDfonts.open();                 // フォントのオープン

  // 表示文字数分ループ処理
  while(1) {
    fn = rand() % (EXFONT24+1);            // 表示フォントサイズランダム決定
    SDfonts.setFontSizeAsIndex(fn);       // フォントサイズの指定
    str = SDfonts.getFontData(buf, str);  // フォントデータの取得
    if (!str)
      break;                               // 文末なら抜ける

    // 1文字分スクロール表示
    for (int8_t t = 0; t < SDfonts.getWidth(); t++) {
      scrollBitmap(tmpbuf, MWIDTH, MHIGTHT, B0001); // 左スクロール
      clearBitmapAt(tmpbuf, MWIDTH, MHIGTHT, MWIDTH-t-1, MHIGTHT-t-1, SDfonts.getWidth(), SDfonts.getHeight());
      setBitmapAt(tmpbuf, MWIDTH, MHIGTHT, MWIDTH-t-1, MHIGTHT-t-1, buf, SDfonts.getWidth(), SDfonts.getHeight());
      memcpy(fbuf,tmpbuf,FBUFSIZE);
      delay(30);
    }
  }
  SDfonts.close(); // フォントのクローズ
}

// ビットマップパターン表示
void test_bitmap() {
  uint8_t tmpbuf[FBUFSIZE]; // 表示パターンバッファデータ
  uint8_t rc;
  uint8_t w,h;

  memset(tmpbuf,0,FBUFSIZE);
  sdbitmap bitmap;
  bitmap.setFilename("IMG2.BMP");

  // ビットマップデータオープン
  rc = bitmap.open();
  w  = bitmap.getWidth();
  h  = bitmap.getHeight();
  
  for (uint8_t i=0; i <= w-MWIDTH; i++) {  
    // データの取得
    bitmap.getBitmapEx(tmpbuf, i, 0, MWIDTH, MHIGTHT, 1);
    memcpy(fbuf,tmpbuf,FBUFSIZE);
    delay(30);
  }
  delay(2000);
  bitmap.close();
}

// セットアップ
void setup() {
  // LEDマトリックス用制御ピンのモード設定
  pinMode(ENABLEPIN,OUTPUT);
  pinMode(DATAPIN, OUTPUT);
  pinMode(LATCHPIN, OUTPUT);
  pinMode(CLOCKPIN, OUTPUT);

  // 制御ピンの初期化
  digitalWrite(ENABLEPIN,HIGH);
  digitalWrite(CLOCKPIN, LOW);
  digitalWrite(LATCHPIN, HIGH);

  // SDカード利用フォントライブラリの初期化
  SDfonts.init(CS_SD);         // フォント管理の初期化

  // 1msec間隔タイマー割り込み設定
  ticker.attach_ms(1, fontout); 
}

// デモループ
void loop(){
  test_bitmap();  // ビットマップデータロードテスト
  test_iroha();   // いろは歌デモ表示
  //clearBuf();   // 表示用バッファ初期化
  delay(1000);
}

今回の動作確認でデジタル出力、SPI通信普通に使えることが分かりました。
次はI2Cを調べてみます。

2016年6月22日 (水)

ESP-WROOM-02を始めました

そろそろ、IoT関連をやりたいなぁと思い、
スイッチサイエンスさんのESPr Developer(ESP-WROOM-02開発ボード)を購入しました。

Dscn5328

スイッチサイエンスさんの下記の記事を参考にしてArduino IDE 1.6.9上に環境を構築しました。
ESP-WROOM-02開発ボードをArduino IDEで開発する方法

01

特に問題なく、チカチカ出来ました。

Dscn5331

ブレッドボードに差し込むよう、オスピンヘッドを取り付けました。

後で知ったのですが、スイッチサイエンスさんではピンソケット付きも販売しているようです。

ESPr Developer(ピンソケット実装済)
02

この形態が正式なのかも...

ざっと調べた感じはで、I/O、SPI、I2C関連はArduinoと同等、タイマ割り込みは
全く異なった実装方法っぽいです。

取りあえず、I2C接続デバイス、SPI接続を色々とつなげてArduinoとの互換レベルを
調べてみたいと思います。

I2Cはスレーブでの利用はまだ対応出来ていないようです。

関連情報
  ・ESP-WROOM-02(公式サイト)
    http://espressif.com/en/products/hardware/esp-wroom-02/overview
    Resourceにドキュメント、SDK、ツールが公開されています。

  ・ESP8266 Arduino Core documentation for version 2.3.0
    http://esp8266.github.io/Arduino/versions/2.3.0/doc/reference.html   
    コア部および標準ライブラリに関するドキュメント。目を通しておく必要ありです。

  ・ESP8266
   http://links2004.github.io/Arduino/index.html
   クラスライブラリ等がリスト、インデックスにて整理されているマニュアルです。
   だだし、説明分等が無いのが残念。ソースから自動生成したっぽい。

  ・ESP8266 Community Wiki
   http://www.esp8266.com/wiki/doku.php
   ESP8266の情報が集まっているWikiサイトのようです。ここをチェックすれば、
   ESP8266に関するよりディープな情報を取得出来そうです。

  ・スイッチサイエンス ESPr Developer(ESP-WROOM-02開発ボード)
     https://www.switch-science.com/catalog/2500/

  ・スイッチサイエンス マガジン ESP-WROOM-02関連記事
     http://mag.switch-science.com/tag/esp-wroom-02/

  ・電子工作と介護と生活と・・・
    https://www.mgo-tec.com/category/arduino/esp8266-wroom
    スイッチサイエンスさんが、リンクを貼っているブログです。情報満載です。

  ・BRILLIANTSERVICE TECHNICAL BLOG - 技適OKな中華IoTモジュールを使いこなす
    http://bril-tech.blogspot.jp/2015/07/okiot.html
    内部構造的な解説が大変参考になりました。

  ・息子と一緒に Makers - ESP-WROOM-02 のWiFiを止めるには?
   http://makers-with-myson.blog.so-net.ne.jp/2016-05-15
   WiFi止めるとかなり、消費電力を抑えられるようです。

  ・息子と一緒に Makers - ESP-WROOM-02 でタイマー割り込みを使ってみた
   http://makers-with-myson.blog.so-net.ne.jp/2016-05-13
   ESPではTickerという機能でタイマー割り込み するのが定番のようですが、別の
   方法もあるようです(要調査)。

  ・Qiita - ESP-WROOM-02 Arduino互換ボードのGPIOはこうやって使う
   http://qiita.com/umi_kappa/items/ac3d37db44a2dcfe71fd
   GPIOピンの割り付けが参考なまりました。

2016年6月21日 (火)

Arduino用ビットマップファイルロードライブラリを作りました

16x16LEDマトリックス表示用に作成したSDカード上のビットマップファイルをロードする機能を
ライブラリ化しました。

サンプルスケッチを作成して動作確認をしてみると、結構バグがありました。
画像サイズによっては正しく動作しない場合がありました。

あまりニーズがないと思われますが公開いたします。

・Arduino用Bitmap画像ロードライブラリ
    https://github.com/Tamakichi/Arduino-SD-Bitmap

形式としてはWindows形式のモノクロビットマップファイルファイルのみ対応となります。

こんな画像をペイントツールにて作成し、SDカードに突っ込んで利用出来ます。

02

コンソールにロードしたパターンを表示

01

これで、モノクログラフィック液晶モジュールなんかにも簡単に画像表示出来そうです。
ビットマップファイルからの画像の部分取り出しも行えるので、ゲームなんかのキャラクタ
にも利用出来そうです。

//
// sdbitmap_sample.ino
// SDカードビットマップファイル操作ライブラリサンプルスケッチ
// たま吉さん 2016/06/21
//
// 概要: SDカード内の画像ファイル LOGO1.BMP,LOGO2.BMP の内容をコンソール出力します。
//

#include <SD.h>
#include <sdbitmap.h>

#define CS_SD     (10)    // SDカードモジュールCS

// ビットパターン表示
// d: 8ビットパターンデータ
void bitdisp(uint8_t d) {
  for (uint8_t i=0; i<8;i++) {
    if (d & 0x80>>i) 
      Serial.print("#");
    else
      Serial.print(" ");
  }
}

// ビットデータデータの表示
// buf:ビットデータ 
// w  :幅(ピクセル)
// h  :高(ピクセル)
//
void bmpdisp(uint8_t *buf, uint16_t w, uint16_t h) {

  uint16_t bn = (w+7)>>3; // 1ライン当たりのバイト数
  uint16_t ln = bn*h;     // 総バイト数

  Serial.print(w,DEC);
  Serial.print("x");      
  Serial.println(h,DEC);      
  for (uint16_t i = 0; i < ln; i += bn ) {
      for (uint16_t j = 0; j < bn; j++) {
        bitdisp(buf[i+j]);
      }
      Serial.println();
  }
  Serial.println();
} 

//
// getBitmap(uint8_t*bmp, uint8_t mode) のテスト
//
void test1() {
  uint8_t tmpbuf[600];        // 表示パターンバッファデータ
  uint16_t w,h,sz;

  memset(tmpbuf,0,600);
  sdbitmap bitmap;
  bitmap.setFilename("LOGO2.BMP");

  // ビットマップデータオープン
  bitmap.open();
  w  = bitmap.getWidth();
  h  = bitmap.getHeight();
  sz = bitmap.getImageSize();
 
  // ビットデータロード
  bitmap.getBitmap(tmpbuf,1);

  // パターン表示
  Serial.print("FILE:LOGO1.BMP size=");
  Serial.print(w,DEC);
  Serial.print("x");
  Serial.print(h,DEC);
  Serial.print(" ");
  Serial.print(sz,DEC);
  Serial.println("byte");
  bmpdisp(tmpbuf,w,h);
  bitmap.close(); 
}

//
//  sdbitmap::getBitmapEx(uint8_t*bmp, uint16_t x, uint16_t y, uint8_t w, uint8_t h, uint8_t mode) のテスト
//
void test2() {
  uint8_t tmpbuf[100];        // 表示パターンバッファデータ
  uint16_t w,h,sz;

  memset(tmpbuf,0,100);
  sdbitmap bitmap;
  bitmap.setFilename("LOGO1.BMP");

  // ビットマップデータオープン
  bitmap.open();
  w  = bitmap.getWidth();
  h  = bitmap.getHeight();
  sz = bitmap.getImageSize();

  Serial.print("FILE:LOGO1.BMP size=");
  Serial.print(w,DEC);
  Serial.print("x");
  Serial.print(h,DEC);
  Serial.print(" ");
  Serial.print(sz,DEC);
  Serial.println("byte");

  for (uint16_t i = 0; i < h; i+=17) {
    for (uint16_t j = 0; j < w; j+= 32) {
      // ビットデータロード
      bitmap.getBitmapEx(tmpbuf, j, i, 32, 17,1);
      // パターン表示
      bmpdisp(tmpbuf,32, 17);
    }
  }   
  bitmap.close(); 
}

void setup() {
  Serial.begin(115200);
  SD.begin(CS_SD);
  test1();
  test2();
}

void loop() {

}

ArduinoはSRAMが2kバイトほどしかないので、大きい画像の全てをロードすることは
出来ませんが、部分取り出しを上手く使えば大きな画像をそれなりに利用出来ると
思います。

2016年6月19日 (日)

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

前回からの続きです。

モノクロ(2値)のWindowsビットマップファイルを汎用的に利用したいなぁと思い、
ライブラリ化を目指して機能を追加しています。

取りあえず、手持ちのアナログジョイスティックを繋げて、ビットマップ画像を
「ぐりぐり」と任意にスクロール表示出来るよう、機能追加しました。

実装したものの、想像していたよりは面白くなかったです。 Otz..
(一度に16x16ドットしか表示出来ないのが敗因ですね)

まあ、ビットマップファイル操作機能は今後フラフィック液晶なんかにも使おうと思います。

接続の様子

Dscn5322

動作の様子その1

下記のモノクロビットマップ画像658x431(36kバイト)から、任意の座標から16x16ドットを
切り出して表示をしています。青空文庫の「芥川龍之介 蜘蛛の糸」をキャプチャしたものです。

01

36kバイトの画像データの全てをArduinoにロードすることは出来ませんが、
ビットマップ画像から部分切り出しでデータをロードすることで表示可能にしています。


動作の様子その2

グラフィック画像っぽいののも試してみました。画像サイズは96x69です。

02

思っていたよりも面白くなかったですが、ビットマップ画像操作ライブラリの動作確認と
割り切ることにします^^


スケッチ ダウンロード sample6.zip (19.8K)   (2016/06/21 バグがあり修正しました)

ビットマップ画像の操作については、下記のソースを参考にさせて頂きました。
   Adafruit-SSD1331-OLED-Driver-Library-for-Arduino/examples/bmp/bmp.pde

ソース自体は全面的に作り直しですが、ヘッダー部と、画像の取り出し部分が大変参考になりました。

スケッチは3つのソースファイルに分かれています。
   sample6.ino   ・・・  メイン
   sdbitmap.h    ・・・  sdbitmapクラス定義ヘッダファイル
   sdbitmap.cpp ・・・  sdbitmapクラス定義本体

sample6.ino

// sample6.ino
// aitendo 16x16LEDドットマトリックスの制御サンプル ビットマップファイル表示
// 2016/06/19 たま吉さん
//

#include <arduino.h>
#include <MsTimer2.h>
#include <string.h>
#include "sdbitmap.h"

#define DATAPIN	  (7)	  // TB62706のSERIAL-INへ
#define LATCHPIN  (9)	  // TB62706のLATCHへ
#define CLOCKPIN  (8)	  // TB62706のCLOCKへ
#define ENABLEPIN (6)     // TB62706のENABLEへ
#define CS_SD     (10)    // SDカードモジュールCSへ

// 表示用バッファ
uint8_t fbuf[32];        // 表示パターンバッファデータ(16x16)

//
// 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() {
  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<<1)+1]);
  new_shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, fbuf[_line<<1]);

  new_digitalWrite(LATCHPIN, HIGH);  //送信終了
  _line++;
  if (_line == 16)
    _line = 0;
}

//
// バッファクリア
//
void clearBuf() {
   memset(fbuf,0,32);
}

void test_bitmapEx2() {
  uint8_t tmpbuf[32];        // 表示パターンバッファデータ
  uint16_t w,h,x=0,y=0;
  int16_t  px,py;
  int16_t dx,dy;
  uint16_t tm;
  
  memset(tmpbuf,0,32);
  sdbitmap bitmap;
  bitmap.setFilename("IMG3.BMP");

  // ビットマップデータオープン
  bitmap.open();
  w  = bitmap.getWidth();
  h  = bitmap.getHeight();
  x = 0; y= 0;

  bitmap.getBitmapEx(tmpbuf, x, y, 16, 16, 1);
  memcpy(fbuf,tmpbuf,32);

  while(1) {
    dx =  analogRead(A1);  
    dy =  analogRead(A0); 
    px = x;
    py = y;
    
    if (x>0 && dx > 520)
      x--;
    else if (x < w-16 && dx < 490) 
      x++;
    if (y>0 && dy < 490)
      y--;
    else if (y < h-16 && dy > 520) 
      y++;

    if (px!=x || py!=y) {
      dx = 40-abs(dx-512)/16;
      dy = 40-abs(dy-512)/16;
      tm = min(dx,dy);
      bitmap.getBitmapEx(tmpbuf, x, y, 16, 16, 1);
      memcpy(fbuf,tmpbuf,32);
    } else
      tm = 30;
    delay(tm);
  }
  delay(2000);
  bitmap.close();
}

void setup() {
  //Serial.begin(115200);
  
  // LEDマトリックス用制御ピンのモード設定
  pinMode(ENABLEPIN,OUTPUT);
  pinMode(DATAPIN, OUTPUT);
  pinMode(LATCHPIN, OUTPUT);
  pinMode(CLOCKPIN, OUTPUT);

  // 制御ピンの初期化
  digitalWrite(ENABLEPIN,HIGH);
  digitalWrite(CLOCKPIN, LOW);
  digitalWrite(LATCHPIN, HIGH);

  // SDカード利用開始
  SD.begin(CS_SD);     // フォント管理の初期化
  
  // 割り込み開始
  MsTimer2::set(1, fontout); //  1ライン描画/1回 版
  MsTimer2::start();

  // デモ
  test_bitmapEx2();  // ビットマップデータロードテスト
}

void loop(){
} 

sdbitmap.h

// 
// sdbitmap.h
// ビットマップファイル操作クラス
// 2016/06/18 たま吉さん
//

#ifndef __SDBITMAP_H__
#define __SDBITMAP_H__

#include <arduino.h>
#include <SD.h>
#include <SPI.h>

// クラス定義
class sdbitmap {
 
 // メンバ変数の定義
 private:
   char*    _filename;         // ビットマップファイル名
   File	    _bmpfile;          // ファイルオブジェクト
   uint8_t  _sts;              // ファイルアクセス状態(0:初期 1:オープン中1)
   int16_t  _bmpWidth;         // 画像幅
   int16_t  _bmpHeight;        // 画像高さ
   uint32_t _bmpImageoffset;   // Start of image data in file
   uint32_t _rowSize;          // 1ラインのバイトサイズ
   boolean  _flip;             // 画像格納方向
	 
 // メンバ関数の定義
 public:
   sdbitmap();		           // コンストラクタ
   void	    init();	           // 初期化
   void	    setFilename(char* str);// ファイルの設定
   uint8_t  open();                // ファイルのオープン
   void	    close();               // ファイルのクローズ
   int16_t  getWidth();            // 画像幅の取得
   int16_t  getHeight();           // 画像高さの取得	 

   uint8_t getByte(uint16_t x, uint16_t y); // 指定位置から8ドット(バイトデータ)取り出し
   uint8_t getBitmap(uint8_t*bmp,           // ビットマップデータの切り出し取得(高速版)
   uint16_t x, uint16_t y, 
	uint8_t w, uint8_t h, uint8_t mode);

   uint8_t getBitmapEx(uint8_t*bmp,         // ビットマップデータの切り出し取得
   uint16_t x, uint16_t y, 
   uint8_t w, uint8_t h, uint8_t mode);
   uint8_t getBitmap(uint8_t*bmp, uint8_t mode); // ビットマップデータの取得  

 private:
   uint16_t read16();		// ワードデータ読み込み
   uint32_t read32();		// ロングデータ読み込み
};

#endif

sdbitmap.cpp

//
// sdbitmap.cpp
// ビットマップファイル操作クラス
// 2016/06/21 たま吉さん
//

#include "sdbitmap.h"
#define DEBUG_BMPLOAD 0

//
// コンストラクタ
//

sdbitmap::sdbitmap() {
	init();
}

//
// 初期化
//
void sdbitmap::init() {
	_filename = NULL;
	_sts = 0;
}

//
// ファイル名設定
//
void sdbitmap::setFilename(char* str) {
	_filename = str;	
}

//
// ワードデータ読み込み
//
uint16_t sdbitmap::read16() {
  uint16_t result;
  ((uint8_t *)&result)[0] = _bmpfile.read(); // LSB
  ((uint8_t *)&result)[1] = _bmpfile.read(); // MSB
  return result;
}

//
// ロングデータ読み込み
//
uint32_t sdbitmap::read32() {
  uint32_t result;
  ((uint8_t *)&result)[0] = _bmpfile.read(); // LSB
  ((uint8_t *)&result)[1] = _bmpfile.read();
  ((uint8_t *)&result)[2] = _bmpfile.read();
  ((uint8_t *)&result)[3] = _bmpfile.read(); // MSB
  return result;
}


//
// ビットマップファイルのオープン 
// 引数なし
// 戻り値	0:正常終了
//			1:オープン失敗
//			2:フォーマットエラー
// 
uint8_t	sdbitmap::open() {
  uint8_t  bmpDepth;              // Bit depth (currently must be 24)
  uint32_t tmp_val;

  _flip    = true;      		  // BMP is stored bottom-to-top

  // ファイルオープン

#if DEBUG_BMPLOAD == 1
  Serial.println();
  Serial.print("Loading image '"); Serial.print(_filename);  Serial.println('\'');
#endif
 
  // Open requested file on SD card
  if ((_bmpfile = SD.open(_filename)) == NULL) {

#if DEBUG_BMPLOAD == 1
    Serial.print("File not found");
#endif

    return 1;	// オープン失敗
  }

  // [ファイルヘッダ] (14バイト)
  //   アドレス (サイズ)  名称  内容
  //   0x0000 (2)  bfType  ファイルタイプ 通常は'BM'
  //   0x0002 (4)  bfSize  ファイルサイズ (byte)
  //   0x0006 (2)  bfReserved1 予約領域 常に 0
  //   0x0008 (2)  bfReserved2 予約領域 常に 0
  //   0x000A (4)  bfOffBits ファイル先頭から画像データまでのオフセット (byte)
  //

  if(read16() != 0x4D42) 			  // BMPシグニチャチェック(2バイト)
	return 2;						  // フォーマットエラー
	
  tmp_val = read32();			   	  // ファイルサイズの取得(4バイト)
#if DEBUG_BMPLOAD == 1    
    Serial.print("File size: "); Serial.println(tmp_val);
#endif
    tmp_val = read32();				  // 予約領域の取得(4バイト)
    _bmpImageoffset = read32();		  // オフセット値の取得(4バイト)
#if DEBUG_BMPLOAD == 1    
    Serial.print("Image Offset: "); Serial.println(_bmpImageoffset, DEC);
#endif

  // [情報ヘッダ] (40バイト)
  //   0x000E (4)  bcSize          ヘッダサイズ 40
  //   0x0012 (4)  bcWidth         画像の幅 (ピクセル)
  //   0x0016 (4)  bcHeight        画像の高さ (ピクセル)
  //   0x001A (2)  bcPlanes        プレーン数 常に 1
  //   0x001C (2)  bcBitCount      1画素あたりのデータサイズ
  //   0x001E (4)  biCompression   圧縮形式 0:BI_RGB(無圧縮) 1:BI_RLE8 2:BI_RLE4 3: BI_BITFIELDS 4:BI_JPEG 5: BI_PNG
  //   0x0022 (4)  biSizeImage     画像データ部のサイズ (byte) 
  //   0x0026 (4)  biXPixPerMeter  横方向解像度
  //   0x002A (4)  biYPixPerMeter  縦方向解像度
  //   0x002E (4)  biClrUsed       格納されているパレット数
  //   0x0032 (4)  biCirImportant  重要なパレットのインデックス
  //
    
  tmp_val = read32();		// ヘッダサイズの取得

#if DEBUG_BMPLOAD == 1        
    Serial.print("Header size: "); Serial.println(tmp_val);
#endif

  _bmpWidth  = read32();	// 画像幅の取得
  _bmpHeight = read32();	// 画像高さの取得
   
  if(read16() != 1)     // プレーン数の取得(必ず1である必要がある)
 	return 2;
 
  bmpDepth = read16();  // 1ピクセル当たりのビット数
#if DEBUG_BMPLOAD == 1        
    Serial.print("Bit Depth: "); Serial.println(bmpDepth);
#endif

  if (bmpDepth != 1)	// 2値(白,黒)
  	return 2;			// 形式エラー

  if(read32() != 0 )  	// 圧縮形式:無圧縮か?
  	return 2;			// 形式エラー

  // 1ラインのバイト数
  _rowSize = (((_bmpWidth+7)>>3) + 3) & ~3;
  if(_bmpHeight < 0) {
    _bmpHeight = - _bmpHeight;
    _flip      = false;
  }

#if DEBUG_BMPLOAD == 1    
    Serial.print("flip: "); Serial.println(_flip);
    Serial.print("Image size: "); Serial.print(_bmpWidth); Serial.print('x'); Serial.println(_bmpHeight);
#endif
  return 0;
}

//
// ファイルのクローズ
//
void sdbitmap::close() {
  _bmpfile.close();
}

//
// 画像幅の取得
//
int16_t sdbitmap::getWidth() {
	return _bmpWidth;
}

//
// 画像高さの取得
//
int16_t sdbitmap::getHeight() {
	return _bmpHeight;
}

//
// ビットマップデータの取得
// 引数
//  bmp : データ格納アドレス
//  mode: 0:通常 1:反転
// 戻り値
//  0:     正常終了
//  0以外  異常終了
//

uint8_t sdbitmap::getBitmap(uint8_t*bmp, uint8_t mode) {
  getBitmap(bmp, 0, 0, _bmpWidth, _bmpHeight, mode);
}

//
// ビットマップデータの切り出し取得
// 引数
//  bmp : データ格納アドレス
//  x   : 取り出し位置:横 (8の倍数であること)
//  y   : 取り出し位置:縦
//  w   : 取り出し幅 (8の倍数であること)
//  h   : 取り出し高さ
//  mode: 0:通常 1:反転
// 戻り値
//  0:     正常終了
//  0以外  異常終了
// 
uint8_t sdbitmap::getBitmap(uint8_t*bmp, uint16_t x, uint16_t y, uint8_t w, uint8_t h, uint8_t mode) {
  uint32_t pos = 0;
  uint16_t ptr = 0;

  uint16_t bx = x>>3;
  uint16_t bw = (w+7)>>3;
  uint8_t bit_w = w & 7;
  
  if (y + h > _bmpHeight)
    return -1;
  if ( ((x + w)>>3) > _rowSize)
    return 1;

  for ( uint16_t row = y; row < y+h ; row++ ) { // ラインループ
    if(_flip) 
      pos = _bmpImageoffset + (_bmpHeight - 1 - row) * _rowSize + bx;
    else
      pos = _bmpImageoffset + row * _rowSize + bx;
      
    // ファイルのシーク  
    if( _bmpfile.position() != pos ) // Need seek?
      _bmpfile.seek(pos);

    // 1ライン分のデータの取得
    for ( uint16_t col = bx ; col < bx+bw ; col++ ) {
      bmp[ptr++] =  mode ? ~_bmpfile.read(): _bmpfile.read();
    }    
    if (bit_w && ptr) // 8の倍数でない
      bmp[ptr-1] &= 0xff<<(8-bit_w);
  }
}

//
// 指定位置から8ビット(1バイト)取り出し
//
uint8_t sdbitmap::getByte(uint16_t x, uint16_t y) {
  uint8_t d1,d2;
  uint32_t pos = 0;
  uint16_t bx = x>>3;        // 取り出しバイト位置:横
  uint8_t bit_x = x & 7;     // ビット位置

  if (bx >= _rowSize || y >= _bmpHeight ) 
    return 0;

  if(_flip) 
    pos = _bmpImageoffset + (_bmpHeight - 1 - y) * _rowSize + bx;
  else
    pos = _bmpImageoffset + y * _rowSize + bx;

    // ファイルのシーク  
    if( _bmpfile.position() != pos )
      _bmpfile.seek(pos);

  d1 = _bmpfile.read();
  if (bit_x) {
    // 8の倍数でない
    d1<<=bit_x;
    d2 = (bx+1 >= _rowSize) ? 0:_bmpfile.read()>>(8-bit_x);
  } else {
    // 8の倍数
    d2 = 0;
  }
  return d1|d2;
}

//
// ビットマップデータの切り出し取得
// 引数
//  bmp : データ格納アドレス
//  x   : 取り出し位置:横
//  y   : 取り出し位置:縦
//  w   : 取り出し幅 
//  h   : 取り出し高さ
//  mode: 0:通常 1:反転
// 戻り値
//  0:     正常終了
//  0以外  異常終了
// 
uint8_t sdbitmap::getBitmapEx(uint8_t*bmp, uint16_t x, uint16_t y, uint8_t w, uint8_t h, uint8_t mode) {
  // ラインループ
  uint16_t ptr = 0;
  uint8_t d;
  uint8_t bit_w = w % 8;
  for (uint16_t row = y; row < y+h ; row++ ) { 
    for (uint16_t col = x; col < x + w ; col += 8 ) {
      bmp[ptr++] = mode? ~getByte(col,row):getByte(col, row);      
    }
    if (bit_w && w > 8) // 右端の端数ビットの補正
      bmp[ptr-1] &= 0xff<<(8-bit_w);
  }  
}

もう少し整理して、ビットマップファイルの操作部分をArduinoのlibraryディレクトリに
登録できるよう、ライブラリ化したいと思います。

2016年6月16日 (木)

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

前回からの続きです。

取りあえず、SDカードにWindows ビットマップファイル(モノクロ)を入れてその画像を
表示出来るようにしました。
前回からビットマップファイルを操作するクラスを作成・追加しました。

次のような画像をペイントツールで作成して表示してみました。

01

動作の様子


この方法だと、画像ファイルを差し換えるだけで任意のメッセージを表示出来ますね。

スケッチ
  ダウンロード sample4.zip (7.9K)

※ライブラリは含まれていません。別途ダウンロードして下さい。

   ・MsTimer2
     http://playground.arduino.cc/Main/MsTimer2

  ・漢字フォントライブラリSDカード版
    https://github.com/Tamakichi/Arduino-KanjiFont-Library-SD

ビットマップファイルの表示部は次のような感じです。

void test_bitmap() {
  uint8_t tmpbuf[32];        // 表示パターンバッファデータ
  uint8_t rc;
  uint8_t w,h;

  memset(tmpbuf,0,32);
  sdbitmap bitmap;
  bitmap.setFilename("IMG2.BMP");

  // ビットマップデータオープン
  rc = bitmap.open();
  w  = bitmap.getWidth();
  h  = bitmap.getHeight();
  
  Serial.print(F("bitmap open rc="));
  Serial.println(rc);

  for (uint8_t i=0; i<w; i+=16) {  
    // データの取得
    bitmap.getBitmap(buf, i, 0, 16, 16, 1);

    // 1文字分スクロール表示
    for (int8_t t = 0; t < 16; t++) {
      scrollBitmap(tmpbuf, 16, 16, B0001);
      clearBitmapAt(tmpbuf, 16, 16, 15-t, 0, 16, h);
      setBitmapAt(tmpbuf,   16 ,16, 15-t ,0, buf, 16, h);
      memcpy(fbuf,tmpbuf,32);
      delay(30);
    }
  }
  delay(2000);
  bitmap.close();
}

巨大なビットマップファイルも扱えるよう、ビットマップファイルから任意の位置の
画像データを取り出して表示出来るよう作成しました(まだまだ作成中)。
bitmap.getBitmap(buf, i, 0, 16, 16, 1)が16x16のサイズの画像を取り出しています。

現状、取り出す座標指定が横座標が8の倍数である必要がありますが、これも
完全に任意の座標を指定できるようにしたいと考えています。

アナログジョイスティック操作で巨大画像を上下左右スクロール表示するってな
感じのものを実装し、ビットマップファイル操作ライブラリを完成させたいと思います。
その5に続きます。

2016年6月12日 (日)

Alliexpressで注文した商品が来ないので全額払い戻し

Aliexpressで電子パーツ類を注文したのですが、保証期間リミットが近いのに商品が来ません。
期間延長を要求したのですが、延長してもらえず「全額払い戻し」の紛争を起こしました。
売り手は受け入れてくれて全額返金となりました。

01_2

Aliexpressでは配達品質の選択が可能なのですが、送料無料を選択すると、
業者によっては配達の追跡が出来ない場合があります。

この業者も商品掲載ページに送料無料の場合は追跡出来ない旨を説明していて、
もし追跡を希望するなら、有料の配達業者を指定するよう記載しています。

確実・早く到着が必須の商品はそれなりの配達業者を指定する必要がありますね。
まあ、全額返金されたので今回のトラブルはこれでOKとします。

2016年6月10日 (金)

書籍 「絶対現場主義 C#入門」、ウエット(泥臭い)で面白い

株式会社ラトルズが発行している「絶対現場主義 C#入門」の電子書籍版を購入。

同社通販サイトに会員登録時に500ポイント(500円相当)をもらったので、
活用しようと、比較的安い書籍をてきとーにチョイスして購入したのですが面白い技術書でした。

この筆者は何もなんだろう?

【電子版】絶対現場主義 C#入門

01

私にとって、オブジェクト指向を改めて勉強(再認識)するには良本でした。
入門をうたっていますが「C#に関しては」という感じで、他の言語で全くプログラム
を組んだことが無い人というか実務経験(お仕事)の無い人が読んでも面白味がくみ取れない
かもしれません。

実務を経験した人なら、ウエット(泥臭い)なブラックユーモアに共感をもって読み進めること
が出来ると思います。

2016年6月 7日 (火)

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

前回の続きです。

日本語表示をしたいと思い、自作の漢字フォントライブラリ(SDカード版)を使ってみました。
機能は以前作成したものと同じですが、かなり簡略化出来ました。表示も明るいです。

01


SDカードを利用するにあたり、3.3Vで動かす必要がありますが
レベルシフト等が面倒(パーツも増える)なので、aitendoのあちゃんでいいの(Arduino)に
変更しました。

LEDドライバ TB62706の推奨利用条件は4.5V~5.5Vなのですが、3.3Vでも問題なく
利用出来ています。

回路図(結線)的には「aitendo 16x16LEDマトリックスの制御 (1)」に掲載の回路図に
microSDカードモジュール(SPI接続)を追加しただけです。

04

aitendoに私が使っているものと同じっぽいのがありますね。
マイクロSDモジュール [MSD-M6P]

02

動作の様子


「いろは歌」をスクロール表示しています。表示するフォントデータはSDカードから
逐次読みだしています。乱数でフォントサイズを変えてスクロール表示しています。
(20x20、24x24ドットのフォントは当然はみ出して表示となります)

ダイナミック駆動による表示のために1msecのタイマー割り込みを行いつつ、
SPI接続のSDカードにアクセスしています。
ちょっと心配でしたが、問題なくデータ取得出来ています。

スケッチ  ダウンロード sample3.zip (3.9K) 

※ライブラリは含まれていません。別途ダウンロードして下さい。
   ・MsTimer2
     http://playground.arduino.cc/Main/MsTimer2

  ・漢字フォントライブラリSDカード版
    https://github.com/Tamakichi/Arduino-KanjiFont-Library-SD

メインのスケッチのみ掲載します。

// sample3.ino
// aitendo 16x16LEDドットマトリックスの制御サンプル 漢字フォントライブラリ利用バージョン
// 2016/06/07 たま吉さん
//

#include <arduino.h>
#include <MsTimer2.h>
#include <sdfonts.h>
#include <string.h>

void scrollBitmap(uint8_t *bmp, uint16_t w, uint16_t h, uint8_t mode);
void clearBitmapAt(uint8_t* bmp, uint16_t w, uint16_t h, int16_t x, int16_t y, uint8_t cw, uint8_t ch);
void setBitmapAt(
 uint8_t *dstbmp, uint16_t dstw, uint16_t dsth, int16_t dstx, int16_t dsty,
 uint8_t *srcbmp, uint16_t srcw, uint16_t srch);
 
#define DATAPIN		(7)	// TB62706のSERIAL-INへ
#define LATCHPIN 	(9)	// TB62706のLATCHへ
#define CLOCKPIN 	(8)	// TB62706のCLOCKへ
#define ENABLEPIN    (6)     // TB62706のENABLEへ
#define CS_SD        (10)    // SDカードモジュールCSへ

// 表示用バッファ
uint8_t fbuf[32];        // 表示パターンバッファデータ
uint8_t buf[MAXFONTLEN]; // フォントデータ格納アドレス(最大24x24/8 = 72バイト)

//
// 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() {
  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<<1)+1]);
  new_shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, fbuf[_line<<1]);

  new_digitalWrite(LATCHPIN, HIGH);  //送信終了
  _line++;
  if (_line == 16)
    _line = 0;
}

//
// バッファクリア
//
void clearBuf() {
   memset(fbuf,0,32);
}

//
// いろは歌デモ
//
void test_iroha() {
  char* str="色はにほへど散りぬるを我が世たれぞ常ならむ有為の奥山今日越えて浅き夢見じ酔ひもせず";
  uint8_t fn;

  // 表示文字数分ループ処理
  while(1) {
    fn = rand() % (EXFONT24+1);            // 表示フォントサイズランダム決定
    SDfonts.setFontSizeAsIndex(fn);       // フォントサイズの指定
    str = SDfonts.getFontData(buf, str);  // フォントデータの取得
    if (!str)
      break;                               // 文末なら抜ける

    // 1文字分スクロール表示
    for (int8_t t = 0; t < SDfonts.getWidth(); t++) {
      scrollBitmap(fbuf, 16, 16, B0001);
      clearBitmapAt(fbuf, 16, 16, 15-t, 15-t, SDfonts.getWidth(), SDfonts.getHeight());
      setBitmapAt(fbuf, 16,16,15-t,15-t, buf, SDfonts.getWidth(), SDfonts.getHeight());
      delay(40);
    }
  }
}

void setup() {
  // LEDマトリックス用制御ピンのモード設定
  pinMode(ENABLEPIN,OUTPUT);
  pinMode(DATAPIN, OUTPUT);
  pinMode(LATCHPIN, OUTPUT);
  pinMode(CLOCKPIN, OUTPUT);

  // 制御ピンの初期化
  digitalWrite(ENABLEPIN,HIGH);
  digitalWrite(CLOCKPIN, LOW);
  digitalWrite(LATCHPIN, HIGH);

  // SDカード利用フォントライブラリの初期化
  SDfonts.init(CS_SD);                // フォント管理の初期化
  SDfonts.open();                     // フォントのオープン
  
  // 割り込み開始
  MsTimer2::set(1, fontout); //  1ライン描画/1回 版
  MsTimer2::start();
}

// デモループ
void loop(){
  clearBuf();     // 表示用バッファ初期化
  test_iroha();   // いろは歌デモ表示
  delay(1000);
}


スケッチの簡単な説明

デモ表示の大半の処理はtest_iroha()関数が行っています。
この関数内では、文字列strから逐次文字を取り出して該当するフォントデータを
SDカードから取得しています。そのデータをscrollBitmap(),clearBitmapAt(),setBitmapAt()
にてビットマップデータ加工をして表示用バッファfbufに書き込んでいます。

scrollBitmap(),clearBitmapAt(),setBitmapAt()は、sample3.zipのlibmatrix.cpp内に
定義しています。これらは作成中の汎用ビットマップ加工関数群の一部です。

汎用的なビットマップデータ加工ライブラリをちびちびと作っているのですが
中々完成しません(今回を機に機能拡張していきたい)^^。

このシリーズもうちょっと続きます。

windowsのbitmap画像フォーマット(モノクロ2値)の画像ファイルをSDカードに入れて
読みだしてマトリックス表示する機能を試作中です^^
その4に続きます。

« 2016年5月 | トップページ | 2016年7月 »