SPI制御の熱電対温度モジュール(MAX31855)(4) SDカードI/F接続

今回は、前回の熱電センサ2接続にさらにマイクロSDカードI/Fを並列接続する例を紹介します。

pic3-2

●SDカード併用制御の概要

先の2個並列制御の回路にSDカードI/Fを追加して同時に使用します。回路は図3のようにしています。#290 microSDカードボードは筆者が製作したマイクロSDカードのI/Fボードです。一般的なSDカードI/Fが付いたシールドも使用できます。
SDカードはリード/ライトを確認するために、10件記録したら記録した内容を一括で読み出し、シリアルで出力します。結果はArduino-IDEのシリアル・モニタで確認できます(CTRL+SHIFT+Mで起動)。

SDカードI/Fは前回述べたようにSPIのデータ・モードが「モード0」で、温度モジュールの「モード1」と異なります。そのため、SDカードのアクセス直前にモード0に切り替える処理、温度モジュールをアクセスする直前にモード1に切り替える処理が追加されています。

drw3-4_WSD

<サンプルスケッチ ReadTempW_SD.zip>


/*
  熱電対コンバータ 温度読み出しサンプル
  copyright (c) 2013 T.N www.wsnak.com

  13/01/14 新規
  13/01/15 Wバージョン
  13/01/16 SDカード併用テスト
  13/01/16 SDカード併用テスト(トランジスタ オープンコレクタ接続対応)

  熱電対センサモジュールSPI#1
    MISO (D12)
    CLK  (D13)
    CS   (D8)

  熱電対センサモジュールSPI#2
    MISO (D12)
    CLK  (D13)
    CS   (D9)

  注意 MISOは3ステート、オープンコレクタ出力にはなっていないので、
  並列接続時はトランジスタのオープン・コレクタ回路などのバッファ
  を入れる必要あり(その場合はビット反転の必要あり)

*/

#define OPEN_COLLECTOR      // センサモジュールのMISO出力(ビット反転)

#include <SD.h>       // SDライブラリ
#include <SPI.h>

#define SPI_CS_ON    digitalWrite(SPI_cs, LOW)       // /cs = L
#define SPI_CS_OFF   digitalWrite(SPI_cs, HIGH)      // /cs = H
#define SPI_CS2_ON   digitalWrite(SPI_cs2, LOW)      // /cs = L
#define SPI_CS2_OFF  digitalWrite(SPI_cs2, HIGH)     // /cs = H
#define SPI_SD_ON    digitalWrite(SPI_SD, LOW)       // /cs = L
#define SPI_SD_OFF   digitalWrite(SPI_SD, HIGH)      // /cs = H

const int SPI_cs  = 8;    // 熱電対センサモジュール CSポート番号
const int SPI_cs2 = 9;    // 熱電対センサモジュール CSポート番号
const int SPI_SD  = 10;   // SDカード CSポート番号

byte spiDat[4];
char strBuf[16];

File myFile;                            // ファイルハンドル
const char *fName = "test0002.txt";     // SDカード保存ファイル名

byte Count;

// -------------------------
// 初期化
// -------------------------
void setup()
{
  Serial.begin(19200);             // シリアルポート初期化

  pinMode(SPI_cs, OUTPUT);        // センサモジュール#1 cs
  pinMode(SPI_cs2, OUTPUT);       // センサモジュール#2 cs
  pinMode(SPI_SD, OUTPUT);        // SDカード cs

  SPI_CS_OFF;
  SPI_CS2_OFF;
  SPI_SD_OFF;

  if (!SD.begin(SPI_SD)) {    // SDオブジェクト初期化
    Serial.println("initialization failed!"); // 初期化失敗
  } else {
    Serial.println("initialization done.");   // 初期化成功
    Serial.println(fName);
  }

  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV4);  // SPIクロック分周比
  SPI.setBitOrder(MSBFIRST);            // 送信ビット順番

  writeSd("test SD & TC");
  Count = 0;                      // レコード書き込み回数
}

// -------------------------
// メインループ
// -------------------------
void loop() {
  word val1, val2;

  // 温度センサ1
  val1 = getSpiData(0);
  getTemp(val1, strBuf);
  Serial.print(strBuf);
  delay(1);
  writeSd(strBuf);          // SDカードへ文字列書き込み

  Serial.print("  ");

  // 温度センサ2
  val2 = getSpiData(1);
  getTemp(val2, strBuf);
  Serial.println(strBuf);
  delay(1);
  writeSd(strBuf);          // SDカードへ文字列書き込み

  Count++;
  if(Count == 10) {
    Serial.println("**** read SD 10 ****");
    // 10回目の書き込みのときまとめて読み出す

    SPI.setDataMode(SPI_MODE0);     // SPIデータモード切替
    myFile = SD.open(fName);
    if (myFile) {
      Serial.println("---- read SD ----");

      // 無くなるまで読み出しを繰り返す
      while (myFile.available()) {
        // 1行読み出してシリアル送信
        Serial.write(myFile.read());
      }
      // ファイルをクローズ
      myFile.close();
      Serial.println("---- end ----");
    } else {
      Serial.println("read failed");
    }
//    while(1);   // halt
  }
  delay(1000);      // 1秒
}

//
// SDカードへ文字列書き込み
//
byte writeSd(char *str) {
  SPI.setDataMode(SPI_MODE0);     // SPIデータモード切替

  myFile = SD.open(fName, FILE_WRITE);

  if(myFile) {
    myFile.println(str);        // 1行書き込み
    myFile.close();
  } else {
    return false;
  }
  return true;
}

//
// 温度モジュールからSPIでデータを読み出す
//
word getSpiData(byte num) {
  byte i;

  SPI.setDataMode(SPI_MODE1);     // SPIデータモード切替

  if(num == 0) {
    SPI_CS_ON;
  } else {
    SPI_CS2_ON;
  }

  for(i = 0; i < 2; i++) {          // 2バイトだけ受信
#ifdef OPEN_COLLECTOR
    spiDat[i] = ~SPI.transfer(0);   // ダミーデータ送信(1バイト受信)(ビット反転)
#else
    spiDat[i] = SPI.transfer(0);    // ダミーデータ送信(1バイト受信)
#endif
  }
  SPI_CS_OFF;
  SPI_CS2_OFF;

  return ((word)spiDat[0] << 8) | (word)spiDat[1];
}

//
// SPIで読み出したデータを温度値の文字列に変換する
//
void getTemp(word spival16, char *str) {
  word val, vali;
  byte sign, vals;
  val = spival16 >> 2;

  if(val & 0x2000) {  // 符号ビットをチェック
    // 負数(2の補数)
    val = ~val + 1;   // 正数に戻す
    val &= 0x3FFF;    // 数値抽出
    sign = true;      // 負数マーク
  } else {
    // 正数
    sign = false;
  }

  // 整数部分と小数部分に分ける
  vali = val >> 2;          // 整数部(上位11ビット)
  vals = (byte)val & 0x03;  // 小数部(下位2ビット)
  vals = vals * 25;         // 25=0.25*100 小数部を整数化

  // 表示用文字列作成
  if(sign) {
    // 負数
    sprintf(str, "-%d.%-2d", vali, vals);
  } else {
    // 整数
    sprintf(str, "+%d.%-2d", vali, vals);
  }
}


この記事は2013年1~2月頃にCQ出版のブログへ掲載したものを少し修正したものです。
参考文献

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