PCF8574 IO EXPANDER の序でにEEPROMもドキュメントを
残そうと取り組んでみました、皆様のようにサクッ!!っとC言語とかで
制御出来なくて地道にPICマイコンのアセンブラで組んでみましたが
思いの外難しくて時間が掛かりました。
(ソースプログラムはこちらからダウンロード)
特記すべきはネット記事では見つからなかったものの良く探せば同様
のトラブルが在った事を解決後に知りましたが下記の様な事です・・・
EEPROMの書き込み時間は最低 5ms を必要とする
・・・という事実、これを知らなかったばかりに書き込み後直ちに
読み出しすると最初のスレーブアドレスを送信してフリーズして
仕舞うのです、この問題を解決するためにオシロスコープとにらめっこ
して何日無駄にしたか・・・・はぁ、って感じです、たまたま
デバッグする為にタイマーを入れたらすんなり動いたので
「なんで?」
もしやインターバルが必要なのかとネット検索したら同様のトラブル
の記事がみつかりまして「ああ、やっぱりそうか」と、更には
EEPROMのデータシートを視れば書き込みに5msと書いて有る
ではないですか、そんな訳で無駄な悪戦苦闘を強いられました。
データシートの当該部分です赤枠内
↓
取り敢えずこの動画はEEPROM のメモリー番地 0x000~0x0FF
の255のアドレスに00/01/02/03・・・・FD/FE/FF/00と一個ずつ加算
して書いて同時に読み出してLチカさせています。
↓
実際のI2C波形です、一つずつインクリメントしている様子が判ります
↓
ちゃんと書けているか確認しました、以前から所持していた秋月電子
PIC PROGRAMMER を使いました、この基板はPICだけで無く
アプリケーション・ソフトをダウンロードすればEEPROMの
読み書き込みも可能なのです
↓
但し、これを使うに当たっては色々と問題が在りました
先ず、今時のパソコンにはCOM1(9pin-D-sub / serial)が無い
で、あるにも関わらず我がDELL T3500には付いていた、だから今まで
PIC PROGRAMMERは問題無く動いていた、なのに秋月電子の
アプリケーション・ソフト、Serial EEPROM Programmer Ver6.5.8
は何故だか「エラー’13’型式が合いません」なるシステムエラーが出て
使えないのです、ならばという事で古いノートパソコンを引っ張り出して
それにインストールされている windows xp professional の元で
動かしたものの同様のエラーで動作しません、もうなにをやってもダメ
そこで思いついたのは USB/Serial変換器 REX -USB60F
これです ↓
これを使うことでSerial EEPROM Programmer Ver6.5.8は動くのです
折角COM1 / serial ポートが在るのにそれはダメでわざわざ
USB/Serial変換器を使うと動くという矛盾、その嫌らしさ・・・・
然かも COM14 とか、もう信じられない
という訳でちゃんと書けていることが確認出来ました
↓
オシロスコープで波形観測するには肝心な部分だけを視たいのに
他の波形が重複して見辛いことこの上ないですよね、その問題は
簡単に解決出来ました、PICの空きポートを利用してそこにトリガー
パルスを出してディレーで眺めれば楽勝です
製作した EEPROM 基板です、LEDは短絡しています
↓
単純にEEPROMだけですが、保護ダイオード、パスコン、チェック端子
とシンプルな基板です
↓

全体回路図
↓
これでは何も見えませんね、PIC部分
↓
EEPROM部分
↓
I2Cのプロトコルは下記の通り、データシートの抜粋です
デバッグしていて何が一番知りたかったか、それは実際の波形です
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は待って呉れ」とは書かれていないのです、データシートの
嫌らしさ、不親切さは自社の欠点や不利益な部分を別の真実という形で表現
し結果的に危険性が伝わらない、と云う形で書かれていると私は永年感じて
居ます
↓

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

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

読み出し START→ 0xA0→ ACK→ 0x00→ ACK
↓
読み出し 0x00→ ACK→ RESTART→ 0xA1
↓

読み出し 上の写真の 0xA1 は重複、続いて ACK→ 0x55→ NACK→ STOP
↓
書き込み START→ 0xA0→ ACK→ 0x00→ ACK
↓

書き込み 0x00→ ACK→ 0x55→ ACK→ STOP
↓

こうした具体的な波形で無いと私には無理。
プログラムです、下記のファイルと成ります
・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