目次

遠隔温湿度測定

 2020年の温湿度測定は、遠隔でと考えてRaspberryPiを
 利用します。

 RaspberryPiのGUI画面は、次のように定義。




 グラフの緑線は温度、紫線は湿度、黄線は換算日照値を
 表現し、水色縦線の左が当日、右が昨日の情報です。

 グラフは、中段の温度、湿度を描画。

 中段が、収穫地点なので、そこの情報を参照して
 シートを開けて、風を入れるとか、閉めて室温を
 保つための作業が必要か否かの判断ができるよう
 にしてみました。

 3地点の温度と湿度を測定し、TWELITEを使いRaspberryPiに
 データ転送して、実現します。



 TWELITEは、DIPタイプを利用。



 RaspberryPiとTWELITEの間にUSB/シリアルの
 変換基板を入れて対応。

 USB/シリアルは、秋月電子で販売されている
 Arduinoキットに使われている基板を流用。



 RaspberryPi3では、USBコネクタが4チャネルあるので
 キーボード、マウスを接続しても、2チャネル分残り
 ここから、電源供給できるので、基板にコネクタをつけ
 挿し込むだけで、対応可能。



 ソフトウエアで見ると、言語にPythonを使います。

 RaspberryPiのGlue言語はPythonなので、GUI画面は
 PySimpleGUIを利用して、GUIとwidgetを使い実現。

 PySimpleGUIを利用すると、画面のレイアウトは
 次のように記述できます。

layout = [
  [
    sg.Text('忍路ビニルハウス', font=topfontsize,size=(topLabelLength,1)),
    sg.Text('温湿度推移', font=topfontsize,size=(topLabelLength,1)),
    lblYMD ,
    lblHourMinute ,
    sg.Text(' ', size=(labelLength,1)),
    sg.Text(' ', size=(labelLength,1)),
    sg.Button('-X-',border_width = 1, key = 'Exit' )
  ],
  [
    sg.Text(' ', size=(labelLength,1))
  ],
  [
    sg.Text('上段',font =  topfontsize,size=(labelLength,1)),
    lblTtemp ,
    sg.Text('℃',font =  topfontsize,size=(labelLength,1)),
    lblThumi,
    sg.Text('%',font =  topfontsize,size=(labelLength,1)),
    sg.Text('要充電',font =  topfontsize,size=(labelLength,1)),
    lblCharge
  ],
  [
    sg.Text('中段',font = topfontsize,size=(labelLength,1)),
    lblMtemp,
    sg.Text('℃',font = topfontsize,size=(labelLength,1)),
    lblMhumi,
    sg.Text('%',font = topfontsize,size=(labelLength,1))
  ],
  [
    sg.Text('下段',font = topfontsize,size=(labelLength,1)),
    lblBtemp,
    sg.Text('℃',font = topfontsize,size=(labelLength,1)),
    lblBhumi,
    sg.Text('%',font = topfontsize,size=(labelLength,1))
  ],
  [
    sg.Text(' ', size=(labelLength,1))
  ],
  [
    heigthgraph,
    xgraph
  ],
  [
    xpad,
    timeruler,
    sg.Text('時刻',font=topfontsize,size=(labelLength,1))
  ],
  [
    sg.Text(' ', size=(labelLength,1))
  ]
]

 タイルを並べるように、GUIを構成する部品widgetを並べて
 画面を定義できるのが、特徴。

 widgetの中のラベル、ボタン、グラフィック等は、別途
 定義して、精密に記述できます。

xpad = sg.Graph(
         (50,40)        ,
         (0, 0)         ,
         (40,40)        ,
         key = '-xpad-' #,
         #background_color = 'white'
       )

heigthgraph = sg.Graph(
           (50,SIZE_Y)           ,
           (0, 0)                ,
           (40,SIZE_Y)           ,
           key = '-heigthgraph-' ,
           background_color = 'white'
        )

timeruler = sg.Graph(
           (SIZE_X,40)          ,
           (0, 0)               ,
           (SIZE_X,40)          ,
           key = '-timeruler-' ,
           background_color = 'white'
        )

xgraph = sg.Graph(
           GRAPH_SIZE    ,
           (0, 0)        ,
           DATA_SIZE     ,
           key = '-GRAPH-' ,
           background_color = 'white'
        )

lblYMD        = sg.Text(
                  text = dt.getY_M_D()     ,
                  font = topfontsize       ,
                  size = (topLabelLength,1)
                )

lblHourMinute = sg.Text(
                  text = dt.getHH_MM(),
                  font = topfontsize  ,
                  size = (topLabelLength,1)
                )

lblTtemp = sg.Text(
             text = str(top_temp)          ,
             justification    = 'right'    ,
             font             = topfontsize,
             background_color = 'Green1'   ,
             size = (labelLength,1)
           )

lblThumi = sg.Text(
             text = str(top_humi)          ,
             justification    = 'right'    ,
             font             = topfontsize,
             background_color = 'Magenta2' ,
             size = (labelLength,1)
           )

lblCharge = sg.Text(
              text = scharge                ,
              justification    = 'right'    ,
              font             = topfontsize,
              background_color = 'White'    ,
              size = (labelLength,1)
            )

lblMtemp = sg.Text(
             text = str(mid_temp)          ,
             justification    = 'right'    ,
             font             = topfontsize,
             background_color = 'Green2'   ,
             size = (labelLength,1)
           )

lblMhumi = sg.Text(
             text = str(mid_humi)          ,
             justification    = 'right'    ,
             font             = topfontsize,
             background_color = 'Magenta2' ,
             size = (labelLength,1)
           )

lblBtemp = sg.Text(
             text = str(bot_temp)          ,
             justification    = 'right'    ,
             font             = topfontsize,
             background_color = 'Green2'   ,
             size=(labelLength,1)
           )

lblBhumi = sg.Text(
             text = str(bot_humi)          ,
             justification    = 'right'    ,
             font             = topfontsize,
             background_color = 'Magenta2' ,
             size=(labelLength,1)
           )

 tkinterでは、情報が散逸している印象がありますが
 PySimpleGUIでは、次のURLで多くの情報公開がされて
 います。

https://pysimplegui.readthedocs.io/en/latest/



 Call reference 、Cookbookを参照すると、大よその
 使い方がわかります。

 GUIのwidgetでは、以下を利用。

 Tcl/Tkのwidgetと対比すると、次のようになります。

 画面の構成を定義してから、次のようにイベント
 ループを用意して、表示と通信の協調動作を確立。

# endless loop
oneshot = True
elapsedtime = 0
state_next = 0 
while True:
  # 定期的に '__TIMEOUT__' イベントが発行される
  event, values = window.Read(timeout=DELAY)

  # 一度だけ実行
  if oneshot == True :
    oneshot = False 
    gdt.drawVerticalRuler(heigthgraph)
    gdt.drawHorizontalRuler(timeruler)
    # get initiaize data
    tmplist = comdt.generateDummyPrimitive()
    # replace
    aaghouse.update( tmplist )
    # draw 
    gdt.drawLineTimeX(dt.getHH_MM(),aaghouse,xgraph)
    # values
    atime = int( dt.getHourMinute() )
    if (atime % 2) == 1 :
      atime -= 1 ;
    satime = calcdt.concatenate( int( atime / 100 ) , int( atime % 100 ) ) 
    alist = aaghouse[satime].split(',')
    top_temp , mid_temp , bot_temp = alist[0:3]
    top_humi , mid_humi , bot_humi = alist[3:6]
    # print( dt.getHourMinute() , atime , satime , alist)

  # update 
  state = dt.getSecond()
  if state != prestate :
    elapsedtime = state - prestate
    if elapsedtime < 0 :
      elapsedtime = elapsedtime + 60
    prestate = state

    state_next = state_next + elapsedtime

    if state_next >= 6 :
      # adjust
      state_next = state_next - 6
      # update Year , Month and Day
      lblYMD.Update( value = dt.getY_M_D() )
      # update Hour and Minute
      lblHourMinute.Update( value = dt.getHH_MM() )
      # get parameters from COM port
      alist = comdt.getInfoFromCom()
      aaghouse.update( alist )
      # values
      atime = int( dt.getHourMinute() )
      satime = calcdt.concatenate( int( atime / 100 ) , int( atime % 100 ) )
      print( atime , satime )
      # key is included
      if satime in aaghouse :
        xlist = aaghouse[satime].split(',')
        #print( '*' , alist )
        # copy 
        top_temp , mid_temp , bot_temp = xlist[0:3]
        top_humi , mid_humi , bot_humi = xlist[3:6]
        # update values
        lblTtemp( value = str( top_temp ) )
        lblMtemp( value = str( mid_temp ) )
        lblBtemp( value = str( bot_temp ) )
        lblThumi( value = str( top_humi ) )
        lblMhumi( value = str( mid_humi ) )
        lblBhumi( value = str( bot_humi ) )
        #  時刻
        hhmm = dt.getHH_MM()
        #listvalues = [ top_temp , mid_temp , bot_temp]
        #aaghouse[hhmm] = listvalues # store values to dictionary
        # draw 
        gdt.drawLineTimeX(dt.getHH_MM(),aaghouse,xgraph)

  # No perform
  if event in (None, 'Exit'):
      break

 イベントループで利用するメソッドは、別のPythonスクリプト
 で定義しています。

 利用したいメソッドを定義しているファイルを
 指定するため、importで宣言します。

import PySimpleGUI as sg
import ghousecalc  as calcdt
import ghousedt    as dt
import ghousesv    as sdt
import ghousepv    as pdt
import ghousecom   as comdt
import ghousegra   as gdt

 Arduino側のソースコードは、以下。

#include <TimerOne.h>
#include <LiquidCrystal.h>
#include <Wire.h>
#include <TroykaDHT.h>

#define OFF 0
#define ON  OFF+1

/* pin assignment */
#define BOTTOM 0
#define MIDDLE 1
#define TOP    2
#define LAST   3

#define LED_BIT 5

/* Real Time Clock address */
#define ROM_ADRS   0x50
#define ROM_ADRS1  0x51

#define XINTERVAL 1000000
#define YLIMIT    170
#define RSIZE     16
#define SYS_ADRS  0x1fff0

/* LCD rs , e , D4 , D5 , D6 , D7 */
LiquidCrystal lcd( 2, 3, 4, 5, 6, 7 );

/* sensor */
#define PIN_DHT_B 8
#define PIN_DHT_M 9
#define PIN_DHT_T 10

DHT dhtB(PIN_DHT_B,DHT11);
DHT dhtM(PIN_DHT_M,DHT11);
DHT dhtT(PIN_DHT_T,DHT11);

/* function prototype */
void update_trigger();
void show_help();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
byte getHex(char x);
void rs_print(int x);
void makeLCDString();
void oneShot();
void put_light_dark();
byte convHEX2BCD(byte x);
void showRtc();
void getDateTime();
void saveInfo();
void put_eeprom(unsigned long xadr,byte xdat);
void comShotX();
void update_rtc();

/* variables */
boolean tflag ;
boolean uflag ;
boolean oflag ;
boolean dflag ; /* day or night */
boolean rflag ; /* RTC */
boolean sflag ; /* save flag */
boolean cflag ; /* communication flag */
boolean bflag ; /* battery charge */

char sbuf[16] ;
byte sindex ;

byte cmd ;
byte xcnt ;
byte scnt ;
word adv ;

/* temparature */
int  temp[4] ;
byte tempbcd[3] ;

/* humidity */
int  humi[3] ;
byte humibcd[3] ;

/* LCD buffer */
char lineU[17];
char lineL[17];

/* EEPROM storage */
unsigned long rom_address ;

/* time */
byte xdatx[6];

/* emulate Real Time Clock */
byte clk_year  ;
byte clk_month ;
byte clk_day   ;
byte clk_hour  ;
byte clk_min   ;
byte clk_sec   ;

void setup()
{
  /* initialize serial */
  Serial.begin(38400);
  sindex = 0 ;
  rs_puts("Hello !");
  crlf();
  show_help();
  /* clear flags */
  tflag = OFF ;
  uflag = OFF ;
  oflag = ON ;
  dflag = OFF ;
  sflag = OFF ;
  cflag = OFF ;
  bflag = OFF ;
  /* initialize port values */
  PORTB = 0x04 ;
  PORTC = 0x00 ;
  PORTD = 0x00 ;
  /* initialize port direction */
  DDRB = 0xf7 ;
  DDRC = 0x00 ;
  DDRD = 0xfe ;
  /* variables */
  xcnt = 0 ;
  scnt = 0 ;
  clk_year = 20 ; /* 2020 */
  clk_month = 8 ; /* August */
  clk_day   = 1 ; /* 1st  */
  clk_hour  = 0 ; /* 0 hour */
  clk_min   = 0 ; /* 0 minutes */
  clk_sec   = 0 ; /* 0 seconds */
  /* 1000ms period */
  Timer1.initialize(XINTERVAL);
  Timer1.attachInterrupt(update_trigger);
  /* initialize LCD */
  lcd.begin( 16, 2 );
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Measure");
  lcd.setCursor(0, 1);
  lcd.print("Hello, world!");
  /* LCD string default */
  for ( byte ii = 0 ; ii < 16 ; ii++ ) {
    *(lineL+ii) = ' ' ;
    *(lineU+ii) = ' ' ;
  }
  *(lineU+ 0) = 'T';
  *(lineU+ 4) = '|';
  *(lineU+ 5) = 'M';
  *(lineU+ 9) = '|';
  *(lineU+10) = 'B';
  *(lineU+14) = '|';
  *(lineU+15) = 'N';
  *(lineU+16) = '\0';
  *(lineL+ 0) = 't';
  *(lineL+ 4) = '|';
  *(lineL+ 5) = 'm';
  *(lineL+ 9) = '|';
  *(lineL+10) = 'b';
  *(lineL+14) = ' ';
  *(lineU+15) = ' ';
  *(lineL+16) = '\0';
  /* Real Time Clock configration */
  Wire.begin();
  /* others */
  rom_address = 0;
  dhtB.begin();
  dhtM.begin();
  dhtT.begin();
}

void loop()
{
  float humidity  ;
  float temperature ;
  byte  btmp ;
  /* one time handling */
  if ( oflag == ON ) {
    /* clear flag */
    oflag = OFF ;
    /* default */
    lcd.setCursor(0,1);
    lcd.print("Namara Firm    ");
  }
  /* RTC handling */
  if ( rflag == ON ) {
    rflag = OFF ;
    update_rtc();
  }
  /* command interpreter */
  if ( uflag == ON ) {
    /* clear flag */
    uflag = OFF ;
    /* get command */
    cmd = *(sbuf+0) ;
    /* help */
    if ( cmd == '?' ) { show_help(); }
    /* one shot */
    if ( cmd == 'T' ) { oneShot(); }
    /* one shot */
    if ( cmd == 'X' ) { comShotX(); }
    /* show Months Days hour minute */
    if ( cmd == 'a' ) { showRtc(); }
    /* new line */
    crlf() ;
  }
  /* timer handling */
  if ( tflag == ON ) {
    /* clear flag */
    tflag = OFF ;
    /* get current Date and Time */
    getDateTime();
    /* light or dark */
    put_light_dark();
    /* get thermometer and humidity */
    for ( int ii = TOP ; ii > -1 ; ii-- ) {
      /* get data */
      if ( ii == BOTTOM ) {
        dhtB.read();
        if ( dhtB.getState() == DHT_OK ) {
          humidity    = dhtB.getHumidity();
          temperature = dhtB.getTemperatureC();
        }
      }
      if ( ii == MIDDLE ) {
        dhtM.read();
        if ( dhtM.getState() == DHT_OK ) {
          humidity    = dhtM.getHumidity();
          temperature = dhtM.getTemperatureC();
        }
      }
      if ( ii == TOP ) {
        dhtT.read();
        if ( dhtT.getState() == DHT_OK ) {
          humidity    = dhtT.getHumidity();
          temperature = dhtT.getTemperatureC();
        }
      }
      /* convert */
      *(temp+ii) = (int)temperature ;
      *(humi+ii) = (int)humidity ;
      /* show ( LCD ) */
      makeLCDString();
      lcd.setCursor(0,0); lcd.print( lineU );
      lcd.setCursor(0,1); lcd.print( lineL );
    }
    /* convert BCD */
    for ( byte i = 0 ; i < 3 ; i++ ) {
      *(tempbcd + i) = convHEX2BCD( *(temp+i) );
      *(humibcd + i) = convHEX2BCD( *(humi+i) );
    }
  }
  /* send data to Raspberry Pi every 0.5 minutes */
  if ( cflag == ON ) {
    cflag = OFF ;
    comShotX();
    /* battery check */
    btmp = PINB ;
    btmp &= 8 ;
    bflag = OFF ;
    if ( btmp == 0 ) { bflag == ON ; }
  }
  /* store data to EEPROM every 2 minutes */
  if ( sflag == ON ) {
    sflag = OFF ;
    saveInfo();
  }
}

void update_trigger()
{
  /* set flag */
  rflag = ON ;
  /* judge */
  if ( scnt == 29 || scnt == 59 || scnt == 89 ) {
    cflag = ON ;
  }
  if ( scnt == 119 ) {
    cflag = ON ;
    sflag = ON ;
  }
  /* inrement */
  xcnt++ ;
  scnt++ ;
  scnt %= 120 ;
  /* set flag */
  tflag = OFF ;
  if ( xcnt & ON ) { tflag = ON ; }
}

void show_help()
{
  rs_puts("? help")           ; crlf();
  rs_puts("T one shot")       ; crlf();
  rs_puts("X one shot")       ; crlf();
  rs_puts("a show date time") ; 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');
}

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

void rs_print(int x)
{
  char msg[5] ;
  word tmp ;
  /* default */
  *(msg+4) = '\0' ;
  /* sign */
  *(msg+0) = ' ' ;
  tmp = x ;
  if ( x < 0 ) {
    tmp *= (-1) ;
    *(msg+0) = '-' ; 
  }
  /* generate code */
  *(msg+3) = tmp % 10 + '0' ; tmp /= 10 ;
  *(msg+2) = tmp % 10 + '0' ; tmp /= 10 ;
  *(msg+1) = tmp % 10 + '0' ;
  /* zero surpress */
  if ( *(msg+1) == '0' ) {
    *(msg+1) = ' ' ;
    if ( *(msg+2) == '0' ) { *(msg+2) = ' ' ; }
  }
  /* show */
  rs_puts( msg );
}

void makeLCDString()
{
  int tmp ;
  byte i ;
  byte j ;
  /* upper */
  for ( i = BOTTOM ; i < LAST ; i++ ) {
    /* get value */
    tmp = *(temp+TOP-i) ;
    /* calculate offset */
    j = (i << 2) + i ;
    /* sign handling */
    *(lineU+1+j) = ' ' ;
    if ( tmp < 0 ) {
      *(lineU+1+j) = '-' ;
      tmp *= (-1); 
    }
    *(lineU+3+j) = tmp % 10 + '0' ; /* x1 */
    tmp /= 10 ;
    *(lineU+2+j) = tmp % 10 + '0' ; /* x10 */
  }
  /* day or night */
  *(lineU+15) = '_' ;
  if ( dflag ) { *(lineU+15) = '*' ; }
  /* lower */
  for ( i = BOTTOM ; i < LAST ; i++ ) {
    /* get value */
    tmp = *(humi+TOP-i) ;
    /* calculate offset */
    j = (i << 2) + i ;
    *(lineL+3+j) = tmp % 10 + '0' ; /* x1 */
    tmp /= 10 ;
    *(lineL+2+j) = tmp % 10 + '0' ; /* x10 */
  }
}

void oneShot()
{
  int *ptr ;
  byte i ;
  byte j ;
  byte sel ;
  char xch ;
  /* loop */
  for ( j = 0 ; j < 2 ; j++ ) {
    /* set pointer */
    ptr = temp ;
    if ( j > 0 ) { ptr = humi ; } 
    /* send */
    for ( i = 0 ; i < 3 ; i++ ) {
      /* calculate */
      sel = 4 * j + i ;
      /* header */
      switch ( sel ) {
        case 0  : xch = 'T' ; break ;
        case 1  : xch = 'M' ; break ;
        case 2  : xch = 'B' ; break ;
        case 4  : xch = 't' ; break ;
        case 5  : xch = 'm' ; break ;
        case 6  : xch = 'b' ; break ;
        default : xch = ' ' ; break ;
      }
      rs_putchar( xch );
      /* value */
      rs_print( *(ptr+i) );
      /* separator */
      rs_putchar('|');
    }
    /* day or night */
    if ( j == 0 ) { rs_print( *(ptr+LAST) ); }
  }
  /* sun power */
  rs_putchar(',');
  rs_print( adv );
  /* battery */
  rs_putchar(',');
  xch = '0' ;
  if ( bflag == ON ) { xch = '1' ; }
  rs_putchar( xch );
  /* new line */ 
  crlf();
}

void comShotX()
{
  int *ptr ;
  byte i ;
  char xch ;
  /* temparature */
  ptr = temp ; /* set pointer */
  for ( i = 0 ; i < 3 ; i++ ) {
    /* value */
    rs_print( *(ptr+i) );
    /* separator */
    xch = ',' ;
    if ( i == 2 ) { xch = '|' ; }
    /* send */
    rs_putchar( xch );
  }
  /* humidity */
  ptr = humi ; /* set pointer */
  for ( i = 0 ; i < 3 ; i++ ) {
    /* value */
    rs_print( *(ptr+i) );
    /* separator */
    xch = ',' ;
    if ( i == 2 ) { xch = '|' ; }
    /* send */
    rs_putchar( xch );
  }
  /* sun power */
  rs_print( adv );
  rs_putchar(',');
  /* battery */
  xch = '0' ;
  if ( bflag == ON ) { xch = '1' ; }
  rs_putchar( xch );
  /* new line */ 
  crlf();
}

byte convHEX2BCD(byte x)
{
  byte result ;

  /* lower */
  result = (x % 10);
  /* upper */
  result += ((x / 10) << 4);

  return result ;
}

void put_light_dark()
{
  /* get state */
  adv = analogRead( LAST );
  *(temp+3) = adv ;
  /* default (night) */
  dflag = OFF ;
  /* day */
  if ( adv > YLIMIT ) { dflag = ON ; }
}

void showRtc()
{
  byte ii ;
  byte tmp ;
  byte tmpH ;
  byte tmpL ;
  /* show */
  for ( ii = 0 ; ii < 6 ; ii++ ) {
    tmp = *(xdatx+ii) ;
    tmpL = (tmp & 15 ) + '0' ;
    tmp >>= 4 ;
    tmpH = tmp + '0' ;
    rs_putchar( tmpH );
    rs_putchar( tmpL );
    if ( ii < 2  ) { rs_putchar('-'); }
    if ( ii == 2 ) { rs_putchar(' '); }
    if ( ii == 3 ) { rs_putchar(':'); }
    if ( ii == 4 ) { rs_putchar(':'); }
  }
  crlf();
}

void getDateTime()
{
  *(xdatx+0) = convHEX2BCD( clk_year  ) ;
  *(xdatx+1) = convHEX2BCD( clk_month ) ;
  *(xdatx+2) = convHEX2BCD( clk_day   ) ;
  *(xdatx+3) = convHEX2BCD( clk_hour  ) ;
  *(xdatx+4) = convHEX2BCD( clk_min   ) ;
  *(xdatx+5) = convHEX2BCD( clk_sec   ) ;
}

void saveInfo()
{
  byte     xtmp[13];
  unsigned long yadr ;
  byte     ii ;
  /* copy */
  *(xtmp+ 0) = 0x20 ;           /* year */
  *(xtmp+ 1) = 0x20 ;           /* year */
  *(xtmp+ 2) = *(xdatx+1);      /* MM */
  *(xtmp+ 3) = *(xdatx+2);      /* DD */
  *(xtmp+ 4) = *(xdatx+3);      /* hh */
  *(xtmp+ 5) = *(xdatx+4);      /* mm */
  *(xtmp+ 6) = *(tempbcd+2);    /* TOP */
  *(xtmp+ 7) = *(tempbcd+1);    /* MIDDLE */
  *(xtmp+ 8) = *(tempbcd+0);    /* BOTTOM */
  *(xtmp+ 9) = *(temp+3) >> 2 ; /* photo  */
  *(xtmp+10) = *(humibcd+2);    /* humidity TOP */
  *(xtmp+11) = *(humibcd+1);    /* humidity MIDDLE */
  *(xtmp+12) = *(humibcd+0);    /* humidity BOTTOM */
  /* debug */
  rs_putchar('='); crlf();
  /* generate address */
  yadr = rom_address ;
  /* store */
  for ( ii = 0 ; ii < 13 ; ii++ ) {
    /* put 1 byte */
    put_eeprom( yadr , *(xtmp+ii) );
    /* update address */
    yadr++ ; 
  }
  /* update ROM address */
  rom_address += RSIZE ;
  /* roll over reset */
  if ( rom_address > SYS_ADRS ) { rom_address = 0 ; }
}

void put_eeprom(unsigned long xadr,byte xdat)
{
  byte adh ;
  byte adl ;
  byte xx ;
  boolean bflag ;
  /* copy */
  xx = xdat ;
  /* set block number */
  bflag = OFF ;
  if ( xadr > 0xffff ) { bflag = ON ; }
  /* separate address */
  adl = xadr & 0xff ;
  adh = (xadr >> 8) & 0xff ;
  /* write 1 byte */
  if ( bflag ) { Wire.beginTransmission(ROM_ADRS1); }
  else         { Wire.beginTransmission(ROM_ADRS ); }
  Wire.write(adh); /* upper address */
  Wire.write(adl); /* lower address */
  Wire.write(xx ); /* data */
  Wire.endTransmission();
  /* wait 5ms */
  delay(5);
}

void update_rtc()
{
  byte month ;
  /* set month */
  month = clk_month ;
  /* second */
  clk_sec++ ;
  /* judge */
  if ( clk_sec == 60 ) {
    /* clear */
    clk_sec = 0 ;
    /* minute */
    clk_min++ ;
  }
  /* minute */
  if ( clk_min == 60 ) {
    /* clear */
    clk_min = 0 ;
    /* hour */
    clk_hour++ ;
  }
  /* hour */
  if ( clk_hour == 24 ) {
    /* clear */
    clk_hour = 0 ;
    /* increment */
    clk_day++ ;
    /* day */
    switch ( month ) {
      case  1 :
      case  3 :
      case  5 :
      case  7 :
      case  8 :
      case 10 : if ( clk_day == 32 ) {
                  clk_day = 1 ;
                  month++ ;
                }
                break;

      case 12 : if ( clk_day == 32 ) {
                  clk_day = 1 ;
                  month = 1 ;
                  clk_year++ ;
                }
                break;

      case  2 : if ( clk_day == 29 ) {
                  clk_day = 1 ;
                  month++ ;
                }
                break;

      default : if ( clk_day == 31 ) {
                   clk_day = 1 ;
                   month++ ;
                 }
                 break;

    }
    clk_month = month ;
  }
}

/* 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 ;
    }
  }
}

 Arduinoは、次の構成で通信と測定を担当。



 動作は、次のように単純にしてあります。

 センサーは、2秒周期で測定をしながら
 30秒ごとに情報を送信。

 通信先のTWELITEは、USBでPersonal Computerに
 接続できるようにしてあります。



 USBケーブルを用意すれば、RaspberryPiでも
 Windowsマシンでも接続可能。

 Arduinoに接続するTWELITEは、以下。




目次

inserted by FC2 system