目次

データ集計装置

 温度計測装置は、常時温度を測定し、LCDに表示します。



 温度計測装置は、単独での動作。

 1日のうちの温度変化をグラフにするため
 日付、時刻と温度データを集めておきます。

 温度計測装置は、EEPROMにデータを格納して
 いるので、データ集計装置を作成して情報を
 取得。

 データ集計装置に必要な機能を列挙すると、以下。

 EEPROMは、温度計測装置から外せるようになっています。




 EEPROM基板をArduinoに接続し、EEPROMのデータだけを
 吸い上げれば、データ集計の元情報を取得できます。


 秋月電子のArduino基板を使って、データ集計用の
 専用装置を作成すればよいはず。



 データ集計専用のArduinoスケッチを作成します。

 端末ソフトでArduinoに接続したEEPROMから
 データを取得するだけとします。

 用意したコマンドは、以下。

 このコマンドインタプリタを内蔵したスケッチは、以下。

/*
  romtstx.ino

  PORTB
    PB5 (output) LED
    PB4 (output) --
    PB3 (output) --
    PB2 (output) --
    PB1 (output) --
    PB0 (output) --
 
  PORTC
    PC5 (output) SCL
    PC4 (output) SDA
    PC3 (output) --
    PC2 (output) --
    PC1 (output) --
    PC0 (output) --

*/
#include <Wire.h>

#define OFF 0
#define ON  OFF+1

#define BSIZE 256

#define ROM_ADRS  0x50

#define LED_BIT 5

boolean uflag ;

/* variables */
char sbuf[4] ;
byte sindex ;

byte cmd ;
byte ydat[32];
byte zdat[BSIZE] ;

void update_trigger();
void show_help();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void get_page_eeprom(word xadr);
void loadEEPROM();
void showBuffer();
char getHex(byte x);

void setup()
{
  Serial.begin(9600);
  rs_puts("Hello !");
  crlf();
  /* port value */
  PORTB = 0x00 ;
  PORTC = 0x00 ;
  PORTD = 0x00 ;
  /* port direction */
  DDRB = 0xff ;
  DDRC = 0xf0 ;
  DDRD = 0xfe ;
  /* flags */
  uflag = OFF ; 
  /* enable IIC bus */
  Wire.begin();
}

void loop()
{
  /* command interpreter */
  if ( uflag == ON ) {
    /* clear flag */
    uflag = OFF ;
    /* get command */
    cmd = *(sbuf+0) ;
    /* help */
    if ( cmd == '?' ) { show_help(); }
    /* show EEPROM context */
    if ( cmd == 'D' ) { showBuffer(); }
    /* load data from EEPROM */
    if ( cmd == 'L' ) { loadEEPROM(); }
    /* new line */
    crlf() ;
  }
}

void show_help()
{
  rs_puts("? help")           ; crlf();
  rs_puts("D display buffer") ; crlf();
  rs_puts("L load data")      ; crlf();
}

void rs_putchar(char x)
{
  Serial.write(x);
}

void rs_puts(char *ptr)
{
  while ( *ptr ) {
    rs_putchar( *ptr );
    ptr++;
  }
}

void crlf()
{
  rs_putchar('\r');
  rs_putchar('\n');
}

void get_page_eeprom(word xadr)
{
  byte adh ;
  byte adl ;
  /* separate address */
  adl = xadr & 0xff ;
  adh = (xadr >> 8) & 0x1f ;
  /* write entry address */
  Wire.beginTransmission(ROM_ADRS);
  Wire.write(adh); /* upper address */
  Wire.write(adl); /* lower address */
  Wire.endTransmission();
  /* get 32 bytes */
  Wire.requestFrom(ROM_ADRS,32);
  /* copy */
  if ( Wire.available() ) {
    for ( adl = 0 ; adl < 32 ; adl++ ) {
      *(ydat+adl) = Wire.read();
    }
  }
  /* show */  
  for ( adl = 0 ; adl < 32 ; adl++ ) {
    adh = *(ydat+adl) ;
    rs_putchar( getHex( (adh >> 4) & 15 ) );
    rs_putchar( getHex( adh & 15 ) );
    rs_putchar(' ');
    if ( (adl % 16) == 15 ) { crlf(); }
  }
  /* wait */
  delay(100);
}

void loadEEPROM()
{
  word i ;
  byte j ;
  word xad ;
  for ( i = 0 ; i < 256 ; i++ ) {
    xad = (i << 5) ;
    get_page_eeprom( xad ) ;
  }
}

void showBuffer()
{
  byte tmp ;
  word ii ;
  char msg[2] ;
  for ( ii = 0 ; ii < BSIZE ; ii++ ) {
    /* get */
    tmp = *(zdat+ii) ;
    /* lower */
    *(msg+1) = getHex( tmp & 15 ); 
    /* upper */
    *(msg+0) = getHex( (tmp >> 4) & 15 );
    /* impress */
    rs_putchar( *(msg+0) );
    rs_putchar( *(msg+1) );
    rs_putchar( ' ' );
    /* new line */
    if ( (ii & 15) == 15 ) { crlf(); }
  }
}

char getHex(byte x)
{
  char result ;
  /* default */
  result = '0' ;
  /* judge */
  if ( 0 <= x && x <= 9 ) { result = x + '0' ; }
  if ( x > 9 ) { result = x - 10 + 'A' ; }
  
  return result ;
}

/* receive interrupt */
void serialEvent()
{
  char ch;

  if ( Serial.available() > 0 ) {
    /* get 1 character */
    ch = Serial.read();
    /* store */
    *(sbuf+sindex) = ch ;
    /* increment */
    sindex++ ;
    /* judge */
    if ( ch == '\r' ) {
      sindex = 0 ; 
      uflag  = ON ;
    }
  }
}

 コマンド'L'は、関数loadEEPROMに処理を一任しています。

 関数loadEEPROMは、関数get_page_eepromを利用して
 ページ単位(1ページ=32バイト)で配列にEEPROM
 の情報を格納後、表示させます。

 TeraTermで操作すると、次のようになります。



 このままでは、ファイルに転送できないので
 クリップボードを使わない方法で、ファイル
 に情報を格納します。

 コマンド'L'で表示している内容は、ログを取る
 機能でファイルに転送。




 ログでは、操作も記録されるので、次のようになります。


L
06 01 16 34 22 40 18 85 06 01 16 36 22 40 18 85 
06 01 16 38 22 39 17 84 06 01 16 40 22 40 18 85 
06 01 16 42 22 39 18 84 06 01 16 44 22 39 17 84 
06 01 16 46 23 39 17 84 06 01 16 48 23 40 18 85 
06 01 16 50 22 40 21 85 06 01 16 52 22 40 24 85 
06 01 16 54 22 40 25 85 06 01 16 56 21 40 26 85 
06 01 16 58 21 41 26 85 06 01 17 00 22 40 26 85 
06 01 17 02 21 41 25 85 06 01 17 04 22 40 24 85 
06 01 17 06 22 40 22 85 06 01 17 08 22 40 21 85 
06 01 17 10 22 40 21 85 06 01 17 12 22 40 21 85 

 テキストファイルになっているので、テキストエディタで
 操作は削除すれば、1レコード(8バイト)の情報が1行
 に2つあるとわかります。

 spreadsheetでグラフ描画がしたいので、CSV形式に
 変換して、扱いやすくしていきます。

 テキストデータの整形に利用するスクリプト言語では
 AWKが最も使いやすいので、AWKスクリプトを作成して
 いきます。

 1行を1レコードに

  1行を1レコードにするには、8フィールドのデータを
  表示したなら、改行することで実現。

{
    for ( i = 1 ; i < 17 ; i++ ) {
      printf("%s ",$i)
      if ( i == 8  || i == 16 ) printf("\n")
    }
}

 日付等の情報以外は表示しない

  1フィールド目が、FFであれば、1レコード表示を
  スキップすればよいはず。

{
  if ( $1 != "FF" ) {
    for ( i = 1 ; i < 17 ; i++ ) {
      printf("%s ",$i)
      if ( i == 8  || i == 16 ) printf("\n")
    }
  }
}

 日付をわかりやすく見せる

  1フィールドと2フィールドの間に、「/」を入れて対応。

{
  if ( $1 != "FF" ) {
    for ( i = 1 ; i < 17 ; i++ ) {
      printf("%s",$i)
      if ( i == 1  || i == 9 )  printf("/")
      if ( i == 8  || i == 16 ) printf("\n")
    }
  }
}

  1レコードは、8フィールドなので、2レコード目の
  処理も入れてます。

 時刻をわかりやすく見せる

  3フィールドと4フィールドの間に、「:」を入れて対応。

{
  if ( $1 != "FF" ) {
    for ( i = 1 ; i < 17 ; i++ ) {
      printf("%s",$i)
      if ( i == 1  || i == 9 )  printf("/")
      if ( i == 3  || i == 11 ) printf(":")
      if ( i == 8  || i == 16 ) printf("\n")
    }
  }
}

  1レコードは、8フィールドなので、2レコード目の
  処理もORで追加してます。

 CSV形式になるようにカンマを追加

  日付、時刻を除外したフィールドに「,」を入れて対応。

{
  if ( $1 != "FF" ) {
    for ( i = 1 ; i < 17 ; i++ ) {
      printf("%s",$i)
      if ( i == 1  || i == 9 )  printf("/")
      if ( i == 2  || i == 10 ) printf(",")
      if ( i == 3  || i == 11 ) printf(":")
      if ( 3  < i && i <  8 ) printf(",")
      if ( 11 < i && i < 16 ) printf(",")
      if ( i == 8  || i == 16 ) printf("\n")
    }
  }
}

  このスクリプトを利用したときに、生成されるCSV形式ファイル
  の内容は、以下となります。

06/01,16:34,22,40,18,85
06/01,16:36,22,40,18,85
06/01,16:38,22,39,17,84
06/01,16:40,22,40,18,85
06/01,16:42,22,39,18,84
06/01,16:44,22,39,17,84
06/01,16:46,23,39,17,84
06/01,16:48,23,40,18,85
06/01,16:50,22,40,21,85

 照度値を生値に戻す

  照度値は、1バイトに収容するために、実際の値の1/4に
  しています。さらに16進数にしてあるので生値に戻しておき
  ます。

  16進数2けたは、文字列になっているので関数を用意し
  それを呼び出して使うだけとします。

  16進数を10進数に変換する関数は、if文で15回の判定を
  使います。

function getValue(x)
{
  result = 0
  if ( x == "1" ) { result =  1 }
  if ( x == "2" ) { result =  2 }
  if ( x == "3" ) { result =  3 }
  if ( x == "4" ) { result =  4 }
  if ( x == "5" ) { result =  5 }
  if ( x == "6" ) { result =  6 }
  if ( x == "7" ) { result =  7 }
  if ( x == "8" ) { result =  8 }
  if ( x == "9" ) { result =  9 }
  if ( x == "A" ) { result = 10 }
  if ( x == "B" ) { result = 11 }
  if ( x == "C" ) { result = 12 }
  if ( x == "D" ) { result = 13 }
  if ( x == "E" ) { result = 14 }
  if ( x == "F" ) { result = 15 }

  return result 
}

  文字列を分割するには、関数substrを使えばよいので
  スクリプトは、次のようにまとめられます。

function getValue(x)
{
  result = 0
  if ( x == "1" ) { result =  1 }
  if ( x == "2" ) { result =  2 }
  if ( x == "3" ) { result =  3 }
  if ( x == "4" ) { result =  4 }
  if ( x == "5" ) { result =  5 }
  if ( x == "6" ) { result =  6 }
  if ( x == "7" ) { result =  7 }
  if ( x == "8" ) { result =  8 }
  if ( x == "9" ) { result =  9 }
  if ( x == "A" ) { result = 10 }
  if ( x == "B" ) { result = 11 }
  if ( x == "C" ) { result = 12 }
  if ( x == "D" ) { result = 13 }
  if ( x == "E" ) { result = 14 }
  if ( x == "F" ) { result = 15 }

  return result 
}

{
  if ( $1 != "FF" ) {
    for ( i = 1 ; i < 17 ; i++ ) {
      if ( i != 8 && i != 16 ) {
        printf("%s",$i)
      } 
      if ( i == 1 || i == 9 )  printf("/")
      if ( i == 2 || i == 10 ) printf(",")
      if ( i == 3 || i == 11 ) printf(":")
      if ( 3  < i && i <  8 ) printf(",")
      if ( 11 < i && i < 16 ) printf(",")
      if ( i == 8 || i == 16 ) {
        num = getValue(substr($i,1,1)) * 16 + getValue(substr($i,2,1))
        printf("%d\n",4*num)
      }
    }
  }
}

  このスクリプトを利用したときに、生成されるCSV形式ファイル
  の内容は、以下となります。

06/01,16:34,22,40,18,532
06/01,16:36,22,40,18,532
06/01,16:38,22,39,17,528
06/01,16:40,22,40,18,532
06/01,16:42,22,39,18,528
06/01,16:44,22,39,17,528

 CSV形式ファイルをspreadsheetに取り込んで
 表示すると、次のようになります。



 色づけした線は、次の物理量を表現

 グラフからわかることをリスト。


目次

inserted by FC2 system