↑ 14ピンPIC用汎用基板モジュール
  ソケットには16F1705を挿入
  最近良く使用します



↑ RA4、RA5に差し込むLED
  実験やデバッグ等に便利
  LED1個の物も存在します



↑ 4ビット分のタクトスイッチ
  基板上でプルアップされています



↑ 構成を回路図化したもの
  回路図と言うほどの物では無いですが
  プルアップ抵抗はPIC基板では無く、
  SWモジュール内に存在します



↑ PIC基板にLED・SW基板を装着
  タクトSWはRC0とRC1に接続
  SCL・SDAバスに接続した形です
  SWでスレーブからのACKを模します



↑ RC1(SDA)ラインのSWを押した
  これによりACKを送出したつもり
  LEDがちゃんと読まれて反応しています
PIC16F1705のI/Oポート

以前から素朴な疑問が心にくすぶっていたのですが・・・

PICのマニュアルを読むと、PORT書込み命令に対する動作はREAD-MODIFY-WRITE
であると記載されています。
つまり、BCF命令等でPORTに書き込むと、該当PORTを読んでから変更して出力する、
と言う事と解釈していました。
書込みですから、当然該当TRISビットはクリア状態です。
つまり、PORTを出力設定状態で、読み込み命令を実行したら、
該当PORTの状態をちゃんと読み込みできるのか
さらに16F1705はODCONレジスタでPORTをオープンドレイン出力に設定できます。
と言う事は、I/Oポート出力設定のままで、手動I2Cバス制御できるのでは?



汎用実験基板を使ってI/Oポートの実験してみる

今回も14ピン用汎用PIC基板を使用しました。
それと、LEDモジュールと4ビット分のタクトSWモジュールです。
LEDモジュールの動作
RA4 出力で赤色LED発光
RA5 出力で緑色LED発光
タクトSWモジュールの動作
タクトSWはプルアップされており、SWオンでラインがGNDとなります。

条件
RC0、RC1をそれぞれデジタルI/O、出力モード、オープンドレインモードに設定
RC0、RC1でLATC1=1に設定
そのままでRC1ビットを読み込み、LEDで状態表示
RA4,RA5はデジタル出力

プログラム
RC1のビットを読み込み、1なら赤LED発光、0なら緑LED発光

結果
RC1ラインのSWを押す(RC1=0)と緑LED発光、
離す(RC1=1)と緑LED発光
これでデジタルポートが出力状態のまま、同ポート読み込みができている様に見える。
う~む、ならばこの状態でI2Cバス制御が概ね可能と思われます。

使用したテストプログラムはサンプル1のソース内「TEST1」です。

↑ 動作用の回路図
  これも超簡単回路です
  サンプル1、2両方で使いますが
  サンプル1では、クリスタルとSW使用
  サンプル2では使用していません


サンプルプログラム 1

ソースファイル

PIC16F1705_TM1637_test01.asm

使用ツール
 MPLAB'X IDE Ver3.05
 MPLAB'X IPE Ver3.05
 PICKIT3




↑ サンプル1 実行
  時:分表示ですが、電源投入したばかり
  0分となっています
  ドットが1/2の確率で映らない



↑ サンプル1実行
  SWを押して分:秒表示させた所
  電源投入したばかりなので、
  19秒と表示されています



↑ RA4、RA5ピンに差し込む水晶基板
  時計用の32,768KHZです
MSSPモジュールを使用しないで、I2Cモジュールを動かしてみる

と言う訳でここからが本題、I2Cマスタ送信用低レベルルーチンの実験をしてみます。
とりあえず、前回使った、GROVE4桁7セグLEDを動かしてみます。
ここで作成するのは低レベルルーチンのみで、プログラム全体は前回の、
MSSPモジュールを使用した時のプログラムを、そのまま流用します。

実験結果
一見問題無く動作します。
I2Cバスビット間やその他のディレイは、どの位にすれば良いか不明だったので、
マクロを使用しました。
これで、マクロ定義を変更すれば、すべての同じディレイを一気に変更できます。
実験的に、10us以下ではTM1637は動作しませんでした。
遅い分には問題無い様です。
これで、TM1637は1パルス幅は10us以上必要と言えそうです。
これはACKの反応やコマンド間でも、ほぼ同じと思います。(注1)
ACKでは、最後のデータビットを送出後、SCLラインをLとし、SDAラインをHとします。
すると、TM1637はACKを返してきますので、SDAはLとなります。
その後、PIC側でSCLラインをHとしても、SDAラインは強制的にLのままです。
さらにその後、SCLをLとすると、ACK応答は終了し、SDAラインは解放されます。
これで、1バイト転送は終了と言う事になるようです。
まさにPICマニュアルのマスタ送信説明図と同じ動作です。
I2Cバスを考えた人って、頭良いですね、素晴らしい  (^^ゞ
これらの実験は、PICKIT3のインサーキットデバッグ機能を使用し、ステップ動作で
のんびりバスラインを見ながら行いました。
オシロを使用しなくとも、バスライン動作を間接的に確認でき、面白いです。

注1)
AQM1602Aでは単なるコマンド間(コマンド種類でも)やデータ間では、それぞれ
必要ディレイが違っていましたが、TM1637は割と一律でした。



サンプルプログラム1 GROVE 4桁LEDモジュールを使用した時計

今の所は、ただの経過時計なのですが、0秒~59分59秒まで、
あるいは0分~23時59分までを結構正確に表示します。
なぜ「正確」なのかは、時計用水晶モジュールを使用したからです。
RA3をGNDに落とすと、00分:00秒表示となります。
RA3オープン(プルアップ)で、00時:00分表示となります。
時刻校正用プログラムを追加すれば、普通のデジタル時計として使えます。

当初は内部発振を分周して、約1秒を作るつもりだったのですが・・・
システムクロック32MHZでは、単純に考えてもタイマ1でも無理
内部発振のLFINTOSCの31KHZをタイマ1クロックソースにと思ったのですが、
システム動作用のHF(MF)INTOSCと共存は不可と判明
タイマ1とタイマ0を使えば良いかなとも思ったのですが・・・(注1)
せっかく存在する、タイマ1専用発振回路を使用する事にしました。
CPU基板に接続する水晶モジュールも超簡単で数分で製作できますしね。
システムクロック用発振回路は同じピン使用の関係で共存しませんが、問題無いです。
システムは内部発振32MHZ、タイマ1は専用回路で32.768KHZ水晶発振と言う構成に。
よって、システムは高速動作、タイマ1はのんびりカウントが簡単に実現。(注2)

プログラムは、タイマ1によるインタバル割込みでカウントアップ・表示させます。
それだけではつまんないので、1秒サイクルで、ドットが点滅する様にしました・・・
どのみちつまんない事には変わりありませんが・・・


注1)
システムクロックを2MHZ程度まで落とせば、タイマ1クロックソースをFOSC/4に選択して、
簡単かつ十分対応できそうです。
単に、時計用の小さな水晶振動子がジャンク箱にいっぱい転がっていたのと、
タイマ1専用発振回路を使ってみたかった、ただそれだけです・・・ m(__)m
何せ今まで、使用する用途が無かった・・・

注2)
シミュレーション・デバッガではどの様に設定すれば実現できるかが解りませんでした。
PICKIT3を使用した実機デバッグも、プログラムステップ動作とタイマ1動作が
まったく同期しないので、デバッガの「ステップ動作」は意味が無かった、と言うより
変な動作になってしまい、デバッグどころの話では無くなりました・・・
結局、デバッガによるデバッグは無しでのプログラミングとなりました。
使用ルーチンは単純かつ使い回ししているので、とりあえず動作はしていますが・・・
一応、デバッグ用プログラムで疑似的に割り込みルーチンを呼び出す形にして、
簡単な動作確認はしていますが・・・
当局の事だから、どこかに単純ミスがあるかも。


↑ サンプル2実行   AQM1602に文字表示


ソースファイル

PIC16F1705_I2C_test02.asm

使用ツール
 MPLAB'X IDE Ver3.05
 MPLAB'X IPE Ver3.05
 PICKIT3
サンプルプログラム2 AQM-1602XAを動かしてみる

これはプログラム自体は前出の、PIC16F1823MSSPモジュールを使用したのと同じです。
サブルーチン名を変えず、低レベルルーチン内容のみ入れ替えました。
つまり、MSSPモジュール部分を削除し、I/O操作のみとしました。
今の所、受信部分が無いので、極めてシンプルになりました。
パーティーラインを意識しなくても良いならば、MSSPは要らないのでは?
つまり、バスに1人しか乗っていないのなら、今回の手動I/O操作の方が簡単かな。
今回は、PIC16F1705のI/Oピン・オープンドレイン切替機能を使用していますが、
今回程度の制御レベルならば、オープンドレイン機能の無いPIC16F1823等でも
I/O入出力切替をこまめにすれば、実現可能と思われます。
安価・高機能・大容量・・・う~む・・・
当局内では、PIC16F1705が1番のお気に入りPICとなりつつあります・・・



I2Cバス制御 低レベルサブルーチン
 今回使用した、I2C制御ルーチンです
 PICがマスタ、送信のみとなります。
 プログラム詳細は、ソースファイルを参照して下さい。

(1)STARTCON:スタートコンディションを送信します
  基本は、SCL=1の時にSDAを1から0にすると、スタートとなります。
 1)SCL=SDA=1の状態で、SDA=0とします。
 2)その後、SCL=0として終了

(2)SEND_BYTE:データを送信します
  基本はSCL=0の時にSDA値を出力させ、SCL=1の時のSDA値が確定情報となります。
 1)SCL=0の時にデータビットをSDAに出力
 2)そのまま、SCL=1、DELAY、SCL=0と変化させる
 3)これを8回繰り返す。
 4)SCL=0の時にSDA=1とする。
 5)その後、SCL=1とし、強制的にSDA=0となる事(ACK)を確認
 6)その後、SCL=0とし、終了

(3)STOPCON:ストップコンディションを送信
  基本はSCL=1の時にSDAを0から1にするとストップとなります
 1)SCL=0の状態でCDA=0とします。
 2)その後、SCL=1と、これがストップコンディションとなります。
 3)その後、SDA=1とし、バスアイドル状態とします




その他・追記等

受信につきましては、PIC同士で実験しようかと思ったのですが、
「本物」のスレーブの挙動が当局自身よく解っていないのと、 
PIC同士の相互通信なら、SPI接続の方が良さげな感じがします。
I2C接続センサモジュール等入手したら、それに絡めて実験してみたいと思います。


追記 2017年03月

PIC16F1705でMSSPモジュールによるI2C制御を行うには、
PPSモジュールの設定が必要となります。
PIC16F1823の様にMSSPをイネーブルにしただけでは動作しない場合があります。
下記ページを参照してください

 MSSPモジュール基本ルーチン群のまとめ
戻る  実験・製作の記録TOPへ戻る