なんでも作っちゃう、かも。

Arduino/Make/フィジカルコンピューティング/電子工作あたりで活動しています。スタバの空きカップを使ったスタバカップアンプなど製作。最近はもっぱらArduinoと3Dプリンタの自作に興味があります。

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

Posted by arms22 on 2009年10月24日 4  1

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



Ads by Google

4 Comments

says..."管理人のみ閲覧できます"
このコメントは管理人のみ閲覧できます
2010.01.15 13:11 | | # [edit]
arms22 says..."Re: スケッチが動かない!"
こんばんわ。ご指摘ありがとうございます。

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

Arduinoとの接続図ですが、確かに"555"の向きが逆になっています!
トップの写真と向きを合わせて回路を組んで下さい。すみません。。
2010.01.15 23:27 | URL | #- [edit]
says..."管理人のみ閲覧できます"
このコメントは管理人のみ閲覧できます
2010.10.11 14:35 | | # [edit]
arms22 says..."Re: TwEEPROMの使い方"
TwEEPROM.read(アドレス)でアドレスの値が戻り値として返ってきます。
TwEEPROM.write(アドレス,データ)でアドレスにデータが書き込まれます。
アドレスは(デバイスアドレス<<16 | メモリアドレス)です。
2010.10.12 09:16 | URL | #- [edit]

Leave a reply






管理者にだけ表示を許可する

該当の記事は見つかりませんでした。