SSブログ

I2Cを使う PIC16F876A PCF8574AN

お客様の案件で I2C を使う回路設計の必要が在りました
はい、過去形ですが実は没に成って仕舞った案件です
然し乍ら設計者のさがで一度始めると納得行くまでやって仕舞う
この悪い癖、何とかしなければならないのですが・・・・

でも、やって置けば其れだけ後々何かの役に立つ事も有るでしょう
という訳でドキュメントを残す意味で簡単な回路を組んでみました
まず、使用するICは・・・・

CPU が PIC16F876A  28pin Dip MICROCHIP社
日本語マニュアルが用意されているので製作記事が多いです
このPICにはMSSP(Master Synchronous Serial Port)が内蔵され
これがあることでI2Cが利用しやすいわけです
他のデバイスICと高速にシリアル通信をするためのモジュールで、SPIと
I2Cという2種類の動作モードで使うことができます。

F4671628-01

 RC3/SCK/SCLとRC4/SDI/SDA を使います。

bandicam 2018-12-10 11-31-00-992




IO Expander が PCF8574AN TEXAS社
16pin Dip で 8bit I/O です
回路を組む上で注意しなければならない事が有ります
それは出力で使うときの電流値です
Low出力は50mA流せますからリレー動きますよね
ところが
High出力はたったの4mA
LEDを点灯しようとしても昔のLEDだと暗くて話しに成りません
もう一つ押さえておきたいことは入力として使用した場合
OPEN = High だという事です、入力端子の空きピン処理は考慮に
入れて置かなければなりませんね
F5170249-01
pcf8574a-pin
またスレーブアドレスが僅かな型式違いで異なるので知らないと焦ります
驚くのは同じPCF8574Aでもスレーブアドレスが違うって・・・何?
購入するときは良く確認しなければなりません

bandicam 2018-12-07 00-02-28-302

bandicam 2018-12-10 09-41-15-897


どう考えてもおかしい、このスレーブアドレスで設計された記事を
全く見掛けません、マニュアルのダウンロードにもご注意下さい
仮にスレーブアドレス 0x20 とした場合、READ アドレスは 0x21
てなければならない、なのに A0 = High と成ったときに 0x21に
成って居ます、通常は LSBがHigh に成った場合スレーブアドレスは
0x02加算されなければなりません、なんで?
bandicam 2018-12-06 23-59-09-840




これらを使って LEDの点滅、詰まり Lチカ をやってみようと思います
この組み合わせにした理由ですが下記の様な条件が在ったからです・・・

・GPIOを使う
・LEDを50個ぐらい使う
・スイッチを20個ぐらい使う
・メンブレン・パネルに実装したい
・UART / I2C は可能
・SPI はダメ

・・・とこんな条件なのですがGPIOではピン数が限定的でとても
これだけの I/O はカバー仕切れません、その為に IO Expander を採用しました
I2Cにしたのは過去にハードウェアのみ経験しているからです

ところが採用したい I2C のソフトウェアに問題が在るのです
私はめっきりソフトウェアに弱いので皆様のように C言語でサクッ!! っと
プログラミング出来ません、なのでどうするか・・・・

・アセンブラ言語とする
・可能な限りネット検索してプログラムを引っぱってくる
・ブレッドボードを使う

・・・・こんな地味ぃな戦略なのです

2018/12/07(金)
ブレッドボードに仮組みしてみました

DSCN9756

写真で出来て居る事は、出力制御です、8bit 出力の確認をLEDで
行って居ます。
ここで判った事ですが上でも書いたように出力が Low / High で
電流値が大きく異なり、実際のLEDを接続するとこんな感じです。
この写真は出力Highの様子です、LEDは点いているのか消えているのか
良く視ないと判別がつきません
DSCN9752

一方でこの写真は出力Lowの様子で、これが正常ですよね。
DSCN9753

この様にバッファー・ドライバー無しで使うときは注意が必要です
トランジスタ・アレイ程度ならHighでドライブ出来ると思いますが
確認はマストですね。

話が少し逸れますが、使用している PIC KIT3 ですが壊した経緯が
有ります、原因はVDDに +24V が印加された為、PIC KIT3のあの
スケルトンで中が燃えているのが見えました、ひやぁーーー、でした
まぁ回路屋なので回路図をネット検索して探し、壊れて居そうな部品
をRSコンポーネンツで購入し直しました、ですがもう二度とあんな事は
嫌なのでプロテクタを中間に入れて使用しています。
DSCN9772

ツェナーダイオードの大きめのを入れ、抵抗が燃え切れる様にしました
序でなのでPIC KIT3が付いたままだと動かない事、って有りますよね
なので CLK / DAT をスイッチで切れる様にもして居ます、以来
気をつけているのでトラブルは無いですが、また在ると嫌だな。

DSCN9773

ブレッドボードで製作した回路ではプログラムに書かれたHEXデータ
1byte 分をLED表示するというものです
参考にと言うかコピーしたプログラムで引用元はこちらです

ソースコードの窓をこのブログに作りたいのですが面倒なので
後回しです、下記の通りです、折り返しが出ていますので
コピペの後、ご注意下さいこのままだとコンパイルエラーが出ます
因みにコンパイラは MICROCHIP社MPLABXIDEを使って居ます
ここから
;***************************************************************************************************************

;This software is provided in an “AS IS” condition,NO WARRANTIES in any form apply to this software.

; picmicrolab.com 5.31.2014
;***************************************************************************************************************
; PCF8574 I2C  8-bit IO expander interface with PIC16F876A;
;-------------------------------------------------------------------------------------;
		LIST 	P=PIC16F876A
		include	P16f876A.inc

 __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF & _HS_OSC & _LVP_OFF & _DEBUG_OFF & _CPD_OFF

	    org		0x00
reset:	goto start
	    org		0x04
start:

	bcf		STATUS, RP0
	bcf		STATUS, RP1
	movlw		0x28
	movwf		SSPCON
	bsf		STATUS, RP0
	BSF		SSPSTAT, SMP
	BCF		SSPSTAT, CKE
	CLRF		TRISB
	BSF		TRISC, 0x04	;SDA
	BSF		TRISC, 0x03	;SCL
	MOVLW		0x21
	MOVWF		SSPADD
LOOP:	
	BCF		STATUS,RP0
SENDB:
	BCF		PIR1,SSPIF	
;*********************START****************************************************
	BSF		STATUS, RP0	
	BSF		SSPCON2, SEN	; INITIATE START
	BCF		STATUS, RP0
SENDB2:
	BTFSS		PIR1, SSPIF	;START COMPLETED?YES SKIP NEXT
;*********************SLAVE ADDRESS-READ AFTER SETTING WORD ADDRESS*************

	GOTO		SENDB2
	BCF		PIR1, SSPIF	;YES,CLEAR FLAG
	MOVLW		0x40;		;0x40 is the  SLAVE ADDRESS   
	MOVWF		SSPBUF		;INITIATE SEND 
;SLAVE ADDRESS
SENDB3:
	BTFSS		PIR1, SSPIF	;SEND COMPLETED? YES,SKIP NEXT
	GOTO		SENDB3
	BCF		PIR1, SSPIF	;YES,CLEAR FLAG
	BSF		STATUS, RP0
	BTFSC		SSPCON2,ACKSTAT	;ACK RECEIVED FROM SLAVE?IF YES SKIP
	GOTO	 	SENDB5		;IF NO,END 

;*********************SEND Control Byte ****************************
	BCF		STATUS, RP0
	MOVLW		0x55		;Port Data		
	MOVWF		SSPBUF		;BEGIN TRANSMISSION
SENDB4:
	BTFSS		PIR1,SSPIF	;SEND COMPLETED?IF YES SKIP NEXT
	GOTO		SENDB4
	BCF		PIR1,SSPIF	;YES,CLEAR FLAG
	BSF		STATUS, RP0
	BTFSC		SSPCON2,ACKSTAT	;ACK RECEIVED FROM SLAVE?IF YES SKIP
	GOTO		SENDB5		;IF NO,END 
;*********************STOP****************************************************

    	BSF		STATUS,RP0
	BSF		SSPCON2,PEN
	BCF		STATUS,RP0
SENDBI:
	BTFSS		PIR1,SSPIF	
	GOTO		SENDBI
	BCF		PIR1,SSPIF
;*********************SEND NOACK TO END TRANSACTION*****************************
	BSF		STATUS,RP0
	BSF		SSPCON2,ACKDT	;SELECT NOACK
	BSF		SSPCON2,ACKEN	;INITIATE ACKNOWLEDGE SEQUENCE
	BCF		STATUS,RP0
SENDBC:
	BTFSS		PIR1,SSPIF	;ACK SEQUENCE COMPLEMENTED;IF YES SKIP
	GOTO		SENDBC	
	BCF		PIR1,SSPIF
;*********************	INITIATE STOP*******************************************
SENDB5:	
	BSF		STATUS,RP0
 	BSF		SSPCON2,PEN
	BCF		STATUS,RP0
SENDBE:	
	BTFSS		PIR1,SSPIF	
	GOTO		SENDBE
	BCF		PIR1,SSPIF

	goto		LOOP

end

ここまで

スレーブアドレス下記の部分です
MOVLW 0x40; ;0x40 is the SLAVE ADDRESS
LED表示データは下記の部分です
MOVLW 0x55 ;Port Data
プログラムの大まかな流れは
・I2Cの設定
・スタート・コンディションの開始
・スレーブアドレス送信 + WRITE モード
・ACK待ち
・LEDに表示するデータ送信
・ACK待ち
・ストップ・コンディションの開始
・LOOP

これらは全てI2Cの様々な解説に書かれていることです、こちらが参考に成ります

実際のCLK/DATの波形です、上がCLK  下がDAT
何故か同期はビデオだと良く見えました、なんで?
DSCN9754

DSCN9761



---記事制作中---
ブレッド・ボードですが一度作るとそのままにして置く事が多く
本来の何度でも作り直せるという目的から外れてしまうのでここは
ユニバーサル基板に組み付けようという事に成りました

先ずは PIC 基板、ICソケットを使い他のPICにも換えられる様に
しました、特に水晶発振ユニットは無くしたいのでこれも
ICソケットに実装しています
DSCN9765

DSCN9766

この基板は I/O OUT で出力基板です、出力の状態がLEDで判りやすく
してあります、又、スレーブアドレスも自由に変えられるようDIP SW
にしてあります
DSCN9769

DSCN9770

この基板は I/O IN 入力基板です
データを自由に変えたいのでDIGI SW を1byte分用意しました
スレーブアドレスも自由に変えられるようDIP SWです
DSCN9767

DSCN9768

マスターとスレーブを繋ぐケーブルですMOLEX-4P を使いました
DSCN9771

動画は I/O IN を動かして居ます
DIGI SW で読み込んだデータを PIC 基板のLEDでモニタして居ます


I/O IN で使うプログラムは下記の通り
ここから
;***************************************************************************************************************

;This software is provided in an AS IS condition,NO WARRANTIES in any form apply to this software.

; picmicrolab.com 5.31.2014 Modified Dec,6/2018 Maru
; 大まかな流れ
; I2C-BUS 設定 → (LOOP)スタート・コンディション開始 → スレーブアドレス読み出し送信 → スレーブからデータ受信
; → NAC送信 → ストップ・コンディション通知 → LOOP
;***************************************************************************************************************
; PCF8574AN I2C  8-bit IO expander interface with PIC16F876A;
;-------------------------------------------------------------------------------------;
		LIST 	P=PIC16F876A
		include	P16f876A.inc

 __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF & _HS_OSC & _LVP_OFF & _DEBUG_OFF & _CPD_OFF

	    org		0x00
reset:
	goto		start
	    org		0x04
start:
;******************************************************************************
;I2C-BUSの初期設定
	bcf		STATUS, RP0
	bcf		STATUS, RP1	;BANK0 for SSPCON
	movlw		0x28		;0x28 = シリアルポートを動作させ、SDA とSCL ピンをシリアルポートピンにする。
					;0x28 = I2C マスターモード、クロック= FOSC / (4 * (SSPADD+1) )
	movwf		SSPCON
	bsf		STATUS, RP0	;BANK1 for SSPSTAT
	BSF		SSPSTAT, SMP	;1= 標準速度モード(100kHz および1MHz)、スルーレート制御は行わない
	BCF		SSPSTAT, CKE	;0 = I2C 仕様に準拠する入力レベル
	CLRF		TRISB
	BSF		TRISC, 0x04	;SDA High
	BSF		TRISC, 0x03	;SCL High
	MOVLW		0x21		;I2C-BUS speed 値が小さい程早く成る
	MOVWF		SSPADD
LOOP:	
	BCF		STATUS,RP0
SENDB:
	BCF		PIR1,SSPIF	;SSPIF: 同期シリアルポート(SSP) 割り込みフラグ・クリア
;*********************START****************************************************
;スタートコンディション開始
	
	BSF		STATUS, RP0	
	BSF		SSPCON2, SEN	; INITIATE START
	BCF		STATUS, RP0
SENDB2:
	BTFSS		PIR1, SSPIF	;START COMPLETED?YES SKIP NEXT スタート・コンディションが完了したか?
;*********************SLAVE ADDRESS-READ AFTER SETTING WORD ADDRESS*************
;スレーブアドレスを書き込むと同時に読み出し設定を行う
;0x70 は書き込み時のスレーブアドレス、0x71は読み出しのスレーブアドレス
;「読み出しを行う」 と言う 「書き込みを行う」

	GOTO		SENDB2
	BCF		PIR1, SSPIF	;YES,CLEAR FLAG 割り込みフラグ・クリア
	MOVLW		0x71		;0x73 is the  SLAVE READ ADDRESS  スレーブ読み出しアドレス
	MOVWF		SSPBUF		;INITIATE SEND この瞬間に送信される
;SLAVE ADDRESS
SENDB3:
	BTFSS		PIR1, SSPIF	;SEND COMPLETED? YES,SKIP NEXT 送信完了?
	GOTO		SENDB3
	BCF		PIR1, SSPIF	;YES,CLEAR FLAG 割り込みフラグ・クリア
	BSF		STATUS, RP0
	BTFSC		SSPCON2,ACKSTAT	;ACK RECEIVED FROM SLAVE?IF YES SKIP
					; スレーブからの ACK待ち 0=受信済み次ぎをスキップ
	GOTO	 	SENDB5		;IF NO,END 
;*********************READ**********************************************
;スレーブから読み出す
	BSF		SSPCON2,RCEN	;RCEN = 1 受信許可
	BCF		STATUS,RP0
READB1:
	BTFSS		PIR1,SSPIF	;受信完了?
	GOTO		READB1
	BCF		PIR1,SSPIF	;フラグ・クリア
	MOVF		SSPBUF,W	;SSPBUF(読み出したデータ) → W
	MOVWF		PORTB		;W → PORTB に即出力
;*********************SEND Control Byte ****************************
;  PCF8574ANを出力で使うとき使用する
;	BCF		STATUS, RP0
;	MOVLW		0x55		;Port Data		
;	MOVWF		SSPBUF		;BEGIN TRANSMISSION
;SENDB4:
;	BTFSS		PIR1,SSPIF	;SEND COMPLETED?IF YES SKIP NEXT
;	GOTO		SENDB4
;	BCF		PIR1,SSPIF	;YES,CLEAR FLAG
;	BSF		STATUS, RP0
;	BTFSC		SSPCON2,ACKSTAT	;ACK RECEIVED FROM SLAVE?IF YES SKIP
;	GOTO		SENDB5		;IF NO,END 
;*********************STOP****************************************************
;
;	BSF		STATUS,RP0
;	BSF		SSPCON2,PEN
;	BCF		STATUS,RP0
;SENDBI:
;	BTFSS		PIR1,SSPIF	
;	GOTO		SENDBI
;	BCF		PIR1,SSPIF
;*********************SEND NOACK TO END TRANSACTION*****************************
;スレーブに対して NACK (NoACK)を返して受け取った事を通知する
	BSF		STATUS,RP0
	BSF		SSPCON2,ACKDT	;SELECT NOACK			----]
	BSF		SSPCON2,ACKEN	;INITIATE ACKNOWLEDGE SEQUENCE ----]この二つでNACKとる成る
	BCF		STATUS,RP0
SENDBC:
	BTFSS		PIR1,SSPIF	;ACK SEQUENCE COMPLEMENTED;IF YES SKIP NACK送信完了?
	GOTO		SENDBC	
	BCF		PIR1,SSPIF	;フラグ・クリア	
;*********************	INITIATE STOP*******************************************
;ストップ・コンディションの開始
SENDB5:	
	BSF		STATUS,RP0
 	BSF		SSPCON2,PEN	;PEN = 1 ストップ・コンディション開始
	BCF		STATUS,RP0
SENDBE:	
	BTFSS		PIR1,SSPIF	;送信完了?	
	GOTO		SENDBE
	BCF		PIR1,SSPIF	;フラグ・クリア

	goto		LOOP		;繰り返す

end

ここまで
プログラムの流れは下記の様に成ります
・I2Cの設定
・スタート・コンディションの開始
・スレーブアドレス送信 + READ モード
・ACK待ち
・DIGI SWのデータ受信
・PORTBへ出力しLED点灯
・NACK送信
・ストップ・コンディションの開始
・LOOP

READして居る時の波形です、上がCLK  下がDAT
写真の綴り間違えました REEDでは無くREADです
頭の中に Austin Reed が入ってました
DSCN9760

慣れるとオシロスコープの波形でデータが読めますね

2018/12/10(月)朝
回路図が書き上がりました

PCF8574AN_I2C


このままだと拡大しても文字が読めませんね
部分的に分解して視やすくします

bandicam 2018-12-10 08-39-38-092

bandicam 2018-12-10 08-39-46-403



bandicam 2018-12-10 08-39-57-072

2018/12/10(月)夜
PICですがPIC16F876Aを止めPIC16F886にしました、理由は
内部発振回路を使って外付けの水晶発振子を無くしたかったからです
良いことにPIC16F876 と PIC16F886 はピンコンパチなのと内部
レジスタが殆ど一緒、少なくとも今回の評判用に使うレジスタは全く
同じでした。
bandicam 2018-12-10 20-59-12-513


動画はループ・プログラムです。
出力を +1 して繰り返しています、 向かって左が PIC 水晶発振子
が無くなっていますね。
右は IO Expander 、タイマーを入れてわざと遅くしています
PIC側のLEDはモニタとして使用しています
出力側のLEDは逆論理と成って居ます。


プログラムは下記の通り、下手なので笑わないで下さいね
;***************************************************************************************************************
;This software is provided in an “AS IS” condition,NO WARRANTIES in any form apply to this software.
; picmicrolab.com 5.31.2014  
; Modified Dec,10,2018 by maru
;***************************************************************************************************************
; PCF8574 I2C  8-bit IO expander interface with PIC16F876A;
;-------------------------------------------------------------------------------------;
		LIST 	P=PIC16F886
		include	P16f886.inc
;サブルーチンは別ファイルをコール
	EXTERN	TIMADJ,TIM8ms,TIM100ms,TIM500ms,TIM10ms,ADGET,OUT_A,OUT_B,OUT_C,SWON,SWON2
			;別ファイルに存在するサブルーチンのラベル名を宣言する
			;別ファイルでは必ず GLOBAL で受ける、つまり EXTERN と GLOBAL はペア。
; __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF & _HS_OSC & _LVP_OFF & _DEBUG_OFF & _CPD_OFF
__CONFIG  _CONFIG1 , _CP_OFF & _DEBUG_OFF  & _CPD_OFF & _LVP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSCIO & _BOR_OFF
	    org		0x00
reset:	
	    goto start
	    org		0x04
start:
;==============================================
;***	iNTERNAL OSC 設定 ( OSCCON-8Fh )
;OSCINIT
	BANKSEL		OSCCON
	MOVLW   	70h        	;CLOCK=4MHz (70H=8MHzでMAX)
        MOVWF   	OSCCON
       	BCF		STATUS,5	;Back to BANK0
;        RETURN
;==============================================
	;OUTPUT DATA INIT
	BANKSEL		W_TEMP
	clrf		W_TEMP
	movlw		0x00		;DATA -> W
	movwf		W_TEMP		;W -> W_TEMP
;==============================================	
;I2C の為の初期化
;==============================================
	BANKSEL		SSPCON
	movlw		0x28
	movwf		SSPCON
	bsf		STATUS, RP0
	BSF		SSPSTAT, SMP
	BCF		SSPSTAT, CKE
	CLRF		TRISB
;	BSF		TRISC, 0x04	;SDA]
;	BSF		TRISC, 0x03	;SCL]  このオリジナル・プログラムは無くても動く
	MOVLW		0x21		;I2C BUS speed  小さい程早く成る
	MOVWF		SSPADD
;==============================================	
LOOP:
	BANKSEL		W_TEMP
	MOVF		W_TEMP,W	;W_TEMP -> W
	MOVWF		PORTB		;W → PORTB に即出力(モニタとして使用)
	CALL		TIM100ms	;時間正確ではない、他のプログラムのコピー
;==============================================
;LOOP: オリジナル・。プログラムのLOOP位置
	BANKSEL		STATUS
	BCF		STATUS,RP0
	BCF		PIR1,SSPIF
;*********************START****************************************************
	BANKSEL		SSPCON2
	BSF		SSPCON2, SEN	; INITIATE START
SENDB2:
	BANKSEL		PIR1
	BTFSS		PIR1, SSPIF	;START COMPLETED?YES SKIP NEXT
;*********************SLAVE ADDRESS-READ AFTER SETTING WORD ADDRESS*************
	GOTO		SENDB2
	BCF		PIR1, SSPIF	;YES,CLEAR FLAG
	MOVLW		0x70		;PCF8574 is 0x40 the SLAVE ADDRESS  
					;BUT
					;PCF8574AN is 0x70 the SLAVE ADDRESS
	MOVWF		SSPBUF		;W -> SSPBUF 直ちに送信開始 BEGIN TRANSMISSION 
SENDB3:
	BTFSS		PIR1, SSPIF	;SEND COMPLETED? YES,SKIP NEXT
	GOTO		SENDB3
	BCF		PIR1, SSPIF	;YES,CLEAR FLAG
	BANKSEL		SSPCON2
	BTFSC		SSPCON2,ACKSTAT	;ACK RECEIVED FROM SLAVE?IF YES SKIP
	GOTO	 	SENDB5		;IF NO,END 
;*********************SEND Control Byte ****************************
	BANKSEL		W_TEMP
;	MOVLW		0x88		;Port Data -> W
	MOVF		W_TEMP,W	;W_TEMP -> W
	MOVWF		SSPBUF		;W -> SSPBUF 直ちに送信開始 BEGIN TRANSMISSION
	INCF		W_TEMP,F	;W_TEMP = W_TEMP + 1
SENDB4:
	BTFSS		PIR1,SSPIF	;SEND COMPLETED?IF YES SKIP NEXT
	GOTO		SENDB4
	BCF		PIR1,SSPIF	;YES,CLEAR FLAG
	BSF		STATUS, RP0
	BTFSC		SSPCON2,ACKSTAT	;ACK RECEIVED FROM SLAVE?IF YES SKIP
	GOTO		SENDB5		;IF NO,END 
;*********************	INITIATE STOP*******************************************
SENDB5:	
	BANKSEL		SSPCON2
 	BSF		SSPCON2,PEN
	BCF		STATUS,RP0
SENDBE:	
	BTFSS		PIR1,SSPIF	
	GOTO		SENDBE
	BCF		PIR1,SSPIF

	goto		LOOP

end
 
以下はサブルーチン subroutin.asm です、余計なのがいっぱい
書かれています、無視して下さい。



;*********************************************************************************** ; PIC16F886 Extra Subroutines Ver 1.00 2009/11/25 ;*********************************************************************************** list p=16F886 ; 翻訳時にリストファイルを作ります #include ; 12F683用定義ファイルを読み込みます errorlevel -302 ; 翻訳時に302エラーが出ないようにします errorlevel -205 ; 翻訳時に205エラーが出ないようにします errorlevel -305 ; 翻訳時に305エラーが出ないようにします ;============================================================ GLOBAL TIMADJ,TIM8ms,TIM100ms,TIM500ms,TIM10ms,ADGET,OUT_A,OUT_B,OUT_C,SWON,SWON2 ;サブルーチンのラベル名がメインプログラムでEXTERNで宣言されて居る ;その為、必ずGLOBALで受ける、つまり EXTERN と GLOBAL はペア ;============================================================ CODE ;サブルーチン、ここから ;============================================================ ;A/D コンバータースタート、10bit有る、ADINITで左シフトに設定してあるので上位8ビットがTEMP1に入る ;ADCON0のbit2を1にするとスタートし、それが0に成ったらA/D変換終了 ;A/D回路はノイズが出るらしく、ここではいちいちA/Dを使う設定をし、変換したら使わない設定にするADCON0,0 ADGET ;A/D Convertion BSF ADCON0,0 ;USE A/D Convertion CALL SC01 BSF ADCON0,1 ;A/D Covert to start CALL SC01 ;Wait 40us for A/D Convertion Capacitor Charge Time LP00B CLRWDT ;WATCH DOG TIMER RESET BTFSC ADCON0,1 GOTO LP00B MOVF ADRESH,W ;A/D Value MSB to W MOVWF TEMP1 ;W to TEMP1 BSF STATUS,5 ;Change to Bank1 (STATUS Register Bit5 set to 1) MOVF ADRESL,W ;A/D Value LSB to W BCF STATUS,5 ;Back to Bank0 (STATUS Register Bit5 set to 0) MOVWF TEMP2 ;W to TEMP2 BCF ADCON0,0 ;NO-USE A/D Convertion (For Noise cut) RETURN SC01 ;Timer 40us MOVLW 24H MOVWF COUNT LP01B DECFSZ COUNT,F ;Dec COUNT untill 0 GOTO LP01B RETURN ;============================================================ ;TEMP3レジスタの数値を01--FFhで変化させる事で待ち時間を設定出来る TIMADJ ;Adjustable TIMER MOVLW D'1' ;DataA write to the W register(under the ALU) MOVWF COUNT4 ;Data set to the COUNT4 LP5B MOVLW D'12' ;DataA write to the W register(under the ALU) MOVWF COUNT3 ;Data set to the COUNT3 LP5C DECFSZ COUNT2 ;COUNT2 DEC GOTO LP5C ;CNTR INC UNTILL 0 CLRWDT ;WATCH DOG TIMER RESET MOVF TEMP3,W ;TEMP1 to W MOVWF COUNT2 ;W to COUNT2 DECFSZ COUNT3 ;COUNT3 DEC GOTO LP5C ;REPT DEC UNTILL 0 DECFSZ COUNT4 ;REPT2 DEC GOTO LP5B ;REPT2 DEC UNTILL 0 RETURN ;BACK TO Main Rutin ;============================================================ ;10ms待つ TIM10ms ;10msTIMER MOVLW D'1' ;DataA write to the W register(under the ALU) MOVWF COUNT3 ;Data set to the COUNT2 LP08B MOVLW D'13' ;DataA write to the W register(under the ALU) MOVWF COUNT2 ;Data set to the COUNT LP08C INCFSZ COUNT ;CNTR INC GOTO LP08C ;CNTR INC UNTILL 256 CLRWDT ;WATCH DOG TIMER RESET DECFSZ COUNT2 ;COUNT DEC GOTO LP08C ;COUNT DEC UNTILL 0 DECFSZ COUNT3 ;COUNT2 DEC GOTO LP08B ;COUNT2 DEC UNTILL 0 RETURN ;BACK TO MAIN ;============================================================ ;8ms待つ TIM8ms ;8msTIMER MOVLW D'1' ;DataA write to the W register(under the ALU) MOVWF COUNT3 ;Data set to the COUNT2 LP08D MOVLW D'11' ;DataA write to the W register(under the ALU) MOVWF COUNT2 ;Data set to the COUNT LP08E INCFSZ COUNT ;CNTR INC GOTO LP08E ;CNTR INC UNTILL 256 CLRWDT ;WATCH DOG TIMER RESET DECFSZ COUNT2 ;COUNT DEC GOTO LP08E ;COUNT DEC UNTILL 0 DECFSZ COUNT3 ;COUNT2 DEC GOTO LP08D ;COUNT2 DEC UNTILL 0 RETURN ;BACK TO MAIN ;============================================================ ;100ms待つ TIM100ms ;100msTIMER MOVLW D'10' ;DataA write to the W register(under the ALU) MOVWF COUNT3 ;Data set to the COUNT2 LP08F MOVLW D'13' ;DataA write to the W register(under the ALU) MOVWF COUNT2 ;Data set to the COUNT LP08G INCFSZ COUNT ;CNTR INC GOTO LP08G ;CNTR INC UNTILL 256 CLRWDT ;WATCH DOG TIMER RESET DECFSZ COUNT2 ;COUNT DEC GOTO LP08G ;COUNT DEC UNTILL 0 DECFSZ COUNT3 ;COUNT2 DEC GOTO LP08F ;COUNT2 DEC UNTILL 0 RETURN ;BACK TO MAIN ;============================================================ ;500ms待つ TIM500ms ;100msTIMER MOVLW D'50' ;DataA write to the W register(under the ALU) MOVWF COUNT3 ;Data set to the COUNT2 LP08H MOVLW D'13' ;DataA write to the W register(under the ALU) MOVWF COUNT2 ;Data set to the COUNT LP08I INCFSZ COUNT ;CNTR INC GOTO LP08I ;CNTR INC UNTILL 256 CLRWDT ;WATCH DOG TIMER RESET DECFSZ COUNT2 ;COUNT DEC GOTO LP08I ;COUNT DEC UNTILL 0 DECFSZ COUNT3 ;COUNT2 DEC GOTO LP08H ;COUNT2 DEC UNTILL 0 RETURN ;BACK TO MAIN ;============================================================ ;PORTAが出力に設定されて居る場合PTAレジスタのビットを立てればそのビットを出力する OUT_A NOP ;PORT OUTPUT ROUTIN CLRWDT ;WATCH DOG TIMER RESET MOVF PTA,W ;DATA COPY FROM PTA TO W RESISTER MOVWF PORTA ;DATA COPY FROM W TO PORTA RETURN ;============================================================ ;PORTBが出力に設定されて居る場合PTAレジスタのビットを立てればそのビットを出力する OUT_B NOP ;PORT OUTPUT ROUTIN CLRWDT ;WATCH DOG TIMER RESET MOVF PTB,W ;DATA COPY FROM PTB TO W RESISTER MOVWF PORTB ;DATA COPY FROM W TO PORTB RETURN ;============================================================ ;PORTCが出力に設定されて居る場合PTCレジスタのビットを立てればそのビットを出力する OUT_C NOP ;PORT OUTPUT ROUTIN CLRWDT ;WATCH DOG TIMER RESET MOVF PTC,W ;DATA COPY FROM PTC TO W RESISTER MOVWF PORTC ;DATA COPY FROM W TO PORTC RETURN ;============================================================ ;入力はPA0(17pin) ;ここでは入力が H-->L-->H を一通り経由すると SWFLAGのbit2 が0-->1に成る ;チャタリングは30msに設定されて居る ;特徴は入力の状態をずっと見ているのでは無く時々見に行きフラグを変化させている ;その為、入力を見に行って他のことが何も出来ないのではなく同時に並行して他の ;作業を出来ることである ;------------------------------ SWON CLRWDT BCF SWFLAG,2 ;SW ON のフラグをクリア BCF STATUS,Z BCF STATUS,C BCF STATUS,DC MOVLW D'1' ;D'5'--->W 1= 10ms MOVWF COUNT4 ;W--->COUNT4 ;-----------------------SW ポートの H/Lチェック MOVF TRISA,W ;IO-->W MOVWF PTA ;W-->PTA BTFSC PTA,0 ;SW=Hつまり押されていない、次へ ;SW=Lつまり押された、次をスキップ GOTO SWONC ;押されて居ないへ進む ;-----------------------SW ポートは L チャタリングチェック SWONB CLRWDT CALL TIM10ms CALL TIM10ms CALL TIM10ms MOVF TRISA,W ;IO-->W MOVWF PTA ;W-->PTA BTFSC PTA,0 ;SW=1つまり押されていない、次へ ;SW=0つまり押された、次をスキップ RETURN ;押されて居ない、チャタリング、MAINへ戻る ; CALL TIM10ms ;10ms timer チャタリング対策 ; DECFSZ COUNT4,1 ;COUNT4 = COUNT4 - 1 ゼロに成ったら次をスキップ ;ゼロで無いならば次へ進む ; GOTO SWONB ;再度押されたかチェックを繰り返す ;----------------------- MOVLW D'1' ; 1 --> W SUBWF SWFLAG,1 ;SWFLAG=SWFLAG-1 BTFSC STATUS,C ;C=1(キャリーフラグ)ならばプラス、次へ ;C=0ならばゼロかマイナス次をスキップ GOTO SWONB1 BTFSS STATUS,Z ;Z=0ならマイナス次 Z=1ならゼロ次をスキップ GOTO SET0 ;SWFLAGをゼロにしてMAINに戻る SWONB1 SUBWF SWFLAG,1 ;SWFLAG=SWFLAG-1 BTFSC STATUS,C ;C=1(キャリーフラグ)ならばプラス、次へ ;C=0ならばゼロかマイナス次をスキップ GOTO SWONB2 BTFSS STATUS,Z ;Z=0ならマイナス次 Z=1ならゼロ次をスキップ GOTO SET2 ;SWFLAGを2にしてMAINに戻る SWONB2 SUBWF SWFLAG,1 ;SWFLAG=SWFLAG-1 BTFSC STATUS,C ;C=1(キャリーフラグ)ならばプラス、次へ ;C=0ならばゼロかマイナス次をスキップ GOTO SWONB3 BTFSS STATUS,Z ;Z=0ならマイナス次 Z=1ならゼロ次をスキップ GOTO SET2 ;SWFLAGを2にしてMAINに戻る SWONB3 GOTO SET0 ;SWFLAGをゼロにしてMAINに戻る ;-----------------------SW ポートは H チャタリングチェック SWONC CLRWDT CALL TIM10ms CALL TIM10ms CALL TIM10ms MOVF TRISA,W ;IO-->W MOVWF PTA ;W-->PTA BTFSS PTA,0 ;SW=0つまり押されていない、次をスキップ ;SW=1つまり押された、次へ RETURN ;押されて居ない、チャタリング、MAINへ戻る ; CALL TIM10ms ;10ms timer チャタリング対策 ; DECFSZ COUNT4,1 ;COUNT4 = COUNT4 - 1 ゼロに成ったら次をスキップ ;ゼロで無いならば次へ進む ; GOTO SWONC ;再度押されたかチェックを繰り返す ;----------------------- MOVLW D'1' ; 1 --> W SUBWF SWFLAG,1 ;SWFLAG=SWFLAG-1 BTFSC STATUS,C ;C=1(キャリーフラグ)ならばプラス、次へ ;C=0ならばゼロかマイナス次をスキップ GOTO SWONC1 BTFSS STATUS,Z ;Z=0ならマイナス次 Z=1ならゼロ次をスキップ GOTO SET1 ;SWFLAGを1にしてMAINに戻る SWONC1 SUBWF SWFLAG,1 ;SWFLAG=SWFLAG-1 BTFSC STATUS,C ;C=1(キャリーフラグ)ならばプラス、次へ ;C=0ならばゼロかマイナス次をスキップ GOTO SWONC2 BTFSS STATUS,Z ;Z=0ならマイナス次 Z=1ならゼロ次をスキップ GOTO SET1 ;SWFLAGを1にしてMAINに戻る SWONC2 SUBWF SWFLAG,1 ;SWFLAG=SWFLAG-1 BTFSC STATUS,C ;C=1(キャリーフラグ)ならばプラス、次へ ;C=0ならばゼロかマイナス次をスキップ GOTO SWONC3 BTFSS STATUS,Z ;Z=0ならマイナス次 Z=1ならゼロ次をスキップ GOTO SET3 ;SWFLAGを3にしてMAINに戻る、つまりSWは一通りの経過を経て押された SWONC3 GOTO SET0 ;SWFLAGをゼロにしてMAINに戻る ;----------------------- SET0 CLRF SWFLAG ;SET0 RETURN SET1 MOVLW D'1' ;SET1 MOVWF SWFLAG ;W --> SWFLAG RETURN SET2 MOVLW D'2' ;SET2 MOVWF SWFLAG ;W --> SWFLAG RETURN SET3 MOVLW D'3' ;SET3 つまりSW操作は正しく一通り行われた MOVWF SWFLAG ;W --> SWFLAG BSF SWFLAG,2 ;SW ON のフラグを立てる RETURN ;============================================================ ;入力はPA1(18pin) ;ここでは入力が H-->L-->H を一通り経由すると SWFLAG2のbit2 が0-->1に成る ;チャタリングは30msに設定されて居る ;特徴は入力の状態をずっと見ているのでは無く時々見に行きフラグを変化させている ;その為、入力を見に行って他のことが何も出来ないのではなく同時に並行して他の ;作業を出来ることである SWON2 CLRWDT BCF SWFLAG2,2 ;SW ON のフラグをクリア BCF STATUS,Z BCF STATUS,C BCF STATUS,DC MOVLW D'1' ;D'5'--->W 1= 10ms MOVWF COUNT4 ;W--->COUNT4 ;-----------------------SW ポートの H/Lチェック MOVF TRISA,W ;IO-->W MOVWF PTA ;W-->PTA BTFSC PTA,1 ;SW=Hつまり押されていない、次へ ;SW=Lつまり押された、次をスキップ GOTO SWON2C ;押されて居ないへ進む ;-----------------------SW ポートは L チャタリングチェック SWON2B CLRWDT CALL TIM10ms CALL TIM10ms CALL TIM10ms MOVF TRISA,W ;IO-->W MOVWF PTA ;W-->PTA BTFSC PTA,1 ;SW=1つまり押されていない、次へ ;SW=0つまり押された、次をスキップ RETURN ;押されて居ない、チャタリング、MAINへ戻る ; CALL TIM10ms ;10ms timer チャタリング対策 ; DECFSZ COUNT4,1 ;COUNT4 = COUNT4 - 1 ゼロに成ったら次をスキップ ;ゼロで無いならば次へ進む ; GOTO SWON2B ;再度押されたかチェックを繰り返す ;----------------------- MOVLW D'1' ; 1 --> W SUBWF SWFLAG2,1 ;SWFLAG2=SWFLAG2-1 BTFSC STATUS,C ;C=1(キャリーフラグ)ならばプラス、次へ ;C=0ならばゼロかマイナス次をスキップ GOTO SWON2B1 BTFSS STATUS,Z ;Z=0ならマイナス次 Z=1ならゼロ次をスキップ GOTO SETB0 ;SWFLAG2をゼロにしてMAINに戻る SWON2B1 SUBWF SWFLAG2,1 ;SWFLAG2=SWFLAG2-1 BTFSC STATUS,C ;C=1(キャリーフラグ)ならばプラス、次へ ;C=0ならばゼロかマイナス次をスキップ GOTO SWON2B2 BTFSS STATUS,Z ;Z=0ならマイナス次 Z=1ならゼロ次をスキップ GOTO SETB2 ;SWFLAG2を2にしてMAINに戻る SWON2B2 SUBWF SWFLAG2,1 ;SWFLAG2=SWFLAG2-1 BTFSC STATUS,C ;C=1(キャリーフラグ)ならばプラス、次へ ;C=0ならばゼロかマイナス次をスキップ GOTO SWON2B3 BTFSS STATUS,Z ;Z=0ならマイナス次 Z=1ならゼロ次をスキップ GOTO SETB2 ;SWFLAG2を2にしてMAINに戻る SWON2B3 GOTO SETB0 ;SWFLAG2をゼロにしてMAINに戻る ;-----------------------SW ポートは H チャタリングチェック SWON2C CLRWDT CALL TIM10ms CALL TIM10ms CALL TIM10ms MOVF TRISA,W ;IO-->W MOVWF PTA ;W-->PTA BTFSS PTA,1 ;SW=0つまり押されていない、次をスキップ ;SW=1つまり押された、次へ RETURN ;押されて居ない、チャタリング、MAINへ戻る ; CALL TIM10ms ;10ms timer チャタリング対策 ; DECFSZ COUNT4,1 ;COUNT4 = COUNT4 - 1 ゼロに成ったら次をスキップ ;ゼロで無いならば次へ進む ; GOTO SWON2C ;再度押されたかチェックを繰り返す ;----------------------- MOVLW D'1' ; 1 --> W SUBWF SWFLAG2,1 ;SWFLAG2=SWFLAG2-1 BTFSC STATUS,C ;C=1(キャリーフラグ)ならばプラス、次へ ;C=0ならばゼロかマイナス次をスキップ GOTO SWON2C1 BTFSS STATUS,Z ;Z=0ならマイナス次 Z=1ならゼロ次をスキップ GOTO SETB1 ;SWFLAG2を1にしてMAINに戻る SWON2C1 SUBWF SWFLAG2,1 ;SWFLAG2=SWFLAG2-1 BTFSC STATUS,C ;C=1(キャリーフラグ)ならばプラス、次へ ;C=0ならばゼロかマイナス次をスキップ GOTO SWON2C2 BTFSS STATUS,Z ;Z=0ならマイナス次 Z=1ならゼロ次をスキップ GOTO SETB1 ;SWFLAG2を1にしてMAINに戻る SWON2C2 SUBWF SWFLAG2,1 ;SWFLAG2=SWFLAG2-1 BTFSC STATUS,C ;C=1(キャリーフラグ)ならばプラス、次へ ;C=0ならばゼロかマイナス次をスキップ GOTO SWON2C3 BTFSS STATUS,Z ;Z=0ならマイナス次 Z=1ならゼロ次をスキップ GOTO SETB3 ;SWFLAG2を3にしてMAINに戻る、つまりSWは一通りの経過を経て押された SWON2C3 GOTO SETB0 ;SWFLAG2をゼロにしてMAINに戻る ;----------------------- SETB0 CLRF SWFLAG2 ;SETB0 RETURN SETB1 MOVLW D'1' ;SETB1 MOVWF SWFLAG2 ;W --> SWFLAG2 RETURN SETB2 MOVLW D'2' ;SETB2 MOVWF SWFLAG2 ;W --> SWFLAG2 RETURN SETB3 MOVLW D'3' ;SETB3 つまりSW操作は正しく一通り行われた MOVWF SWFLAG2 ;W --> SWFLAG2 BSF SWFLAG2,2 ;SW ON のフラグを立てる RETURN ;******************************************************************************************** END
 
・PIC16F886 を内部発信で使い外付け水晶発振子を無くした
・PCF8574ANを二個使い、一個が入力、もう一個を出力とした
・I2Cで通信しています
・・・という動画です


波形はこんな感じです、CLKスピードは100KHzぐらいです

ソースファイルですが下記の様に成りました
・p16f886.inc  MICROCHIP社で用意されているものに少し追加してます
・p16f886-5.asm メイン・プログラムです
・sub_i2c.asm サブルーチンです
・sub_PCF-8574_read.asm サブルーチンです、読み出しに特化してます
・sub_PCF-8574_write.asm サブルーチンです、書き込みに特化してます

p16f886.inc 追加部分のみ書き出します

;==========================================================================
CBLOCK   H'20'	;20hからユーザーのメモリが連続して割り当てられる開始宣言
W_TEMP		;For Interupt
S_TEMP		;For Interupt
COUNT		;For サブルーチン変数
COUNT2		;For サブルーチン変数
COUNT3		;For サブルーチン変数
COUNT4		;For サブルーチン変数
COUNT10		;For サブルーチン変数
COUNT11		;For サブルーチン変数
COUNT12		;For サブルーチン変数
COUNT13		;For サブルーチン変数
TMR0_INT_C	;TMR0割込回数カウンタ(65.28msでインクリメント但し水晶=4MHz)
TMR0_INT_D	;上記カウンタが255を超えたら+1するカウンタ
		; MAX = 4244.8秒 ( 65.28ms x 255 x 255 ) およそ70分
FLAG		;FLAG RESISTER
		;0=
		;1=
		;2=
		;3=
		;4=
		;5=
		;6=
		;7=
SWFLAG		;SW FLAG ONLY RESISTER
		;0=SWの状態ビット0
		;1=SWの状態ビット1
		;2=SW ON ビット、MAINプログラムではこれが立った事でSW ONを知る
		;3=
		;4=
		;5=
		;6=
		;7=
SWFLAG2		;SW FLAG ONLY RESISTER
		;0=SWの状態ビット0
		;1=SWの状態ビット1
		;2=SW ON ビット、MAINプログラムではこれが立った事でSW ONを知る
		;3=
		;4=
		;5=
		;6=
		;7=
COUNTB		;For Interrupt 避難用
COUNT2B		;For Interrupt 避難用
COUNT3B		;For Interrupt 避難用
COUNT4B		;For Interrupt 避難用
TEMP1		;For A/D value MSB
TEMP2		;For A/D value LSB
TEMP3		;For Adjustable timer routin
PTA		;For I/O register
PTB		;For I/O register
PTC		;For I/O register
PTE		;For I/O register
READADRS	;スレーブアドレス・リード
WRITEADRS	;スレーブアドレス・ライト
ENDC		;20hからユーザーのメモリが連続して割り当てられた終了宣言

p16f886-5.asm

;***************************************************************************************************************
;This software is provided in an “AS IS” condition,NO WARRANTIES in any form apply to this software.
; picmicrolab.com 5.31.2014  
; Modified Dec,10,2018 by maru
;***************************************************************************************************************
; PCF8574 I2C  8-bit IO expander interface with PIC16F876A;
;-------------------------------------------------------------------------------------;
	LIST		P=PIC16F886
	include		P16f886.inc
	errorlevel  	-302		; 翻訳時に302エラーが出ないようにします
	errorlevel  	-205		; 翻訳時に205エラーが出ないようにします
	errorlevel  	-305		; 翻訳時に305エラーが出ないようにします
;サブルーチンは別ファイルをコール
;	EXTERN	TIMADJ,TIM8ms,TIM100ms,TIM500ms,TIM10ms,ADGET,OUT_A,OUT_B,OUT_C,SWON,SWON2
EXTERN	PCF8574_READ,I2C_INIT,START_I2C,STOP_I2C,PCF8574_WRITE
			;別ファイルに存在するサブルーチンのラベル名を宣言する
			;別ファイルでは必ず GLOBAL で受ける、つまり EXTERN と GLOBAL はペア。
; __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF & _HS_OSC & _LVP_OFF & _DEBUG_OFF & _CPD_OFF
__CONFIG  _CONFIG1 , _CP_OFF & _DEBUG_OFF  & _CPD_OFF & _LVP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSCIO & _BOR_OFF
	    org		0x00
reset:	
	    goto start
	    org		0x04
start:
;===============================================================================
;スレーブアドレスの宣言
	WSADRS		EQU	    H'0070'	;LED側 スレーブアドレス WRITE
	RSADRS		EQU	    H'0073'	;デジスイッチ側 スレーブアドレス READ
		
	MOVLW   	WSADRS			;data -> W
	MOVWF		WRITEADRS		;W -> F
	MOVLW   	RSADRS			;data -> W
	MOVWF		READADRS		;W -> F
	
;	READADRS	;スレーブアドレス・リード・レジスタ
;	WRITEADRS	;スレーブアドレス・ライト・レジスタ
;===============================================================================
;***	iNTERNAL OSC 設定 ( OSCCON-8Fh )
;OSCINIT
	BANKSEL		OSCCON
	MOVLW   	70h        	;CLOCK=4MHz (70H=8MHzでMAX)
        MOVWF   	OSCCON
       	BCF		STATUS,5	;Back to BANK0
;===============================================================================
;I2C の為の初期化
	CALL		I2C_INIT
;===============================================================================
LOOP:
;===============================================================================
;PCF8574READ
	CALL		START_I2C
	CALL		PCF8574_READ
	CALL		STOP_I2C
;===============================================================================	
	BANKSEL		W_TEMP
	MOVF		W_TEMP,W	;W_TEMP -> W
	MOVWF		PORTB		;W → PORTB に即出力(モニタとして使用)
;===============================================================================
;PCF8574WRITE
	CALL		START_I2C
	CALL		PCF8574_WRITE
	CALL		STOP_I2C
;*******************************************************************************
	goto		LOOP

end

sub_i2c.asm

	list      	p=16F886	; 翻訳時にリストファイルを作ります
	#include 		; 定義ファイルを読み込みます
	errorlevel  	-302		; 翻訳時に302エラーが出ないようにします
	errorlevel  	-205		; 翻訳時に205エラーが出ないようにします
	errorlevel  	-305		; 翻訳時に305エラーが出ないようにします
	;***********************************************************************
;サブルーチン、PCF8574を読む
	GLOBAL	I2C_INIT,START_I2C,STOP_I2C
	;サブルーチンのラベル名がメインプログラムでEXTERNで宣言されて居る
	;その為、必ずGLOBALで受ける、つまり EXTERN と GLOBAL はペア
;===============================================================================
CODE	;サブルーチン、ここから
;===============================================================================
I2C_INIT
;===============================================================================
;I2C の為の初期化
	BANKSEL		SSPCON
	movlw		0x28		;0x28 = シリアルポートを動作させ、SDA とSCL ピンをシリアルポートピンにする。
					;0x28 = I2C マスターモード、クロック= FOSC / (4 * (SSPADD+1) )
	movwf		SSPCON
	BANKSEL		SSPSTAT		;BANK1 for SSPSTAT
	BSF		SSPSTAT, SMP
	BCF		SSPSTAT, CKE
	CLRF		TRISB
	MOVLW		0x14		;I2C BUS speed  小さい程早く成る
	MOVWF		SSPADD
	NOP
	RETURN
;********************* START CONDITION *****************************************
START_I2C
	BANKSEL		SSPCON2
	BSF		SSPCON2, SEN	; INITIATE START
SENDB2:
	BANKSEL		PIR1
	BTFSS		PIR1, SSPIF	;START COMPLETED?YES SKIP NEXT
	GOTO		SENDB2
	BCF		PIR1, SSPIF	;YES,CLEAR FLAG
	RETURN
;*********************	INITIATE STOP*******************************************
STOP_I2C
SENDB5:	
	BANKSEL		SSPCON2
 	BSF		SSPCON2,PEN
	BCF		STATUS,RP0
SENDBE:	
	BTFSS		PIR1,SSPIF	
	GOTO		SENDBE
	BCF		PIR1,SSPIF
	RETURN
				
END

sub_PCF-8574_read.asm
	list      	p=16F886	; 翻訳時にリストファイルを作ります
	#include 		; 定義ファイルを読み込みます
	errorlevel  	-302		; 翻訳時に302エラーが出ないようにします
	errorlevel  	-205		; 翻訳時に205エラーが出ないようにします
	errorlevel  	-305		; 翻訳時に305エラーが出ないようにします
	;***********************************************************************
;サブルーチン、PCF8574を読む
	GLOBAL	PCF8574_READ
	;サブルーチンのラベル名がメインプログラムでEXTERNで宣言されて居る
	;その為、必ずGLOBALで受ける、つまり EXTERN と GLOBAL はペア
;===============================================================================
CODE	;サブルーチン、ここから
;===============================================================================
;	READADRS	;スレーブアドレス・リード・レジスタ
PCF8574_READ
	MOVF		READADRS,W	;F -> W  スレーブ デジスイッチ読み出しアドレス
	MOVWF		SSPBUF		;W -> F  INITIATE SEND この瞬間に送信される
;SLAVE ADDRESS
SENDC3:
	BTFSS		PIR1, SSPIF	;SEND COMPLETED? YES,SKIP NEXT 送信完了?
	GOTO		SENDC3
	BCF		PIR1, SSPIF	;YES,CLEAR FLAG 割り込みフラグ・クリア
	BANKSEL		SSPCON2
	BTFSC		SSPCON2,ACKSTAT	;ACK RECEIVED FROM SLAVE?IF YES SKIP
					; スレーブからの ACK待ち 0=受信済み次ぎをスキップ
	GOTO		SENDX5		;IF NO,END 
;*********************READ******************************************************
;スレーブから読み出す
	BSF		SSPCON2,RCEN	;RCEN = 1 受信許可
	BANKSEL		PIR1
READB1:
	BTFSS		PIR1,SSPIF	;受信完了?
	GOTO		READB1
	BCF		PIR1,SSPIF	;フラグ・クリア
	MOVF		SSPBUF,W	;SSPBUF(読み出したデータ) → W
	MOVWF		W_TEMP		;W -> W_TEMP  I/O EXPANDER へ出力するデータの確保
;*********************SEND NOACK TO END TRANSACTION*****************************
;スレーブに対して NACK (NoACK)を返して受け取った事を通知する
	BANKSEL		SSPCON2
	BSF		SSPCON2,ACKDT	;SELECT NOACK			----]
	BSF		SSPCON2,ACKEN	;INITIATE ACKNOWLEDGE SEQUENCE ----]この二つでNACKとる成る
	BANKSEL		PIR1
SENDCC:
	BTFSS		PIR1,SSPIF	;ACK SEQUENCE COMPLEMENTED;IF YES SKIP NACK送信完了?
	GOTO		SENDCC	
	BCF		PIR1,SSPIF	;フラグ・クリア	
	RETURN
;*********************	NG INITIATE STOP****************************************
SENDX5:	
	BANKSEL		SSPCON2
 	BSF		SSPCON2,PEN
	BCF		STATUS,RP0
SENDXE:	
	BTFSS		PIR1,SSPIF	
	GOTO		SENDXE
	BCF		PIR1,SSPIF
;*******************************************************************************
RETURN
	
END

sub_PCF-8574_write.asm
	list      	p=16F886	; 翻訳時にリストファイルを作ります
	#include 		; 定義ファイルを読み込みます
	errorlevel  	-302		; 翻訳時に302エラーが出ないようにします
	errorlevel  	-205		; 翻訳時に205エラーが出ないようにします
	errorlevel  	-305		; 翻訳時に305エラーが出ないようにします
;*******************************************************************************
;サブルーチン、PCF8574を読む
	GLOBAL	PCF8574_WRITE
	;サブルーチンのラベル名がメインプログラムでEXTERNで宣言されて居る
	;その為、必ずGLOBALで受ける、つまり EXTERN と GLOBAL はペア
;===============================================================================
CODE	;サブルーチン、ここから
;===============================================================================
PCF8574_WRITE
;*********************SLAVE ADDRESS-READ AFTER SETTING WORD ADDRESS*************
;	WRITEADRS	;スレーブアドレス・ライト・レジスタ
	MOVF		WRITEADRS,W	;F -> W スレーブ LED 書き込みアドレス
					;PCF8574 is 0x40 the SLAVE ADDRESS  
					;BUT
					;PCF8574AN is 0x70 the SLAVE ADDRESS
	MOVWF		SSPBUF		;W -> SSPBUF 直ちに送信開始 BEGIN TRANSMISSION 
SENDW3:
	BTFSS		PIR1, SSPIF	;SEND COMPLETED? YES,SKIP NEXT
	GOTO		SENDW3
	BCF		PIR1, SSPIF	;YES,CLEAR FLAG
	BANKSEL		SSPCON2
	BTFSC		SSPCON2,ACKSTAT	;ACK RECEIVED FROM SLAVE?IF YES SKIP
	GOTO		SENDY5		;IF NO,END
;*********************SEND Control Byte ****************************************
	BANKSEL		W_TEMP
;	MOVLW		0x88		;Port Data -> W
	MOVF		W_TEMP,W	;W_TEMP -> W
	MOVWF		SSPBUF		;W -> SSPBUF 直ちに送信開始 BEGIN TRANSMISSION
	INCF		W_TEMP,F	;W_TEMP = W_TEMP + 1
SENDW4:
	BTFSS		PIR1,SSPIF	;SEND COMPLETED?IF YES SKIP NEXT
	GOTO		SENDW4
	BCF		PIR1,SSPIF	;YES,CLEAR FLAG
	BANKSEL		SSPCON2
	BTFSC		SSPCON2,ACKSTAT	;ACK RECEIVED FROM SLAVE?IF YES SKIP
	GOTO		SENDY5		;IF NO,END
	RETURN
;*********************	NG INITIATE STOP****************************************
SENDY5:	
	BANKSEL		SSPCON2
 	BSF		SSPCON2,PEN
	BCF		STATUS,RP0
SENDYE:	
	BTFSS		PIR1,SSPIF	
	GOTO		SENDYE
	BCF		PIR1,SSPIF
;*******************************************************************************
RETURN
	
END



---記事制作中---

nice!(0)  コメント(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

ACE AR-200 2 transis..ソースコード枠 ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。