作品タイトル:GR-KURUMIの機能を使う I2C編
表示名:@chobichan
コンセプト・作品説明 |
---|
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)でオシロスコープで見てみました。周波数が変わっている事が判ります。
しかし、ライブラリでサポートして欲しいですね。
極一般のハードウエアエンジニア。たまに雑誌記事を書いています。
twitterアカウント:https://twitter.com/chobichan