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