| 前置き |
radix dec
#include <p16f873.inc>
#include "Macros.h"
#define I2C_ADDRESS 3 ;I2Cのスレーブアドレス
#define I2C_DATA_LENGTH 10 ;送受信データ長
org h'20'
;変数割り当て
tmpW res 1 ;割り込み時退避用
tmpStatus res 1 ;
i2c_ctrl res 1 ;I2Cコントロールバイト
i2c_data res I2C_DATA_LENGTH ;I2Cデータバッファ
usr_data res I2C_DATA_LENGTH ;ユーザ定義データ
org h'00'
goto Init
org h'04'
goto Intr
;-----------------------------------------------------------
;割り込み時の変数退避/復帰
push macro
movwf tmpW
movff STATUS, tmpStatus
endm
pop macro
movff tmpStatus, STATUS
movf tmpW, W
endm
Macros.hはこちら。
I2C_ADDRESSでI2Cスレーブアドレスを設定します。ここでは3とします。
I2C_DATA_LENGTHはマスタと送受信するデータのバイト数です。本コードでは固定とします。
tmpWとtmpStatusは割り込み時にWレジスタとSTATUSレジスタの値の退避用です。
i2c_ctrlはI2Cセッションの最初にマスタから送られてくるコントロールバイトを格納する変数です。
i2c_dataは送受信データを格納するバッファです。
usr_dataは本サンプルのために用意したユーザ定義変数です。
マスタとやりとりする情報の格納先だと思ってください。
|
|
| 初期化処理 |
;-----------------------------------------------------------
;初期化処理
Init:
bank1
movlf b'00011000', TRISC ;PORTCはSCL, SDAは入力、それ以外は出力
bsf PIE1, SSPIE ;I2C割り込み許可
movlf I2C_ADDRESS, SSPADD ;I2Cスレーブアドレス設定
bcf STATUS, C ;アドレスは上位7ビットなので、左に1ビットシフト
rlf SSPADD, f
bank0
movlf b'00001111', OPTION_REG ;
movlf b'00110110', SSPCON ;I2Cを7bitアドレススレーブモードでイネーブル
movlf b'11000000', INTCON ;割り込み許可
goto Main
初期化処理です。ここではI2C関連の処理のみを抜粋しています。
*SSPADDの設定部分ですが、今見るとわざわざ rlf を使わなくても
movlf I2C_ADDRESS << 1, SSPADD
とすれば良いような気がするのですが、何分半年前に書いたコードなので
何か特別な理由があったのかも知れません(なんてテキトーな・・
|
|
| 割り込みハンドラ |
;-----------------------------------------------------------
;割り込みハンドラ
Intr:
;{
push
;コントロールバイトを受信した場合
bank1
btfsc SSPSTAT, D_A
goto Intr_Data
;//コントロールバイトを受信した場合
Intr_Ctrl: ;if(SSPSTAT == 0){
bank0
movff SSPBUF, i2c_ctrl ; i2c_ctrl = SSPBUF;
movlf i2c_data, FSR ; FSR = i2c_data;
btfss i2c_ctrl, 0
goto Intr_End
; //受信(スレーブ->マスタ)指令の場合,バッファにコピーして最初の1バイトを送信
Intr_Ctrl_SendMSB: ; if(i2c_ctrl<0> == 1){
;!ここでマスタに送りたいデータをバッファにコピー
memcpy usr_data, i2c_data, I2C_DATA_LENGTH
movff INDF, SSPBUF ; SSPBUF = *FSR;
bsf SSPCON, CKP ; SSPCON = true; //クロック引き延ばし解除
incf FSR, f ; FSR++;
; }
goto Intr_End ;}
Intr_Data:
bank0
btfss i2c_ctrl, 0
goto Intr_Data_Write
;//スレーブ->マスタ:次のバイトを送信
Intr_Data_Read: ;if(i2c_ctrl<0> == 1){
movff INDF, SSPBUF ; SSPBUF = *FSR;
bsf SSPCON, CKP ; SSPCON = true; //クロック引き延ばし解除
goto Intr_Data_End ;}
;//スレーブ<-マスタ:データをバッファにコピー
Intr_Data_Write: ;else{
movff SSPBUF, INDF ; *FSR = SSPBUF;
Intr_Data_End: ;}
incf FSR, f ;FSR++;
movlw i2c_data + I2C_DATA_LENGTH;
xorwf FSR, W
btfss STATUS, Z
goto Intr_End
;//送受信完了時
Intr_Complete: ;if(FSR == i2c_data + I2C_DATA_LENGTH){
btfsc i2c_ctrl, 0 ; if(i2c_ctrl<0> == 0)
goto Intr_End
;!ここで受信したデータをバッファからユーザ変数へ
memcpy i2c_data, usr_data, I2C_DATA_LENGTH
;}
Intr_End:
bank0
bcf PIR1, SSPIF ;PIR1 = false; //フラグクリア
pop
retfie
;}
コアの処理です。コメントにほぼ等価なC言語を書いてあるのでこちらを参考にしてください。
ただし<i>は変数のi番目のビットの意味です。
FSRとINDFはPICで間接アドレッシングを行うためのレジスタです。
INDFを読み書きすると、FSRに格納してあるアドレスにある変数が読み書きされます。
|
|
| メインループ |
;-----------------------------------------------------------
;メインループ
Main:
;
;ここでループ処理
;
Main_End:
clrwdt ;ウォッチドッグタイマをクリア
goto Main
;-----------------------------------------------------
end
お決まりのメインループです。
|
|