そんなわけで、そろそろワットメーターを片付けることにしよう。まずはArduino MegaをArduino Unoに戻してまずArduino側のSketchからであるが、その前に開発環境のアップデートを。11月30日に、公式にArduino 1.0がリリースされた。これまでは立ち上がるとArduino Alpha 0022と表示されていた(Photo01)のが、Alphaが取れているのが分かる。入手はこちらからで、Windows版の場合は約86MBほどになる。0022からの違いはこちらにあるが、大きな所ではSketchを格納するファイルの拡張子が.pdeから.inoに変わったあたり。Arduino IDEの見かけもちょっと変わったほか、非同期通信をサポートした関係でSerial.print()の振る舞いが多少変化している。Flash Memoryへのプログラムからの書き込みをサポートしたとか、文字列関数が再インプリメントされたり、Ethernet Shieldを前提にEthernetや一部TCP/IP周りのStack/APIが実装されたり、SDカードクラスが追加されていたり、と割と多岐に渡る。とは言え既存のSketchに関しては殆どそのまま動作すると思ってよいだろう。
さて、それではいよいよ完成版である。まずArduino側であるが、基本的な回路は例えば401回の図3で示したものと同じである。ただMTM07出展にあわせて、ワットメーターを専用ケーブルで繋ぐことにしてしまったので、ブレッドボード経由でArduinoと繋ぐためにはこの専用ケーブルとの接続をなんとかせねばならない。ということで、とりあえずまたもや片面ユニバーサル基板を小さく切って(Photo03)簡単なアタッチメントを作り(Photo04)、これを使ってブレッドボードに接続するようにした(Photo05)。
さて、Arduino側のSketchはList 1のようになっている。先程のPhoto05では、10KΩと4.7KΩの抵抗を使って電流側に分圧回路を入れていたが、最終的にはこの分圧回路を外しており、Sketchもこれにあわせてある(もっぱらAMPBIASの値)。これは実際に測定を行ってみたところ、分圧回路を入れた場合に0.2A前後の消費電流が分解能の問題でまともに測定できない、という事が発覚したためだ。前回までで触れたサンプリング周期の問題もそうだが、分解能に関しても0~5Vを10bitでサンプリング、というのはちょっと能力不足を感じるようになってきた。今回の目的はあまり大電流を測ることではない(絶対に無い、とは言い切れないのがあれなのだが)ので、とりあえず運用テストをかけるまではこのまま行くことにした。もし運用テストで問題が発覚したら、今度は例えば0.2Aあたりはもう捨てることにして分圧回路を入れる、という選択肢もありえるだろう。
Sketch側のロジックには概ね変更は無いが、小変更としては、
- 多少最適化をした。減算を1回のArduinoからのサンプリングあたり4回ほど減らした。
- プロトコルを若干変更し、文字列の先頭に"a"、最後に"z"を付ける様にした。これはWindows側のプログラムで、通信結果取得部分のアルゴリズムをちょっと変更したことに対応するものである。
- Serial.print()で結果を送信した後、明示的にSerial.flush()を呼ぶようにした。これにより若干オーバーヘッドが増えたが、データを正しくWindows側に送り出せる様になった。
- サンプリング中のループの中のウェイトを分割し、電圧と電流のサンプリングの間に(ほんのわずかであるが)ウェイトを入れた。本来はこれをやると、電圧と電流のサンプリングタイミングの微妙なずれが拡大するのであまり好ましくはないのだが、例えば電流値がいきなり0になると、それに引きづられて電圧値が落ちるという現象が出ており、これを緩和するための対策である。
ちなみにWindows側のプログラムはこんな感じ(Photo06)に落ち着いたが、こちらについては次回説明したい。
(続く)
List 1:
#define VOLPIN 0
#define AMPPIN 1
#define VOLBIAS 463
#define AMPBIAS 473
int flag; /* 電圧の反転状態を定義 */
void setup()
{
Serial.begin(9600);
flag = 0; /* Flag初期値 */
}
void loop()
{
long numSample; /* サンプリング数 */
long vol, amp; /* 取得した電圧/電流の値 */
long volSum, ampSum; /* 合算した電圧/電流の値 */
numSample = 0; /* サンプリング数取得 */
volSum = 0;
ampSum = 0;
while(1)
{
/* 電圧と電流をサンプリング */
vol = analogRead(VOLPIN);
delayMicroseconds(5);
amp = analogRead(AMPPIN);
numSample++;
/* 両方0なら0としてBreak; */
if (!(vol||amp))
{
numSample = 1;
volSum = 0;
ampSum = 0;
break;
}
else
{
vol -= VOLBIAS;
amp -= AMPBIAS;
}
/* flagの値を判断 */
if ((flag==2)&&(vol>0))
flag=0; /* データサンプリング開始 */
else if ((flag==0)&&(vol<0))
flag++; /* 一度目の値の符号反転 */
else if((flag==1)&&(vol>0))
break; /* 二度目の値の符号反転 */
/* 取得した値を加算 */
if(flag!=2)
{
volSum += abs(vol);
ampSum += abs(amp);
}
delayMicroseconds(5);
}
/* 結果を出力 */
Serial.print("a");
Serial.print(volSum);
Serial.print("\t");
Serial.print(ampSum);
Serial.print("\t");
Serial.print(numSample);
Serial.println("z");
Serial.flush();
while(1)
{
vol = analogRead(VOLPIN)-VOLBIAS;
if (vol < 0) break; /* 次のシーケンスの取得待ち */
delayMicroseconds(100);
}
flag++; /* flag = 2:次のシーケンス待ち */
}