目次

RTCなしスケッチ作成

 センサーデータの換算処理時間が、長いかなとして
 RTC(Real Time Clock)を利用してきました。

 RTCは、IICバスを使っているので、ワンチップマイコン
 内蔵のタイマー、カウンタを使ったクロックを利用した
 方が、処理速度と消費電力の関係で有利だと、思い直し
 ました。

 Arduinoを利用したシステムブロック図は、次のように
 描き直し。



 RTCの代役は、1秒ごとのタイマー割込みで実現します。

 1秒ごとのタイマー割込みで、イベント通知フラグを
 セットし、loopの中でフラグを参照する仕様とします。

 MsTimer2ライブラリで、1秒単位の割込みを発生させ
 次の関数でイベント通知フラグをセット。

void update_trigger()
{
  /* set flag */
  rflag = ON ;
  /* judge */
  if ( scnt == 120 ) {
    scnt = 0 ;
    sflag = ON ;
  }
  /* inrement */
  xcnt++ ;
  scnt++ ;
  /* set flag */
  tflag = OFF ;
  if ( xcnt & ON ) { tflag = ON ; }
  /* flashing */
  PORTB &= ~(1 << LED_BIT) ;
  if ( wflag == ON ) {
    if ( xcnt & ON ) { PORTB |= (1 << LED_BIT) ; }
  }
}

 イベント通知フラグは、rflag、sflagを利用。
 1秒ごとの刻時は、rflagを使い、EEPROMへの
 情報保存はsflagを使います。

 イベント通知フラグsflagにより、駆動される関数は
 saveInfo()で、loopの中では、次のように処理。

  if ( sflag == ON ) {
    sflag = OFF ;
    saveInfo();
  }

 関数saveInfoは、単純にグローバル変数に格納している値を
 指定フォーマットでEEPROMに転送するだけとなりました。

void saveInfo()
{
  byte xtmp[8];
  word yadr ;
  byte ii ;
  /* copy */
  *(xtmp+0) = *(xdatx+1);      /* MM */
  *(xtmp+1) = *(xdatx+2);      /* DD */
  *(xtmp+2) = *(xdatx+3);      /* hh */
  *(xtmp+3) = *(xdatx+4);      /* mm */
  *(xtmp+4) = *(tempbcd+2);    /* TOP */
  *(xtmp+5) = *(tempbcd+1);    /* MIDDLE */
  *(xtmp+6) = *(tempbcd+0);    /* BOTTOM */
  *(xtmp+7) = *(temp+3) >> 2 ; /* photo  */
  /* debug */
  rs_putchar('='); crlf();
  /* generate address */
  yadr = rom_address ;
  /* store */
  for ( ii = 0 ; ii < 8 ; 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 ; }
}

 イベント通知フラグrflagにより、駆動される関数は
 update_rtc()で、loopの中では、次のように処理。

  if ( rflag == ON ) {
    rflag = OFF ;
    update_rtc();
  }

 関数update_rtc()は、グローバル変数に格納している値を
 計時フォーマットで加算する他、月日の扱いを入れている
 だけ。

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

 グローバル変数は、年月日時分秒としています。
 リストすると、以下。

 プリフィックスにclkを使い、リアルタイムクロックに
 関係する変数であることを、わかりやすくしてます。

 閏年の処理は、入れてませんが、西暦年を扱えるように
 拡張すれば、簡単な計算で判定できるので、後で追加と
 考えました。

 RTCをエミュレートする関数は、外部のRTCをIICバスで
 接続して処理するよりも、規模が小さく、高速になって
 いると理解できました。

 年月日時分秒は、後でスクリプトで編集しているため
 ダミーで書込みが終わっていれば充分と判断。

 RTCをエミュレートして、Arduino内部にもつので
 コマンドインタプリタのコマンドは、次の種に
 絞れました。

 コマンドを減らしたので、不要となった関数を
 削減できました。

 ArduinoのFlashROM領域の46%を占めてますが
 従来は50%であったので、意外に減っていると
 いえます。

 まとめると、以下。

/*
  thermoe.ino

  not include RTC

  Pin assignment

  PORTB
    PB5 (output) LED
    PB4 (output) --
    PB3 (output) --
    PB2 (output) --
    PB1 (output) --
    PB0 (output) --
 
  PORTC
    PC5 (output) SCL(IIC)
    PC4 (output) SDA(IIC)
    PC3 (output) light sensor
    PC2 (output) sensor 2(TOP)
    PC1 (output) sensor 1(MIDDLE)
    PC0 (output) sensor 0(BOTTOM)
 
  PORTD
    PD7 (output) D7
    PD6 (output) D6
    PD5 (output) D5
    PD4 (output) D4
    PD3 (output) E
    PD2 (output) RS
    PD1 (output) TxD
    PD0 (input)  RxD
*/
#include <MsTimer2.h>
#include <LiquidCrystal.h>
#include <Wire.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 1000
#define XLIMIT    35
#define YLIMIT    170
#define RSIZE     8
#define SYS_ADRS  0x3ff8

#define BSIZE     256

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

/* 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(word xadr,byte xdat);
byte get_eeprom(word xadr);
void update_rtc();

/* variables */
boolean tflag ;
boolean eflag ;
boolean uflag ;
boolean wflag ;
boolean oflag ;
boolean dflag ; /* day or night */
boolean rflag ; /* RTC */
boolean sflag ; /* save flag */

char sbuf[16] ;
byte sindex ;

byte cmd ;
byte xcnt ;
byte scnt ;
int  adv ;
int  tv ;
int  temp[4] ;
byte tempbcd[3] ;
char lineU[17];
char lineL[17];
word rom_address ;
byte xah ;
byte xal ;
char daytime[8];
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(9600);
  sindex = 0 ;
  rs_puts("Hello !");
  crlf();
  /* clear flags */
  tflag = OFF ;
  eflag = OFF ;
  uflag = OFF ;
  wflag = OFF ;
  oflag = ON ;
  dflag = OFF ;
  sflag = OFF ;
  /* initialize port values */
  PORTB = 0x00 ;
  PORTC = 0x00 ;
  PORTD = 0x00 ;
  /* initialize port direction */
  DDRB = 0xff ;
  DDRC = 0x00 ;
  DDRD = 0xfe ;
  /* variables */
  xcnt = 0 ;
  scnt = 0 ;
  clk_year = 19 ; /* 2019 */
  clk_month = 7 ; /* July */
  clk_day   = 1 ; /* 1st  */
  clk_hour  = 0 ; /* 0 hour */
  clk_min   = 0 ; /* 0 minutes */
  clk_sec   = 0 ; /* 0 seconds */
  /* 1000ms period */
  MsTimer2::set(XINTERVAL,update_trigger);
  /* enable */ 
  MsTimer2::start();
  /* 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) = ' ' ;
  }
  *(lineL+16) = '\0';
  *(lineU+ 0) = 'T';
  *(lineU+ 4) = '|';
  *(lineU+ 5) = 'M';
  *(lineU+ 9) = '|';
  *(lineU+10) = 'B';
  *(lineU+14) = '|';
  *(lineU+15) = 'N';
  *(lineU+16) = '\0';
  /* Real Time Clock configration */
  Wire.begin();
  /* others */
  rom_address = 0;
}

void loop()
{
  /* 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(); }
    /* enable */
    if ( cmd == 'G' ) { eflag = ON ; }
    /* disable */
    if ( cmd == 'g' ) { eflag = OFF; }
    /* one shot */
    if ( cmd == 'T' ) { oneShot(); }
    /* 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 */
    for ( int ii = TOP ; ii > -1 ; ii-- ) {
      /* get data */
      adv = analogRead(ii);
      /* convert (voltage) */
      tv = map(adv,0,1023,0,5000); 
      /* convert (temparature) */
      *(temp+ii) = map(tv,300,1600,-30,100);
      /* show ( LCD ) */
      makeLCDString();
      lcd.setCursor(0,0); lcd.print( lineU );
      lcd.setCursor(0,1); lcd.print( lineL );
    }
    /* show ( serial )*/
    if ( eflag == ON ) { oneShot(); }
    /* judge  warning */
    wflag = OFF ;
    if ( *(temp+BOTTOM) > XLIMIT ) { wflag = ON ; }
    if ( *(temp+MIDDLE) > XLIMIT ) { wflag = ON ; }
    if ( *(temp+TOP)    > XLIMIT ) { wflag = ON ; }
    /* convert BCD */
    for ( byte i = 0 ; i < 3 ; i++ ) {
      *(tempbcd + i) = convHEX2BCD( *(temp+i) );
    }
  }
  /* store data to EEPROM every 2 minutes */
  if ( sflag == ON ) {
    sflag = OFF ;
    saveInfo();
  }
}

void update_trigger()
{
  /* set flag */
  rflag = ON ;
  /* judge */
  if ( scnt == 120 ) {
    scnt = 0 ;
    sflag = ON ;
  }
  /* inrement */
  xcnt++ ;
  scnt++ ;
  /* set flag */
  tflag = OFF ;
  if ( xcnt & ON ) { tflag = ON ; }
  /* flashing */
  PORTB &= ~(1 << LED_BIT) ;
  if ( wflag == ON ) {
    if ( xcnt & ON ) { PORTB |= (1 << LED_BIT) ; }
  }
}

void show_help()
{
  rs_puts("? help")           ; crlf();
  rs_puts("G enable")         ; crlf();
  rs_puts("g disable")        ; crlf();
  rs_puts("T 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] ;
  int  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); 
    }
    /* x1 */
    *(lineU+3+j) = tmp % 10 + '0' ;
    /* x10 */
    tmp /= 10 ;
    *(lineU+2+j) = tmp % 10 + '0' ;
  }
  /* day or night */
  *(lineU+15) = '_' ;
  if ( dflag ) { *(lineU+15) = '*' ; }
  /* lower */
  for ( i = 0 ; i < 6 ; i++ ) {
    tmp =  *(xdatx+i) ;
    j = i + i ;
    *(lineL+j+0) = ((tmp >> 4) & 15) + '0' ;
    *(lineL+j+1) = (tmp & 15) + '0' ;
  }
}

void oneShot()
{
  rs_putchar('T'); rs_print( *(temp+TOP)    ); rs_puts(" | ");
  rs_putchar('M'); rs_print( *(temp+MIDDLE) ); rs_puts(" | ");
  rs_putchar('B'); rs_print( *(temp+BOTTOM) ); rs_puts(" | ");
  rs_print( *(temp+LAST) ); 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[8];
  word yadr ;
  byte ii ;
  /* copy */
  *(xtmp+0) = *(xdatx+1);      /* MM */
  *(xtmp+1) = *(xdatx+2);      /* DD */
  *(xtmp+2) = *(xdatx+3);      /* hh */
  *(xtmp+3) = *(xdatx+4);      /* mm */
  *(xtmp+4) = *(tempbcd+2);    /* TOP */
  *(xtmp+5) = *(tempbcd+1);    /* MIDDLE */
  *(xtmp+6) = *(tempbcd+0);    /* BOTTOM */
  *(xtmp+7) = *(temp+3) >> 2 ; /* photo  */
  /* debug */
  rs_putchar('='); crlf();
  /* generate address */
  yadr = rom_address ;
  /* store */
  for ( ii = 0 ; ii < 8 ; 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(word xadr,byte xdat)
{
  byte adh ;
  byte adl ;
  byte xx ;
  boolean bflag ;
  /* copy */
  xx = xdat ;
  /* set block number */
  bflag = OFF ;
  if ( xadr > 0x1fff ) { bflag = ON ; }
  /* separate address */
  adl = xadr & 0xff ;
  adh = (xadr >> 8) & 0x1f ;
  /* 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);
}

byte get_eeprom(word xadr)
{
  byte adh ;
  byte adl ;
  byte result ;
  boolean bflag ;
  /* default */
  result = 0 ;
  /* set block number */
  bflag = OFF ;
  if ( xadr > 0x1fff ) { bflag = ON ; }
  /* separate address */
  adl = xadr & 0xff ;
  adh = (xadr >> 8) & 0x1f ;
  /* impress address */
  if ( bflag ) { Wire.beginTransmission(ROM_ADRS1); }
  else         { Wire.beginTransmission(ROM_ADRS) ; }
  Wire.write(adh); /* upper address */
  Wire.write(adl); /* lower address */
  Wire.endTransmission();
  /* read 1 byte */
  if ( bflag ) { Wire.requestFrom(ROM_ADRS1,1); }
  else         { Wire.requestFrom(ROM_ADRS ,1); }
  if ( Wire.available() ) { result = Wire.read() ; }

  return result ;
}

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


目次

inserted by FC2 system