目次

カラーセンサー情報取得2

 浜松ホトニクスからI2Cバスインタフェースをもつ
 カラーセンサーが発売になっています。



 このカラーセンサーは、3.3Vで動作するので5Vから3.3Vを
 作り出す回路とプルアップ抵抗を入れる基板を半田付け
 しました。3.3Vがあれば、キャパシタとプルアップ抵抗を
 いれるだけですが。



 電圧変換回路には、白色LEDをZennerダイオードの代わりに
 使っています。

 3.3Vを生成できなかったので、シリコンダイオードを入れて
 3.2Vまで電圧を引き上げました。



 1チャネルのI2Cバスは、ArduinoのアナログポートA5、A4に
 なっています。A5(SCL)、A4(SDA)を使う場合、ライブラリ
 のWireを利用します。

 ピンアサインは、以下。



 Arduino、中継基板、カラーセンサーを接続すると
 つぎのようになります。




 3.3Vを出力しているArduinoの場合、そのまま
 その電圧を利用した方がよいでしょう。

 1チャネルのカラーセンサー情報取得スケッチは、以下。

#include <MsTimer2.h>
#include "Wire.h"

#define OFF 0
#define ON  OFF+1

#define LED_BIT 5

#define DEVICE_ID    0x2A
#define CONTROL_REG  0x00

#define NPER 1500

/* event flag */
boolean eflag ;
boolean tflag ;
boolean uflag ;

/* timing counter */
byte xcnt ;

/* serial interface */
byte cmd ;
byte sindex ;
char sbuf[4] ;

/* RGB and IR */
word xrgbi[4] ;

/* LED flashing */
void  send_led(byte x)
{
  if ( x ) { PORTB |=  (1 << LED_BIT) ; }
  else     { PORTB &= ~(1 << LED_BIT) ; }
}

/* generate trigger */
void  update_trigger(void)
{
  /* LED flashing */
  send_led( xcnt & ON );
  /* trigger */
  xcnt++ ;
  if ( xcnt & ON ) { tflag = ON ; }
}

/* putchar on serial interface */
void  rs_putchar(char x)
{
  Serial.write(x);
}

/* puts on serial interface */
void  rs_puts(char *x)
{
  while ( *x ) {
    rs_putchar( *x ) ;
    x++ ;
  }
}

/* new line */
void  crlf()
{
  rs_putchar('\r');
  rs_putchar('\n');
}

void  show_help()
{
  rs_puts("? help")    ; crlf();
  rs_puts("E execute") ; crlf();
  rs_puts("I idle")    ; crlf();
}

void show_value(word x)
{
  word tmp ;
  char msg[6] ;
  byte i ;
  /* copy */
  tmp = x ;
  /* delimiter */
  *(msg+5) = '\0' ;
  /* separate */
  for ( i = 0 ; i < 5 ; i++ ) {
    /* value -> digit number */
    *(msg+4-i) = (tmp % 10)+ '0' ;
    /* next */
    tmp /= 10 ;
  }
  /* zero surppress */
  if ( x < 10000 ) {
    *(msg+0) = ' ' ;
    if ( x < 1000 ) {
      *(msg+1) = ' ' ;
      if ( x < 100 ) {
        *(msg+2) = ' ' ;
        if ( x < 10 ) {
          *(msg+3) = ' ' ;
        }
      }
    }
  }
  /* show */
  rs_puts( msg ) ;
  rs_putchar(' ') ;
}

void get_color()
{
  byte i ;
  word tmp ;
  /*
    preset gain mode exposure time (each color ch)
      00 = 87.5us
      01= 1.4ms
      10= 22.4ms
      11= 179.2ms
  */
  Wire.beginTransmission(DEVICE_ID);
  Wire.write(CONTROL_REG);
  Wire.write(0x83);                 /* reset ADC and wakeup */
  Wire.endTransmission(OFF);
  Wire.beginTransmission(DEVICE_ID);
  Wire.write(CONTROL_REG);
  Wire.write(0x03);
  Wire.endTransmission(ON);
  /* total exposure time */
  delay(180*4); 
  /* get each color value */
  Wire.beginTransmission(DEVICE_ID);
  Wire.write(0x03);
  Wire.endTransmission(OFF);
  Wire.requestFrom(DEVICE_ID,8,ON);
  /* 8 x 2 x 4 */
  for ( i = 0 ; i < 4 ; i++ ) {
    /* upper value */
    tmp = Wire.read();
    /* shift */
    tmp <<= 8;
    /* add lower value */
    tmp |= Wire.read();
    /* store */
    *(xrgbi+i) = tmp ;
  }
}

void setup()
{
  /* initialize serial port */
  Serial.begin(9600);
  sindex = 0 ;
  /* set initial state */
  PORTB = 0x00 ;
  PORTC = 0x00 ;
  PORTD = 0x01 ;
  /* direction */
  DDRB = 0xff ;
  DDRC = 0xff ;
  DDRD = 0xfe ;
  /* clear flags */
  tflag = OFF ;
  eflag = OFF ;
  uflag = OFF ;
  /* initialize variables */
  xcnt = 0 ;
  *(xrgbi+0) = 0 ; *(xrgbi+1) = 0 ;
  *(xrgbi+2) = 0 ; *(xrgbi+3) = 0 ;
  /* trigger period */
  MsTimer2::set(NPER,update_trigger);
  /* enable */ 
  MsTimer2::start();
  /* enable I2C bus interface */
  Wire.begin();
}

void loop()
{
  /* serial handling */
  if ( uflag == ON ) {
    /* clear flag */
    uflag = OFF ;
    /* new line */
    crlf();
    /* get command */
    cmd = *(sbuf+0) ;
    /* help */
    if ( cmd == '?' ) { show_help() ; }
    /* enable */
    if ( cmd == 'E' ) { eflag = ON ; }
    /* disable */
    if ( cmd == 'I' ) { eflag = OFF ; }
  }
  /* timer handling */
  if ( tflag == ON ) {
    /* clear flag */
    tflag = OFF ;
    /* get color values */
    get_color();
    /* show */
    if ( eflag == ON ) {
      rs_puts("R : ") ; show_value( *(xrgbi+0) );
      rs_puts("G : ") ; show_value( *(xrgbi+1) );
      rs_puts("B : ") ; show_value( *(xrgbi+2) );
      rs_puts("IR: ") ; show_value( *(xrgbi+3) );
      crlf();
    }
  }
}

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

 端末ソフトTeraTermを利用し、カラーセンサーの取得情報を表示させます。



 利用しているカラーセンサーは、感度、露光時間を変更できるので
 新たにコマンドを用意して設定変更できるようにしました。
 新設コマンドは、以下。

 ステータスに関しては、次のように1文字か数字で表現し
 1行に4文字で表示。

 スケッチのコードは、以下。

#include <MsTimer2.h>
#include <EEPROM.h>
#include "Wire.h"

#define OFF 0
#define ON  OFF+1

#define LED_BIT 5

#define DEVICE_ID    0x2A
#define CONTROL_REG  0x00

#define NPER 800

#define SCODE_ADR 0x100
#define SHOW_ADR  0x101
  
/* event flag */
boolean eflag ;
boolean tflag ;
boolean uflag ;

/* state flag */
boolean gflag ; /* select only green information */
boolean mflag ; /* mask flag */

/* timing counter */
byte xcnt 

/* serial interface */
byte cmd ;
byte sindex ;
char sbuf[4] ;

/* RGB and IR */
word xrgbi[4] ;

/* sensor command */
byte scmd ;

/* LED flashing */
void  send_led(byte x)
{
  if ( x ) { PORTB |=  (1 << LED_BIT) ; }
  else     { PORTB &= ~(1 << LED_BIT) ; }
}

/* generate trigger */
void  update_trigger(void)
{
  /* LED flashing */
  send_led( xcnt & ON );
  /* trigger */
  xcnt++ ;
  if ( xcnt & ON ) { tflag = ON ; }
}

/* putchar on serial interface */
void  rs_putchar(char x)
{
  Serial.write(x);
}

/* puts on serial interface */
void  rs_puts(char *x)
{
  while ( *x ) {
    rs_putchar( *x ) ;
    x++ ;
  }
}

/* new line */
void  crlf()
{
  rs_putchar('\r');
  rs_putchar('\n');
}

void  show_help()
{
  rs_puts("? help")                                  ; crlf();
  rs_puts("E execute")                               ; crlf();
  rs_puts("I idle")                                  ; crlf();
  rs_puts("S set sensibility 1:high 0:low")          ; crlf();
  rs_puts("L set exposure time Length(0/1/2/3)")     ; crlf();
  rs_puts("G set only Green information 1:YES 0:NO") ; crlf();
  rs_puts("M set mask 1:YES 0:NO")                   ; crlf();
  rs_puts("s show staus")                            ; crlf();
}

void show_value(word x)
{
  word tmp ;
  char msg[6] ;
  byte i ;
  /* copy */
  tmp = x ;
  /* delimiter */
  *(msg+5) = '\0' ;
  /* separate */
  for ( i = 0 ; i < 5 ; i++ ) {
    /* value -> digit number */
    *(msg+4-i) = (tmp % 10)+ '0' ;
    /* next */
    tmp /= 10 ;
  }
  /* zero surppress */
  if ( x < 10000 ) {
    *(msg+0) = ' ' ;
    if ( x < 1000 ) {
      *(msg+1) = ' ' ;
      if ( x < 100 ) {
        *(msg+2) = ' ' ;
        if ( x < 10 ) {
          *(msg+3) = ' ' ;
        }
      }
    }
  }
  /* show */
  rs_puts( msg ) ;
  rs_putchar(' ');
}

void get_color()
{
  byte i ;
  word tmp ;
  /*
    preset gain mode exposure time (each color ch)
      00 =  87.5us => 0.9ms
      01 =   1.4ms => 2.0ms
      10 =  22.4ms => 23ms
      11 = 179.2ms => 180ms
  */
  i = scmd & 3 ;
  if ( i == 3 ) { tmp = 180 * 4; }
  if ( i == 2 ) { tmp =  23 * 4; }
  if ( i < 2 )  { tmp =   2 * 4; } 
  Wire.beginTransmission(DEVICE_ID);
  Wire.write(CONTROL_REG);
  Wire.write(0x83);                 /* reset ADC and wakeup */
  Wire.endTransmission(OFF);
  Wire.beginTransmission(DEVICE_ID);
  Wire.write(CONTROL_REG);
  /* set High or Low and exposure length */
  Wire.write( scmd );
  Wire.endTransmission(ON);
  /* total exposure time */
  delay(tmp); 
  /* get each color value */
  Wire.beginTransmission(DEVICE_ID);
  Wire.write(0x03);
  Wire.endTransmission(OFF);
  Wire.requestFrom(DEVICE_ID,8,ON);
  /* 8 x 2 x 4 */
  for ( i = 0 ; i < 4 ; i++ ) {
    /* upper value */
    tmp = Wire.read();
    /* shift */
    tmp <<= 8;
    /* add lower value */
    tmp |= Wire.read();
    /* store */
    *(xrgbi+i) = tmp ;
  }
}

void show_yn()
{
  char msg[2];
  /* delimiter */
  *(msg+1) = '\0' ;
  /* sensibility */
  {
    *(msg+0) = 'L' ;
    if ( scmd & 8 ) { *(msg+0) = 'H' ; }
    rs_puts( msg );
  }
  /* exposure length */
  {
    rs_putchar( '0'+(scmd & 3) );
  }
  /* Green */
  {
    *(msg+0) = 'N' ;
    if ( gflag == ON ) { *(msg+0) = 'Y' ; }
    rs_puts( msg );
  }
  /* Mask */
  {
    *(msg+0) = 'N' ;
    if ( mflag == ON ) { *(msg+0) = 'Y' ; }
    rs_puts( msg );
  }
  /* new line */
  crlf();
}

void store_param(byte which,byte x)
{
  word madr ;
  /* sensibility or exposure length */
  if ( which < 2 ) { madr = SCODE_ADR ; }
  /* Green information */
  if ( which == 2 ) { madr = SHOW_ADR ; }
  /* store */
  EEPROM.write(madr,x);
}

void show_color(boolean x)
{
  /* only Green information */
  if ( x ) {
    rs_puts("G :") ; show_value( *(xrgbi+1) );
  } 
  else
  /* all color informations */
  {
    rs_puts("R :") ; show_value( *(xrgbi+0) );
    rs_puts("G :") ; show_value( *(xrgbi+1) );
    rs_puts("B :") ; show_value( *(xrgbi+2) );
    rs_puts("IR:") ; show_value( *(xrgbi+3) );
  }
  crlf();
}

void setup()
{
  /* initialize serial port */
  Serial.begin(9600);
  sindex = 0 ;
  /* set initial state */
  PORTB = 0x00 ;
  PORTC = 0x00 ;
  PORTD = 0x01 ;
  /* direction */
  DDRB = 0xff ;
  DDRC = 0xff ;
  DDRD = 0xfe ;
  /* clear flags */
  tflag = OFF ;
  eflag = OFF ;
  uflag = OFF ;
  gflag = OFF ;
  /* resume previous state */
  xcnt = EEPROM.read(SCODE_ADR);
  if ( xcnt == 0xff ) {
    scmd = 11 ;
    EEPROM.write(SCODE_ADR,scmd);
  } else {
    scmd = xcnt ;
  }
  xcnt = EEPROM.read(SHOW_ADR);
  if ( xcnt != OFF ) { gflag = ON ; } 
  /* initialize variables */
  for ( xcnt = 0 ; xcnt < 4 ; xcnt++ ) {
    *(xrgbi+xcnt) = 0 ;
  }
  xcnt = 0 ;
  /* trigger period */
  MsTimer2::set(NPER,update_trigger);
  /* enable */ 
  MsTimer2::start(); 
  /* enable I2C bus interface */
  Wire.begin();
}

void loop()
{
  /* serial handling */
  if ( uflag == ON ) {
    /* clear flag */
    uflag = OFF ;
    /* new line */
    crlf();
    /* get command */
    cmd = *(sbuf+0) ;
    /* help */
    if ( cmd == '?' ) { show_help() ; }
    /* enable */
    if ( cmd == 'E' ) { eflag = ON ; }
    /* disable */
    if ( cmd == 'I' ) { eflag = OFF ; }
    /* write sensibility state */
    if ( cmd == 'S' ) {
      /* set default (selct LOW) */
      scmd &= 0xf7 ;
      /* set flag (HIGH or LOW) */
      if ( *(sbuf+1) == '1' ) { scmd |= (1 << 3) ; }
      /* store EEPROM */
      store_param(0,scmd);
    }
    /* write exposure length */
    if ( cmd == 'L' ) {
      /* clear */
      scmd &= 0xfc ;
      /* generate code */
      scmd |= ((*(sbuf+1) - '0') & 3);
      /* store EEPROM */
      store_param(1,scmd);
    }
    /* write only Green information */
    if ( cmd == 'G' ) {
      /* default */
      gflag = OFF ;
      /* judge */
      if ( *(sbuf+1) == '1' ) { gflag = ON ; }
      /* store */
      store_param(2,gflag);
    }
    /* write mask */
    if ( cmd == 'M' ) {
      /* default */
      mflag = OFF ;
      /* judge */
      if ( *(sbuf+1) == '1' ) { mflag = ON ; }
    }
    /* show status */
    if ( cmd == 's' ) { show_yn(); }
  }
  /* timer handling */
  if ( tflag == ON ) {
    /* clear flag */
    tflag = OFF ;
    /* get color values */
    get_color();
    /* show */
    if ( eflag == ON ) { show_color(gflag) ; }
  }
}

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

 一度指定したパラメータは、EEPROMに格納するので
 電源を切って再度入れても、前回の指定した環境で
 使えるようになっています。

 Arduinoに接続して、?でコマンドを確認。



 sコマンドで動作環境を確認、Gコマンドで全色情報か
 緑色情報のみの表示かを変更できることを確認。



 端末ソフトでは、タイプする量が多いので
 Processingのスケッチで操作が簡単になる
 ようにします。

 テストするためのProcessingのスケッチを作成しました。

import processing.serial.*;

Serial cport;
PImage imgExecute ;
PImage imgIdle    ;
PImage imgExit    ;
PImage imgStatus  ;

int FRATE = 60 ;

int WX = 640 ;
int WY = 480 ; 

int XBEGIN = 100 ;
int YBEGIN = 100 ;
int WIDTH  = 150 ;
int HEIGHT = 150 ;

String stmp ;

boolean isRangeOk(int x,int bx,int ex)
{
  boolean result ;
  /* default */
  result = false ;
  /* judge */
  if ( bx <= x && x <= ex ) { result = true ; }

  return result ;
}       

void setup()
{
  size(640,480);
  /* title caption */
  frame.setTitle("Test 03");
  /* select framerate */
  frameRate(FRATE);
  /* select back ground color with BLACK */
  background(0,0,0);
  //println(Serial.list());
  String arduinoPort = Serial.list()[4];
  /* initialize serial port */
  cport = new Serial(this,arduinoPort,9600);
  //sidx = 0 ;
  scflag = false ;
  /* get image */
  imgExecute = loadImage("execute.png");
  imgIdle    = loadImage("idle.png");
  imgStatus  = loadImage("status.png");
  imgExit    = loadImage("exit.png");
  /* */
  stmp = "" ;
}

void draw()
{
  /* button */
  image(imgExecute, 20,402);
  image(imgIdle   ,120,402);
  image(imgStatus ,240,402);
  image(imgExit   ,360,402);
  /* serial receive */
  if ( cport.available() > 4 ) {
    background(0,0,0);
    fill(255,0,0);
    stmp = cport.readStringUntil('\n');
    stmp = trim(stmp);
    textSize(20);
    text(stmp, 100, 100);
  } 
}

void mouseClicked()
{
  if ( mouseButton == LEFT ) {
    /* execute */
    if ( isRangeOk(mouseX,20,70) &&
         isRangeOk(mouseY,402,422)    ) {
      /* debug */
      println("execute");
      /* send command */
      cport.write('E'); 
      cport.write('\r');
    }
    /* idle */
    if ( isRangeOk(mouseX,120,170) &&
         isRangeOk(mouseY,402,422)    ) {
      /* debug */
      println("idle");
      /* send command */
      cport.write('I'); 
      cport.write('\r');
    }
    /* status */
    if ( isRangeOk(mouseX,240,290) &&
         isRangeOk(mouseY,402,422)    ) {
      /* debug */
      println("Status");
      /* send command */
      cport.write('S'); 
      cport.write('\r');
    }
    /* exit */
    if ( isRangeOk(mouseX,360,390) &&
         isRangeOk(mouseY,402,422)    ) {
      /* debug */
      println("exit");
      exit();
    }
  } 
  /* Exit */
  if ( mouseButton == RIGHT ) {
    exit();
  } 
}

 画面は、次のようになります。



 ボタンexecute、idle、status、EXITをクリックすると
 指定された動作を実行します。

 ボタンexecuteの機能

  シリアルポートから、Arduinoにコマンド'E'を送信します。

  Arduinoは、基板上のLEDを点滅させます。
  点滅停止のコマンドを送信しない限り、点滅を継続します。

 ボタンidleの機能

  シリアルポートから、Arduinoにコマンド'I'を送信します。

  Arduinoは、基板上のLED点滅を終了します。

 ボタンstatusの機能

  シリアルポートから、Arduinoにコマンド'S'を送信します。

  Arduinoは、その時点の状態を文字列runかidleで
  返してきます。

  Processingでは、Arduinoが返してくる文字列を
  取得し表示します。

  ボタンexecuteクリック後の画面。



  ボタンidleクリック後の画面。



  Arduinoのように、受信割込みを使わないで
  drawの中で、受信バッファに文字列があるか
  を確認後、取り出して表示します。

  if ( cport.available() > 0) {
    background(0,0,0);
    fill(255,0,0);
    stmp = cport.readStringUntil('\n');
    stmp = trim(stmp);
    textSize(20);
    text(stmp, 100, 100);
  }

 ボタンEXITの機能

  Processingのスケッチを終了します。

 Arduinoのスケッチは、以下。

#include <MsTimer2.h>

#define OFF 0
#define ON  OFF+1

#define LED_BIT 5

#define NPER 500

/* event flag */
boolean eflag ;
boolean tflag ;
boolean uflag ;

/* serial interface */
byte cmd ;
byte sindex ;
char sbuf[4] ;
byte xcnt ;
char msg[5] ;

/* LED flashing */
void  send_led(byte x)
{
  if ( x ) { PORTB |=  (1 << LED_BIT) ; }
  else     { PORTB &= ~(1 << LED_BIT) ; }
}

/* generate trigger */
void  update_trigger(void)
{
  tflag = ON ;
}

/* putchar on serial interface */
void  rs_putchar(char x)
{
  Serial.write(x);
}

/* puts on serial interface */
void  rs_puts(char *x)
{
  while ( *x ) {
    rs_putchar( *x ) ;
    x++ ;
  }
}

/* new line */
void  crlf()
{
  rs_putchar('\r');
  rs_putchar('\n');
}

void  show_help()
{
  rs_puts("? help")    ; crlf();
  rs_puts("E execute") ; crlf();
  rs_puts("I idle")    ; crlf();
  rs_puts("S status")  ; crlf();
}

void setup()
{
  /* initialize serial port */
  Serial.begin(9600);
  sindex = 0 ;
  /* set initial state */
  PORTB = 0x00 ;
  PORTC = 0x08 ;
  PORTD = 0x01 ;
  /* direction */
  DDRB = 0xff ;
  DDRC = 0xff ;
  DDRD = 0xfe ;
  /* clear flags */
  tflag = OFF ;
  eflag = OFF ;
  uflag = OFF ;
  /* */
  xcnt = 0 ;
  /* trigger period */
  MsTimer2::set(NPER,update_trigger);
  /* enable */ 
  MsTimer2::start(); 
}

void loop()
{
  /* serial handling */
  if ( uflag == ON ) {
    /* clear flag */
    uflag = OFF ;
    /* get command */
    cmd = *(sbuf+0) ;
    /* help */
    if ( cmd == '?' ) { show_help() ; }
    /* enable */
    if ( cmd == 'E' ) { eflag = ON ; }
    /* disable */
    if ( cmd == 'I' ) { eflag = OFF ; }
    /* show status */
    if ( cmd == 'S' ) {
      /* default */
      strcpy(msg,"idle");
      /* check */
      if ( eflag == ON ) { strcpy(msg,"run "); }
      /* show message */
      rs_puts( msg );
      crlf();
    }
  }
  /* timer handling */
  if ( tflag == ON ) {
    /* clear flag */
    tflag = OFF ;
    /* default */
    send_led( OFF );
    /* judge */
    if ( eflag == ON ) {
      if ( xcnt & ON ) { send_led( ON ); }
    }
    /* update */
    xcnt++ ;
  }
}

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

 ProcessingとArduino間で、情報交換できるようになったので
 ProcessingスケッチをRGBおよび輝度の数値と比率をバーで
 表示できるようにします。

 受信バッファに入れられている情報を活用するには
 次の内容を処理します。

 必要な情報を取得できるように、Arduinoスケッチに
 コマンド'C'を用意します。

 コマンド'C'を送信すると、その時点のカラーセンサー
 の情報を取得してProcessingスケッチに返します。

 この機能をいれたArduinoスケッチは、以下。

#include <MsTimer2.h>
#include <EEPROM.h>
#include "Wire.h"

#define OFF 0
#define ON  OFF+1

#define LED_BIT 5

#define DEVICE_ID    0x2A
#define CONTROL_REG  0x00

#define NPER 800

#define SCODE_ADR 0x100
#define SHOW_ADR  0x101
  
/* event flag */
boolean eflag ;
boolean tflag ;
boolean uflag ;

/* state flag */
boolean gflag ; /* select only green information */
boolean mflag ; /* mask flag */

/* timing counter */
byte xcnt ;

/* serial interface */
byte cmd ;
byte sindex ;
char sbuf[4] ;

/* RGB and IR */
word xrgbi[4] ;

/* sensor command */
byte scmd ;

/* LED flashing */
void  send_led(byte x)
{
  if ( x ) { PORTB |=  (1 << LED_BIT) ; }
  else     { PORTB &= ~(1 << LED_BIT) ; }
}

/* generate trigger */
void  update_trigger(void)
{
  /* LED flashing */
  send_led( xcnt & ON );
  /* trigger */
  xcnt++ ;
  if ( xcnt & ON ) { tflag = ON ; }
}

/* putchar on serial interface */
void  rs_putchar(char x)
{
  Serial.write(x);
}

/* puts on serial interface */
void  rs_puts(char *x)
{
  while ( *x ) {
    rs_putchar( *x ) ;
    x++ ;
  }
}

/* new line */
void  crlf()
{
  rs_putchar('\r');
  rs_putchar('\n');
}

void  show_help()
{
  rs_puts("? help")                                  ; crlf();
  rs_puts("E execute")                               ; crlf();
  rs_puts("I idle")                                  ; crlf();
  rs_puts("C one shot")                              ; crlf();
  rs_puts("S set sensibility 1:high 0:low")          ; crlf();
  rs_puts("L set exposure time Length(0/1/2/3)")     ; crlf();
  rs_puts("G set only Green information 1:YES 0:NO") ; crlf();
  rs_puts("M set mask 1:YES 0:NO")                   ; crlf();
  rs_puts("s show staus")                            ; crlf();
}

void show_value(word x)
{
  word tmp ;
  char msg[6] ;
  byte i ;
  /* copy */
  tmp = x ;
  /* delimiter */
  *(msg+5) = '\0' ;
  /* separate */
  for ( i = 0 ; i < 5 ; i++ ) {
    /* value -> digit number */
    *(msg+4-i) = (tmp % 10)+ '0' ;
    /* next */
    tmp /= 10 ;
  }
  /* zero surppress */
  if ( x < 10000 ) {
    *(msg+0) = ' ' ;
    if ( x < 1000 ) {
      *(msg+1) = ' ' ;
      if ( x < 100 ) {
        *(msg+2) = ' ' ;
        if ( x < 10 ) {
          *(msg+3) = ' ' ;
        }
      }
    }
  }
  /* show */
  rs_puts( msg ) ;
  rs_putchar(' ');
}

void get_color()
{
  byte i ;
  word tmp ;
  /*
    preset gain mode exposure time (each color ch)
      00 =  87.5us => 0.9ms
      01 =   1.4ms => 2.0ms
      10 =  22.4ms => 23ms
      11 = 179.2ms => 180ms
  */
  i = scmd & 3 ;
  if ( i == 3 ) { tmp = 180 * 4; }
  if ( i == 2 ) { tmp =  23 * 4; }
  if ( i < 2 )  { tmp =   2 * 4; } 
  Wire.beginTransmission(DEVICE_ID);
  Wire.write(CONTROL_REG);
  Wire.write(0x83);                 /* reset ADC and wakeup */
  Wire.endTransmission(OFF);
  Wire.beginTransmission(DEVICE_ID);
  Wire.write(CONTROL_REG);
  /* set High or Low and exposure length */
  Wire.write( scmd );
  Wire.endTransmission(ON);
  /* total exposure time */
  delay(tmp); 
  /* get each color value */
  Wire.beginTransmission(DEVICE_ID);
  Wire.write(0x03);
  Wire.endTransmission(OFF);
  Wire.requestFrom(DEVICE_ID,8,ON);
  /* 8 x 2 x 4 */
  for ( i = 0 ; i < 4 ; i++ ) {
    /* upper value */
    tmp = Wire.read();
    /* shift */
    tmp <<= 8;
    /* add lower value */
    tmp |= Wire.read();
    /* store */
    *(xrgbi+i) = tmp ;
  }
}

void show_yn()
{
  char msg[2];
  /* delimiter */
  *(msg+1) = '\0' ;
  /* sensibility */
  {
    *(msg+0) = 'L' ;
    if ( scmd & 8 ) { *(msg+0) = 'H' ; }
    rs_puts( msg );
  }
  /* exposure length */
  {
    rs_putchar( '0'+(scmd & 3) );
  }
  /* Green */
  {
    *(msg+0) = 'N' ;
    if ( gflag == ON ) { *(msg+0) = 'Y' ; }
    rs_puts( msg );
  }
  /* Mask */
  {
    *(msg+0) = 'N' ;
    if ( mflag == ON ) { *(msg+0) = 'Y' ; }
    rs_puts( msg );
  }
  /* new line */
  crlf();
}

void store_param(byte which,byte x)
{
  word madr ;
  /* sensibility or exposure length */
  if ( which < 2 ) { madr = SCODE_ADR ; }
  /* Green information */
  if ( which == 2 ) { madr = SHOW_ADR ; }
  /* store */
  EEPROM.write(madr,x);
}

void show_color(boolean x)
{
  /* only Green information */
  if ( x ) {
    rs_puts("G :") ; show_value( *(xrgbi+1) );
  } 
  else
  /* all color informations */
  {
    rs_puts("R :") ; show_value( *(xrgbi+0) );
    rs_puts("G :") ; show_value( *(xrgbi+1) );
    rs_puts("B :") ; show_value( *(xrgbi+2) );
    rs_puts("IR:") ; show_value( *(xrgbi+3) );
  }
  crlf();
}

void setup()
{
  /* initialize serial port */
  Serial.begin(9600);
  sindex = 0 ;
  /* set initial state */
  PORTB = 0x00 ;
  PORTC = 0x00 ;
  PORTD = 0x01 ;
  /* direction */
  DDRB = 0xff ;
  DDRC = 0xff ;
  DDRD = 0xfe ;
  /* clear flags */
  tflag = OFF ;
  eflag = OFF ;
  uflag = OFF ;
  gflag = OFF ;
  /* resume previous state */
  xcnt = EEPROM.read(SCODE_ADR);
  if ( xcnt == 0xff ) {
    scmd = 11 ;
    EEPROM.write(SCODE_ADR,scmd);
  } else {
    scmd = xcnt ;
  }
  xcnt = EEPROM.read(SHOW_ADR);
  if ( xcnt != OFF ) { gflag = ON ; } 
  /* initialize variables */
  for ( xcnt = 0 ; xcnt < 4 ; xcnt++ ) {
    *(xrgbi+xcnt) = 0 ;
  }
  xcnt = 0 ;
  /* trigger period */
  MsTimer2::set(NPER,update_trigger);
  /* enable */ 
  MsTimer2::start(); 
  /* enable I2C bus interface */
  Wire.begin();
}

void loop()
{
  /* serial handling */
  if ( uflag == ON ) {
    /* clear flag */
    uflag = OFF ;
    /* new line */
    crlf();
    /* get command */
    cmd = *(sbuf+0) ;
    /* help */
    if ( cmd == '?' ) { show_help() ; }
    /* enable */
    if ( cmd == 'E' ) { eflag = ON ; }
    /* disable */
    if ( cmd == 'I' ) { eflag = OFF ; }
    /* one shot */
    if ( cmd == 'C' ) {
      /* get color values */
      get_color();
      /* show */
      show_color(gflag);
    }
    /* write sensibility state */
    if ( cmd == 'S' ) {
      /* set default (selct LOW) */
      scmd &= 0xf7 ;
      /* set flag (HIGH or LOW) */
      if ( *(sbuf+1) == '1' ) { scmd |= (1 << 3) ; }
      /* store EEPROM */
      store_param(0,scmd);
    }
    /* write exposure length */
    if ( cmd == 'L' ) {
      /* clear */
      scmd &= 0xfc ;
      /* generate code */
      scmd |= ((*(sbuf+1) - '0') & 3);
      /* store EEPROM */
      store_param(1,scmd);
    }
    /* write only Green information */
    if ( cmd == 'G' ) {
      /* default */
      gflag = OFF ;
      /* judge */
      if ( *(sbuf+1) == '1' ) { gflag = ON ; }
      /* store */
      store_param(2,gflag);
    }
    /* write mask */
    if ( cmd == 'M' ) {
      /* default */
      mflag = OFF ;
      /* judge */
      if ( *(sbuf+1) == '1' ) { mflag = ON ; }
    }
    /* show status */
    if ( cmd == 's' ) { show_yn(); }
  }
  /* timer handling */
  if ( tflag == ON ) {
    /* clear flag */
    tflag = OFF ;
    /* get color values */
    get_color();
    /* show */
    if ( eflag == ON ) { show_color(gflag) ; }
  }
}

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

 Processingで情報の表示は、次のようにします。



 ArduinoからRGBと輝度の情報は、5桁の数字で送信されます。
 R、G、B、IRの文字列を探し出して、RGBの数字に分解すれば
 バー表示に必要な数値に変換できそうです。

 この処理には、Stringからcharに変換して対応しました。

    stmp = trim(cport.readStringUntil('\n'));
    char[] ss = stmp.toCharArray();
    textSize(20);
    text(stmp,20,40);
    loop = rx = gx = bx = ix = 0 ;
    for (char ch : ss) {
      /* check entry */
      if ( ch == ':' ) { loop++ ; }
      /* calculate */
      if ( isAcode(ch) == true ) {
        if ( loop == 1 ) { rx = rx * 10 + (ch-'0') ; }
        if ( loop == 2 ) { gx = gx * 10 + (ch-'0') ; }
        if ( loop == 3 ) { bx = bx * 10 + (ch-'0') ; }
        if ( loop == 4 ) { ix = ix * 10 + (ch-'0') ; }
      }
    }

 もう少しうまい方法がありそうですが、確実に動くことが優先です。

 RGBと輝度の値がわかれば、画面表示とバー表示の関数を作成します。

void show_values(int x,int y,int z,int u)
{
  int sx = 20 ;
  int sy = 120 ;
  int offset = 30 ;
  /* select size */
  textSize(15) ;
  /* write */
  text("R :"+nf(x,5),sx,sy+offset*0);
  text("G :"+nf(y,5),sx,sy+offset*1);
  text("B :"+nf(z,5),sx,sy+offset*2);
  text("IR:"+nf(u,5),sx,sy+offset*3);
}

void show_bars(int x,int y,int z,int u)
{
  int rgbi = max(max(x,y),max(z,u));
  int rate_r ;
  int rate_g ;
  int rate_b ;
  int rate_i ;
  int sx = 100 ;
  int sy = 110 ;
  int offset = 26 ;
  /* calculate ratio */
  rate_r = (int)( (x * 100.0) / rgbi ) ;
  rate_g = (int)( (y * 100.0) / rgbi ) ;
  rate_b = (int)( (z * 100.0) / rgbi ) ;
  rate_i = (int)( (u * 100.0) / rgbi ) ;
  /* show bar */
  fill(255,  0,  0); rect(sx,sy+offset*0,rate_r,20);
  fill(  0,255,  0); rect(sx,sy+offset*1,rate_g,20);
  fill(  0,  0,255); rect(sx,sy+offset*2,rate_b,20);
  fill(255,255,255); rect(sx,sy+offset*3,rate_i,20);
}

 まとめると、次のようになります。

import processing.serial.*;

Serial cport;
PImage imgGet     ;
PImage imgExecute ;
PImage imgIdle    ;
PImage imgExit    ;

int FRATE = 25 ;

String stmp ;

boolean scflag ;

int loop ;
int rx ;
int gx ;
int bx ;
int ix ;

boolean isRangeOk(int x,int bx,int ex)
{
  boolean result ;
  /* default */
  result = false ;
  /* judge */
  if ( bx <= x && x <= ex ) { result = true ; }

  return result ;
}

boolean isAcode(char x)
{
  boolean result ;
  /* default */
  result = false ;
  /* judge */
  if ( x != 'R' && x != 'G' && x != 'B' && 
       x != ':' && x != 'I' && x != ' '    ) {
    result = true ;
  }

  return result ;
}

void show_values(int x,int y,int z,int u)
{
  int sx = 20 ;
  int sy = 120 ;
  int offset = 30 ;
  /* select size */
  textSize(15) ;
  /* write */
  text("R :"+nf(x,5),sx,sy+offset*0);
  text("G :"+nf(y,5),sx,sy+offset*1);
  text("B :"+nf(z,5),sx,sy+offset*2);
  text("IR:"+nf(u,5),sx,sy+offset*3);
}

void show_bars(int x,int y,int z,int u)
{
  int rgbi = max(max(x,y),max(z,u)) ;
  int rate_r ;
  int rate_g ;
  int rate_b ;
  int rate_i ;
  int sx = 100 ;
  int sy = 110 ;
  int offset = 26 ;
  /* calculate ratio */
  rate_r = (int)( (x * 100.0) / rgbi ) ;
  rate_g = (int)( (y * 100.0) / rgbi ) ;
  rate_b = (int)( (z * 100.0) / rgbi ) ;
  rate_i = (int)( (u * 100.0) / rgbi ) ;
  /* show bar */
  fill(255,  0,  0); rect(sx,sy+offset*0,rate_r,20);
  fill(  0,255,  0); rect(sx,sy+offset*1,rate_g,20);
  fill(  0,  0,255); rect(sx,sy+offset*2,rate_b,20);
  fill(255,255,255); rect(sx,sy+offset*3,rate_i,20);
}

void setup()
{
  size(440,340);
  /* title caption */
  surface.setTitle("Test 04");
  /* select framerate */
  frameRate(FRATE);
  /* select back ground color with BLACK */
  background(0,0,0);
  // シリアルポートのリスト取得
  // println(Serial.list());
  String arduinoPort = Serial.list()[4];
  /* initialize serial port */
  cport = new Serial(this,arduinoPort,9600);
  cport.clear();
  cport.bufferUntil('\n');
  scflag = false ;
  /* get image */
  imgGet     = loadImage("get.png");
  imgExecute = loadImage("execute.png");
  imgIdle    = loadImage("idle.png");
  imgExit    = loadImage("exit.png");
}

void draw()
{
  /* button */
  image(imgGet    , 20,300);
  image(imgExecute, 80,300);
  image(imgIdle   ,140,300);
  image(imgExit   ,220,300);
  /* serial receive */
  if ( scflag == true ) {
    scflag = false ;
    background(0,0,0);
    fill(255,255,255);
    stmp = trim(cport.readStringUntil('\n'));
    char[] ss = stmp.toCharArray();
    textSize(20);
    text(stmp,20,40);
    loop = rx = gx = bx = ix = 0 ;
    for (char ch : ss) {
      /* check entry */
      if ( ch == ':' ) { loop++ ; }
      /* calculate */
      if ( isAcode(ch) == true ) {
        if ( loop == 1 ) { rx = rx * 10 + (ch-'0') ; }
        if ( loop == 2 ) { gx = gx * 10 + (ch-'0') ; }
        if ( loop == 3 ) { bx = bx * 10 + (ch-'0') ; }
        if ( loop == 4 ) { ix = ix * 10 + (ch-'0') ; }
      }
    }
    // print('\n');
    // print(str(rx)+" "+str(gx)+" "+str(bx)+" "+str(ix));
    print('\n');
    /* show values */
    show_values(rx,gx,bx,ix);
    /* draw bars */
    int rate_rgbi = max(max(rx,gx),max(bx,ix));
    if ( rate_rgbi > 0 ) { show_bars(rx,gx,bx,ix); } 
  }
}

void mouseClicked()
{
  if ( mouseButton == LEFT ) {
    /* get */
    if ( isRangeOk(mouseX, 20, 70) &&
         isRangeOk(mouseY,300,320)    ) {
      /* debug */
      println("Get");
      /* send command */
      cport.write('C'); 
      cport.write('\r');
    }
    /* execute */
    if ( isRangeOk(mouseX, 80,130) &&
         isRangeOk(mouseY,300,320)    ) {
      /* debug */
      println("Execute");
      /* send command */
      cport.write('E'); 
      cport.write('\r');
    }
     /* idle */
    if ( isRangeOk(mouseX,140,190) &&
         isRangeOk(mouseY,300,320)    ) {
      /* debug */
      println("Idle");
      /* send command */
      cport.write('I'); 
      cport.write('\r');
    }
    /* exit */
    if ( isRangeOk(mouseX,220,390) &&
         isRangeOk(mouseY,300,320)    ) {
      /* send command */
      cport.write('I'); 
      cport.write('\r');
      /* debug */
      println("exit");
      exit();
    }
  } 
  /* Exit */
  if ( mouseButton == RIGHT ) {
    /* send command */
    cport.write('I'); 
    cport.write('\r');
    exit();
  }
}

void serialEvent(Serial p)
{
  scflag = true ;
}

 このProcessingスケッチは、受信割込みを使っています。
 受信バッファに、1レコード分のデータが格納されたなら
 イベントフラグでdraw()の中にある、対応ブロックに通知
 しています。


目次

inserted by FC2 system