コンピュータの温度センサーとしてよく使われている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接続する
