お客様の案件で I2C を使う回路設計の必要が在りました
はい、過去形ですが実は没に成って仕舞った案件です
然し乍ら設計者のさがで一度始めると納得行くまでやって仕舞う
この悪い癖、何とかしなければならないのですが・・・・
でも、やって置けば其れだけ後々何かの役に立つ事も有るでしょう
という訳でドキュメントを残す意味で簡単な回路を組んでみました
まず、使用するICは・・・・
CPU が PIC16F876A 28pin Dip MICROCHIP社
日本語マニュアルが用意されているので製作記事が多いです
このPICにはMSSP(Master Synchronous Serial Port)が内蔵され
これがあることでI2Cが利用しやすいわけです
他のデバイスICと高速にシリアル通信をするためのモジュールで、SPIと
I2Cという2種類の動作モードで使うことができます。
I2Cという2種類の動作モードで使うことができます。
↓

RC3/SCK/SCLとRC4/SDI/SDA を使います。
↓
IO Expander が PCF8574AN TEXAS社
16pin Dip で 8bit I/O です
回路を組む上で注意しなければならない事が有ります
それは出力で使うときの電流値です
Low出力は50mA流せますからリレー動きますよね
ところが
High出力はたったの4mA
LEDを点灯しようとしても昔のLEDだと暗くて話しに成りません
もう一つ押さえておきたいことは入力として使用した場合
OPEN = High だという事です、入力端子の空きピン処理は考慮に
入れて置かなければなりませんね
↓


またスレーブアドレスが僅かな型式違いで異なるので知らないと焦ります
驚くのは同じPCF8574Aでもスレーブアドレスが違うって・・・何?
購入するときは良く確認しなければなりません
特にこのマニュアル
どう考えてもおかしい、このスレーブアドレスで設計された記事を
全く見掛けません、マニュアルのダウンロードにもご注意下さい
仮にスレーブアドレス 0x20 とした場合、READ アドレスは 0x21
てなければならない、なのに A0 = High と成ったときに 0x21に
成って居ます、通常は LSBがHigh に成った場合スレーブアドレスは
0x02加算されなければなりません、なんで?
↓
これらを使って LEDの点滅、詰まり Lチカ をやってみようと思います
この組み合わせにした理由ですが下記の様な条件が在ったからです・・・
・GPIOを使う
・LEDを50個ぐらい使う
・スイッチを20個ぐらい使う
・メンブレン・パネルに実装したい
・UART / I2C は可能
・SPI はダメ
・・・とこんな条件なのですがGPIOではピン数が限定的でとても
これだけの I/O はカバー仕切れません、その為に IO Expander を採用しました
I2Cにしたのは過去にハードウェアのみ経験しているからです
ところが採用したい I2C のソフトウェアに問題が在るのです
私はめっきりソフトウェアに弱いので皆様のように C言語でサクッ!! っと
プログラミング出来ません、なのでどうするか・・・・
・アセンブラ言語とする
・可能な限りネット検索してプログラムを引っぱってくる
・ブレッドボードを使う
・・・・こんな地味ぃな戦略なのです
2018/12/07(金)
ブレッドボードに仮組みしてみました
↓
写真で出来て居る事は、出力制御です、8bit 出力の確認をLEDで
行って居ます。
ここで判った事ですが上でも書いたように出力が Low / High で
電流値が大きく異なり、実際のLEDを接続するとこんな感じです。
この写真は出力Highの様子です、LEDは点いているのか消えているのか
良く視ないと判別がつきません
↓
一方でこの写真は出力Lowの様子で、これが正常ですよね。
↓
この様にバッファー・ドライバー無しで使うときは注意が必要です
ソースコードの窓をこのブログに作りたいのですが面倒なので
後回しです、下記の通りです、折り返しが出ていますので
コピペの後、ご注意下さいこのままだとコンパイルエラーが出ます
トランジスタ・アレイ程度ならHighでドライブ出来ると思いますが
確認はマストですね。
話が少し逸れますが、使用している PIC KIT3 ですが壊した経緯が
有ります、原因はVDDに +24V が印加された為、PIC KIT3のあの
スケルトンで中が燃えているのが見えました、ひやぁーーー、でした
まぁ回路屋なので回路図をネット検索して探し、壊れて居そうな部品
をRSコンポーネンツで購入し直しました、ですがもう二度とあんな事は
嫌なのでプロテクタを中間に入れて使用しています。
↓
ツェナーダイオードの大きめのを入れ、抵抗が燃え切れる様にしました
序でなのでPIC KIT3が付いたままだと動かない事、って有りますよね
なので CLK / DAT をスイッチで切れる様にもして居ます、以来
気をつけているのでトラブルは無いですが、また在ると嫌だな。
↓
ブレッドボードで製作した回路ではプログラムに書かれたHEXデータ
1byte 分をLED表示するというものです
参考にと言うかコピーしたプログラムで引用元はこちらです
https://www.picmicrolab.com/pcf8574-i2c-8-bit-io-expander/
因みにコンパイラは 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
何故か同期はビデオだと良く見えました、なんで?
↓
—記事制作中—
ブレッド・ボードですが一度作るとそのままにして置く事が多く
本来の何度でも作り直せるという目的から外れてしまうのでここは
ユニバーサル基板に組み付けようという事に成りました
先ずは PIC 基板、ICソケットを使い他のPICにも換えられる様に
しました、特に水晶発振ユニットは無くしたいのでこれも
ICソケットに実装しています
↓
この基板は I/O OUT で出力基板です、出力の状態がLEDで判りやすく
してあります、又、スレーブアドレスも自由に変えられるようDIP SW
にしてあります
↓
この基板は I/O IN 入力基板です
データを自由に変えたいのでDIGI SW を1byte分用意しました
スレーブアドレスも自由に変えられるようDIP SWです
↓
マスターとスレーブを繋ぐケーブルですMOLEX-4P を使いました
↓
動画は 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 が入ってました
↓
慣れるとオシロスコープの波形でデータが読めますね
2018/12/10(月)朝
回路図が書き上がりました
このままだと拡大しても文字が読めませんね
部分的に分解して視やすくします
2018/12/10(月)夜
PICですがPIC16F876Aを止めPIC16F886にしました、理由は
内部発振回路を使って外付けの水晶発振子を無くしたかったからです
良いことにPIC16F876 と PIC16F886 はピンコンパチなのと内部
レジスタが殆ど一緒、少なくとも今回の評判用に使うレジスタは全く
同じでした。
↓
動画はループ・プログラムです。
出力を +1 して繰り返しています、
向かって左が PIC 水晶発振子
向かって左が 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
—記事制作中—