CAN制御機器の製作(6) 温度測定ノード

リレー・ノードはホストから受信するだけの一方通行でしたが、こんどは逆に温度測定ノードからホストへ送信するアプリケーションを作ります。

●温度測定ノードの動作

このノードは一定周期で温度を測定し、ホスト・ノードへ測定温度を送信します。温度測定はディジタル温度センサADT7410で摂氏温度を求め、それを10倍した整数値でホストへ送信させます。測定周期は約2秒とします。

ホスト・ノードでは受信した温度データを10/1にして小数点第一位までの数値として温度を表示します。ホスト側はとりあえず、シリアル送信でPC側へ温度値を表示させるようにします。

ADT7410(I2C制御)の使い方については、以前掲載した「I2C温度センサADT7410を使う」も参照してください。

●温度測定ノードの回路

ADT7410はI2C制御なので、ArduinoのA4、A5ポートにADT7410のSDA、SCLを接続します。それ以外はCANコントローラとの接続用に、リレー・ノードやホスト・ノードと同じく、D2~D5の4本をSPI信号として使用します。

接続図を次に示します。

282_292_ADT7410

図の下半分が温度測定ノードです。リレー・ノードを接続する場合は、CAN-H、CAN-Lどうしを並列に接続します。このとき終端以外のノードはターミネータを無効にします。

I2Cの温度計を何個か接続することもできますが、今回は1ノードに付き温度測定1点とします。

CANコントローラにはWSN292が使えますが、現在の手持ちの関係で、WSN220を使っています。

●メッセージの定義

温度センサの識別番号は2~5としているので、 メッセージID(SID値) “xxx xccc cccc” の”xxxx”の値は “0100″~”0101″となります。コマンドコード”ccc cccc”は”000 0001″とします。

一般形はノード識別番号を”n”とすると、

メッセージID = n<<7 + 1 となります。

今回は固定値として定義します。

#define cmMSG_TMP1_VAL (2<<7 + 1)       // 温度測定ノード1
#define cmMSG_TMP2_VAL (3<<7 + 1)       // 温度測定ノード2
#define cmMSG_TMP3_VAL (4<<7 + 1)       // 温度測定ノード3
#define cmMSG_TMP4_VAL (5<<7 + 1)       // 温度測定ノード4

#define cmMSG_TMP_VAL (MODE_NUM<<7 + 1) // 一般形

複数の温度ノードで識別番号を共通にして、枝番(”ccc cccc”の部分)で指定しても良いのですが、今回はノード毎に変えることにしました。

また、測定した温度値はデータ・フィールド2バイトに摂氏温度を10倍したものを整数値で格納することにします。従って、DLC値(メッセージ設定時のデータ長)=2となります。

●プログラムの説明 (can_node_temp.ino)

今回はCAN受信はしないで、周期的に温度データをCAN送信するだけという前提で簡単に作ります。ディレイで周期を作って繰り返し測定、CAN送信するようにします。もし、CAN受信も並列で行う場合は、ディレイ中も受信処理が必要となるため、単純なディレイ処理では問題があります。

//
// CAN 温度測定ノード
//   13/11/20 www.wsnak.com
//
//   ADT7410 16bit ワンショット・モード 2秒周期
//

#include <Wire.h>
#include <wCan2515.h>

#define MODE_NUM 2    // 温度測定ノード1
//#define MODE_NUM 3    // 温度測定ノード2
//#define MODE_NUM 4    // 温度測定ノード3
//#define MODE_NUM 5    // 温度測定ノード4
#define cmMSG_TMP_VAL (MODE_NUM<<7 + 1)           // CANメッセージID

int I2CAdrs = 0x48;    // ADT7410 I2Cスレーブアドレス

wCan2515 Can(2, 4, 3, 5, CAN_BRP_16MHz_125KBPS);  // CANインスタンス
// D2:SCK, D3:SO, D4:SI, D5:SS (SI/SOクロス)

byte CanBuf[14];    // CAN送受信バッファ

int LedPin = 13;    // オンボードLEDのポート番号

// 初期化
void setup(void) {
  Wire.begin();                   // I2Cマスタ初期化
  pinMode(LedPin, OUTPUT);        // D13のLED用出力ポート

  // CANコントローラ フィルタ設定(全メッセージを受信しないように)
  Can.setFilterMode(0, FILTER_MOD_SID_HIT);   // RxBuf0 フィルタ使用
  Can.setFilterMode(1, FILTER_MOD_SID_HIT);   // RxBuf1 フィルタ使用

  Can.setMask(0, MASK_SID_CPL_MATCH);       // RxBuf0 マスク無効(完全一致)
  Can.setMask(1, MASK_SID_CPL_MATCH);       // RxBuf1 マスク無効(完全一致)
  Can.setFilter(0, 0x000);                  // フィルタ0値
  Can.setFilter(1, 0x000);                  // フィルタ1値
  Can.setFilter(2, 0x000);                  // フィルタ2値
  Can.setFilter(3, 0x000);                  // フィルタ3値
  Can.setFilter(4, 0x000);                  // フィルタ4値
  Can.setFilter(5, 0x000);                  // フィルタ5値
  // ※あり得ないID値を設定して実質受信を拒否する

  Can.setOpMode(CAM_MODE_NORMAL);
}

// メインループ
void loop(void) {
  uint16_t val;
  float tmp;
  long int ival;
  int tmp10;
  byte cbuf[8];

  // ADT7410 ワンショット リトリガ再設定
  Wire.beginTransmission(I2CAdrs);  // S.C発行,CB送信
  Wire.write(0x03);                 // Configuration register 選択
  Wire.write(0x20 | 0x80);          // one-shot mode 設定
  Wire.endTransmission();           // ストップ・コンディション
  delay(300);                       // 240ms以上

  // 温度読み出し
  Wire.requestFrom(I2CAdrs, 2);       // S.C発行,CB送信
  val = (uint16_t)Wire.read() << 8;   // データの読み出し(上位)
  val |= Wire.read();                 // データの読み出し(下位)

  // 摂氏温度 換算
  ival = (long int)val;
  if(val & 0x8000) {            // 符号判定
    // 負数
    ival = ival - 65536;
  }
  tmp = (float)ival / 128.0;    // 摂氏温度

  tmp10 = (int)(tmp * 10.0);    // 10倍した整数値

  cbuf[0] = tmp10 >> 8;
  cbuf[1] = (byte)tmp10;

  // CAN送信バッファへ送信メッセージ、データを設定
  Can.setTxBuf(0, cmMSG_TMP_VAL, cbuf, 2, true);
  Can.txReq(0);             // 送信要求発行
  digitalWrite(LedPin, HIGH);     // LED ON(送信中)

  // 送信完了待ち
  while(!Can.checkTxComp(0)) {
    delay(10);
  }
  digitalWrite(LedPin, LOW);      // LED OFF(送信完了)

  delay(1600);
}

今回のプログラムは「CAN制御機器の製作(4) リレー・ノード(2)」の 受信CAN処理 (can_sample2.ino)にADT7410から温度を読み出す処理を追加して作りました。温度は16ビット、ワンショットモードで測定します。ADT7410に関しては「I2C温度センサADT7410を使う」で説明しているのでそちらも参照してください。

温度ノードは4つまで増やせるようにしていますが、ノード毎にメッセージを変えている関係で、プログラムもノードに合わせて個別に用意します。プログラムを共通にしてジャンパなどで切り替えてもよいのですが、今回はコンパイルし直して個別にダウンロードするようにしています。

11行目から14行目は、どの温度測定ノードにするかを指定する定義です。使うノードの定義だけコメントアウトを外してコンパイルし直してください。掲載プログラムでは “NODE_NUM” = “2″が有効になっています。

今回のノードではCAN受信はしないので、無駄な処理をさせないようにCANメッセージを受信しないようにしてみました。32~42行目であり得ないメッセージ値をフィルタに設定して、実質的に受信を拒否するようにしています。メッセージID(SID値)の0×000は使わないという前提です。

ADT7410はワンショットモードで使うため、メインループで約2秒毎にトリガを掛けるようにしています。57~60行目がワンショットのトリガです。測定、変換に最低240msの時間がかかるため、61行目で約300ms待たせています。

64行目で変換の終わった温度を読み出して、69行目から摂氏温度に変換しています。このあたりは「I2C温度センサADT7410を使う」で説明しています。

今回、ホストノードへ送信するのは、摂氏温度を10倍した整数値としているため、76行目で10倍した整数に変換しています。78、79行目では、その10倍値をCANメッセージ用に送信バッファ”cbuf[ ]“へ1バイトずつ格納しています。

82行目より、CANメッセージをCAN送信バッファへ格納してメッセージの送信要求を発行します。

87行目でCAN送信が完了するのを待って(通常、すぐに完了する)、約1.6秒待って1サイクルの処理を終わります。

●複数ノードの接続

温度測定ノードを複数接続するときのイメージ図です。ついでにリレー・ノードも含めています。

temp_node_block

機材の関係で、たくさんノードを用意するのは困難だと思いますが、部分的にノードを入れ替えて動作確認するとよいと思います。

なお、言うまでもありませんが、温度測定ノードは熱電対やアナログ温度センサで測定したものでも同じフォーマットのCANメッセージで摂氏温度を送信すれば、そのまま使えます。

●測定結果

実際に温度測定ノードとホスト・ノードを接続し、ホストノード(Arduino-IDEのシリアル・モニタ)で受信した温度を表示したときのものを示します。約2秒周期で温度データがホスト・ノードへ送られてきます。ホスト・ノードでは受信したタイミングでシリアルでPCへ温度値を表示するようにしてあります。

T1= 13.4
T1= 13.5
T1= 13.5
T1= -28.6 ← ここで急速冷却
T1= -26.9
T1= -25.5
T1= -23.0
T1= -20.0
T1= -17.7
T1= -15.6
T1= -13.9
T1= -12.4
T1= -10.8
T1= -9.4
T1= -8.1
T1= -6.7
T1= -5.3
T1= -4.3
T1= -3.2
T1= -2.3
T1= -1.5
T1= -0.9
T1= -0.4
T1= -0.2
T1= 0.0
T1= 0.5
T1= 1.3
T1= 2.0
 :
 :
T1= 16.7 ← 常温
T1= 16.8
T1= 16.8

途中、冷却スプレーでADT7410を急速冷却して測定温度が氷点下になることも確認しました。その後、0℃に達したあと、常温に戻っています。

ホストノード側のプログラムは次回説明します。


CANについては下記書籍で説明していますのでよろしければ、ご覧ください。
書籍「動かして学ぶCAN通信」 → 書籍紹介ページ

ArduinoのCAN関係の記事は下記書籍でも扱っています(WSN292など使用)。CANなどの専用ライブラリに付いても解説しています。
書籍「Arduino実験キットで楽ちんマイコン開発」 → 書籍紹介ページ

図やテキストの無断転写はお断りします。

コメントは受け付けていません。