コンピュータの温度センサーとしてよく使われているLM75が入手できたので、PICに接続してみる。
■ 検証環境
・NXP LM75AD
・Microchip PIC12F1822
・MPLAB X IDE 1.60 / MPLAB XC8 C Compiler V1.12
■ 参考回路図と通信規格
回路図ファイル(20130512-lm75-circuit.CE3)をダウンロードする
LM75のアドレスを、最終ビットを立ててアクセスすると、2バイトの温度データが返ってくる。
1番ピンがどこなのか、非常に分かりにくいが、一般的なパッケージ印刷では『ムカデ状のチップに横向きにシルク印刷されている場合、文字の左下が1番ピン』という慣用に従ってみると、うまくアクセスできた。
■ LM75センサーをユニバーサル基盤に無理やり取り付ける
表面実装用のチップなので、ハンダ付けに若干苦労しました。
■ PIC12F1822用プログラムのコア部分
センサーから得られた値は、8で割ると「℃」の整数の単位となる。実際にこのセンサーを使う場合には、8で割った余りも小数点以下の数値として使えるだろう。
main.c
#include <stdio.h> #include <stdlib.h> #include <xc.h> #include "i2c-lib.h" /* PIC Configuration 1 */ __CONFIG(FOSC_INTOSC & // INTOSC oscillator: I/O function on CLKIN pin WDTE_OFF & // WDT(Watchdog Timer) disabled PWRTE_ON & // PWRT(Power-up Timer) disabled MCLRE_OFF & // MCLR pin function is digital input CP_OFF & // Program memory code protection is disabled CPD_OFF & // Data memory code protection is disabled BOREN_OFF & // BOR(Brown-out Reset) disabled CLKOUTEN_OFF & // CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin IESO_OFF & // Internal/External Switchover mode is disabled FCMEN_OFF); // Fail-Safe Clock Monitor is disabled /* PIC Configuration 2 */ __CONFIG(WRT_OFF & // Flash Memory Self-Write Protection : OFF VCAPEN_OFF & // VDDCORE pin functionality is disabled PLLEN_OFF & // 4x PLL disabled STVREN_ON & // Stack Overflow or Underflow will not cause a Reset BORV_HI & // Brown-out Reset Voltage Selection : High Voltage DEBUG_OFF & // In-Circuit Debugger disabled, ICSPCLK and ICSPDAT are general purpose I/O pins LVP_OFF); // Low-voltage programming : disable #ifndef _XTAL_FREQ /* 例:4MHzの場合、4000000 をセットする */ #define _XTAL_FREQ 4000000 #endif /* printf関数の出力先のスタブ関数を定義する */ void putch(unsigned char ch){ i2c_lcd_putch(ch); return; } int main(int argc, char** argv) { // 基本機能の設定 OSCCON = 0b01101010; // 内部オシレーター 4MHz TRISA = 0b00101111; // IOポートRA0(AN0),RA1(SCL),RA2(SDA),RA5(RX)を入力モード(RA3は入力専用)、RA4(TX)を出力モード ANSELA = 0b00000000; // A/D変換をAN0,AN1,AN2,AN4を無効 PORTA = 0; i2c_enable(); OPTION_REGbits.nWPUEN = 0; // I2C プルアップ抵抗 有効 WPUA = 0b00000110; // pull-up (RA1=SCL, RA2=SDA pull-up enable) while(1) { i2c_lcd_init(); i2c_lcd_puts("LM75 temperature"); i2c_lcd_set_cursor_pos(0x40); // カーソルを2行目に移動 printf("%03d deg-C", i2c_lm75_read_temperature()); __delay_ms(500); } return (EXIT_SUCCESS); }
i2c_lib.c
#include <stdio.h> #include <stdlib.h> #include <xc.h> #include "i2c-lib.h" #ifndef _XTAL_FREQ /* 例:4MHzの場合、4000000 をセットする */ #define _XTAL_FREQ 4000000 #endif // LM75アドレスは 0b1001000 = 0x48 #define LM75_I2C_ADDR 0b1001000 unsigned int i2c_lm75_read_temperature(void) { unsigned int temperature; i2c_start(); i2c_send_byte(LM75_I2C_ADDR<<1 | 1); // i2cアドレスを1ビット左にシフトし、末尾にR/Wビット(Read=1)を付与 temperature = i2c_read_byte(1) << 8; // 読み取り後ACK temperature |= i2c_read_byte(0); // 読み取り後NO_ACK temperature = (temperature >> 5) / 8; i2c_stop(); return temperature; } // I2Cバスを有効化 void i2c_enable(void) { SSP1STAT = 0b10000000; // I2C 100kHz SSP1ADD = 9; // I2Cバス Baud rate, 4MHz/((SSP1ADD + 1)*4) = 100kHz SSP1CON1 = 0b00101000; // I2C有効, Master Mode } // I2Cバスを無効化 void i2c_disable(void) { SSP1CON1 = 0b00001000; // I2C無効, Master Mode } // I2C書き込みサイクルの開始(Start Conditionの発行) void i2c_start(void) { SSP1CON2bits.SEN = 1; // Start Condition Enabled bit i2c_wait(); } // I2C書き込みサイクルの開始(Repeat Start Conditionの発行) void i2c_repeat_start(void) { SSP1CON2bits.RSEN = 1; // Start Condition Enabled bit i2c_wait(); } // I2C書き込みサイクルの終了(Stop Conditionの発行) void i2c_stop(void) { SSP1CON2bits.PEN = 1; // Stop Condition Enable bit i2c_wait(); } // I2C通信がビジー状態を脱するまで待つ void i2c_wait(void) { while ( ( SSP1CON2 & 0x1F ) || ( SSP1STATbits.R_nW ) ); } // I2Cバスにデータを送信(1バイト分) void i2c_send_byte(unsigned char data) { SSP1BUF = data; i2c_wait(); } //I2Cバスからデータ受信 // ack=1 : 受信後ACKを送信し、次のデータを送るようスレーブデバイスに指示 // ack=0 : 受信後NO_ACKを送信し、これ以上受信しないことをスレーブデバイスに指示 unsigned char i2c_read_byte(int ack) { SSP1CON2bits.RCEN = 1; i2c_wait(); unsigned char data = SSP1BUF; i2c_wait(); if(ack) SSP1CON2bits.ACKDT = 0; // ACK else SSP1CON2bits.ACKDT = 1; // NO_ACK SSP1CON2bits.ACKEN = 1; i2c_wait(); return data; }
■ 関連記事
・I2C温度センサーLM75ADをRaspberry Piに接続する
・Raspberry piにi2c LCD接続する