ArduinoでグラフィックLCDを動かす(AQM1248A編)(10)

このページをスマホなどでご覧になる場合は、画面を横長にする方が読みやすくなります。
目次へ  前のページへ (6) (7) (8) (9) (10) (11) (12) (13) (14) 次のページへ
2016年05月04日 公開。

4-1-7.AQM1248AでHello,World!(ビットマップ転送)

AQM1248Aの画面の制御の方法は、一通り説明したので、ここで、実際に画面にメッセージを表示してみましょう。定番の"Hello, World!"を表示する事にします。

画面にメッセージを表示するといっても、AQM1248Aには、文字コードを送ると画面に文字が表示される様な、高度な機能は内蔵されていません。たとえ文字列を送るとしても、それらをビットマップ(ピクセルの集合で構成された絵)として送る必要があります。

4-1-7-1.転送するビットマップのデザイン

メッセージのビットマップを作成する際に、まず文字の大きさを考える必要があります。複数のページにまたがる大きなビットマップを作ると、データの扱いがちょっと面倒になるので、縦方向は8ピクセル以内に収める方が楽です。

MGLCDという液晶表示用のライブラリを作った時に、フォントを作ったので、それをそのまま使うと、フォントを作る手間が省けます。MGLCD用のフォントは、縦方向が7ピクセルでデザインされており、行間のスペースを1ピクセル含めたとしても、1ページで収まるようになっています。(MGLCDライブラリの話は、また後で出てきます)

またMGLCDライブラリ用のフォントは、横方向が5ピクセルの固定幅になっています。文字間に1ピクセルのスペースを開けるとすると、1文字あたり、6ピクセルの幅になります。"Hello, World!"は、13文字の文字列ですから、全体で6×13=78ピクセル幅になります。

MGLCDライブラリのファイルからフォントをコピーすると楽なのですが、それではビットマップ作成の手順の説明にならないため、ここでは、フォントの形だけを拝借し、それを2進数に変換する作業などは、一からやり直すことにします。

ビットマップを作る方法は色々ありますが、ここでは、視覚的に理解しやすいExcel方眼紙を使う事にします。Excel方眼紙というと、「Excelの使い方としては間違っている」と批判が多いですが、フォントのデザインや小型のビットマップの作成などには、結構便利です。

まずExcelの新規のワークシートを開き、セルの幅を狭めて方眼状にします

次に、A列の幅を少し広げて、A1のセルから順にD0、D1、…、D6、D7と、縦に入力します。(図49参照) これらは、各行のピクセルが、1バイト中の何ビット目かを表わしています。

図49、Excel方眼紙のA列にD0~D7のラベルを打ち込む
図49、Excel方眼紙のA列にD0~D7のラベルを打ち込む

それから、B列以降のセルの必要な部分を黒で塗りつぶし、表示するビットマップをデザインします。MGLCDライブラリの文字コード表を参考にしながら"Hello, World!"の文字列を塗りつぶしていきます。(図50参照)

図50、セルを黒で塗りつぶし、ビットマップを入力
図50、セルを黒で塗りつぶし、ビットマップを入力

デザインが終わったら、各列の白黒のパターンを、1バイトの16進数(16進数2桁)に変換します。(図51参照)

図51、各列の白黒のパターンを2桁の16進数に変換
図51、各列の白黒のパターンを2桁の16進数に変換

B列を例に挙げて説明します。D7からD0までを下から上に見ると、白、黒、黒、黒、黒、黒、黒、黒となっています。白を0、黒を1として、2進数に変換すると、01111111B(Bは2進数である事を表す記号)となります。それを16進数に変換すると7FHとなります。(図52参照) 2進数4桁が16進数1桁に対応しますから、上位4ビット(D4~D7)と下位4ビット(D0~D3)をそれぞれ16進数1桁に変換し、変換結果を並べて書けばよい事になります。

図52、白黒のパターンを16進数に変換する方法
図52、白黒のパターンを16進数に変換する方法

2進数から16進数への変換に慣れていない人は、図53の変換表を使うといいでしょう。

図53、白黒パターンを16進数に変換する際の変換表
図53、白黒パターンを16進数に変換する際の変換表
4-1-7-2.Hello, World!を表示するスケッチの作成

それでは、先ほどの作業で得られたビットマップをAQM1248Aの画面に表示するスケッチを作ります。

作成したスケッチをリスト9に示します。このスケッチはハードウェアSPIでAQM1248Aと通信する前提で作ってあります。また、Arduino IDE 1.0.X、1.6.X、および1.7.Xのいずれでも動作します。

リスト9、Hello, World!を表示するスケッチCOPY
#include <SPI.h>

#define DI_PIN  9
#define CS_PIN 10

#ifndef SPI_CLOCK_DIV32 // for arduino M0(怒) 
  #define SPI_CLOCK_DIV32 32
#endif

void LcdCommand(uint8_t cmd)
{
  digitalWrite(CS_PIN,LOW);
  digitalWrite(DI_PIN,LOW);
  SPI.transfer(cmd);
  digitalWrite(CS_PIN,HIGH);
} // LcdCommand

void LcdData(uint8_t dat)
{
  digitalWrite(CS_PIN,LOW);
  digitalWrite(DI_PIN,HIGH);
  SPI.transfer(dat);
  digitalWrite(CS_PIN,HIGH);
} // LcdCommand

void InitializeLcd()
{
  LcdCommand(0xae);
  LcdCommand(0xa0);
  LcdCommand(0xc8);
  LcdCommand(0xa3);

  LcdCommand(0x2c);
  delay(2);
  LcdCommand(0x2e);
  delay(2);
  LcdCommand(0x2f);

  LcdCommand(0x23);
  LcdCommand(0x81);
  LcdCommand(0x1c);

  LcdCommand(0xa4);
  LcdCommand(0x40);
  LcdCommand(0xa6);
  LcdCommand(0xaf);
} // InitializeLcd

void ClearScreen()
{
  for(int page=0; page<6; page++) {
    LcdCommand(0xb0+page); // Page address set
    LcdCommand(0x10);      // Column address set upper bit
    LcdCommand(0x00);      // Column address set lower bit
    for(int x=0; x<128; x++) {
      LcdData(0);
    } // for x
  } // for page
}  // ClearScreen

void Hello()
{
  const uint8_t BitMap[] = 
    {
      0x7f,0x08,0x08,0x08,0x7f,0x00, // H
      0x38,0x54,0x54,0x54,0x18,0x00, // e
      0x00,0x41,0x7f,0x40,0x00,0x00, // l
      0x00,0x41,0x7f,0x40,0x00,0x00, // l
      0x38,0x44,0x44,0x44,0x38,0x00, // o
      0x00,0x58,0x38,0x00,0x00,0x00, // ,
      0x00,0x00,0x00,0x00,0x00,0x00, // ' '
      0x3f,0x40,0x38,0x40,0x3f,0x00, // W
      0x38,0x44,0x44,0x44,0x38,0x00, // o
      0x7c,0x08,0x04,0x04,0x08,0x00, // r
      0x00,0x41,0x7f,0x40,0x00,0x00, // l
      0x38,0x44,0x44,0x48,0x7f,0x00, // d
      0x00,0x00,0x5f,0x00,0x00,0x00  // !
    };

  LcdCommand(0xb0); // Page address set
  LcdCommand(0x10); // Column address set upper bit
  LcdCommand(0x00); // Column address set lower bit
  for(int i=0; i<sizeof(BitMap); i++) {
    LcdData(BitMap[i]);
  } // for i
} // Hello

void setup() {
  pinMode(DI_PIN,OUTPUT);
  pinMode(CS_PIN,OUTPUT);
  digitalWrite(CS_PIN,HIGH);
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV32);
  SPI.setDataMode(SPI_MODE3);
  SPI.setBitOrder(MSBFIRST);
  InitializeLcd();
  ClearScreen();
  Hello();
}

void loop() {
}

setup関数では、RS信号および/CS信号に使うピンの初期化とSPIの初期化を行った後、InitializeLcd関数を呼び出でAQM1248Aの初期化を行い、ClearScreen関数で画面の消去を行ない、さらにHello関数を呼び出して"Hello, World!"の表示を行っています。

Hello関数では、BitMapというuint8_t型(符号なし8ビット整数)の配列定数に、先ほど作成したビットマップデータを保存しています。

Hello関数は、Page address setコマンド(表9参照)、Column address set upper bitコマンド(表10参照)、Column address set lower bitコマンド(表11参照)を順に発行して、画面の左上のビットマップを転送できる状態にしておいてから、BitMap配列定数の内容を順にLcdData関数で送信しています。

このスケッチを実行したときの画面写真29に示します。

写真29、リスト9の実行結果
↑ 画像をクリックすると拡大
写真29、リスト9の実行結果
広告
【コラム】ビットマップを埋め込んだスケッチの可読性を向上する方法

スケッチ内にビットマップを埋め込む場合、リスト9に示す様に、16進数がずらずらと並ぶ、暗号の様な読みにくいスケッチになってしまいます。

リスト9では何の文字のビットマップであるかをコメントで示し、何とかスケッチの可読性(読みやすさの事。英語でreadabilityという)を確保していましたが、文字列ではなく、絵のビットマップの場合は、コメントではビットマップの内容を説明しにくい事もあります。

このコラムでは、マクロ定義をうまく使う事で、リストを見ればどんなビットマップが埋め込まれているかが一目で分かるようにする方法を紹介します。この方法は、MGLCDライブラリの中のフォント定義にも使われています。

まず、リスト10に示すs、M、_の3種類のマクロを定義します。マクロに使う文字はなんでもいいのですが、Mはできるだけ目立つ文字に、_はできるだけ目立たない文字にしてあるところがポイントです。

リスト10、ビットマップの可読性を上げるための3種類のマクロCOPY
#define s ((((((((((((((((0
#define M <<1)+1)
#define _ <<1))

そして、図52の様な01111111Bのパターンだと、0x7fと書く代わりに、次の様に記述します。

リスト11、可読性を高めたビットマップの記述例COPY
s  _ M M M M M M M 

この記述は、マクロを展開すると次の様に解釈されます。

リスト12、リスト11をマクロ展開した結果COPY
((((((((((((((((0<<1))<<1)+1)<<1)+1)<<1)+1)<<1)+1)<<1)+1)<<1)+1)<<1)+1)

一見複雑な式ですが、落ち着いて式を見ると、左シフトと足し算を組み合わせて、ビットマップの2進数を評価する式になっている事が分ります。計算結果は、もちろん16進表記で7FHになります。

このマクロを使ってリスト9のHello関数を書き直すと、リスト13の様になります。このリストを見ると、一目でどんなビットマップが埋め込まれているかが理解できる様になっているのが分かるでしょう。反面、リストがとても長くなるのが欠点です。(コンパイル後はリスト9と同じコードになるので、Arduinoのフラッシュメモリをたくさん使ったり、実行速度が低下する事はありません)

リスト13、リスト9のHello関数の可読性を高めた例COPY
void Hello()
{
  #define s ((((((((((((((((0
  #define M <<1)+1)
  #define _ <<1))
  
  const uint8_t BitMap[] = 
    {
      s  _ M M M M M M M  ,
      s  _ _ _ _ M _ _ _  ,
      s  _ _ _ _ M _ _ _  ,
      s  _ _ _ _ M _ _ _  ,
      s  _ M M M M M M M  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ M M M _ _ _  ,
      s  _ M _ M _ M _ _  ,
      s  _ M _ M _ M _ _  ,
      s  _ M _ M _ M _ _  ,
      s  _ _ _ M M _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ M _ _ _ _ _ M  ,
      s  _ M M M M M M M  ,
      s  _ M _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ M _ _ _ _ _ M  ,
      s  _ M M M M M M M  ,
      s  _ M _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ M M M _ _ _  ,
      s  _ M _ _ _ M _ _  ,
      s  _ M _ _ _ M _ _  ,
      s  _ M _ _ _ M _ _  ,
      s  _ _ M M M _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ M _ M M _ _ _  ,
      s  _ _ M M M _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ M M M M M M  ,
      s  _ M _ _ _ _ _ _  ,
      s  _ _ M M M _ _ _  ,
      s  _ M _ _ _ _ _ _  ,
      s  _ _ M M M M M M  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ M M M _ _ _  ,
      s  _ M _ _ _ M _ _  ,
      s  _ M _ _ _ M _ _  ,
      s  _ M _ _ _ M _ _  ,
      s  _ _ M M M _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ M M M M M _ _  ,
      s  _ _ _ _ M _ _ _  ,
      s  _ _ _ _ _ M _ _  ,
      s  _ _ _ _ _ M _ _  ,
      s  _ _ _ _ M _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ M _ _ _ _ _ M  ,
      s  _ M M M M M M M  ,
      s  _ M _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ M M M _ _ _  ,
      s  _ M _ _ _ M _ _  ,
      s  _ M _ _ _ M _ _  ,
      s  _ M _ _ M _ _ _  ,
      s  _ M M M M M M M  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ M _ M M M M M  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _  ,
      s  _ _ _ _ _ _ _ _
    };

  #undef s
  #undef M
  #undef _

  LcdCommand(0xb0); // Page address set
  LcdCommand(0x10); // Column address set upper bit
  LcdCommand(0x00); // Column address set lower bit
  for(int i=0; i<sizeof(BitMap); i++) {
    LcdData(BitMap[i]);
  } // for i
} // Hello
【コラム】ビットマップを16進数に自動変換するExcelのワークシート

図51のワークシートを作成する方法の説明では、ビットマップから16進数列への変換は、人が行っていました。この変換をExcelに任せる事が出来ます。

まず、下のリンクから、bmp2hex.xlsxというExcel 2013用のワークシートをダウンロードしてください。

ビットマップ16進変換用ワークシート: bmp2hex.xlsx (21kB)

ダウンロードしたbmp2hex.xlsxを開くと、図54の様な画面になります。

図54、bmp2hex.xlsxを開いた時の画面
図54、bmp2hex.xlsxを開いた時の画面

最初はD0~D7(1行目~8行目)には何も入力されていませんが、試しにE4のセルに1を入力してみます。(図55参照)

図55、D4のセルに1を入力した結果
図55、D4のセルに1を入力した結果

そうすると、1を入力したE4のセルが黒に塗りつぶされ、下のE9のセルには、その列のビットマップを16進数に変換した08が表示されます。

16進数に変換したいビットマップを、黒にしたいセルに1を入力する事により入力していくと、リアルタイムでビットマップが16進数に変換されていきます。もし間違ったセルに1を入力した場合は、その1を削除すると白に戻ります。

"Hello, world!"の文字列のビットマップを入力し終わると、図56の様になります。

図56、bmp2hex.xlsxに"Hello, World!"の文字列を入力し終わった時の画面
図56、bmp2hex.xlsxに"Hello, World!"の文字列を入力し終わった時の画面

次のページでは、指定した座標に点を描画する関数を作成します。

目次へ  前のページへ (6) (7) (8) (9) (10) (11) (12) (13) (14) 次のページへ

このページで使われている用語の解説

関連ページ

関連製品

122X32モノクログラフィックLCDシールド 商品名 122X32モノクログラフィックLCDシールド
税抜き小売価格 3333円
販売店 スイッチサイエンス
サポートページ
GLCD学習シールドキット 商品名 GLCD学習シールドキット
税抜き小売価格 1410円
販売店 スイッチサイエンス
サポートページ
Arduino 電子工作
このサイトの記事が本になりました。
書名:Arduino 電子工作
ISBN:978-4-7775-1941-5
工学社の書籍の内容の紹介ページ
本のカバーの写真か書名をクリックすると、Amazonの書籍購入ページに移動します。