がじぇっとるねさす

ホビーとエレクトロニクスを繋げるサイト

がじぇるね工房

作品タイトル:GR-KURUMIの機能を使う I2C編

表示名:@chobichan

GR-KURUMIの機能を使う I2C編

コンセプト・作品説明
GR-KURUMIのI2C機能を使用します
####

I2Cを使ってみる

I2CデバイスはWireライブラリを使えば簡単に利用できます。世の中に沢山のI2Cデバイスが存在しますが、ここではデータの入力方向として温湿度センサー、出力方向としてキャラクター液晶を操作してみます。

 



温湿度センサーは秋月電子通商のAE-HDC1000を、LCDは秋月電子通商のAQM1602A-RN-GBWを使用しています。

共にI2C接続なので少ない配線で利用できる便利なデバイスです。

 

 

####

温湿度センサーAE-HDC1000

AE-HDC1000はHDC1000と言うセンサーをユーザーが使いやすい様に基板化したモジュールです。
基板上にI2Cで必要な10KΩのプルアップ抵抗も実装されていますので、特にブレッドボードに抵抗を用意しなくても構いません。

温度は-20℃から85℃まで、湿度は0%から100%まで計測可能です。
特徴的なのは消費電力がとても小さい事で、電池等で動かす装置に最適です。

 

 

 

以下にサンプルコードを記載しておきます。
定期的にシリアルに温度、湿度を出力するプログラムです。

 

/*GR-KURUMI Sketch Template Version: V1.12*/
#include  
#include    //I2Cを使う為に宣言

#if !defined( _MULTITASK_H_ )
#define  dly_tsk(tim)  delay(tim)
#define  rot_rdq()
#define  loc_cpu()     interrupts()
#define  unl_cpu()     noInterrupts()
#endif /*_MULTITASK_H_ */

int HDC1000blkWrite(unsigned char addr, const unsigned char *dat, unsigned int len);
int HDC1000blkRead( unsigned char reg, unsigned char data[], int len );
int HDC1000writeConfig(unsigned short config);
void HDC1000readConfig(unsigned short *config);
void HDC1000readDeviceID(unsigned short *id);
void HDC1000readManufactureID(unsigned short *manu);
void HDC1000readSerialID0(unsigned short *id0);
void HDC1000readSerialID1(unsigned short *id1);
void HDC1000readSerialID2(unsigned short *id2);
int HDC1000readTemperature(unsigned short *tmp,unsigned short *humi);
float HDC1000temperature2Degree( unsigned short temperature );
float HDC1000humidity2Percent( unsigned short humidity );

//HDC1000の内部レジスタアドレス
#define  HDC1000_ADR          (0x40 >> 0)
#define  HDC1000_TEMPERATURE  0x00
#define  HDC1000_HUMIDITY     0x01
#define  HDC1000_CONFIG       0x02
#define  HDC1000_SERIAL_ID2   0xfb
#define  HDC1000_SERIAL_ID1   0xfc
#define  HDC1000_SERIAL_ID0   0xfd
#define  HDC1000_MANU_ID      0xfe
#define  HDC1000_DEVICE_ID    0xff

void setup()
{
  Serial.begin(9600);
  Wire.begin();  //for display and temp sensor

  HDC1000writeConfig(0x8000);  //reset
  delay(10);
  HDC1000writeConfig(0x1000);  //config set resolution 14bit 0b0000 0000 00000000

  while( 1 )
  {
    unsigned short tempUS,humiUS;
    HDC1000readTemperature( &tempUS, &humiUS );  //温度、湿度データを取得

    float tempF = HDC1000temperature2Degree( tempUS ) + 0.05f;  //変換値を摂氏に換算
    float humiF = HDC1000humidity2Percent( humiUS ) + 0.05f;  //変換値をパーセントに換算
    char buf[32];
    sprintf( buf, "%f", tempF );
    String Temp = "Temperature:";
    Temp += buf;
    Temp += "c";

    sprintf( buf, "%f", humiF );
    String Humi = "Humidity:";
    Humi += buf;
    Humi += "%";

    Serial.println( Temp );
    Serial.println( Humi );

    delay(10 * 1000UL);
  }
}

// the loop routine runs over and over again forever:
void loop()
{
}


 

/****************************************************************************/
/* I2C block Write                                                          */
/****************************************************************************/
int HDC1000blkWrite(unsigned char addr, const unsigned char *dat, unsigned int len)
{
  Wire.beginTransmission(addr);
  Wire.write(dat,len);
  return Wire.endTransmission();
}

/*************************************************************************/
/* any bytes data read                                                   */
/*************************************************************************/
int HDC1000blkRead( unsigned char reg, unsigned char data[], int len )
{
  Wire.beginTransmission( HDC1000_ADR );
  Wire.write( reg );
  Wire.endTransmission(false); //endTransmission but keep the connection active

  Wire.requestFrom( HDC1000_ADR, len ); //Ask for bytes, once done, bus is released by default

  unsigned long baseTime = millis();
  while( Wire.available() < len ) //Hang out until we get the # of bytes we expect
  {
    if( (millis() - baseTime) > 100UL ) return (-1);
  }

  for(int i = 0 ; i < len; i++)
    data[i] = Wire.read();    

  return 0;
}

/*************************************************************************/
/* write configration                                                    */
/*************************************************************************/
int HDC1000writeConfig(unsigned short config)
{
  unsigned char cmd[3];

  cmd[0] = HDC1000_CONFIG;
  cmd[1] = (unsigned char)(config >> 8);
  cmd[2] = (unsigned char)config;

  return HDC1000blkWrite( HDC1000_ADR, cmd, sizeof(cmd) );
}

/*************************************************************************/
/* read configration                                                     */
/*************************************************************************/
void HDC1000readConfig(unsigned short *config)
{
  unsigned char temp[2];

  HDC1000blkRead( HDC1000_CONFIG, temp, sizeof(temp) );

  *config = (temp[0] << 8) | temp[1];
}


/*************************************************************************/
/* read device id                                                     */
/*************************************************************************/
void HDC1000readDeviceID(unsigned short *id)
{
  unsigned char temp[2];

  HDC1000blkRead( HDC1000_DEVICE_ID, temp, sizeof(temp) );

  *id = (temp[0] << 8) | temp[1];
}

/*************************************************************************/
/* read manufacture id                                                   */
/*************************************************************************/
void HDC1000readManufactureID(unsigned short *manu)
{
  unsigned char temp[2];

  HDC1000blkRead( HDC1000_MANU_ID, temp, sizeof(temp) );

  *manu = (temp[0] << 8) | temp[1];
}

/*************************************************************************/
/* read serial id  msb                                                   */
/*************************************************************************/
void HDC1000readSerialID2(unsigned short *id2)
{
  unsigned char temp[2];

  HDC1000blkRead( HDC1000_SERIAL_ID2, temp, sizeof(temp) );

  *id2 = (temp[0] << 8) | temp[1];
}

/*************************************************************************/
/* read serial id  middle                                                */
/*************************************************************************/
void HDC1000readSerialID1(unsigned short *id1)
{
  unsigned char temp[2];

  HDC1000blkRead( HDC1000_SERIAL_ID1, temp, sizeof(temp) );

  *id1 = (temp[0] << 8) | temp[1];
}

/*************************************************************************/
/* read serial id  lsb                                                   */
/*************************************************************************/
void HDC1000readSerialID0(unsigned short *id0)
{
  unsigned char temp[2];

  HDC1000blkRead( HDC1000_SERIAL_ID0, temp, sizeof(temp) );

  *id0 = (temp[0] << 8) | temp[1];
}

/*************************************************************************/
/* read temperatue                                                       */
/*************************************************************************/
int HDC1000readTemperature(unsigned short *tmp,unsigned short *humi)
{
  unsigned char temp[4];

  temp[0] = HDC1000_TEMPERATURE;
  HDC1000blkWrite( HDC1000_ADR, (const unsigned char *)temp, 1 );
  dly_tsk(7 * 2);
  Wire.requestFrom( HDC1000_ADR, sizeof(temp) ); //Ask for bytes, once done, bus is released by default
  unsigned long nextTime = millis() + 100UL;
  while( Wire.available() < sizeof(temp) ) //Hang out until we get the # of bytes we expect
  {
    if( nextTime < millis() ) return (-1);
  }
  for(int i = 0 ; i < sizeof(temp); i++)
    temp[i] = Wire.read();    

  *tmp = (temp[0] << 8) | temp[1];
  *humi = (temp[2] << 8) | temp[3];

  return 0;
}

/*************************************************************************/
/* temperatue to degree                                                  */
/*************************************************************************/
float HDC1000temperature2Degree( unsigned short temperature )
{
  return (float)temperature / 65536.0 * 165.0 - 40.0;
}

/*************************************************************************/
/* humidity to percent                                                   */
/*************************************************************************/
float HDC1000humidity2Percent( unsigned short humidity )
{
  return (float)humidity / 65536.0 * 100.0;
}



 

 

シリアルに出力した温度、湿度の結果です。ターミナルソフトにはXBeeのツールのX-CTUを使用しています。

####

キャラクター液晶 AQM1602A-RN-GBW

AQM1602A-RN-GBWは16文字×2行のキャラクタ出力が可能な液晶です。文字にはASCIIコードとカナ文字を表示できます。
コントローラICはST7032iを使用しています。
特徴的なのはとても消費電力が小さい点で、電池駆動の装置等に向きます。

 

 

 

以下にサンプルコードを記載しておきます。
定期的にシリアルに温度、湿度を出力するプログラムです。

 

/*GR-KURUMI Sketch Template Version: V1.12*/
#include  
#include    //I2Cを使う為に宣言

#if !defined( _MULTITASK_H_ )
#define  dly_tsk(tim)  delay(tim)
#define  rot_rdq()
#define  loc_cpu()     interrupts()
#define  unl_cpu()     noInterrupts()
#endif /*_MULTITASK_H_ */

int HDC1000blkWrite(unsigned char addr, const unsigned char *dat, unsigned int len);
int HDC1000blkRead( unsigned char reg, unsigned char data[], int len );
int HDC1000writeConfig(unsigned short config);
void HDC1000readConfig(unsigned short *config);
void HDC1000readDeviceID(unsigned short *id);
void HDC1000readManufactureID(unsigned short *manu);
void HDC1000readSerialID0(unsigned short *id0);
void HDC1000readSerialID1(unsigned short *id1);
void HDC1000readSerialID2(unsigned short *id2);
int HDC1000readTemperature(unsigned short *tmp,unsigned short *humi);
float HDC1000temperature2Degree( unsigned short temperature );
float HDC1000humidity2Percent( unsigned short humidity );

void ST7032Iinit( void );
void ST7032Iclear( void );
void ST7032IOnOff( unsigned char onoff );
void ST7032Ilocate( int x, int y );
void ST7032Icontrast( unsigned char cnt );
int ST7032IwriteString( const char *str );
int ST7032IwriteString( const char *str, unsigned int len );
int ST7032IwriteString( String str );
void displayUpdate( String line0, String line1 );

//HDC1000の内部レジスタアドレス
#define  HDC1000_ADR          (0x40 >> 0)
#define  HDC1000_TEMPERATURE  0x00
#define  HDC1000_HUMIDITY     0x01
#define  HDC1000_CONFIG       0x02
#define  HDC1000_SERIAL_ID2   0xfb
#define  HDC1000_SERIAL_ID1   0xfc
#define  HDC1000_SERIAL_ID0   0xfd
#define  HDC1000_MANU_ID      0xfe
#define  HDC1000_DEVICE_ID    0xff

//ST7032Iの内部レジスタアドレス
#define  ST7032I_ADR          0x3e
#define  AQM0802A_LINES       2  //
#define  AQM0802A_COLUMN      16  //液晶にはAQM0802AとAQM1602Aが有り、文字数が異なります。
#define  AQM0802A_DISPLAY_ON  0x04
#define  AQM0802A_DISPLAY_OFF 0x00
#define  AQM0802A_CURSOR_ON   0x02
#define  AQM0802A_CURSOR_OFF  0x00
#define  AQM0802A_BLINK_ON    0x01
#define  AQM0802A_BLINK_OFF   0x00
#define  LCD_RESET   6  //lcd reset

void setup()
{
  Wire.begin();  //for display and temp sensor

  HDC1000writeConfig(0x8000);  //reset
  delay(10);
  HDC1000writeConfig(0x1000);  //config set resolution 14bit 0b0000 0000 00000000

  pinMode(LCD_RESET, OUTPUT);  //reset LCD
  digitalWrite(LCD_RESET, HIGH);
  delay(2);
  digitalWrite(LCD_RESET, HIGH);

  ST7032Iinit();  //initialize LCD
  ST7032IOnOff( AQM0802A_DISPLAY_ON | AQM0802A_CURSOR_OFF | AQM0802A_BLINK_OFF );

  while( 1 )
  {
    unsigned short tempUS,humiUS;
    HDC1000readTemperature( &tempUS, &humiUS );  //温度、湿度データを取得

    float tempF = HDC1000temperature2Degree( tempUS ) + 0.05f;  //変換値を摂氏に換算
    float humiF = HDC1000humidity2Percent( humiUS ) + 0.05f;  //変換値をパーセントに換算
    char buf[32];
    sprintf( buf, "%2.1f", tempF );
    String Temp = "Temp:";
    Temp += buf;
    Temp += "c";

    sprintf( buf, "%2.1f", humiF );
    String Humi = "Humi:";
    Humi += buf;
    Humi += "%";

    displayUpdate( Temp, Humi );

    delay(1 * 1000UL);
  }
}

// the loop routine runs over and over again forever:
void loop()
{
}

 

/*************************************************************************/
/* I2C block Write                                                       */
/*************************************************************************/
int ST7032IblkWrite(unsigned char addr, const unsigned char *dat, unsigned int len)
{
  Wire.beginTransmission(addr);
  Wire.write(dat,len);
  return Wire.endTransmission();
}

/*************************************************************************/
/* write command                                                         */
/*************************************************************************/
int ST7032IwriteCommand(unsigned char t_command)
{
  unsigned char cmd[2];

  cmd[0] = 0x00;  //Co=0,RS=0,another bit=0
  cmd[1] = t_command;

  return ST7032IblkWrite( ST7032I_ADR, cmd, sizeof(cmd) );
}

/*************************************************************************/
/* write data                                                            */
/*************************************************************************/
int ST7032IwriteData(unsigned char t_data)
{
  unsigned char dat[2];

  dat[0] = 0x40;  //Co=0,RS=1,another bit=0
  dat[1] = t_data;

  return ST7032IblkWrite( ST7032I_ADR, dat, sizeof(dat) );
}


/*************************************************************************/
/* ST7032I初期化                                                         */
/*************************************************************************/
void ST7032Iinit( void )
{
  dly_tsk(40);
  ST7032IwriteCommand( 0x38 );  //function set
  delayMicroseconds(27);
  ST7032IwriteCommand( 0x39 );  //function set
  delayMicroseconds(27);
  ST7032IwriteCommand( 0x14 );  //internal OSC frequency
  delayMicroseconds(27);
  ST7032IwriteCommand( 0x70 );  //contrast set
  delayMicroseconds(27);
  ST7032IwriteCommand( 0x56 );  //power/icon/contrast control
  delayMicroseconds(27);
  ST7032IwriteCommand( 0x6c );  //follower control
  //delayMicroseconds(27);
  dly_tsk( 200 );
  ST7032IwriteCommand( 0x38 );  //function set
  delayMicroseconds(27);
  ST7032IwriteCommand( 0x01 );  //clear display
  delayMicroseconds(27);
  ST7032IwriteCommand( 0x0c );  //display on/off control
  dly_tsk(2);
}


/*************************************************************************/
/* clear display                                                         */
/*************************************************************************/
void ST7032Iclear( void )
{
  ST7032IwriteCommand( 0x01 );  //clear display
  dly_tsk(2);
}


/*************************************************************************/
/* display on/off                                                        */
/*************************************************************************/
void ST7032IOnOff( unsigned char onoff )
{
  ST7032IwriteCommand( onoff | 0x08 );  //display on/off,cursor on/off,blink on/off
  dly_tsk(2);
}


/*************************************************************************/
/* locate                                                                */
/*************************************************************************/
void ST7032Ilocate( int x, int y )
{
  int temp = x + (y * AQM0802A_COLUMN);

  if(temp >= AQM0802A_COLUMN) temp = (temp - AQM0802A_COLUMN) + 0x40;

  ST7032IwriteCommand( (unsigned char)temp | 0x80 );  //set ddram address
  dly_tsk(2);
}


/*************************************************************************/
/* set contrast         */
/*************************************************************************/
void ST7032Icontrast( unsigned char cnt )
{
  //コントラスト調整
  ST7032IwriteCommand( 0x2a );  //RE=1
  ST7032IwriteCommand( 0x79 );  //SD=1
  ST7032IwriteCommand( 0x81 );  //contrast set
  ST7032IwriteCommand( cnt );  //contrast max
  ST7032IwriteCommand( 0x78 );  //SD=0
  ST7032IwriteCommand( 0x28 );  //set character size is normal.
  dly_tsk(100);
}


/*************************************************************************/
/* write strings                                                         */
/*************************************************************************/
int ST7032IwriteString( const char *str )
{
  unsigned char dat[1 * AQM0802A_COLUMN + 1];
  int len = strlen(str);

  dat[0] = 0x40;  //Co=0,RS=1,another bit=0
  len = (len > sizeof(dat) - 1) ? sizeof(dat) - 1 : len;
  memcpy( &dat[1], str, len );

  return ST7032IblkWrite( ST7032I_ADR, dat, len + 1 );
}


/*************************************************************************/
/* write strings                                                         */
/*************************************************************************/
int ST7032IwriteString( const char *str, unsigned int len )
{
  unsigned char dat[1 * AQM0802A_COLUMN + 1];

  dat[0] = 0x40;  //Co=0,RS=1,another bit=0
  len = (len > sizeof(dat) - 1) ? sizeof(dat) - 1 : len;
  memcpy( &dat[1], str, len );

  return ST7032IblkWrite( ST7032I_ADR, dat, len + 1 );
}


/*************************************************************************/
/* write strings                                                         */
/*************************************************************************/
int ST7032IwriteString( String str )
{
  return ST7032IwriteString( (const char *)&str[0], str.length() );
}

/***************************************************************************/
/* i2c display control and temperature/humidity sensor sampling task       */
/***************************************************************************/
void displayUpdate( String line0, String line1 )
{
  ST7032Iclear();
  ST7032IwriteString( line0 );
  ST7032Ilocate( 0, 1 );
  ST7032IwriteString( line1 );
}

液晶に出力した温度、湿度の結果です。基板が違うとか、細かいところは気にしないでください。

####

I2Cの速度を変えてみる

I2CデバイスによってはSCLの速度が400KHzまで対応している物が有ります。
本家ArduinoではWireライブラリにWire.setclock()と言う関数が存在し、ある程度の任意の周波数を設定できます。
http://playground.arduino.cc/Main/WireLibraryDetailedReference

残念ながら現在のGR-KURUMIのライブラリではサポートされていません。ライブラリのソースコード
gr_common/RLduino78/libralies/Wire/utility
以下のtwi.hを開くと、 TWI_FREQと言うマクロでSCLの周波数が定義されています。この周波数を変更する事で、SCLの周波数を変える事ができます。

 

 

SCLの周波数を変更前(100KHz)と変更後(400KHz)でオシロスコープで見てみました。周波数が変わっている事が判ります。

しかし、ライブラリでサポートして欲しいですね。

 

@chobichan

極一般のハードウエアエンジニア。たまに雑誌記事を書いています。
twitterアカウント:https://twitter.com/chobichan

フォローする

share

ページトップへ