[[lbed]] #contents 2013/07/15からのアクセス回数 &counter; ** 温度センサーLM73とつなぐ [#lf3f1c8b] [[LCD>lbed/02-LCDにテキスト表示]]でLCDに表示することができたので、 [[LCDクラス>lbed/02-LCDにテキスト表示]]でLCDに表示することができたので、 次は温度センサーとつないでみます。 ここで使う温度センサーは、I2Cという通信インタフェースを使用します。 I2Cインタフェースでは、SDA, SCLにプルアップ抵抗が必要なので、手元にあった 4.7KΩの抵抗を使ってプルアップしています。 &ref(LM73.png); I2Cがp27, p28を使用するので、LCDの接続以下に変更します。 MyARM: StartBoard - p40 3.3V:p40 - p30 DB7:p30 - p29 DB6:p29 - p26 DB5:p28 - p24 DB4:p27 - p25 E:p26 - p8 RS:p24 - p1 GND:p1 GND LM73((△の付いたところが1番で反時計回りに番号が振られている))とMyARMの接続は、 - 2番GND:p1 GND - 3番3.3V:p40 3.3V - 4番SCL:p27 SCL - 6番SDA:p28 SDA &ref(LM73_setting.png); ** テストプログラム [#sf3f2e85] テスト用のプログラムは、以下の通りです。 1秒ごとに温度をLM73から読み取り表示します。 #pre{{ #include<cr_section_macros.h> #include<NXP/crp.h> __CRP extern const unsigned int CRP_WORD = CRP_NO_CRP; #include"lbed.h" #include "TextLCD.h" #include "LM73.h" int main(void) { wait_init(); DigitalOut myled(LED2); TextLCD lcd(p8, p25, p24, p26, p29, p30); // rs, e, d4-7 LM73 lm73(p28, p27); lcd.print("Hello World"); while (1) { float t = lm73.read(); lcd.locate(0, 1); lcd.print("Temp:"); lcd.print(t); myled = !myled; wait_ms(1000); } return 0; } }} ** LM73クラスについて [#h215ce18] LM73クラスは、LM73チップ用に私が作成したユーザライブラリです。 [[raspberrypi/Raspberry PiでIO制御]]でも説明していますが、コンストラクターで - レジスター4に対して、解像度を14bitにする - 以下連続して読み出せるようにポインタを0にセット 後は、readメソッドで2バイト読み込み、バイトスワップを行った後、14bitを取り出し、 補正係数を掛けて温度を計算するだけです。 #pre{{ #include "lbed.h" #include "LM73.h" LM73::LM73(PinName sda, PinName scl) : i2c(sda, scl) { char cmd[2]; // LM73設定 cmd[0] = 0x04; // register 4 cmd[1] = 0x60; // 14bit resolution i2c.write( LM73_ADDR, cmd, 2); // ポインタを0にしておく(readするだけで温度が読めるようになる) cmd[0] = 0x00; i2c.write( LM73_ADDR, cmd, 1); } LM73::~LM73() { } float LM73::read() { char cmd[2]; i2c.read( LM73_ADDR, cmd, 2); // Send command string int int_val = cmd[0] <<1 | cmd[1]>>7; int ceil_val = ((cmd[1] & 0x7f)*200) >>8; return float(int_val + ceil_val/100.0); } }} ** I2Cのクラスについて [#b779362e] I2Cのクラスは、LPC11xx-LPCXpresso-CMSIS-updateのサンプルプログラムを使用しています。 問題は、I2Cが割り込み関数を使っているのですが、C++のメソッドを割り込み関数にできないため、 Cで書かれた割り込み関数を使用しなければなりません。 今回は、i2c.hを_i2c.hに名前を変え((MacOSXでは大文字時を区別しないので、I2Cとの区別のため)) ヘッダファイルの先頭に #pre{{ #ifdef __cplusplus extern"C" { #endif }} 終わりに #pre{{ #ifdef __cplusplus } #endif }} を付けて、C++からI2C用の共通関数を使えるように修正します。 このようにサンプルプログラムの共通関数を活用することで、I2Cは以下の様に簡単に記述することができました。 #pre{{ #include "platform.h" #include "PinNames.h" #include "I2C.h" #include "LPC11xx.h" /* LPC11xx Peripheral Registers */ #include "type.h" #include "_i2c.h" extern volatile uint32_t I2CCount; extern volatile uint8_t I2CMasterBuffer[BUFSIZE]; extern volatile uint8_t I2CSlaveBuffer[BUFSIZE]; extern volatile uint32_t I2CMasterState; extern volatile uint32_t I2CReadLength, I2CWriteLength; I2C::I2C(PinName sda, PinName scl, const char *name) { _name = (char *) name; if (I2CInit((uint32_t) I2CMASTER) == FALSE) /* initialize I2c */ { while (1) ; /* Fatal error */ } } int I2C::read(int address, char *data, int length, bool repeated) { for (int i = 0; i < length; i++) I2CSlaveBuffer[i] = 0x00; I2CWriteLength = 2; I2CReadLength = length; getI2CMasterBuffer()[0] = address; getI2CMasterBuffer()[1] = 0x00; /* address */ getI2CMasterBuffer()[2] = address | RD_BIT; I2CEngine(); for (int i = 0; i < length; i++) data[i] = getI2CSlaveBuffer()[i]; return length; } int I2C::read(int ack) { I2CReadLength = 1; I2CEngine(); return getI2CSlaveBuffer()[0]; } int I2C::write(int address, const char *data, int length, bool repeated) { I2CWriteLength = length+1; I2CReadLength = 0; getI2CMasterBuffer()[0] = address; for (int i = 0; i < length; i++) getI2CMasterBuffer()[i+1] = data[i]; I2CEngine(); return 1; } int I2C::write(int ack) { I2CWriteLength = 2; I2CReadLength = 0; getI2CMasterBuffer()[1] = ack; I2CEngine(); return 1; } }} ** コメント [#sf492497] #vote(おもしろかった,そうでもない,わかりずらい) 皆様のご意見、ご希望をお待ちしております。 #comment_kcaptcha