Arduinoで遊ぼう - 大容量EEPROMに毎日の温度変化を保存する

Arduinoと大容量EEPROMとCOMS温度センサS8100B

Arduinoに搭載されているマイコン(AVR)には電源を切ってもデータが消えないメモリ「EEPROM」が内蔵されている。Duemilanove 168は512バイト、Duemilanove 328は1024バイト、MEGAは4096バイトのEEPROMを内蔵している。
少しだけ情報を保存する場合には内蔵のEEPROMで十分だけど、温度センサの値を数ヶ月に渡って保存したり、インターネットからダウンロードしたファイルを保存するには容量が足りない。そんな時は大容量のEEPROMをArduinoに接続してもりもりデータを保存しよう!今回、I2CインターフェースのEEPROMとCOMS温度センサ「S8100B」を使った簡単な温度ロガーの作り方を紹介するよ。



EEPROMを選ぶ


秋月電子でいろいろなサイズのEEPROMが買える。用途に合わせて最適なEEPROMを選択しよう。今回は512Kbit(64Kbytes)の24LC512を選んだ。
EEPROMを選ぶときは動作電圧とマイコンとのインターフェースに気をつけよう。Arduinoと接続する場合は5V動作、I2CインターフェースのEEPROMがおすすめ。



温度センサ


温度センサには秋月で買ったS8100Bを使った。S8100Bは-20℃から+80℃までの温度を測定できる温度センサICだ。トランジスタみたいな形をしていて、ラベルを正面にして左からVOUT、GND、VDDとなっている。VDDに5Vを接続してやれば、VOUTから温度に応じた電圧が出力される。1℃温度が上がると約-8mV電圧が下がる、右肩下がりの特性になっている。S8100Bの温度と出力電圧の特性をグラフ化した。
s8100b_temp_vout_chart.png
(S8100B 温度-出力電圧 特性)



Arduinoと接続する


I2C EEPROMと温度センサS8100B接続図
(図の555はIC2 EEPROM、NはS8100B)

ArduinoとEEPROMの接続にはアナログ端子の4番と5番を使う。4番にEEPROMのSDAを接続、5番にEEPROMのSCLを接続する。SDA、SCLは1KΩの抵抗でプルアップする。温度センサS8100BのVOUTをアナログ端子の0番に接続する。VOUTは1MΩの抵抗でプルアップする。



ライブラリをダウンロードする


サンプルスケッチを動かすには次の3つのライブラリが必要です。ライブラリをダウンロードしてSKETCHBOOK/librariesフォルダにコピーしてください。

TwEEPROM - I2CEEPROM読み書き用ライブラリ
http://arms22.googlecode.com/files/TwEEPROM001.zip

S8100B - 温度センサ用ライブラリ
http://arms22.googlecode.com/files/S8100B002.zip

Sleep - AVRスリープ用ライブラリ
http://arms22.googlecode.com/files/Sleep003.zip



サンプルスケッチ


スケッチは1秒間隔で温度センサから温度を読み取ってEEPROMに書き込みます。EEPROMに書き込まれた温度データはArduino IDEのシリアルモニタから読み出せます。スケッチは次のコマンドに対応しています。

'd' EEPROMに書き込まれた全温度データを出力します。
'r' EEPROMの内容をクリアします。
'm' モニタ機能をオン・オフします。
'g' Google Chart APIでグラフ表示可能なURLを出力します。


カップヌードル温度測定
(カップヌードルの上において温度を測定した結果)

#include <Sleep.h>
#include <Wire.h>
#include <TwEEPROM.h>
#include <S8100B.h>

#define LOG_STR_ADDR          (0x500000) // device addr + memory addr
#define LOG_MEM_SIZE          (0x10000)
#define LOG_ENT_SIZE          (2)
#define LOG_SIG_ADDR          (LOG_STR_ADDR+LOG_MEM_SIZE-4)
#define LOG_READ_PEROPD       (1000)

Temperature myTemp(0);

void setup()
{
  Wire.begin();
  Serial.begin(115200);

#define LED_PIN 13
  pinMode(LED_PIN,OUTPUT);

  Logger_init();
}

void loop()
{
  static bool moni = false;
  static uint32_t last = 0;
  uint32_t now;

  if(Serial.available()){
    int c = Serial.read();
    if(c == 'd'){
      Logger_printAllTemp();
    }
    else if(c == 'r'){
      Logger_clear();
    }
    else if(c == 'g'){
      Logger_printGoogleChartURL();
    }
    else if(c == 'm'){
      moni = !moni;
      if(moni){
        Serial.println("moni on");
      }
      else{
        Serial.println("moni off");
      }
    }
  }

  Sleep.idle();

  now = millis();
  if((now - last) > LOG_READ_PEROPD){
    digitalWrite(LED_PIN,HIGH);
    int temp = myTemp.read() * 10;
    Logger_writeTemp(temp);
    if(moni){
      print_temp(temp);
      Serial.println();
    }
    digitalWrite(LED_PIN,LOW);
    last = now;
  }
}

void print_temp(int temp)
{
  Serial.print(temp/10,DEC);
  Serial.print(".");
  Serial.print(abs(temp%10),DEC);
}

uint32_t Logger_wtptr;

void Logger_init(void)
{
  uint8_t sig[4];
  Serial.print("setup...");

  sig[0] = TwEEPROM.read(LOG_SIG_ADDR+0);
  sig[1] = TwEEPROM.read(LOG_SIG_ADDR+1);
  sig[2] = TwEEPROM.read(LOG_SIG_ADDR+2);
  sig[3] = TwEEPROM.read(LOG_SIG_ADDR+3);

  if(sig[0] == 't' && sig[1] == 'e' && sig[2] == 'm' && sig[3] == 'p' ){
    Logger_wtptr = LOG_STR_ADDR;
    for(uint32_t rdptr = LOG_STR_ADDR;rdptr<LOG_SIG_ADDR;rdptr+=LOG_ENT_SIZE){
      int temp;
      temp  = TwEEPROM.read(rdptr+0) << 8;
      temp |= TwEEPROM.read(rdptr+1);
      if(temp == 0x7fff){
        Logger_wtptr = rdptr;
        break;
      }
    }
  }
  else{
    Logger_clear();
  }

  Serial.println("done");
}

void Logger_writeTemp(int temp)
{
  uint32_t next = Logger_wtptr + LOG_ENT_SIZE;
  if(next >= LOG_SIG_ADDR){
    next = LOG_STR_ADDR;
  }
  TwEEPROM.write(next+0, 0x7f);
  TwEEPROM.write(next+1, 0xff);
  TwEEPROM.write(Logger_wtptr+0, temp >> 8);
  TwEEPROM.write(Logger_wtptr+1, temp & 0xff);
  Logger_wtptr = next;
}

void Logger_printAllTemp(void)
{
  Serial.println("print log begin");
  uint32_t rdptr = Logger_wtptr - LOG_ENT_SIZE;
  do {
    if(rdptr < LOG_STR_ADDR) {
      rdptr = LOG_SIG_ADDR - LOG_ENT_SIZE;
    }
    int temp;
    temp  = TwEEPROM.read(rdptr+0) << 8;
    temp |= TwEEPROM.read(rdptr+1);
    if(temp == 0x7fff)
      break;
    print_temp(temp);
    Serial.println();
    rdptr -= LOG_ENT_SIZE;
  }
  while(1);
  Serial.println("print log end");
}

void Logger_printGoogleChartURL(void)
{
  Serial.println("---- Google Chart URL ----");
  Serial.print("http://chart.apis.google.com/chart?"
    "cht=lc&"
    "chds=-10,40&"
    "chs=720x360&"
    "chxt=y&"
    "chxl=0:|-10|0|10|20|30|40|&"
    "chxp=0,-10,0,10,20,30,40&"
    "chxr=0,-10,40&"
    "chg=5,5,1,5&"
    "chd=t:");

#define NUMBER_OF_TEMP 360
#define TEMP_STEP 1

  uint32_t rdptr = (Logger_wtptr - LOG_ENT_SIZE) - (NUMBER_OF_TEMP * (LOG_ENT_SIZE * TEMP_STEP));
  if(rdptr < LOG_STR_ADDR){
    rdptr = LOG_SIG_ADDR - (LOG_STR_ADDR - rdptr);
  }
  int count = 0;
  do{
    int temp;
    temp  = TwEEPROM.read(rdptr+0) << 8;
    temp |= TwEEPROM.read(rdptr+1);
    print_temp(temp);

    rdptr += LOG_ENT_SIZE * TEMP_STEP;
    if(rdptr >= LOG_SIG_ADDR)
      rdptr = LOG_STR_ADDR + (rdptr - LOG_SIG_ADDR);

    if(count < NUMBER_OF_TEMP){
      Serial.print(",");
      count++;
    }
    else{
      break;
    }
  }
  while(1);
  Serial.println();
}

void Logger_clear(void)
{
  Serial.print("clear eeprom...");
  TwEEPROM.write(LOG_SIG_ADDR+0,'t');
  TwEEPROM.write(LOG_SIG_ADDR+1,'e');
  TwEEPROM.write(LOG_SIG_ADDR+2,'m');
  TwEEPROM.write(LOG_SIG_ADDR+3,'p');
  TwEEPROM.write(LOG_STR_ADDR+0,0x7f); // end mark1
  TwEEPROM.write(LOG_STR_ADDR+1,0xff); // end mark2
  TwEEPROM.write(LOG_SIG_ADDR-2,0x7f); // end mark dammy1
  TwEEPROM.write(LOG_SIG_ADDR-1,0xff); // end mark dammy2
  Logger_wtptr = LOG_STR_ADDR;
  Serial.println("done");
}




Arduinoをはじめよう
Arduinoをはじめよう
posted with amazlet at 09.10.27
Massimo Banzi
オライリージャパン
売り上げランキング: 3641



コメント

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

Re: スケッチが動かない!

こんばんわ。ご指摘ありがとうございます。

スケッチを修正しました。
'<'がHTMLタグとして認識されて、それ以降のコードが消えていたようです。

Arduinoとの接続図ですが、確かに"555"の向きが逆になっています!
トップの写真と向きを合わせて回路を組んで下さい。すみません。。
Secret

Ads by Google
最近の記事
カテゴリ
Arduino (36)
電子工作 (75)
スタバッテルミン (5)
スタバカップアンプ (9)
電光掲示板 (4)
イベント (21)
太陽電池 (12)
ニキシー管 (19)
ARM系 (8)
PIC系 (20)
USBデバイス (7)
V850系 (17)
Xfind (6)
プログラミング (25)
Android (3)
未分類 (7)
Amazon.co.jp
最近のコメント
ビーコン菅原:MOS FETを使ったマイコン周辺回路の電源の制御方法 (02/10)
arms22:MPPT太陽電池充電(7) (02/09)
arms22:ガリレオ・セブン! (02/08)
Galileo7:ガリレオ・セブン! (02/08)
arms22:Arduinoで遊ぼう - SDメモリカードを読み書きする (01/29)
:目次:Arduino (01/29)
arms22:Arduinoで遊ぼう - SDメモリカードを読み書きする (01/27)
通りすがり:10.3用twitterクライアント「twifp」 (01/21)
最近のトラックバック
以前の記事
リンク
タグ
プライバシーポリシー
当サイトでは、第三者配信による広告サービスを利用しています。このような広告配信事業者は、ユーザーの興味に応じた商品やサービスの広告を表示するため、当サイトや他サイトへのアクセスに関する情報 (氏名、住所、メール アドレス、電話番号は含まれません) を使用することがあります。このプロセスの詳細やこのような情報が広告配信事業者に使用されないようにする方法については、ここをクリックしてください。