#topicpath

** I2C通信と温湿度計 [#sdfb243f]
>>
SHT25(あるいは SHT-25, Strawberry Linux では[[こちら>http://strawberry-linux.com/catalog/items?code=80025]]) を Arduino で扱う。
I2C 通信の練習でもある。~
先日、mbed 祭りに参加したので、mbed でもいいけれど、ついつい Arduino になってしまう。
<<
*** I2C 通信 [#ieb45f87]
+ はじめに~
I2C 通信と SPI 通信は Arduino と他のデバイスとの通信のスタンダードになっている。I2C の学習と練習も兼ねて、[[Sensirion SHT25>http://www.sensirion.com/en/products/humidity-temperature/humidity-temperature-sensor-sht2x/]]のデータを読み出す。~
RIGHT:2014-12-23 (火) 12:20:56
~
+ I2C 通信の基礎知識
++ 配線~
センサー(スレーブ)への配線は4本。Arduino(マスター) 側のどこに接続するかも決まっている。
#style(class=table_left)
|センサー(スレーブ)|Arduino(マスター)(Mega2560, Leonardo, Due などは違うので注意。)|h
|Vin 電源供給 | 3.3V か 5V か(センサーによる)|
|GND グラウンド  | GND |
|SCL クロック     | A5 |
|SDA データ送受信  | A4 |
#clear
++ マスターとスレーブ~
通信は双方向である。ただし、通信のクロックを決める方をマスターといい、それに従うのをスレーブという(という理解でよいのか?)。~
普通、Arduino をマスターにすると思われるので、以下はその前提で話を進める。~
接続について、マスターは一つだけである。しかし、スレーブは複数つないでもいい。~
~
++ アドレス~
複数つないだスレーブは、(通常7bit の)アドレスで区別する。アドレスが同じものは載せられない。センサーの場合、アドレスが固定して~
作られているので、複数の同種センサーは一つのI2C通信のラインに載せられない。~
特に Arduino の場合には、I2C 通信用のポートが1組しかないために、複数の同種センサーは載せられない。mbed などでは、複数の I2C~
のポートが用意されている(ことがある)。~
~
++ プルアップ~
SCL と SDA のラインは数kΩ程度の抵抗でプルアップされている。つまり、これらのラインは、抵抗を介して電源供給線とつながっていて、~
特に何もなければ、電源電圧と同じ電圧になるようになっている。~
気をつけなければならないのは、複数のスレーブを接続した場合であって、スレーブがプルアップ抵抗を含んでいるような場合である。~
利用者がプルアップ抵抗を用意しなくていいように、というメーカー側の親切心が、複数のスレーブがあることによって、抵抗を並列に~
接続することになり、あだとなる。気をつけたい(>自分)。~
~
+ Arduino の Wire ライブラリ~
Arduino は、I2C 通信のために、Wire というライブラリを用意している。これを用いて通信する。Wireについては、[[学習ページ(英語)>http://arduino.cc/en/Reference/Wire?from=Libraries.Wire]]参照の~
こと。[[日本語リファレンスのページ>http://www.musashinodenpa.com/arduino/ref/]]もある。ありがたい。~
関数は多くないので、全部掲載する。
#style(class=table_left)
| 分類| 関数|使い方|h
| 初期化| Wire.begin() | 通信開始。マスターの時には、引数不要。|
| 書き込み| Wire.beginTransmission(アドレス)| どのスレーブに書き込むか、アドレスを指定 |
| |  Wire.write(データ) | データは、1バイトのデータ、文字列、1バイトのデータの配列など。   |
| |  Wire.endTransmission() | 送信終了(戻り値 0 で正常終了)|
|読み込み| Wire.requestFrom(アドレス, バイト数) | どのアドレスのスレーブから、何バイト読むかを指定。|
|  | Wire.available() | 引き続く read() でスレーブ側が何バイト提供するかをあらかじめ調べる。|
| | Wire.read()| 1バイトだけ受け取る。引数なし。戻り値は受信した1バイトのデータ。 |
|その他| Wire.onReceive() | スレーブとして動く時に用いる関数なのでここでは説明しない。|
| | Wire.onRequest() |スレーブとして動く時に用いる関数なのでここでは説明しない。|
#clear
RIGHT:2014-12-23 (火) 13:20:59

*** I2C のレベル変換 [#r5e445b7]
- はじめに~
センサーは、2.1〜3.6V までで動かすように指定されている。Arduino は 3.3V も供給しているので、それを使いましょう。でも、~
SCL, SDA は Arduino 側は 5V で動いている。そのままでは正しく動かないことは明らかなので、電圧を変換する必要がある。~
専用の変換装置もある。例えば、秋月電子では、[[レベル変換モジュール>http://akizukidenshi.com/catalog/g/gM-05452]]として販売している。これを使えばいい。~
~
しかし、いろいろと工夫をする人がいて、(バイポーラー)トランジスタ一つで実現している人もいる。とてもありがたい!~
参考にして使わせていただく。~
~
- リンク
-- [[ねがてぃぶろぐ>http://gomisai.blog75.fc2.com/]] / [[異なる電圧レベル間でI2C その2>http://gomisai.blog75.fc2.com/blog-entry-46.html]]
-- [[Air Variable>http://airvariable.asablo.jp/]] / [[FETで異なる電圧のインターフェース>http://airvariable.asablo.jp/blog/2013/07/25/6922613]] こちらは FET を使った方法。
RIGHT:2014-12-23 (火) 18:12:27
- 配線例~
&ref(CIMG3420.JPG,,30%);~
RIGHT:2014-12-23 (火) 18:23:43
~
*** センサー SHT-25 [#c9b683e1]
- インターネット上の情報源
-- [[データシート>http://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/Humidity/Sensirion_Humidity_SHT25_Datasheet_V3.pdf]](Sensirion, pdf)
-- [[誤り検出符号(CRC checksum)計算方法>http://www.sensirion.com/nc/en/products/humidity-temperature/download-center/?cid=884&did=126&sechash=3fb04c33]]
-- Sensirion に掲載されている[[サンプルプログラム>http://www.sensirion.com/nc/en/products/humidity-temperature/download-center/?cid=8585&did=102&sechash=03a6edbf]]
-- SHT25 Arduino の[[ライブラリ>https://github.com/misenso/SHT2x-Arduino-Library]](github)~
ライブラリを使ってもいいけど、これらを元に自分でプログラムしてみる。~
RIGHT:2014-12-23 (火) 14:24:00
~
- 誤り検出符号のチェック方法~
-- サンプルプログラム([[誤り検出符号(CRC checksum)計算方法>http://www.sensirion.com/nc/en/products/humidity-temperature/download-center/?cid=884&did=126&sechash=3fb04c33]] から抜粋)
 typedef unsigned char u8t; ///< range: 0 .. 255
 const u16t POLYNOMIAL = 0x131; //P(x)=x^8+x^5+x^4+1 = 100110001
 
 u8t SHT2x_CheckCrc(u8t data[], u8t nbrOfBytes, u8t checksum){
   u8t crc = 0;
   u8t byteCtr; 
 
   //calculates 8-Bit checksum with given polynomial
   for (byteCtr = 0; byteCtr < nbrOfBytes; ++byteCtr)
   {
     crc ^= (data[byteCtr]);
     for (u8t bit = 8; bit > 0; --bit)
     {
       if (crc & 0x80) crc = (crc << 1) ^ POLYNOMIAL;
       else crc = (crc << 1);
     }
   }
   if (crc != checksum) return CHECKSUM_ERROR;
   else return 0;
 }
-- コメント
--- 演算子 &はビットAND、^はビットXOR、<<はビット左シフト
--- 変数型 
~
- サンプルコード
 #include <Wire.h>
 
 #define SHT25Address 0x40                 // 7bit のアドレス 1000'000
 #define TempHold     0xE3                 // Trigger T  measurement (hold) 1110'0011
 #define HumidHold    0xE5                 // Trigger RH measurement (hold) 1110'0101
 #define ReadRgstr    0xE7                 // Read Register                 1110'0111
 #define SoftReset    0xFE                 // Soft Reset                    1111'1110
 #define UserRgstr    0x02                 // User Register                 0000'0010
 
 
 /*-------------------------------------------------------------------------------------- I2C
    命令を書き込む。
  */
 int SHT25write(unsigned char command){
   Wire.beginTransmission(SHT25Address);    // I2C: 書き込み開始
   Wire.write(command);                     // I2C: 1バイト書き込み
   return( Wire.endTransmission(false) );   // I2C: 書き込みの成否を返す
 }
 
 /*-------------------------------------------------------------------------------------- I2C
    データを読み込む。Checksum は活用できていない。
  */
 unsigned int SHT25readdata(){
   unsigned int result, checksum;
   int ans;
   
   ans = Wire.requestFrom(SHT25Address, 3);  // I2C: アドレスのデバイスから 3バイト取得する
   while( Wire.available() < ans){}          // I2C: データを待つ 
   result  = (Wire.read()<<8);               // I2C: データを2バイト読む
   result +=  Wire.read();
   result &= ~0x0003;
   checksum= Wire.read();                    // 誤り検出符号を読む
   return result;
 }
 
 /*======================================================================================
   リセット : うまくいかない。
  */
 int SHT25reset(void){
   int result = 0;
 
   result  = SHT25write(SoftReset);
 //  Serial.print("Write Result: ");
 //  Serial.println(result);
   delay(1000);
   result += SHT25write(UserRgstr);
 //  Serial.print("Write Result: ");
 //  Serial.println(result);
   delay(1000);
   
   return result;
 }
 
 /*======================================================================================
   温度の取得
  */
 float SHT25Temp(void){
   while( SHT25write(TempHold) != 0 ){
     Serial.println("Error ");
   }
   return (-46.85 + 175.72 / 65536.0 * (float)(SHT25readdata()));
 }
 
 /*======================================================================================
   湿度の取得
  */
 float SHT25Humid(void){
   while( SHT25write(HumidHold) != 0 ){
     Serial.println("Error ");
   }
   return (-6.0 + 125.0 / 65536.0 * (float)(SHT25readdata()));
 }
 
 void setup(){
   Wire.begin();
   Serial.begin(9600);
   SHT25reset();
   Serial.println("Temp / Humid");
 }
 
 void loop(){
   int ans;
   Serial.print(SHT25Temp());
   Serial.print(", ");
   Serial.println(SHT25Humid());
   delay(1000);
 }
RIGHT:2014-12-23 (火) 17:55:26

トップ   編集 差分 添付 複製 名前変更 リロード   新規 検索 最終更新   ヘルプ   最終更新のRSS