では改めて今回からArduinoのSketchを説明する。List1の初期化ルーチンは前回紹介したそのまんまである。
まず最初のWAIT_LEDとBAUDRATEは、それぞれ「LEDを点灯→消灯までの時間間隔で、単位はμsec」「PC側との通信ボーレイト」である。なので前者は200μsec、後者は9600bpsの意味となる。
続くReceiveBuf[]はUSB(というか、Arduinoから見たらRS232C)ポート経由でとりあえずデータを受信するためのバッファである。前回も紹介したとおり、1回につき1Byteの転送を4回分まとめて受信するので、実はint型でなくchar型でも十分足りる(int型にしたのは、プログラムサイズにゆとりがあるので「なんとなく」である)。次のDisplayBuf[]は、受け取ったバッファの内容を解析して、実際に表示するLEDの数を格納しておくものである(これも冷静に考えればcharで十分なのだが、なんとなくintにしていた)。
さて、次のPosX]/PosY[]は、[365回における図2の配線図における、X方向(水平方向: 図2で言えば抵抗が接続されている側)の配線と、Y方向(垂直方向: 図2で言えば、抵抗を介さず直接Arduinoに接続されている側)の配線が、どのピンにつながっているか、を記述したテーブルである。ここでPosX[]の側が{ 2,3,4,5,6,7,8,9,10,11 }ではなく{ 2,3,4,5,6,7,9,8,10,11 }となっているのは、要するに筆者の配線ミスである。最後に配線をまとめて作ったときに、うっかりひっくり返して配線してしまったようで、テストを行ったらいきなり表示がおかしくなっていた。もちろんここで正しく配線をやり直すのが本筋なのだが、別に配線をいじらなくてもSketchをちょっと手直しするだけで問題なく利用できるという一つの見本になったので、敢えてこのままにしている。よくハードウェアにバグがあって、これをファームウェアで対処するなんて話を耳にされるかもしれないが、まさしくそうした一例である。
さて、続いて次のセットアップルーチンである。こちらは初期状態の設定である。最初の2つのfor()ループは、D02~D19までを全部Digital Outに設定すると共に、D02~D11をLowに、D12~D19をHighにそれぞれ設定する。これによって、全てのLEDには逆電圧がかかる形になるので、全てのLEDは消灯状態になる。
ついでSerial.begin()が呼ばれているが、これはRS232Cを使うためのお約束である。ここで先に定義した通信ボーレートを渡すことで、以後SketchからRS232C経由での通信が可能になる。
最後がバッファのクリアであるが、これよく見るとバグってました。前回紹介したリストでは、
for( lpCnt = 0; lpCnt < 4; lpCnt++ )
{
ReceiveBuf[lpCnt] = 0; /* データ無し */
DisplayBuf[lpCnt] = 0; /* データ無し */
}
となっていますが、本当ならば、
for( lpCnt = 0; lpCnt < 4; lpCnt++ )
{
ReceiveBuf[lpCnt] = 0; /* データ無し */
}
for( lpCnt = 0; lpCnt < 8; lpCnt++ )
{
DisplayBuf[lpCnt] = 0; /* データ無し */
}
としなければいけない所。Sketch開発初期段階ではDisplayBuf[]の数も4つだった(途中でこれだと面倒になるので8つに増やした)んですが、ここを対処し忘れてました。お詫びして訂正します。
ということで何をやっているかといえば、もう単にバッファの0クリアである。Arduinoは電源が来るとすぐに立ち上がって表示を始めようとする。ところが当初はPC側のプログラムが立ち上がっていないから、表示すべきデータがない。で、ReceiveBuf[]もDisplayBuf[]も、電源投入直後は不定(中身に何が入っているか保障されない)状態だから、明示的に0クリアしないと変な表示がしばらく行われる可能性がある、という訳でこの可能性を潰すための対策である。ということで、次回はメインであるloop()の中身を。
List 1(訂正済):
#define WAIT_LED 200
#define BAUDRATE 9600 /* 通信ボーレート */
int ReceiveBuf[4]; /* USB経由で受信したデータのバッファ */
int DisplayBuf[8]; /* データ表示用バッファ */
/* 出力ポートとLEDの位置関係を記述 */
char PosX[10] = { 2, 3, 4, 5, 6, 7, 9, 8,10,11 };
char PosY[8] = { 12,13,14,15,16,17,18,19 };
void setup()
{
int lpCnt;
for( lpCnt = 2; lpCnt < 12; lpCnt++ )
{
pinMode(lpCnt, OUTPUT); /* #2~#11までをDigital Outに設定 */
digitalWrite(lpCnt, LOW); /* 全部Lowに設定=消灯 */
}
for( lpCnt = 12; lpCnt < 20; lpCnt++ )
{
pinMode(lpCnt, OUTPUT); /* #12~#19までをDigital Outに設定 */
digitalWrite(lpCnt, HIGH); /* 全部Highに設定=消灯 */
}
Serial.begin( BAUDRATE ); /* USB経由の通信初期化 */
/* 表示用受信バッファの初期化 */
for( lpCnt = 0; lpCnt < 4; lpCnt++ )
{
ReceiveBuf[lpCnt] = 0; /* データ無し */
}
for( lpCnt = 0; lpCnt < 8; lpCnt++ )
{
DisplayBuf[lpCnt] = 0; /* データ無し */
}
}
List 2:
void loop()
{
int lpCnt, lpCnt2;
int readBuf; /* 受信データを一時的に受けるバッファ */
while( Serial.available() > 0) /* データ到着なら受信を行う */
{
readBuf = Serial.read(); /* まず1Byte読み込み */
if (readBuf == 122) /* 小文字の"z"が来た */
{
for ( lpCnt = 0; lpCnt < 4; lpCnt++ )
{
if(ReceiveBuf[lpCnt] < 11)
{
DisplayBuf[lpCnt*2] = ReceiveBuf[lpCnt];
DisplayBuf[lpCnt*2+1] = 0;
}
else
{
DisplayBuf[lpCnt*2] = 10;
DisplayBuf[lpCnt*2+1] = ReceiveBuf[lpCnt] -10;
}
}
}
else
{
/* 桁送り */
ReceiveBuf[3] = ReceiveBuf[2];
ReceiveBuf[2] = ReceiveBuf[1];
ReceiveBuf[1] = ReceiveBuf[0];
if ((readBuf > 47 ) && ( readBuf < 69 )) /* 読み込んだのは0~'D'の範囲か? */
{
ReceiveBuf[0] = readBuf-48; /* 数字ならその値を格納 : atoi()の代わり */
}
else
{
ReceiveBuf[0] = 0; /* それ以外なら無条件で0 */
}
}
}
/* LED点灯 */
for (lpCnt = 0; lpCnt < 8; lpCnt++)
{
digitalWrite( PosY[lpCnt], LOW );
for (lpCnt2 = 0; lpCnt2 < DisplayBuf[lpCnt]; lpCnt2++)
{
digitalWrite( PosX[lpCnt2], HIGH );
}
delayMicroseconds( WAIT_LED );
for (lpCnt2 = 0; lpCnt2 < DisplayBuf[lpCnt]; lpCnt2++)
{
digitalWrite( PosX[lpCnt2], LOW );
}
digitalWrite( PosY[lpCnt], HIGH );
}
}
(続く)