; Copyright 2005 Yasuhiro Kanzaki ; Filename: f877110SSP01.asm リスト11-1 * list p=16f877A ; プロセッサを定義する #include ; インクルードファイルを読み込む __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _HS_OSC & _LVP_OFF ORG 000h ; リセット時の開始アドレス goto main ; 初期化ルーチン関連の初期化 main bsf STATUS,RP0 ; バンク1を選択 clrf TRISD ; ポートDを出力として設定する bcf OPTION_REG,NOT_RBPU; ポートBのプルアップ イネーブル ;タイマ0の初期化 bcf OPTION_REG,T0CS ; タイマ0 プリスケーラ256 bcf OPTION_REG,PSA ; プリスケーラはタイマ0 bcf STATUS,RP0 ; バンク0を選択 clrf PORTD ; ポートDの出力をクリア ; SSPモジュールの初期化 call sspinit ; SSPモジュールを I2Cで初期化 ; EEPROMへの書き込み call strc ; スタート・コンディション movlw b'10100000' ; call addsnd ; アドレス送信 1010000+0 movlw 01h ; メモリ・アドレス014Chを設定 メモリの範囲内なら何処でも可 call sdax ; メモリ・アドレスもデータとして送信,上位バイトの送信  movlw 4Ch ;  call sdax ; 下位アドレスの送信 movlw 42h ; 42hをデータとしてメモリに書き込む call sdax ; 2バイトのメモリ・アドレスに続いて書き込みデータを送信 movlw 32h ; 次に32hのデータをメモリに書き込む call sdax ; サブルーチンで送信 call stpcon ; ストップ・コンディションを開始し完了後戻る movlw d'150' ; 0.1ms単位のタイマで150msの時間待ち call tm01 ; LCDのテスト・プログラムで作ったタイマ 実際の書き込みのための時間待ち ; EEPROM 読み取り call strc ; スタート・コンディションから始める movlw b'10100000' call addsnd ; メモリ・アドレス指定するのでR/-W=0とする movlw 01h ; 書き込みのときと同じアドレスを2バイト送信する call sdax ;  movlw 4Ch call sdax call rstrc ; 読み取りのモードに変更するため繰り返しスタート・コンディションを開始する movlw b'10100001'; R/-W=1 とする call addsnd ; スレーブ(EEPROM)に再度アドレス・メッセージを送信する call sdar ; マスタがEEPROMからデータを読みACKを返す btfss PORTB,0 ; DIPスイッチの状態をチェックしb0がONなら次で出力 movwf PORTD ; 受信したデータをポートDのLEDに表示 call lsdar ; 最後のデータを受信  btfsc PORTB,0 ; DIPスイッチの状態をチェックしb0がOFFなら次で出力 movwf PORTD ; 受信したデータをポートDのLEDに表示 call stpcon ; ストップ・コンディションを開始し完了後戻る nlop goto nlop ; 何もしないことを繰り返す ;SSP I2C マスター設定  sspinit bsf STATUS,RP0 movlw d'24' ; 100KHz movlw d'2'で約1MHz movwf SSPADD ; ボーレートの設定完了 movlw 080h movwf SSPSTAT ; I2C 標準速度 100KHz bsf TRISC,3 ; SCL ディジタル・ポートを入力に設定 bsf TRISC,4 ; SDA ディジタル・ポートを入力に設定 bcf STATUS,RP0 movlw 028h ; SSPEN ON マスタ・モード movwf SSPCON return ; スタート・コンディション strc bsf STATUS,RP0 ; バンク1設定 bsf SSPCON2,SEN ; スタート・コンディションを開始 coplchk btfsc SSPCON2,SEN ; スタート・コンディションの完了チェック goto coplchk ; bcf STATUS,RP0 return ; 繰り返しスタート・コンディション rstrc bcf PIR1,SSPIF banksel SSPCON2 ; SSPCON2のバンクを選択する MPASMに対するディレクティブ bsf SSPCON2,RSEN ; 繰り返しスタート・コンディションを開始する rstrclp btfsc SSPCON2,RSEN ; 完了のチェック goto rstrclp bcf STATUS,RP0 ; バンク0選択 return ; アドレス送信 addsnd movwf SSPBUF ; Wレジスタに設定された,スレーブに対するアドレス・メッセージをセット bcf PIR1,SSPIF ; SSPIFフラグをクリア オンを待つため adrep1 btfss PIR1,SSPIF; SSPBUFから送信が完了し,ACKの受信タイミングでSSPIFがオン goto adrep1 return ; データ送信 sdax bcf STATUS,RP0 ; バンク0を選択 bcf PIR1,SSPIF ; 割り込みフラグをクリア movwf SSPBUF ; 送信データをセット sdaxrp btfss PIR1,SSPIF; 完了後 goto sdaxrp ; 割り込みフラグ オンを待つ return ; マスタのデータ受信処理 sdar bcf PIR1,SSPIF ; データ受信 banksel SSPCON2 ; bsf STATUS,RP0でバンク1設定と同等 bsf SSPCON2,RCEN; データ受信スタート sdarlp1 btfsc SSPCON2,RCEN; データ受信完了 goto sdarlp1 bcf SSPCON2,ACKDT; ACK=0に設定 bsf SSPCON2,ACKEN; ACKを送信できるようにする sdarlp2 btfsc SSPCON2,ACKEN;ACKの送信完了を待つ goto sdarlp2 banksel SSPBUF ; バンク0を設定 movf SSPBUF,W ; Wレジスタに受信データを取り出す return ; 最終データ受信として NACKを返すそれ以外は sdar と同一 lsdar bcf PIR1,SSPIF banksel SSPCON2 bsf SSPCON2,RCEN sdarlp5 btfsc SSPCON2,RCEN goto sdarlp5 bsf SSPCON2,ACKDT ; ACK=1に設定 No ACKとなる bsf SSPCON2,ACKEN sdarlp6 btfsc SSPCON2,ACKEN goto sdarlp6 banksel SSPBUF movf SSPBUF,W return ; ストップ・コンディション stpcon bcf PIR1,SSPIF ; ストップ・コンディション処理 banksel SSPCON2 ; バンクを選択 bsf SSPCON2,PEN ; ストップ・コンディションを開始 stplp btfsc SSPCON2,PEN ; 完了チェック goto stplp ; 繰り返し banksel PIR1 ; バンク選択 bcf PIR1,SSPIF ; フラグをクリア return ;タイマ処理サブルーチン0.1ms  255 tm01 bcf INTCON,T0IF ; タイマ0の割り込みフラグをクリア sublw 0FFh ; (0FFh-Wレジスタの値)をWレジスタにセット movwf TMR0 ; Wレジスタで受け取った値をカウントアップするようTMR0をセット stmlp btfss INTCON,T0IF ; カウントアップを待つ goto stmlp ; bcf INTCON,T0IF ; return end