[[FrontPage]] #contents 2013/03/09からのアクセス回数 &counter; ** 温度センサーLM35を使う [#h4a516b2] 今回も大野さんの本のお復習いをしています。 温度センサー [[LM35DZのデータシート>http://www.tij.co.jp/jp/lit/ds/jajsb56/jajsb56.pdf]] を見るとLM35Dは、 - 動作温度範囲は、0℃から100℃ - 温度係数はリニアで+10.0mV/℃ と記載されています。 リニアーに10.0mV/℃なら50℃では、0.5Vが観測されるはずです。 例題13では、LM35DZの測定範囲の半分(50℃)でPSoCのBandGap1.3VになるようにPGAの倍率を 計算しています。 #pre{{ 0.5V x 2.667 = 1.3335V }} ADCINC(12bit)が以下のようにセットすると50℃では、1.3335 x 2047/1.3 = 2100となります。 - 入力0Vで、0 - 入力1.3Vで、2047 - 入力2.6Vで、4095 *** ブレッドボードの組み立て [#t327f413] 図8-66を参考にブレッドボードを組み立てます。 &ref(fig8_86.png); LM35には、P0[5]からREFHI(2.6V)を供給し、REFHIを測定するために、RefMuxを使ってP0[2]に出力しています。 &ref(L8_13_Breadboad.png); ポート番号とピンの対応は、以下の図を参考にしてください。 &ref(pin_layout.png); *** ユーザモジュールの配置 [#m5ba4b1e] 以下のユーザモジュールを配置します。 - PGA - ADCINC - RefMux - LCD &ref(L8_13_ABlock.png); ADCINC_1の設定は以下の様になっています。DataFormat: unsigned, Resolution: 12bitです。 &ref(L8_13_ADCINC_1.png); PGA_1の設定は、Gainを2.667, InputをAnalogColumn_InputMux_0にセットし、P0[5]と接続しています。 &ref(L8_13_PGA_1.png); RefMux_1の設定は、REFHIをセットし、出力をP0[2]に接続します。 &ref(L8_13_RefMux_1.png); ピンの設定では、P0[5]をStrongで初期値を1にセットするのがポイントです。 ((これに気づかずに動かなくて手こずりました)) &ref(L8_13_pinout.png); *** main.c [#fecff2e1] main.cはそのまま大野さんのプログラムを拝借しました。 #pre{{ #include <m8c.h> // part specific constants and macros #include "PSoCAPI.h" // PSoC API definitions for all User Modules char strg[] = "ONDO 00.0 "; int read_adc(void) { int ival; ADCINC_1_GetSamples(1); while(ADCINC_1_fIsDataAvailable()==0); ival=ADCINC_1_iClearFlagGetData(); return ival; } char htoc(int ch) { return "0123456789ABCDEF"[ch & 0xf]; } void main(void) { int ival; long lval; ADCINC_1_Start(ADCINC_1_HIGHPOWER); PGA_1_Start(PGA_1_HIGHPOWER); RefMux_1_Start(RefMux_1_HIGHPOWER); // リファレンス実測のためアナログバスに出しておく M8C_EnableGInt; LCD_1_Start(); strg[4] = 0x7e; // 1行5文字目に'→'表示 strg[9] = 0xdf; // 1行9文字目に'゜'を表示 strg[10] = 0x43; // 1行10文字目に'C'を表示 LCD_1_Position(1,0); // 2行目にA/D変換値を表示するための準備 LCD_1_PrCString("A/D read 0000(h)"); // Const文字列表示はPrCStringを使う for(;;) { PRT0DR |= 0x40; // モニタ ival = read_adc(); LCD_1_Position(1,9); // A/D変換値を16進で2行目に表示 LCD_1_PrHexInt(ival); lval = ival; lval = lval * 3946L; // リファレンス実測値(2.570V)とPGAゲイン(×2.667)の差を微修正 lval = lval >> 12; lval *= 1000; // 100℃/4095を0.1℃分解能の整数に換算 lval = lval >> 12; ival = lval & 0xfff; strg[5] = htoc(ival / 100); // 10進3桁の文字列に変換 ival %= 100; strg[6] = htoc(ival / 10); ival %= 10; strg[8] = htoc(ival); strg[11] = '\0'; // 念のための文字列終端コード LCD_1_Position(0,0); LCD_1_PrString(strg); // RAM文字列表示はPrStringを使う PRT0DR &= ~0x40; // モニタ } } }} *** 動かしてみる [#i804190a] 早速動かしてみましょう。 &ref(L8_13_run.png); リファレンスの実測値は、2.6Vではなく2.570Vでした。 ** Raspberry Piと接続 [#p5395d2f] Raspberry Piと接続するためにI2CスレーブをPSocのブレッドボードに追加します。 ユーザモジュールEzI2Csを配置します。 EzI2Csの設定は、I2Cのアドレスには0x20(32)をセットし、以下の様にしました。 &ref(L8_13_EzI2Cs_1.png); EzI2Csを使うことによってI2Cマスターからは、PSoCがEEPROMと同じように扱うことができます。 テストのために、EzI2Cs用のバッファを以下のように定義します。 msgは、LCDの3段目に出力する文字列で、ivalはLM35から読み取った値をリードオンリーとします。 #pre{{ // EzI2Cs用のバッファ struct I2C_Regs { char msg[8]; int ival; // LM35 temp read only to I2C } myI2C_regs = { "1234567", 0 }; }} EzI2Csを追加したことによるmain関数の変更は、変数宣言直後の以下の部分と #pre{{ M8C_EnableGInt; EzI2Cs_1_SetRamBuffer(sizeof(myI2C_regs), 8, (BYTE *)&myI2C_regs); EzI2Cs_1_Start(); }} forループの最初にivalの値をmyI2C_reg.ivalにコピーする以下の部分です。 #pre{{ ival = read_adc(); myI2C_regs.ival = ival; // ivalをI2C用レジスターバッファにセット }} *** Raspberry Piとの接続 [#wff409a7] PSoCとRasperry Piとの接続は、以下の様にします。 - GND: PI-02 3ピンをPSoCのGNDに接続 - SDA: PI-01 2ピンをPSoCのP1[5]に接続 - SLC: PI-01 3ピンをPSoCのP1[7]に接続 &ref(L8_13_I2Cs.png); *** 実行結果 [#kc3f9738] さっそくRaspberry PiのI2C Toolを使って動作を確認してみましょう。 最初にPSoCのI2Cスレーブを認識するところから、i2cdetectを使ってデバイスをスキャンします。 無事0x20が検出できています。 #pre{{ $ sudo i2cdetect 0 WARNING! This program can confuse your I2C bus, cause data loss and worse! I will probe file /dev/i2c-0. I will probe address range 0x03-0x77. Continue? [Y/n] 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- }} 次に"H"をPSoCに送ってみます。((連続してセットすると上手く行きませんでした)) #pre{{ $ sudo i2cset -y 0 0x20 0x00 0x48 # H $ sudo i2cset -y 0 0x20 0x00 }} 最終目的の温度を読み取ると、 #pre{{ $ sudo i2cget -y 0 0x20 0x08 w 0x1a04 }} バイトが入れ替わっているので、正しい値は0x041aが正常に受け取れていることが確認できました。 ** コメント [#e1f6f53f] #vote(おもしろかった[7],そうでもない[0],わかりずらい[0]) #vote(おもしろかった[8],そうでもない[0],わかりずらい[0]) 皆様のご意見、ご希望をお待ちしております。 #comment_kcaptcha