温度センサ(ADT7410)の制御では、液晶モジュールとは違ったI2C通信手順が必要です。その通信手順を中心に説明します。液晶モジュール制御と異なるところ温度センサのI2C通信制御は、液晶モジュールのそれと大きく異なるところがあります。液晶モジュールの制御は、PICマイコンから液晶モジュールに対してデータを送りつけるだけでした。PICマイコンから動作設定のデータを送ったり、表示文字のデータを送ったりという具合に、データの送信はPICマイコンから液晶モジュールの一方向でした。温度センサ制御の場合、液晶モジュールとは異なります。PICマイコンが温度センサから温度データを取得する場合は、温度センサからPICマイコンにデータを返信してもらう必要があります。このようにI2C通信手順でスレーブからマスターにデータを返信する場合、新しい通信手順が必要になります。そこでこの記事では、温度センサのI2C通信手順について、以下の項目に分けて説明します。温度センサの動作設定のI2C通信手順は、液晶モジュールの設定方法とほぼ同じです。温度データ取得の通信手順スレーブからマスターにデータを返信する必要があります。この場合、今まで出てきた通信手順に加え、新しい通信手順が必要になります。温度センサ(ADT7410)の動作設定を行う場合、動作設定のレジスタ(アドレス0x03)にデータ(1バイト)を書き込むことになります。0x03に動作設定データを書き込む手順は以下のようになります。動作設定のI2C通信手順は液晶モジュールを制御した時とだいたい流れは同じです。以下にその流れを説明します。最初に、I2C通信を開始するために、マスターはスタートコンディションを生成します。次にマスターは、スレーブアドレス7ビット+読み書き指定1ビットの8ビットを送信します。スレーブアドレスは0x48です。動作設定を行うための書き込みですので、「スレーブアドレス+読み書き設定」は以下のように0x90になります。マスターがこの1バイトデータを送信した後、スレーブはACKを返信します。次にマスターは書き込み先のレジスタのアドレスを送信します。動作設定のアドレスは0x03ですので、0x03を送信します。マスターが0x03を送信した後、スレーブはACKを返信します。続いてマスターは動作設定の1バイトデータを送信します。この1バイトの中身については次回の記事で詳細に説明します。マスターが1バイトの動作設定データを送信した後、スレーブはACKを返信します。これで、0x03に設定データが書き込まれましたので、マスターはI2C通信を終了するためにストップコンディションを生成します。この通信手順において、いずれの動作も液晶モジュール制御プログラムの時のI2C通信関数が使用できますので、温度センサの動作設定プログラムはそれらの関数を使用して作成します。繰り返しになりますが、液晶モジュールの制御では、マスター(PICマイコン)からスレーブ(液晶モジュールや温度センサ)にデータを送るだけでした。スレーブが生成するACK/NACK信号は別にして、スレーブからマスターへのデータの流れはありませんでした。ところが温度データを取得する場合、温度センサからPICマイコンへデータが送信されることになります。このようなスレーブからマスターへのデータ送信手順は初めて出てきますので、最初に概要を説明します。温度センサが測定した温度データは、温度センサのメモリマップのアドレス0x00と0x01に格納されています。この0x00と0x01のデータを読むには、人間に近いやり取りで表現すると以下のようになります。マスター(PICマイコン)からスレーブ(温度センサ)に「0x00番地からデータを送って!」と伝えるスレーブがマスターに0x00番地に格納されている1バイトデータを送る続いてスレーブがマスターに0x01番地に格納されている1バイトデータを送る(1)でマスターがスレーブに対して読み取るアドレスを指定すると、(2)ではそのアドレスのデータ、(3)ではその次のアドレスのデータ、というようにスレーブは指定されたアドレスから順次データをマスターに返信します。次に、このやり取りをI2C通信に近いやり取りで表現すると以下のようになります。マスターからスレーブに、読み取るデータの開始アドレスである「0x00」を書き込むマスターが、スレーブから0x00番地のデータに格納されているを読み取るマスターが、スレーブから0x01番地に格納されているデータを読み取るこのやり取りが、実際のI2C通信手順ではどうなるか考えてみます。I2C通信手順では、スタートコンディション生成の直後に、必ずスレーブアドレス(7ビット)と読み書き指定(1ビット)を送信します。上の手順で(1)はマスターからスレーブにデータを書き込むわけですから、この読み書き指定の1ビットは「書き込み(0)」となります。(2)と(3)ではマスターがスレーブからデータを読み取っています。(2)と(3)は読み書き指定の1ビットは「読み取り(1)」になるはずですが、(1)で書き込み指定していますので、矛盾が出てきてしまいます。そこでこのような矛盾がないように、このようなケースでは、(1)と(2)の間で再度スタートコンディションを発行して通信の仕切り直しをします。以下は、上の(1)から(3)のやり取りのI2C通信手順詳細について、マスターとスレーブ間でのやり取りを図解したものです。通常のI2C通信では、スタートコンディションから始まりストップコンディションで終わります。上のやり取りのように書き込みと読み取りが混在する場合、読み取りの通信と書き込みの通信の間に、再度スタートコンディションを発行します。そのスタートコンディションで読み取り指定を行い、実際にデータの読み取りを行って、最後のストップコンディション生成で終わります。このように、通信途中で生成するスタートコンディションのことを「リピートスタートコンディション」(スタートコンディションの繰り返し)と呼びます。リピートスタートコンディションといっても、SCL/SDA信号はスタートコンディションと同じです。PICマイコンのI2Cモジュールは内部処理の関係でリピートスタートコンディションの生成はスタートコンディションの生成とは別に用意されています。そのため、リピートスタートコンディション用のI2C通信関数を作成しておくことにします。読み取り通信では、データはスレーブからマスターに送信されますので、データ受信の状態(データが正しく受け取れたか)をマスターからスレーブに返信する必要があります。マスターからスレーブにACK/NACK信号を返信する処理も必要ですので、マスターのACK/NACK返信用のI2C通信関数も作成します。いうことで上の通信を「リピートスタートコンディション」に修正すると以下のようになります。読み取り通信の最後にマスターからスレーブにACKではなくNACKを返信します。これはデータの読み取りが最後であることを意味しています。最後にデータシートのI2C通信手順を確認しましょう。以下の図はデータシートの記載されている、温度データを読み取るI2C通信手順です。今までの説明と合わせて、納得できるまで通信手順を追ってみてください。このデータシートではストップコンディションがありませんが、おそらく書き忘れだと思います。関数の作成I2C通信のデータ読み取りでは、以下の新しい処理が必要です。そのためこれらの関数を作成しておきます。リピートスタートコンディション生成リピートスタートコンディションを生成するには、SSP1CON2レジスタのRSENビットを1にします。RSENに1を設定すると、(勝手に)PICマイコンがSCL信号とSDA信号を制御してスタートコンディションを生成してくれます。RSENを1にしてからPICマイコンがスタートコンディションの生成を終えるまで、待ってあげる必要があります(待たずに割り込みで処理する方法もありますが、処理が難しくなるので実践編では待つことにします)。PICマイコンはスタートコンディションの生成を終えると、「SSP1IF」というレジスタを1にしてくれます。スタートコンディションを生成するには以下の手順になります。SSP1IFを0にしておくSSP1CON2のRSENを1にするSSP1IFが1になるのを待つ(=PICマイコンがスタートコンディションの生成を終えるのを待つ)SSP1IFを0に戻しておくこれをプログラムにすると以下のようになります。この関数は引数、返り値はありません。マスターのスレーブからのデータ受信マスターがスレーブから1バイトのデータを受信するには以下の手順になります。SSP1IFを0にしておくSSP1CON2のRCENを1にするSSP1IFが1になるのを待つ(=PICマイコンが1バイトのデータ受信を終えるのを待つ)SSP1IFを0に戻しておくこの時点で受信したデータはSSP1BUFレジスタに格納されているこれをプログラムにすると以下のようになります。この関数は引数はなく、返り値は受信した1バイトデータです。マスターからスレーブへのACK/NACK返信マスターからスレーブに対してACK信号を生成するには、SSP1CON2レジスタのACKDTとACKENを使用します。Data)はACKかNACKかを指定します。ACKの場合は0、NACKの場合は1をセットします。Enable)に1をセットすると、PICマイコンのI2C通信モジュールがACK/NACK信号を生成してくれます。以下はACK/NACK信号を生成する手順になります。SSP1CON2レジスタのACKDTにACKの場合は0、NACKの場合は1をセットするSSP1CON2レジスタのACKENを1にセットするSSP1IFが1になるのを待つ(=PICマイコンがスタートコンディションの生成を終えるのを待つ)関数の引数をACKかNACKにして1つの関数で対応する方法がありますが、ACK返信とNACK返信の2つの関数にしました。深い意味はありません。