SSブログ

PIC16F886 24LC64 EEPROM I2C アセンブラ

再露出DSCN0050


PCF8574  IO EXPANDER の序でにEEPROMもドキュメントを
残そうと取り組んでみました、皆様のようにサクッ!!っとC言語とかで
制御出来なくて地道にPICマイコンのアセンブラで組んでみましたが
思いの外難しくて時間が掛かりました。
(ソースプログラムはこちらからダウンロード)
特記すべきはネット記事では見つからなかったものの良く探せば同様
のトラブルが在った事を解決後に知りましたが下記の様な事です・・・

EEPROMの書き込み時間は最低 5ms を必要とする

・・・という事実、これを知らなかったばかりに書き込み後直ちに
読み出しすると最初のスレーブアドレスを送信してフリーズして
仕舞うのです、この問題を解決するためにオシロスコープとにらめっこ
して何日無駄にしたか・・・・はぁ、って感じです、たまたま
デバッグする為にタイマーを入れたらすんなり動いたので

「なんで?」

もしやインターバルが必要なのかとネット検索したら同様のトラブル
の記事がみつかりまして「ああ、やっぱりそうか」と、更には
EEPROMのデータシートを視れば書き込みに5msと書いて有る
ではないですか、そんな訳で無駄な悪戦苦闘を強いられました。
データシートの当該部分です赤枠内
bandicam 2018-12-28 07-23-30-631


取り敢えずこの動画はEEPROM のメモリー番地 0x000~0x0FF
の255のアドレスに00/01/02/03・・・・FD/FE/FF/00と一個ずつ加算
して書いて同時に読み出してLチカさせています。

実際のI2C波形です、一つずつインクリメントしている様子が判ります


ちゃんと書けているか確認しました、以前から所持していた秋月電子
PIC PROGRAMMER を使いました、この基板はPICだけで無く
アプリケーション・ソフトをダウンロードすればEEPROMの
読み書き込みも可能なのです
DSCN0047

但し、これを使うに当たっては色々と問題が在りました
先ず、今時のパソコンにはCOM1(9pin-D-sub / serial)が無い
で、あるにも関わらず我がDELL T3500には付いていた、だから今まで
PIC PROGRAMMERは問題無く動いていた、なのに秋月電子の

アプリケーション・ソフト、Serial EEPROM Programmer Ver6.5.8
は何故だか「エラー'13'型式が合いません」なるシステムエラーが出て
使えないのです、ならばという事で古いノートパソコンを引っ張り出して
それにインストールされている windows xp professional  の元で

動かしたものの同様のエラーで動作しません、もうなにをやってもダメ
そこで思いついたのは USB/Serial変換器 REX -USB60F
これです ↓
DSCN0049

これを使うことでSerial EEPROM Programmer Ver6.5.8は動くのです
折角COM1 / serial ポートが在るのにそれはダメでわざわざ
USB/Serial変換器を使うと動くという矛盾、その嫌らしさ・・・・
然かも COM14  とか、もう信じられない
という訳でちゃんと書けていることが確認出来ました
bandicam 2018-12-19 19-56-45-791



オシロスコープで波形観測するには肝心な部分だけを視たいのに
他の波形が重複して見辛いことこの上ないですよね、その問題は
簡単に解決出来ました、PICの空きポートを利用してそこにトリガー
パルスを出してディレーで眺めれば楽勝です

製作した EEPROM 基板です、LEDは短絡しています
DSCN9946

単純にEEPROMだけですが、保護ダイオード、パスコン、チェック端子
とシンプルな基板です

DSCN9947

全体回路図
bandicam 2018-12-18 20-22-22-539

これでは何も見えませんね、PIC部分
bandicam 2018-12-18 20-22-45-987

EEPROM部分
bandicam 2018-12-18 20-23-08-323

I2Cのプロトコルは下記の通り、データシートの抜粋です
bandicam 2018-12-28 07-20-50-075

bandicam 2018-12-28 07-21-05-061

bandicam 2018-12-28 07-21-25-172

bandicam 2018-12-28 07-21-41-500



デバッグしていて何が一番知りたかったか、それは実際の波形です
SCL / SDA の相互位相関係で全てが決まります、それぞれの立ち上がり
立ち下がり、その時の状況で様々な意味を持たせているので抽象的な
データシートの波形では満足できませんでした、特にACKは僅かな凹みが
足跡の様に残るのです、オシロスコープに顔を近づけないと判別出来ない
のですが、ACKが出ている、出ていない、の大きな手掛かりと成ります
写真は下記の条件での波形です

・EEPROM 24LC64 秋月で50円、マイクロチップ社製 255byte x 32頁
・SLAVE ADDRESS  0xA0(WRITE) / 0xA1(READ)
・MEMORY  ADDRESS 0x00
・WRITE & READ  DATA 0x55

WRITE→READ間インターバルはおよそ 6ms
データシートでは「書き込み時間」と称していますが「書いてから読み出す
までに最低5msは待って呉れ」とは書かれていないのです、データシートの
嫌らしさ、不親切さは自社の欠点や不利益な部分を別の真実という形で表現
し結果的に危険性が伝わらない、と云う形で書かれていると私は永年感じて
居ます
DSCN9976

I2C クロック周波数はほぼ100KHz

DSCN9977

オシロスコープ画面、左側が読み出し、右が書き込み
これを延々と繰り返すだけです

DSCN9978

読み出し START→ 0xA0→  ACK→  0x00→  ACK

DSCN9979

読み出し 0x00→  ACK→  RESTART→ 0xA1

DSCN9980

読み出し 上の写真の 0xA1 は重複、続いて ACK→  0x55→  NACK→  STOP

DSCN9981

書き込み START→  0xA0→  ACK→  0x00→  ACK
DSCN9982
書き込み 0x00→  ACK→  0x55→  ACK→  STOP

DSCN9983
こうした具体的な波形で無いと私には無理。

プログラムです、下記のファイルと成ります
・p16f886.inc
・p16f886_24C64_006.asm   メイン
・p16f886_24C64_read.asm   サブルーチン、読み出し
・p16f886_24C64_sub_i2c.asm サブルーチン
・p16f886_24C64_write.asm   サブルーチン、書き込み
・subroutin.asm         サブルーチン

プログラムの流れは・・・

・データ 0x55 を書く
・読み込む
・LEDを点灯させる(PORTB)

・・・と単純で無意味な動作です、然し乍ら方法を知る為には
やらないよりはまし
 ---------------------------------------------------------------------------------
・p16f886.inc はMICRO CHIP 社で配布しているものです
 それに追加した部分だけを示します


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

WRITEADRS	;スレーブアドレス・ライト
WRITEHADRS	;メモリ上位アドレス・ライト
WRITELADRS	;メモリ下位アドレス・ライト
EPROMWDATA	;書き込むデータ
		
READADRS	;スレーブアドレス・リード
READHADRS	;メモリ上位アドレス・リード
READLADRS	;メモリ下位アドレス・リード 

・p16f886_24C64_006.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	E24LC64_READ,I2C_INIT,START_I2C,STOP_I2C,E24LC64_WRITE,IDLE
EXTERN	TIM100ms,TIM8ms,TIM10ms
			;別ファイルに存在するサブルーチンのラベル名を宣言する
			;別ファイルでは必ず 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_ON & _PWRTE_ON & _WDT_OFF & _INTOSCIO & _BOR_OFF
	    org		0x00
reset:	
	    goto start
	    org		0x04
start:
;===============================================================================
;スレーブアドレスとデータの宣言
	;--------------
	WSADRS		EQU	    H'00A0'	;スレーブアドレス WRITE
	WSHADRS		EQU	    H'0000'	;メモリアドレス上位 WRITE
	WSLADRS		EQU	    H'0000'	;メモリアドレス下位 WRITE
	ROMWDATA	EQU	    H'0055'	;E24LC64 に書き込むデータ
	;--------------	
	RSADRS		EQU	    H'00A1'	;スレーブアドレス READ
	RSHADRS		EQU	    H'0000'	;メモリアドレス上位 READ
	RSLADRS		EQU	    H'0000'	;メモリアドレス下位 READ
	;--------------	
	MOVLW   	WSADRS			;data -> W
	MOVWF		WRITEADRS		;W -> F
	MOVLW   	WSHADRS			;data -> W
	MOVWF		WRITEHADRS		;W -> F
	MOVLW   	WSLADRS			;data -> W
	MOVWF		WRITELADRS		;W -> F
	;--------------
	MOVLW		ROMWDATA		;data -> W
	MOVWF		EPROMWDATA		;W -> F
	;--------------
	MOVLW   	RSADRS			;data -> W
	MOVWF		READADRS		;W -> F
	MOVLW		RSHADRS			;data -> W
	MOVWF		READHADRS		;W -> F
	MOVLW		RSLADRS			;data -> W
	MOVWF		READLADRS		;W -> F
	;--------------
;	READADRS	;スレーブアドレス・リード・レジスタ
;	WRITEADRS	;スレーブアドレス・ライト・レジスタ
;===============================================================================
;For PORTA  RA0=OUT using trigger pulse for oscilloscope
	BANKSEL		TRISA
	MOVLW		b'00000000'
	MOVWF		TRISA
	banksel		PORTA
	CLRF		PORTA
;===============================================================================
;For MCLR INIT 1pin MCLR to use reset sw 1pin (PORTE-RE3)
	BANKSEL		PORTE
	CLRF		PORTE
	BANKSEL		ANSEL
	CLRF		ANSEL
	BANKSEL		TRISE
	MOVLW		b'00001000'
	MOVWF		TRISE
;===============================================================================
;***	iNTERNAL OSC 設定 ( OSCCON-8Fh )
;OSCINIT
	BANKSEL		OSCCON
	MOVLW   	70h        	;CLOCK=4MHz (70H=8MHzでMAX)
        MOVWF   	OSCCON
       	BCF		STATUS,5	;Back to BANK0
;===============================================================================
;I2C の為の初期化
LOOP:
	CALL		I2C_INIT
;===============================================================================
;LOOP:
;===============================================================================
;E24LC64WRITE
	CALL		IDLE
	CALL		START_I2C
	CALL		E24LC64_WRITE
	CALL		STOP_I2C
;===============================================================================
;For EEPROM WRITE WAITING TIME(Musd be 5ms minimum) if no wait gonna be freeze
	CALL		TIM10ms	
;===============================================================================
;E24LC64READ
	BANKSEL		PORTA	    ;For oscilloscope trigger 
	CLRF		PORTA	    ;↑
	BSF		PORTA,0	    ;↑
	
	CALL		IDLE
	CALL		START_I2C
	CALL		E24LC64_READ
	CALL		STOP_I2C
	
	banksel		PORTA	    ;For oscilloscope trigger
	BCF		PORTA,0	    ;↑
;===============================================================================	
	BANKSEL		W_TEMP
	MOVF		W_TEMP,W	;W_TEMP -> W
	MOVWF		PORTB		;W → PORTB に即出力(LEDモニタとして使用)
;===============================================================================
	GOTO		LOOP

end


・p16f886_24C64_read.asm   サブルーチン、読み出し

	list      	p=16F886	; 翻訳時にリストファイルを作ります
	#include 		; 定義ファイルを読み込みます
	errorlevel  	-302		; 翻訳時に302エラーが出ないようにします
	errorlevel  	-205		; 翻訳時に205エラーが出ないようにします
	errorlevel  	-305		; 翻訳時に305エラーが出ないようにします
	;***********************************************************************
;サブルーチン、E24LC64を読む
	GLOBAL	E24LC64_READ
	;サブルーチンのラベル名がメインプログラムでEXTERNで宣言されて居る
	;その為、必ずGLOBALで受ける、つまり EXTERN と GLOBAL はペア
;===============================================================================
CODE	;サブルーチン、ここから
;===============================================================================
;	WRITEADRS	;スレーブアドレス・リードの為のライト
E24LC64_READ
	BANKSEL		WRITEADRS
	MOVF		WRITEADRS,W	;F -> W  スレーブアドレス一発目はライトモード
	MOVWF		SSPBUF		;W -> F  INITIATE SEND この瞬間に送信される
;SLAVE ADDRESS
SENDC3:
	BANKSEL		PIR1
	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		$-1		;IF NO,END 
	
;===============================================================================
;	メモリアドレス上位送信
	BANKSEL		READHADRS
	MOVF		READHADRS,W	;F -> W  
	MOVWF		SSPBUF		;W -> F  INITIATE SEND この瞬間に送信される
;SLAVE ADDRESS
SENDC3B:
	BANKSEL		PIR1
	BTFSS		PIR1, SSPIF	;SEND COMPLETED? YES,SKIP NEXT 送信完了?
	GOTO		SENDC3B
	BCF		PIR1, SSPIF	;YES,CLEAR FLAG 割り込みフラグ・クリア
	BANKSEL		SSPCON2
	BTFSC		SSPCON2,ACKSTAT	;ACK RECEIVED FROM SLAVE?IF YES SKIP
					; スレーブからの ACK待ち 0=受信済み次ぎをスキップ
	GOTO		$-1		;IF NO,END 
;	RETURN
;===============================================================================
;	メモリアドレス下位送信
	BANKSEL		READLADRS
	MOVF		READLADRS,W	;F -> W  
	MOVWF		SSPBUF		;W -> F  INITIATE SEND この瞬間に送信される
SENDC3C:
	BANKSEL		PIR1
	BTFSS		PIR1, SSPIF	;SEND COMPLETED? YES,SKIP NEXT 送信完了?
	GOTO		SENDC3C
	BCF		PIR1, SSPIF	;YES,CLEAR FLAG 割り込みフラグ・クリア
	BANKSEL		SSPCON2
	BTFSC		SSPCON2,ACKSTAT	;ACK RECEIVED FROM SLAVE?IF YES SKIP
					; スレーブからの ACK待ち 0=受信済み次ぎをスキップ
	GOTO		$-1		;IF NO,END 
;===============================================================================
	;repeated start
	banksel		SSPCON2
	bsf		SSPCON2,RSEN
	btfsc		SSPCON2,RSEN
	goto		$-1
;===============================================================================
;	READADRS	;スレーブアドレス・リード
	BANKSEL		READADRS	;bank0
	MOVF		READADRS,W	;F -> W  スレーブアドレス・リード
	MOVWF		SSPBUF		;W -> F  INITIATE SEND この瞬間に送信される
SENDC3D:
	BANKSEL		PIR1
	bcf		PIR1,SSPIF
	BTFSS		PIR1, SSPIF	;SEND COMPLETED? YES,SKIP NEXT 送信完了?
	GOTO		SENDC3D
	BCF		PIR1, SSPIF	;YES,CLEAR FLAG 割り込みフラグ・クリア
	BANKSEL		SSPCON2
	BTFSC		SSPCON2,ACKSTAT	;ACK RECEIVED FROM SLAVE?IF YES SKIP
					; スレーブからの ACK待ち 0=受信済み次ぎをスキップ
	GOTO		$-1		; Wait to ACK END
;===============================================================================
;	I2Cから1byte入力しWREGに格納する。デバイスへはNACKを返す。
;	i2c_last_read	最終1byte入力
        bsf		SSPCON2,RCEN    ; 受信を許可
        btfsc		SSPCON2,RCEN
        goto		$-1		; PICが受信許可状態になるまでループ
	
	banksel		PIR1		;bank0
	btfss		PIR1,SSPIF
	goto		$-1
	bcf		PIR1,SSPIF
	
	banksel		SSPBUF		;bank0
	movf		SSPBUF,W
	MOVWF		W_TEMP		;W -> W_TEMP  I/O EXPANDER へ出力するデータの確保
	
	banksel		SSPCON2		;bank1
        bsf		SSPCON2,ACKDT   ; NACKを出力
        bsf		SSPCON2,ACKEN   ; ACKENをセット
        btfsc		SSPCON2,ACKEN
        goto		$-1		; ACKの送信が終了するループ
	
	banksel		PIR1		;bank0
	bcf		PIR1,SSPIF
        
        return

END


・p16f886_24C64_sub_i2c.asm サブルーチン

	list      	p=16F886	; 翻訳時にリストファイルを作ります
	#include 		; 定義ファイルを読み込みます
	errorlevel  	-302		; 翻訳時に302エラーが出ないようにします
	errorlevel  	-205		; 翻訳時に205エラーが出ないようにします
	errorlevel  	-305		; 翻訳時に305エラーが出ないようにします
	;***********************************************************************
;サブルーチン、PCF8574を読む
	GLOBAL	I2C_INIT,START_I2C,STOP_I2C,IDLE

	;サブルーチンのラベル名がメインプログラムでEXTERNで宣言されて居る
	;その為、必ずGLOBALで受ける、つまり EXTERN と GLOBAL はペア
;===============================================================================
CODE	;サブルーチン、ここから
;===============================================================================
I2C_INIT
;===============================================================================
;I2C の為の初期化
	BANKSEL		SSPCON		;BANK0
	movlw		0x28		;0x28 = シリアルポートを動作させ、SDA とSCL ピンをシリアルポートピンにする。
					;0x28 = I2C マスターモード、クロック= FOSC / (4 * (SSPADD+1) )
	movwf		SSPCON
	
	BANKSEL		SSPSTAT		;BANK1
	BSF		SSPSTAT, SMP
	BCF		SSPSTAT, CKE
	CLRF		TRISB		;BANK1
	BSF		TRISC, 0x04	;SDA=IN
	BSF		TRISC, 0x03	;SCL=IN
	MOVLW		0x13		;I2C BUS speed  小さい程早く成る
	MOVWF		SSPADD		;BANK1
	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		;bank1
 	BSF		SSPCON2,PEN
	BCF		STATUS,RP0	;bank0
SENDBE:	
	BTFSS		PIR1,SSPIF	
	GOTO		SENDBE
	BCF		PIR1,SSPIF
	RETURN
;===============================================================================
;idle
IDLE:
    banksel SSPCON2
;    
;    CLRF    SSPCON2
;    btfsc   SSPCON2,ACKDT
;    goto    $-1
;    
    btfsc   SSPCON2,ACKEN
    goto    $-1
    btfsc   SSPCON2,RCEN
    goto    $-3
    btfsc   SSPCON2,PEN
    goto    $-5
    btfsc   SSPCON2,RSEN
    goto    $-7
    btfsc   SSPCON2,SEN
    goto    $-9
    RETURN
				
END

・p16f886_24C64_write.asm   サブルーチン、書き込み

	list      	p=16F886	; 翻訳時にリストファイルを作ります
	#include 		; 定義ファイルを読み込みます
	errorlevel  	-302		; 翻訳時に302エラーが出ないようにします
	errorlevel  	-205		; 翻訳時に205エラーが出ないようにします
	errorlevel  	-305		; 翻訳時に305エラーが出ないようにします
	;***********************************************************************
;サブルーチン、PCF8574を読む
	GLOBAL	I2C_INIT,START_I2C,STOP_I2C,IDLE

	;サブルーチンのラベル名がメインプログラムでEXTERNで宣言されて居る
	;その為、必ずGLOBALで受ける、つまり EXTERN と GLOBAL はペア
;===============================================================================
CODE	;サブルーチン、ここから
;===============================================================================
I2C_INIT
;===============================================================================
;I2C の為の初期化
	BANKSEL		SSPCON		;BANK0
	movlw		0x28		;0x28 = シリアルポートを動作させ、SDA とSCL ピンをシリアルポートピンにする。
					;0x28 = I2C マスターモード、クロック= FOSC / (4 * (SSPADD+1) )
	movwf		SSPCON
	
	BANKSEL		SSPSTAT		;BANK1
	BSF		SSPSTAT, SMP
	BCF		SSPSTAT, CKE
	CLRF		TRISB		;BANK1
	BSF		TRISC, 0x04	;SDA=IN
	BSF		TRISC, 0x03	;SCL=IN
	MOVLW		0x13		;I2C BUS speed  小さい程早く成る
	MOVWF		SSPADD		;BANK1
	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		;bank1
 	BSF		SSPCON2,PEN
	BCF		STATUS,RP0	;bank0
SENDBE:	
	BTFSS		PIR1,SSPIF	
	GOTO		SENDBE
	BCF		PIR1,SSPIF
	RETURN
;===============================================================================
;idle
IDLE:
    banksel SSPCON2
;    
;    CLRF    SSPCON2
;    btfsc   SSPCON2,ACKDT
;    goto    $-1
;    
    btfsc   SSPCON2,ACKEN
    goto    $-1
    btfsc   SSPCON2,RCEN
    goto    $-3
    btfsc   SSPCON2,PEN
    goto    $-5
    btfsc   SSPCON2,RSEN
    goto    $-7
    btfsc   SSPCON2,SEN
    goto    $-9
    RETURN
				
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'1' 		;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


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

nice! 0

コメント 0

コメントを書く

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

世田谷ボロ市PIC16F886--I2C--MCP2.. ブログトップ

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