PIC解説

【PIC】I2C通信のやり方

投稿日:2020-04-01 更新日:

マイコンでLチカが出来たら次はLCDに文字を表示したり、色々なセンサーを扱いたいですよね。今回はマイコンと周辺機器の通信によく使われるI2C通信のやり方をちょっとだけ詳しく解説していきます。

I2C通信とは

I2C (IICやI2Cとも) とはInter-Integrated Circuitの略で、”あい すくえあーど しー”と読みます。普段は面倒なので”あい つー しー”って呼びますけどね。I2C通信の特徴は、

  • SDA (Serial Data) とSCL (Serial Clock) の2本の線だけで通信ができる
  • 複数のデバイスを同一の線に接続できる(複数のデバイスがあっても線は2本だけ)

といったところですね。I2Cと並んでよく使われる通信方式にSPIがありますが、そちらはデバイスごとに1本ずつ追加で線が必要になるので、ピンの少ないマイコンではI2C通信の方が便利なことが多いと思います。

通信フォーマット

I2C通信では通信する2者のうち一方がマスター、他方がスレーブとなり、マスターがクロックを生成して通信を制御します。I2C通信には7-bitモードと10-bitモードがあるのですが、一般的に使われるのは7-bitモードの方なので、今回はそちらで説明していきます。

また、クロックの周波数は規格化されていて100 kHzか400 kHzで通信を行います。

通信のフォーマットはこのようになっています。

マスターがスタートコンディションを送信し、その後7 bitsのスレーブアドレスと1 bitのRead/Write (Read:1  Write:0) の8 bitsを送信したら、スレーブからACK (Acknowledge) が返ってきます。

その後は8 bitsのデータを送信したらACKを返信するサイクルを繰り返します。図では2サイクルしか描いていませんが、もっと連続して通信することも可能です。

受信のときは最終データを受信したらNACK (Not Acknowledge) を返信して最終データであることをスレーブにつたえます。

データの送受信が完了したらマスターがストップコンディションを送信して通信を終了します。

関連レジスタ

PICでI2C通信をするときには、MSSP (Master Synchronous Serial Port) モジュールを使います。型番によってはMSSPを搭載していないものもあるので買う前にデータシートで確認しましょう。また、MSSPを2つ搭載してあるものもあります。

以下のレジスタのxはMSSPが1つの場合には無視、2つあるときは1か2に読み替えてください。

ここでは各ビットの簡単な説明はしますが、使わないところは本当に簡単な説明しかないので、詳しく知りたい方はご自分で調べてください。また、マスターとして使うときの初期化の例も紹介します。

SSPxSTAT

各ビットの説明

SMP (SPI Data Input Sample bit)
1:スルーレート制御無効化(100 kHz) 0:有効化(400 kHz)

CKE (SPI Clock Edge Select)
1:SMBus互換入力有効化0:無効化D/A (Data / Adress)
1:受信データ=データ0:アドレスP (Stop)
1:ストップコンディション検出0:未検出S (Start)
1:スタートコンディション検出 0:未検出R/W (Read / Write information)
(スレーブの場合)
1:Read受信 0:Write受信
(マスターの場合)
1:送信中 0:レディUA (Update Adress)
(10-bitモードのみ)
1:更新必要 0:不要BF (Buffer Full Status)
1:データ転送中 0:転送完了

MSSPモジュールはSPI通信も可能なのでSPIと名前のついているビットもありますが、I2C通信時も使うビットとなっています。SSPxSTAT (SSP Status) レジスタは通信状態を管理するレジスタですが、マスターの場合は自分で通信を制御するのであまり重要ではありません。

設定が必要なのはSMPのみです。100 kHzで使う場合には1、400 kHzで使う場合には0に設定します。
今回は100 kHzで使いますので、

SSPxSTAT = 0x80;

としておきます。

また、プログラム中ではR/Wビットを確認して送信完了を待つのにも使います。

SSPxCON1

各ビットの説明

WCOL (Write Collision Detect)
1:衝突発生0:正常SSPOV (Receive Overflow Indicator)
1:オーバーフロー発生0:正常SSPEN (SSP Enable)
1:MSSPモジュール有効化0:無効化CKP (Clock Polarity Select)
1:ストレッチオフ0:オンSSPM (SSP Mode Select)
1110:I2Cスレーブモード7ビットアドレス 割り込みあり1000:I2Cマスターモード0110:I2Cスレーブモード7ビットアドレス
※他にもモードはあるが割愛

SSPxCON1 (SSP Control 1) レジスタはMSSPモジュールを制御するレジスタで、ここで設定が必要なのはSSPENとSSPMの2つです。SSPEN:1、SSPM:1000とすれば良いので、

SSPxCON1 = 0x28;

とすれば良いでしょう。

SSPxCON2

各ビットの説明

GCEN (General Call Enable)
1:同胞検出許可 0:禁止ACKSTAT (Acknowledge Status)
1:ACK未受信 0:受信済みACKDT (Acknowledge Data)
返信するACK設定
1:NACK 0:ACK

ACKEN (Acknowledge Sequence Enable)
1:ACKDTビットを返信(返信後自動クリア)

RCEN (Receive Enable)
1:受信許可 0:禁止PEN (Stop Condition Enable)
1:ストップコンディション送信(送信後自動クリア)

RSEN (Repeated Start Condition)
1:リピートスタートコンディション送信(送信後自動クリア)

SEN (Start Condition)
1:スタートコンディション送信(送信後自動クリア)

SSPxCON2レジスタは実際に通信を制御するときに使用するレジスタで、初期化で設定すべきことはありませんので、

SSPxCON2 = 0x00;

としておきましょう。

SSPxCON3

各ビットの説明

ACKTIM (Acknowledge Time Status)
1:ACK中 0:非ACK中PCIE (Stop Condition Interrupt Enable)
1:Stop割り込み許可 0:禁止SCIE (Start Condition Interrupt Enable)
1:Start割り込み許可 0:禁止BOEN (Buffer Overwrite Enable)
1:バッファ上書き許可 0:禁止SDAHT (SDA Hold Time Selection)
SDA保持時間
1:300 ns以上 0:100 ns以上SBCDE (Slave Mode Bus Collision Detect Enable)
1:スレーブバス衝突検出有効化 0:無効化AHEN (Adress Hold Enable)
1:アドレス保持有効化 0:無効化DHEN (Data Hold Enable)
1:データ保持有効化 0:無効化

SSPxCON3は主にスレーブのときに使用するレジスタで、マスターのときには特に使用しないので、

SSPxCON3 = 0x00;

としておきます。

SSPxADD

スレーブのとき:

SSPxADD<7:1> の7 bitsにスレーブアドレスを設定することができます。

マスターのとき:

マスターのときはアドレスとは関係がなく、クロックの周波数の設定に使われます。

 周波数 = Fosc / (4 * (SSPxADD<7:0> + 1 ))

という計算式ですので、

 SSPxADD = (Fosc / (4 * 周波数)) - 1;

となります。

SSPxBUF

SSPxBUFは通信に使用するバッファです。ここにデータを書き込めば勝手に送信してくれます。受信したデータもここに格納されます。

SSPxMSK

SSPxMSKはスレーブのときに受け取ったスレーブアドレスにマスクをかけて自分のアドレスと照合できるようです。
正直使い道が分かりませんが…

I2C制御ライブラリ

続いてこれらのレジスタを使ってI2C通信を制御するライブラリを作成します。1から作るのも良いですがすでに多くの方がネットでライブラリを公開されているので、それをベースに作ろうと思います。

最後にまとめたものを掲載するので、過程はどうでもいいという方は下の方にスクロールしてください。

参考にしたのはこちらのサイトです。I2C通信について細かく書かれていますが、英語をたくさん読むのは面倒なので下の方にあるサンプルプログラムだけ頂いちゃいましょう。

頂いたプログラム

プログラムの内容は上記のレジスタの説明を見れば理解できるかと思います。

とても簡潔ですばらしいのですが、このライブラリはPIC16F877A用に作られているので、自分の環境に合わせてカスタマイズしていきます。

今回はPIC16F18326でMSSP2を使います。

変更点

  • 2行目SSPCON → SSPCON1 (これはミスだと思うのですが…)
  • 全体SSP → SSP2
  • 5行目0 → 0x80
  • 6,7行目 → 削除 (main関数で初期化する)
  • 14行目SEN → SSP2CON2bits.SEN
  • 18行目RSEN → SSP2CON2bits.RSEN
  • 22行目PEN → SSP2CON2bits.PEN
  • 35行目 (a)?0:1 → a

主にはMSSPモジュールが2個あることへの対応です。全体のSSPをSSP2に変えるのは、エディタの置換機能で全て置換してしまうと良いです。35行目に関しては、aが0なら1を代入し、1なら0を代入するというのが、直感的ではないと感じたのでaをそのまま代入するようにしました。

これでちゃんと動くと思うのですが、私の環境では動きませんでした…

色々試してみた結果、デフォルトのピンに明示的に割り付けを設定すると上手くいきました。下記プログラムの11~14行目です。
//理由は分からないけどとりあえず動いてるからヨシ
はプログラマーの定番ですよね?この部分の解説はしませんが、もしも私と同様に上手くいかない場合は試してみてください。

以下が完成したライブラリです。

i2c.cとi2c.hをプロジェクトにインポートして、i2c.hをインクルードすればライブラリが使えるようになります。よく分からない場合はi2c.cの関数をmain.cにコピペしても問題ありません。

ここまで来たら気を付けなければいけないのはあと1つだけです。

変更前のライブラリにも書いてありましたが、SDAとSCLはデジタルで”入力”にしないといけません。

それでは次回はこのライブラリを使ってLCDに文字を表示したいと思います。https://rikeden.net/?p=81センサーなどから値を読み取りたい場合にはこちらも参考にどうぞ。https://rikeden.net/?p=233

-PIC解説

執筆者:


  1. Kontrol より:

    貴重な記事ありがとうございます。

  2. 子華 より:

    アドレスマスク(SSPxMSK)は、
    複数スレーブへの同時配信時に使用します。
    (アドレスの割り振り方に工夫が必要です)

    マスクされたアドレスビットがDon’t careとなり、
    マスクされていないアドレスビットのみの一致で
    自分への配信とみなすことができるようになります。

comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


関連記事

【PIC】ADCの使い方 サーミスタで温度測定

今回はADC (Analog to Digital Converter) の使い方を解説します。PICのIOピンは通常デジタルの入出力しか出来ませんが、ADCを使用することでアナログ入力(電圧測定)を …

PICでUSARTに四苦八苦

今回はパソコンとのシリアル通信に挑戦しましたがなかなか苦労しました。最初に結論だけ言うと、 マイコンのTXは相手のRXに、RXはTXに! 逆に接続するよ! ってことでした。それでは本文↓   …

【PIC】ぷちFatFsでmicroSDカードと通信する

今回はPICでmicroSDカードを使用する方法を紹介します。なお、microSDじゃなくて普通のSDカードでも同様にできるはずです。 以下microSDカードも含めてSDカードと呼ぶことにします。S …

【PIC】SPI通信のやり方

多くのPICに搭載されているMSSPモジュールを使うとI2CとSPIの2つのシリアル通信を行うことができます。 今回はSPI通信のやり方(マスター)を紹介します。I2Cについてはこちらを参照してくださ …

PIC超入門!ゼロからLチカまでの道【その2:プロジェクト作成~プロパティ設定】

前回MPLAB X IDEを導入したので、今回はプロジェクトの作成から説明していきます。 前回の記事はこちらhttps://rikeden.net/?p=336 目次1 プロジェクトの作成2 プロパテ …