« 2008年12月 | トップページ | 2009年6月 »

2009年5月の記事

Arduinoメールチェッカー

Arduinoイーサーネットシールドの発熱量の投稿で予告した、イーサネットシールド(Ethernet Shield)を使用したメールチェッカーを作ってみました。以下に示す機能があります:

  • 登録したメールサーバー(POPサーバー)に定期的にアクセスして、着信メール数、送信元(ヘッダーのFrom:フィールド)が登録したアドレスかをチェックする
  • 登録したアドレスからメールが着信した際にLEDを点滅してお知らせする
  • 着信メール数、登録したアドレスからのメール数、登録したアドレスからのメールの場合どのアドレスかを、LCDに表示する
  • 周期チェックに加えて、ボタンによるマニュアル確認

ハード構成

LCDディスプレー、タクトスイッチ、LEDをプロトシールドに載せて、イーサネットシールド上にスタックしました。写真のような3階建て構造になります。

Mailchecker1_2

LCDはポピュラーなSC1602Bではなく、プロトシールドの幅にぴったり収まるSD1602HUOBを秋月さんで購入。このLCDはサイズがぴったりなのとオレンジバックライトがきれいでよいのですが、LCDパネルと基板をつなぐリボンケーブルが露出しておりかつこいつが傷つきやすいので注意が必要です。

結構背が高くなったので、写真のように、横において使用中です。

Mailchecker2

写真の表示は、着信メール数2件(MSG:2)、登録したアドレスからの着信1件(CHK:1)、登録した送信元アドレス"todot"を含むアドレスから着信があったことを示しています。

表示部分を含む全体の回路図は以下です。

Mailcheker_shcematic

電源ケーブルの接続ですが、Arduinoイーサーネットシールドの発熱量で記載したボルテージレギュレーターの発熱対策として、5V ACアダプターの出力をPOWER Pinの+5V(Pin3), GND(Pin4)に接続しました。電源の取り込みはプロトシールドで行い、シールド間の連結を介してイーサネットシールド・Arduino本体に電源を供給しています。

ACアダプタ用ジャックをプロトシールドに載せることができなかったため、パネル取り付け型ジャックから5cmほどケーブルの延ばしてプロトシールドに半田付けしてあります。電源コネクタの取り付けがスマートでないことが不満点です。

スケッチ

スケッチのソースコードはココからダウンロードできます。

POP3はテキスト形式でサーバーとコマンド・レスポンスをやり取りします。Arduinoからは、Ethernet libraryのclient.println()メソッドを使用してコマンドの送信が可能です。POPサーバーからのレスポンス受信はclient.read()メソッドを使用して、改行(LF)までの一行をバッファに格納するgetLine()関数を作って処理しています。

POPサーバーにアクセスしてヘッダーを取得する手順は以下です。

  1. client.connect()を実行してPOPサーバーとのTCPセッションをオープン
    サーバーから、"+OK"レスポンスが返るのを確認
  2. clinet.println()にてユーザー名を送信(0016以降はclient.write()を使用した方がよい)
    →USER xxxx (xxxxがユーザー名)コマンドを送信
  3. clinet.println()にてパスワードを送信(0016以降はclient.write()を使用した方がよい)
    →PASS xxxxxコマンドを送信
  4. STATコマンドを送信
    →"+OK 2 4436"のようなレスポンスが返ります
    →2がメッセージ数、次の数字がOctet数になります
  5. TOP 0 0コマンドを送信して1件目のメールヘッダをダウンロード
    "+OK Message follows"レスポンスに続いてヘッダーを受信し、"From:"を含む行を受信した際に登録したアドレスに一致するかをチェック
  6. ステップ5をメッセージ数繰り返す(TOP 1 0, TOP 2 0・・・の繰り返し)

ソースの以下のコメントを外してコンパイルすることでPOPサーバーとのやり取りをシリアルポートに出力し、PCにて動作確認ができます。(デバッグ機能です)
 //#define DEBUG
シリアルの通信速度(=表示速度)が遅いと、イーサネット通信が不安定になる現象があったため、シリアルの通信速度を最大値(115200bps)に設定してあります。

テスト当初、POPサーバーからヘッダをダウンロードするメールが2件以上になると、起動後最初のチェックはOKなのですが、チェック(サーバーアクセス)を繰り返すとリセットが発生する問題に悩まされました。スタック溢れの可能性を疑い、グローバル変数を使ってスタック領域を使わないようにしたため、少々汚いコードになってしまいました。

最終的には以下に示す通り、メールヘッダのFrom行を検出する処理で呼んでいたメソッドを変更することで解決しました。

当初のコード:ReceiveBuffer.startWith("From:") -- 受信バッファが"From:"で始まるかの判定。当初は、行頭に"From:"が来ることまで含めてマッチングを取ろうとしました

変更後:ReceiveBuffer.contains("From:") -- 受信バッファに"From:"を含むかの判定に変更。原因不明のリセットが解決せず、部分一致のメソッドに変更

ライブラリにバグがあるとも思えず、根本原因は不明です。

使用したライブラリ

IDE-0015標準のライブラリ以外に、以下のライブラリを使用しました。

  • WString.h:POPサーバーに送信するTOPコマンドの編集、受信バッファ内の文字列部分一致検索などのテキスト処理
  • Debounce.h:スイッチのチャタリング除去
  • Metro.h:POPサーバーのチェック周期、LEDの点滅周期など、周期処理の時間を管理
  • Sleep.h:致命的なエラーに遭遇した際に、MCUをStandbyモードに遷移して処理を停止するために使用(Haltの代わりに使用)。「なんでも作っちゃう、かも」さんのライブラリを使用させていただきました。

文字列処理などは、AVR Libcのライブラリ呼び出しでも実現できますが、上記のライブラリを使用するとお手軽かつ、Arduinoらしい簡潔なコードになります。既存のライブラリが豊富な点は、やはりArduinoのメリットだと思います。

設定機能

ありません、、
POPサーバーのIPアドレス(nslookupができないため、ドメイン名での指定はできません)、ユーザー名、パスワード、監視するメールアドレスなどはソースコードにハードコーディングです。

Ethrenet Libraryの修正

clinet.connect()メソッドでサーバーにTCPセッションが接続できない(タイムアウトする)ケースが何回かあったため、ArduinoのForumを覗いてみると、Ethernet Libraryの問題がいくつか報告されていました。その中から、以下の修正コードを盛り込みました。

1) 送信時、1文字単位にIPパケットを生成してしまう問題

オリジナルのコードでは、client.println("Hello World");を動かすと、1文字単位にIPパケットを送信するそうです。CR+LFを含めると13パケットも送信してしまいます。本来なら1パケットで済みますし、1文字(1 byte)のデーターを送るために40 byteのTCP/IPヘッダを送っていることになり、非効率この上ないです。

本職はIPネットワーク屋なので、このようにネットワークの帯域を無駄に消費するヤツは許せないため、即刻修正です。。

2) TCP FINの送信処理に問題があり、clinet.stop()で一旦接続を終了した後に再度client.connet()で再接続を行うと接続できない場合がある。

1)2)の対処を盛り込んだ、Libraryのソースはココから ダウンロードできます。

2009/6/7追記
上記1)2)の問題は、最新のIDE-0016で修正されています。1)の問題に対しては、Clientクラスのwrite()関数を使用することで解決します。IDE-0016を使用した最新版をこの記事で紹介しました。

残問題

Ethernet Shieldに関して以下の問題が残っています。

1)電源ONの際に、Link Upしないことが度々ある

Ethernet shieldの初期化(恐らくW5100チップのリセット)が完全に行われていない模様で、リセットボタンを押すとLink upします。Arduino Forumにも関連スレッドがあり、RESET - GNDピン間にコンデンサを追加すると問題が解消すると投稿がありますが、そこまでは踏み切れません。

2)電源ON後の最初の接続で、client.connetc()がタイムアウトする場合がある(Link upはしている)

どうもLCDの初期化と同様に、電源ON時のリセット処理が不十分なようです。商用のハード開発では、リセット回路のドライブ能力・リセット時間やタイミングは、設計の重要ポイントになっているのですが、このあたりがいまいちなのかしら、、

2009/6/6追記

メールサーバーアクセス方法を変更した改良版を公開しました。

2009/6/7追記

Arduinoイーサーネットシールドの接続処理に、リセット後のタイムアウト問題の調査結果を記載しました。

2009/6/8追記

掲載したスケッチにメモリリークがあることが分かりました。サンプルとしてコードは掲載しておきますが、もし使用される場合はご注意下さい。

2009/6/9追記

メモリーリークの対策版を以下の記事で公開しました。
Arduino TexitStringライブラリのメモリーリーク
Arduinoメールチェッカー(その3)

LiquidCrystal(LCD)ライブラリの初期化コード

2009/8/14追記:
以下に示す問題は最新のIDE-0017で修正が盛り込まれました

ArduinoでLCD(液晶ディスプレイ)を使用する場合、LiquidCrystalライブラリを使用する場合が多いかと思います。このライブラリは、HD44780コントローラー互換チップを使用したLCDで使用可能となっており、秋月電子さんが販売しているSUNLIKE社液晶モジュール、SC1602、SD1602シリーズで使用することができます。

ArduinoのForumでも何回か話題になっているのを見かけましたが、電源ON時にLCDの表示が出ない場合があります。タイミング的な問題のようで、私の環境では数回に1回こうなります。この問題の原因と対策を考えてみました。

HD44780にはパワーオン時のリセット機能があるため、本来なら電源ON時に必要な初期化が自動的に行われる筈です。データーシートによると、「Vccが4.5Vに達した後10ms busy状態が継続する」とあるため、10msはパワーオンリセット期間であるように読み取れます。電源ON時、10ms経過前(パワーオンリセット完了前)にスケッチが起動し、LCDにアクセスしてしまうと表示が出ない問題が発生するのでしょうか?

Arduinoでユーザースケッチが起動するまでには若干の遅延があります。Arduinoがパワーオン(もしくはリセットボタン押下)した場合、先ずブートローダーが起動します。ブートローダーは、PCからのアップロード開始をチェックし、タイムアウト時、Flash ROMに書き込み済みのユーザースケッチを起動します。Duemilanoveなどの自動リセット機能があるボードでは、この遅延は秒以下であるとの記載がArduinoのWebページにあります

ブートローダーがユーザースケッチを起動するまでに500ms程度の遅延があれば、タイミング的にはLCDコントローラーのパワーオンリセットは終わっているはずです。従って、何らかの理由でパワーオンリセットだけでは初期化が不十分になる、もしくはパワーオンリセットが働かないケースがあると思っています。2009/5/26 追記にてこの点を確認する追試を行っています。

データーシートには、パワーオンリセットの条件として、電源の立ち上がり時間が、0.1ms~10ms以内という規定があります。例えば、電源の立ち上がり時間が10msより長い場合、パワーオンリセットが働かないことになります。

そのため、対策としては、LiquidCrystalライブラリの初期化コードにてLCDコントローラーをMCUから初期化することが有効だと思われます。
<arduinoインストールディレクトリ>\hardware\libraries\LiquidCrystal配下のLiquidCrystal.cppに以下の初期化コードを追加することで、問題をほぼ回避できるようになりました。

// For 4-bit Mode
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
  uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) :
  _four_bit_mode(1), _rs_pin(rs), _rw_pin(rw), _enable_pin(enable)
{
  _data_pins[0] = d0;
  _data_pins[1] = d1;
  _data_pins[2] = d2;
  _data_pins[3] = d3;
 
  pinMode(_rs_pin, OUTPUT);
  pinMode(_rw_pin, OUTPUT);
  pinMode(_enable_pin, OUTPUT);
 
  for (int i = 0; i < 4; i++)
    pinMode(_data_pins[i], OUTPUT);

// ---- Initialize HD44780 ------- ←追加部分開始
  delayMicroseconds(15000);      //電源ONからの安定化時間を追加(2009/6/17)
  send_4bit(0x03);
  delayMicroseconds(4500);
  send_4bit(0x03);
  delayMicroseconds(500);
  send_4bit(0x03);
  delayMicroseconds(500);
  send_4bit(0x02);   // function set to 4-bit
// ---- Initialize HD44780 END ---- ←追加部分終了

  command(0x28);  // function set: 4 bits, 2 line, 5x8 dots
  command(0x0C);  // display control: turn display on, cursor off, no blinking
  command(0x06);  // entry mode set: increment automatically, display shift, right shift
  clear();
}

ファイルの末尾に以下の関数を追加
// ---- Initialize HD44780 -------
void LiquidCrystal::send_4bit(uint8_t value) {
  digitalWrite(_rs_pin, LOW);
  digitalWrite(_rw_pin, LOW);

  for (int i = 0; i < 4; i++) {
    digitalWrite(_data_pins[i], (value >> i) & 0x01);
  }

  digitalWrite(_enable_pin, HIGH);
  digitalWrite(_enable_pin, LOW);
}
// ---- Initialize HD44780 END ----

ヘッダファイルも、send_4bit()メンバー関数の追加に伴って変更が必要です。変更を盛り込んだライブラリソースをアップしておきます。
「LiquidCrystal.zip」をダウンロード

上記のコードはLiquidCrystalクラスのコンストラクターにLCDコントローラーの初期化を追加したものです。コンストラクター(C++の用語ですね)は、スケッチの中で、
LiquidCrystal lcd(6, 3, 7, 14, 15, 16, 17);
のようなコードを書いてLCDライブラリーの使用を宣言した際に呼び出されます。コンストラクターには4-bitモード用に加えて8-bitモード用がありますが、Arduinoユーザーは4-bitモードしか使用しないと思いますので、手抜きをして4-bitモードのコンストラクターのみにコードの追加を行っています。

ライブラリのソースコードを変更した際は、LiquidCrystal.cppと同じディレクトリに存在するLiquidCrystal.oファイル(コンパイラが生成したオブジェクトファイル)を削除してからスケッチのコンパイルをやり直します。オブジェクトファイルを一旦削除しないと、ソースの変更が反映されないため注意が必要です。

2009/5/26 追記

電源ON時のパワーオンリセット時間を十分確保することで問題が解消するか否かの追試を行いました。試験の方法としては、コンストラクターの呼び出しをスケッチ起動から1s遅延させます。そのために、コンストラクターの呼び出しをsetupの中に移動しています。

IDE-0015添付のオリジナルライブラリ(MCUからの初期化コードなし)に戻して以下のスケッチを実行すると、電源ON時にに"hello, world!"が表示されない場合があります。

#include <LiquidCrystal.h>

int ledPin = 13;                // LED connected to digital pin 13

void setup()
{
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
   
  //LiquidCrystalのコンストラクター呼び出しを電源ONから1s遅延させる
  //それでも、LCD表示が行われない場合あり
  delay(1000);
  LiquidCrystal lcd(6, 3, 7, 14, 15, 16, 17);
  lcd.print("hello, world!");
}

void loop()
{
  digitalWrite(ledPin, HIGH);   // sets the LED on
  delay(500);                  // waits for a second
  digitalWrite(ledPin, LOW);    // sets the LED off
  delay(200);                  // waits for a second
}

setupの中でコンストラクターを呼び出してしまうと、lcdインスタンスがsetup内でのみ有効となり、loopなど他のスコープで使えなくなるため実用的には意味がない検証用のコードです。この結果から、単にコンストラクター呼び出しを遅らせても問題が解決しないことが分かります。

このスケッチでは、LEDの点滅は始まりますので、プログラムがsetupの中でスタックしていることはなく、loopの処理まで進んでいます。即ち、パワーオンリセット期間中にスケッチが起動するため問題が発生するのではなく、オリジナルのライブラリでは初期化の内容が不足しているということになります、もしくは電源の立ち上がり時間が遅すぎるためパワーオンリセットが機能していないかです。

2009/6/17 追記

HD44780のデーターシートでは、MCUからの初期化の際は、電源ONから最初03Hを送るまでの間隔として15msの指定があります。パワーオンリセット期間満了後にMCUからの初期化を実施せよということですね。当初ブートローダーの起動遅延で、15ms程度の時間は経過するだろうと思い、最初のdelayを割愛したのですが(忘れただけだろ!)、Arduino本体とLCDが別基板の場合など電源ONのタイミングがそろわない場合もあるため、やはり最初の遅延は入れた方がよいかと思います。

私の環境では、15000μs (15ms)の遅延を入れてみました。それでも起動時に問題がある場合は遅延時間を個々に調整してみるとよいです。

2009/6/18 追記

全体的に記述を見直しました。

Arduinoイーサーネットシールドの発熱量

イーサーネットシールド(Ethernet shield)を購入しました。
目的は、PCが起動していない間でもメールチェックを定期的に行って、登録したメールアドレスからの着信があった場合の通知を行うためです(例えば、cocologのコメント書き込み通知メールを監視する)。

これまでは、ブロードバンドルーターのメールチェック機能を使っていました。最近、無線LAN APの入れ替え(マルチセキュリティーとハイパワー対応)を行い、これまで無線LAN APとブロードバンドルーターが別だったのを1台にまとめたのですが(BuffaloのWZR-HP-G300NHに入れ替え)、後継機ではメールチェック機能がなくなってしまいました。個人アカウント宛のメールは毎日チェックしないため、私的には便利な機能だったのですが、プロバイダーのメールサーバーに負荷をかけるため歓迎されない機能なのでしょうか、、

そのため、Arduinoを使ってメールチェッカーを自作することにしました。これまでは、Arduinoにセンサーやモーターなどをつないで、動いたら自己満足の世界でしたが、初の実用アプリ(?)になります。

インターネットアクセス方法について試行錯誤したのですが、結局はイーサーネットシールドを使用することになりました。イーサーネットシールドは少々お高いので、La Foneraを改造してインターネットアクセスの踏み台にする方法(リンクを参照)をトライしていたのですが、安定動作が難しそうだったので断念(この顛末は機会があったら書きます)。

イーサーネットシールドの発熱が思った以上に大きかったので、今回はこの点について書きます。メールチェッカーの記事はこちらを参照して下さい。

Arduinoを単体で動かす場合(PCのUSBから給電しない場合)、私は9VのACアダプターを使用しています。Arduinoの推奨電圧は7~12Vですので、間をとって9Vにしました(あと7Vのアダプターはあまり見かけません)。

イーサーネットシールドをArduino本体にのっけて9Vアダプターから給電すると、Arduino本体のボルテージレギュレーターがかなり発熱します。イーサーネットシールド側でTCP/IP処理を行うW5100チップも思ったより発熱しています。データーシートによると、W5100の消費電力は3.3V動作で146mAです。

9V ACアダプターで長時間動かすのは危険を感じるため、5V ACアダプターをArduinoのPowerコネクタ5V pinにつないで使っています。この接続だと、ボルテージレギュレーターをバイパスするためボルテージレギュレーターの発熱を回避できます。

ちなみに、ACアダプターを接続する外部電源ジャックに5V ACアダプターをつなぐとArduinoが動作しません。理由はArduinoのボルテージレギュレーターを通過する際に一定のロス(電圧降下)が発生するため、ボルテージレギュレーターの出力として5V電圧が得られないためです。私の環境ですと、上記のケースではボルテージレギュレーターの出力は3.4Vになりました。

ArduinoのForumにEthernet Shieldが熱いというスレッドがあり、このスレッドによると、Arduinoのボルテージレギュレーターは安価なlinear typeを使っているため、9V→5V変換の「電圧差(この場合は4V)」x「電流」が熱になる、すなわち消費電流が大きいシールドを載せると発熱が増えるとあります。Arduino単体では消費電力が小さいため発熱の問題はないが、イーサーネットシールドは消費電力が大きくArduino本体の発熱を招くということになります。

Arduino本体 + イーサネットシールド + LCDをつないだ状態で電流を測定してみました。写真に示す通り182mA流れています(起動時200mA程度流れて、その後182mA程度に落ち着きます)。給電は5V ACアダプターから直送(ボルテージレギュレーターバイパス)です。

Ethershield_ma_2

Arudino本体のみの消費電流は24mAでした。

Arduino_ma_2

上記より、全体の消費電力配分は以下となります:

  • Arduino本体    :25mA
  • LCD(バックライト):10mA
  • イーサネットシールド:147mA

LCDのバックライトには、順方向電圧4.2Vに対して47Ωの抵抗を入れているため、17mA流れる計算になりますが、テスターの電圧降下のせいか、電流測定時はバックライトが通常の半分程度でしか点灯していなかったため10mAに補正しました。W5100チップの消費電力データー(146mA)と整合性がとれた値になります。

結論としては、イーサネットシールド(W5100チップ)はAVRに比べると5.8倍消費電力が大きく・そこそこ熱が出るということになります。W5100チップに指を強く押し当て続けるとそこそこ熱いので、気休めにヒートシンクを貼り付けてみました。温度は測っていませんが、40℃以上はありそう。W5100の消費電力はワットにすると0.5W程度ですが、1W以下でここまで発熱するものか、このあたりは詳しくないのでよくわかりません。

ちなみに、ブレッドボードで動いているのは冒頭に記載した、メールチェッカーです。LCDやメール着信表示のLEDやらをプロトシールドに移植したいと思っており、この作業ができたらブログに掲載予定です。

Arduino始めました

半年以上PS3 Linux関連の更新をさぼっておりました。
この間何をしていたかというと、仕事ではまっていたことに加えて、Arduinoという8-bitのマイコンボードを使った電子工作にはまっていたのです。私が、Arduinoを知るきっかけとなった記事はココです。

半年間の成果(?)で、Arduino関連のネタがだいぶたまりましたので、ブログのタイトルを拡張(無理矢理です、、)して、Arduino関連の記事も掲載していこうと思います。また、半年でネタ切れになるかもしれませんが、、、

Arduinoは、Atmel社のAVR(ATMegaシリーズ)という8-bitマイコンを使用しているのですが、メモリーがFlash ROM 32KB + SRAM 2KB (ATMega 328の場合)、クロック16MHzだったりして、Cellに比べると超シンプルですが、ハードが自由にいじれる点が魅力です。

歳がばれますが、学生時代の主力PCだったNEC PC-8801, PC9801はCPUの信号(アドレス・データー線など)がそのまま拡張バスに見えており、IOカードを自作してLEDをチカチカさせたりステッピングモーターをまわしたりして遊んだことがありました。また、Z80CPUを使ったマイコンボードも比較的簡単に自作できました。

32-bit CPU(80486以降でしょうか)& Windowsが主力になってからは、次のようにハードが複雑になって、私が触れる領域を外れていました。

  • ピン数が膨大
  • クロックは100MHzクラス
  • IOはチップセット経由
  • メモリ管理機能などモダンOSを載せることが前提

Windows時代以降でも、H8マイコンなどを使ってマイコンハード工作はできたのだと思いますが、クロス開発環境の整備・作成したプログラムをいちいちROMに焼いたりといった作業が面倒そうなのもハード系から遠ざかる要因でした。ArduinoはWindows/Linux/Mac上で動作するフリーの開発環境が用意されていること、作成したプログラムをUSB経由でAVRのFlash ROMに書き込めるため非常にお手軽です(ROMライターなどの専用書き込み環境が不要)。

今年の正月休みに、Arduino Duemilanoveとブレッドボード・部品を買い込んで遊んでみたところ、久しぶりのハード工作の楽しさに目覚めた次第です。次からはArduinoを使ってみて気がついたことを書いていこうと思います。

« 2008年12月 | トップページ | 2009年6月 »

2018年10月
  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      
無料ブログはココログ