ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

arduinoコミュの複数のds18b20を用いた温度測定について

  • mixiチェック
  • このエントリーをはてなブックマークに追加
arduinoでds18b20をデュアルにしてそれぞれの温度測定をしたいと考えています。
下記サイトを参考にしてシングルでの動作を確認できました。

http://www.pjrc.com/teensy/td_libs_OneWire.html

それからデュアルにして同スケッチを実行すると「CRC is not valid!」のエラーになります。
アドレス部分が削除されたスケッチなので当然の結果なのですが…。

実現したいことはシリアルモニタに下記のようにそれぞれの温度を表示させたいということです。

Temp1 : 26℃
Temp2 : 22℃
1秒待機後、繰り返し

アドレス部分を指定すればと思い、試行錯誤してみましたが行き詰ってしまいました。
ご存知の方がおりましたら、お知恵をお借りできたら幸いです。

コメント(12)

使ったことはありませんが……。

>アドレス部分が削除されたスケッチなので当然の結果なのですが…。

って、どのようなスケッチなんでしょう?
掲示先のサンプル見た限りでは設定したピンに繋いでいると順番に見ていくようになっているみたいですが…。
つまり、そのままで複数のDS18S20を順次読み取れるハズです。

loopの最初でds.search(addr)でアドレスを取得、そのまま取得したアドレスで処理を行い、
loopの頭に戻ってds.search(addr)を実行した時に「次の」アドレスを取得、そのまま取得したアドレスで処理…となっています。
ds.search(addr)に失敗すると、アドレス検索を先頭に戻すためにds.reset_search()で初期化してloopの処理をreturnで中断してます。
# loopからreturnしても、直ぐに次の呼び出しがありますし。

>実現したいことはシリアルモニタに下記のようにそれぞれの温度を表示させたいということです。

ということで、Temp1とTemp2を区別する処理が必要です。
アドレスを格納する2次元配列をグローバルで用意して、setup()の時にds.reset_search()して
ループでds.search()しつつDS18S20か判定してアドレス書く膿瘍のグローバル変数に入れていけば良いでしょう。
>瀬戸っぷさん

早速のコメントありがとうございます。
参考にしたスケッチが間違っていました。

http://www.e-risingstar.com/wordpress/?p=414

こちらのサイトでした。
最初のサイトのスケッチはご指摘の通り複数のDS18B20を読み取ってくれますが、
どちらもTemp1として表示されてしまい、区別できません。

>アドレスを格納する2次元配列をグローバルで用意して〜
マニュアルを読むと個別にDS18B20にIDをが割り当てられているとの記述がありまして、
ds.search()せずともds.select(addr)にIDを入れれば対象を読み取ってくれるかと思いましたが、
IDが分からない…そんな状態です。
http://www.ne.jp/asahi/shared/o-family/ElecRoom/AVRMCOM/DS18B20/DS18B20cnt.html

このページによると、ROMに書かれているアドレスを読み出す必要があるようですね。
>カツベエさん

コメントありがとうございます。
ROMに書かれているアドレスを読み出す為に下記サイトの「Example Program」を実行してみました。

http://www.pjrc.com/teensy/td_libs_OneWire.html

シリアルモニタに次ようなに表示がされ、「28 56 38 B7 3 0 0 CB」がアドレスなのかと思われます。
ds.select()で指定したら読み込むかと試したところ、指定の仕方が悪いのか、これでは駄目なのか、
うまくいきませんでした。

R=28 56 38 B7 3 0 0 CB Device is not a DS18S20 family device.
R=28 F1 13 B7 3 0 0 9A Device is not a DS18S20 family device.
No more addresses.
新しい方のコード見てみました。

デバイスの指定がうまくいかないという事で、ちょっとライブラリやデバイスのデータシートを見てみたのですが、以下の点は大丈夫でしょうか?

ds.select() の直前に 毎回 ds.reset() を実行してバスのリセットを行っているか。
ds.select(Addr)のアドレスは、配列に入れてポインタで渡しているか。


あとは両方読めてるか確認するだけなら 最初に貼ってあったPJRCのスケッチのデバイスファミリーIDさえ18b20用に直せば、つながってるすべての18b20のレジスタ内容が取得、表示されるはずなのでそこから温度の部分だけ抜き出して処理すればいいと思いますよ。

> if ( addr[0] != 0x10) { // <-0x10は18S20のIDなので、18B20の 0x28に修正する
> Serial.print("Device is not a DS18S20 family device.\n");
> return;
> }
>ねこ蔵さん

コメントありがとうございます。
シリアルモニタで見る限り両方読めているようです。

> ds.select(Addr)のアドレスは、配列に入れてポインタで渡しているか。

ds.select(Addr)の(Addr)にそのまま「28 56 38 B7 3 0 0 CB」を入れても動きません。
それが「配列に入れて、ポインタで渡す」ということだと思うのですが、まだ理解できていないのでもう少し調べてみます。
すでに理解されてたらすみませんが、こんな感じを意図しています。

byte DEV1[8] = {0x28, 0x56, 0x38, 0xb7, 0x03, 0x00, 0x00, 0xcb};

とあらかじめ宣言、代入しといて

ds.select(DEV1); //DEV1はDEV1[0......7]の先頭アドレスをあらわす

みたいな感じで先頭のアドレスを渡してあげる感じです。

あと大丈夫だとはおもいますが、ds.skip();は削除してますよね?
物があれば実際に試して報告できるのですが、、、、
>ねこ蔵さん
コメントありがとうございます。
今ままでこんな感じにそのまま代入してました(^^;
そしてコンパイルでエラー…
ds.select(0x28, 0x56, 0x38, 0xb7, 0x03, 0x00, 0x00, 0xcb);

ご指摘の通り宣言してから代入したら指定したds18b20だけの温度が取得できました。
ありがとうございます。一歩前進できました。
スケッチがまとまったらまたこちらに報告しますね。
takさん

おめでとうございます。単なるドライバのつくりの問題ですが、複数バイトのデータ(特に文字列)を関数に渡す場合は、こういう感じで変数のポインタで指定する事が多いと思います。

Arduino言語?といっても、結局はC言語(ドライバはC++)とマクロの組み合わせ見たいな物ですので、ある程度のC言語の知識はあったほうが幅は広がったり、問題が起こったときにドライバのソースから追ったりできるので、便利かもしれませんね。
みなさまアドバイスありがとうございましたm(__)m
あんまり纏まってないスケッチになってしまってますが、一応期待の動作はします。
forとcaseを使えば少しは纏まると思いやってみましたが余計に汚くなりました…。

--ここから--
#include <OneWire.h>

OneWire ds(6); // on pin 6

void setup(void) {
Serial.begin(9600);
}

void loop(void) {
byte i;
byte data01[12];
byte data02[12];
float celsius;

byte dev01[8] = {
0x28, 0x56, 0x38, 0xb7, 0x03, 0x00, 0x00, 0xcb };
byte dev02[8] = {
0x28, 0xF1, 0x13, 0xb7, 0x03, 0x00, 0x00, 0x9a };

//--1st ds18b20--//

ds.reset();
ds.select(dev01);
ds.write(0x44,1); // start conversion, with parasite power on at the end
delay(1000);

ds.reset();
ds.select(dev01);
ds.write(0xBE); // Read Scratchpad

for ( i = 0; i < 9; i++) { // we need 9 bytes
data01[i] = ds.read();
}

if (OneWire::crc8(data01,8) != data01[8]) {
Serial.println("CRC is not valid!");
return;
}

// convert the data to actual temperature
int raw01 = (data01[1] <<8) | data01[0];
celsius = (float)raw01 / 16.0 ;
Serial.print(" Temp1 : ");
Serial.print(celsius);
Serial.println(" Celsius ");

//--2nd ds18b20--//

ds.reset();
ds.select(dev02);
ds.write(0x44,1); // start conversion, with parasite power on at the end
delay(1000);

ds.reset();
ds.select(dev02);
ds.write(0xBE); // Read Scratchpad

for ( i = 0; i < 9; i++) { // we need 9 bytes
data02[i] = ds.read();
}

if (OneWire::crc8(data02,8) != data02[8]) {
Serial.println("CRC is not valid!");
return;
}

// convert the data to actual temperature
int raw02 = (data02[1] <<8) | data02[0];
celsius = (float)raw02 / 16.0 ;
Serial.print(" Temp2 : ");
Serial.print(celsius);
Serial.println(" Celsius ");
}

--ここまで--
>>[11]

>forとcaseを使えば少しは纏まると思いやってみましたが余計に汚くなりました…。

二次元配列とか使うとまとまるかと。
data01やdata02、row01やrow02はそれぞれ同じ変数の使いまわしでもOKかと思われます。

#include <OneWire.h>

OneWire ds(6); // on pin 6

byte dev[2][8] = {
{0x28, 0x56, 0x38, 0xb7, 0x03, 0x00, 0x00, 0xcb },
{0x28, 0xF1, 0x13, 0xb7, 0x03, 0x00, 0x00, 0x9a }
};

void setup(void) {
Serial.begin(9600);
}

void loop(void) {
byte i ,data[12];
int raw, devno;
float celsius;

for(devno = 0;devno < 2;devno++) {
ds.reset();
ds.select(dev[devno]);
ds.write(0x44,1); // start conversion, with parasite power on at the end
delay(1000);

ds.reset();
ds.select(dev[devno]);
ds.write(0xBE); // Read Scratchpad

for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}

if (OneWire::crc8(data,8) != data[8]) {
Serial.println("CRC is not valid!");
return;
}

// convert the data to actual temperature
raw = (data[1] <<8) | data[0];
celsius = (float)raw / 16.0 ;
switch(devno) {
case 0:Serial.print(" Temp1 : ");break;
case 1:Serial.print(" Temp2 : ");break;
}
Serial.print(celsius);
Serial.println(" Celsius ");
}
}

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

arduino 更新情報

arduinoのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング