; list p=PIC16F628 #include ; ; Kubitama EIA-574 Unit Version 1.0A ; (c) 2004 Sugihara Toshio. ; All rights reserved. ; PIC16F628 ; Clock=4.00MHz 1.00M orders/s osc=XT ; WDT=off PowerupTimer=on ; Protect=off BrownoutDetect=On ; LowVoltageProg=off MCLR=Enable ; Memory for Bank 0 counth equ H'20' ;カウントルーチン用 countm equ H'21' countl equ H'22' wlooph equ H'23' ;待ち専用ルーチン用 wloopl equ H'24' adrh equ H'25' adrl equ H'26' startadrh equ H'27' startadrl equ H'28' stopadrh equ H'29' stopadrl equ H'2a' adrflag equ H'2b' ;bit0=始点発見 bit1=終点発見 lcbuf equ H'2c' lccount equ H'2d' readh equ H'2e' readl equ H'2f' eibuf equ H'30' ;EIA574のバッファ eicount equ H'31' eihexa equ H'32' eihexb equ H'33' lcwrflag equ H'34' ;Writeで00 Readでff sendend equ H'35' ;送信終了条件成立でff。不成立で00 ;プログラムの開始点 boot org H'0' goto start warukomi org H'4' goto start start ;I/Oなどの初期化 clrf INTCON clrf STATUS clrf PORTB clrf PORTA movlw B'00111000' ;Select Bank 1 movwf STATUS movlw B'01000111' ;TMR0 overflows per 65.536 msec.(1/256) movwf OPTION_REG movlw B'11110010' ;A3,A2,A0が出力 movwf TRISA movlw B'10011011';B6,B5,B2が出力 movwf TRISB bcf STATUS,RP0 ;Select Bank 0 movlw B'11011010' ;赤点灯。B4,B3,B1をpull-up movwf PORTB movlw B'11110011' ;待ち状態に対応する値を送る movwf PORTA movlw B'00000111' ;コンパレータを使わない movwf CMCON ;タイマの初期化 clrf TMR0 ;値を初期化 bcf INTCON,T0IF ;あふれフラグを下げる startloop ;青ボタンを待つ clrf countl ;時間カウンタをクリア bsf PORTB,4 btfsc PORTB,4 goto startloop ;押されていなかったら最初に戻る bluebtnloop call wait8ms bsf PORTB,4 btfsc PORTB,4 goto startloop ;押されていなかったら最初に戻る decfsz countl,F ;2秒経過した? goto bluebtnloop ;いいえ。ループする。 ;はい。 bcf PORTB,6 ;赤ランプを消す ;EIA-574に最初の情報を出力 ;最初の改行 movlw H'0a' call EIsendbyte btfsc eibuf,0 ;エラーだった? goto start ;はい。ブート時点まで戻る ;いいえ。 ;HELO movlw A'H' call EIsendbyte movlw A'E' call EIsendbyte movlw A'L' call EIsendbyte movlw A'O' call EIsendbyte movlw H'0a' call EIsendbyte btfsc eibuf,0 ;エラーだった? goto start ;はい。ブート時点まで戻る ;いいえ。 ;バージョン movlw A'V' call EIsendbyte movlw A'=' call EIsendbyte movlw H'00' call EIsendhex movlw H'10' call EIsendhex movlw H'0a' call EIsendbyte btfsc eibuf,0 ;エラーだった? goto start ;はい。ブート時点まで戻る ;いいえ。 ;アクセス要求をする bcf PORTB,0 bsf STATUS,RP0 ;Select Bank 1 bcf TRISB,0 ;B0を出力にする bcf STATUS,RP0 ;Select Bank 0 bcf PORTB,0 ;アクセス要求を送る clrf countl acreqloop bsf PORTB,1 ;返事を受けるピンをプルアップ call wait8ms call wait8ms btfss PORTB,1 ;くびたまは要求を受け入れた? goto startac ;はい。 ;いいえ。 decfsz countl,F ; 4秒たっても受け入れられなかった? goto acreqloop ; いいえ。まだ続ける。 goto start ; はい。ブート時点に戻る startac call wait8ms btfsc PORTB,1 ;接触不良などの異常チェック goto acreqloop ;異常なので受け入れをチェックに戻る ;正常。 ;アクセスの開始 bsf PORTB,2 ;くびたまのEEPROMの電源を入れる call wait8ms bcf PORTA,2 ;(反転)ライトプロテクトをかける ;転送開始・終了位置の検索 clrf adrflag ;発見フラグの初期化 clrf adrh ;アドレスの初期化 clrf adrl ;最初の読み取りコマンドを送信 call LCwriteRH btfsc lcbuf,0 goto start ;エラーだったらブートまで戻る ;メモリからデータの読み取り acnext call LCreadbyte movwf readh call LCsendACK call LCreadbyte movwf readl call LCsendACK ;値のチェック incf readh,W btfss STATUS,Z ;上位バイトはff? goto acinc ;いいえ。 ;はい。 incf readl,W btfsc STATUS,Z ;下位バイトはff? goto foundffff ;はい。 ;いいえ。 movf readl,W andlw H'f0' xorlw H'f0' btfss STATUS,Z ;f0-feの範囲? goto acinc ;いいえ。 ;はい。 ;fff0-fffeの範囲だった foundfffx ;開始位置を現在のアドレスにする movf adrh,W movwf startadrh movf adrl,W movwf startadrl ;fffx(始点)発見フラグを上げる bsf adrflag, 0 goto acinc ;ffffだった foundffff ;以前にffffが見つかっている場合はfffxとして扱う btfsc adrflag,1 ;終点フラグは上がってる? goto foundfffx ;はい。 ;いいえ。 ;終点アドレスを現在のアドレスにする movf adrh,W movwf stopadrh movf adrl,W movwf stopadrl ;始点が見つかっていれば完了 btfsc adrflag,0 goto doneac ;始点にも現在のアドレスをセット movf adrh,W movwf startadrh movf adrl,W movwf startadrl ;終点フラグ・始点フラグを両方上げる bsf adrflag,1 ;終点 bsf adrflag,0 ;始点 goto acinc ;それ以外の値だった。 ;または特定の値での処理が終わったあと acinc ;アドレスに2を加える movlw D'2' addwf adrl,F btfsc STATUS,Z incf adrh,F ;アドレスが8000hに達していたら抜ける btfss adrh,7 ;8000hに来た? goto acnext ;いいえ。 ;はい。 ;ffffが見つかっていればデータ完成 btfsc adrflag,1 ;終点フラグがあがってる? goto doneac ;はい。 ;いいえ。 goto start ;ブート時点まで戻る doneac ;読み取りを終わるためにもう1バイトだけ読む call LCreadbyte call LCsendNOACK call LCstop ;A4は入力になる。 ;EIA-574転送。アドレス情報以降。 ;開始点アドレス movlw A'S' call EIsendbyte movlw A'=' call EIsendbyte movf startadrh,W call EIsendhex movf startadrl,W call EIsendhex movlw H'0a' call EIsendbyte btfsc eibuf,0 ;エラーだった? goto start ;はい。ブート時点まで戻る ;いいえ。 ;終了点アドレス movlw A'E' call EIsendbyte movlw A'=' call EIsendbyte movf stopadrh,W call EIsendhex movf stopadrl,W call EIsendhex movlw H'0a' call EIsendbyte btfsc eibuf,0 ;エラーだった? goto start ;はい。ブート時点まで戻る ;いいえ。 ;BEG movlw A'B' call EIsendbyte movlw A'E' call EIsendbyte movlw A'G' call EIsendbyte movlw H'0a' call EIsendbyte btfsc eibuf,0 ;エラーだった? goto start ;はい。ブート時点まで戻る ;いいえ。 ;先頭アドレスから順次出力 clrf sendend ;終了アドレスへの到達フラグを初期化 ;始点アドレスのセット movf startadrh,W movwf adrh movf startadrl,W movwf adrl ;読み取りコマンドの送出 call LCwriteRH btfsc lcbuf,0 goto start ;エラーだったら最初に戻る ;メモリのデータを順次読み出す sendNextWord ;24LC256から読み取る call LCreadbyte movwf readh call LCsendACK call LCreadbyte movwf readl call LCsendACK ;EIA-574へ送る movf readh,W call EIsendhex movf readl,W call EIsendhex movlw H'0a' call EIsendbyte btfsc eibuf,0 ;エラーだった? goto start ;はい。ブート時点まで戻る ;いいえ。 ;終了フラグが上がっていたら抜ける btfsc sendend,0 ;送信終了フラグが上がっている? goto sendfinish ;はい。 ;いいえ。 ;アドレスを進める call incadrby2 ;最終アドレスに達していたら終了フラグを上げる movf stopadrh,W xorwf adrh,W btfss STATUS,Z ;上位アドレスは等しい? goto sendNextWord ;いいえ。 ;はい。 movf stopadrl,W xorwf adrl,W btfss STATUS,Z ;下位アドレスは等しい? goto sendNextWord ;いいえ。 ;はい。 ;終了フラグを上げる movlw H'ff' movwf sendend goto sendNextWord ;送信終了 sendfinish ;もう1回だけ読んで24LC256へのアクセスを終える call LCreadbyte call LCsendNOACK call LCstop ;A4は入力になる。 ;EIA-574にEND(改行2つ)を送る。 movlw A'E' call EIsendbyte movlw A'N' call EIsendbyte movlw A'D' call EIsendbyte movlw H'0a' call EIsendbyte movlw H'0a' call EIsendbyte btfsc eibuf,0 ;エラーだった? goto start ;はい。ブート時点まで戻る ;いいえ。 ;青を表示 bsf PORTB,5 waityel clrf countl ;待ちカウンタをリセット bsf PORTB,3 ;黄ボタンをプルアップ call wait8ms btfsc PORTB,3 ;黄ボタンが押された? goto waityel ;いいえ。 ;はい。 waityel2s bsf PORTB,3 call wait8ms btfsc PORTB,3 goto waityel ;離したので黄ボタン押し待ちに戻る decfsz countl,F goto waityel2s ;黄ボタンを2秒間押し続けた場合 writeNewEnd ;ライトプロテクトを外す bsf PORTA,2 ;反転論理 ;終点アドレスより1つ(2)後の位置にffffを書く movf stopadrh,W movwf adrh movf stopadrl,W movwf adrl ;アドレスを1つ先にする call incadrby2 ;ここにffffを書き込む call LCwriteWH btfsc lcbuf,0 goto start ;エラーなのでブート movlw H'ff' call LCsendbyte btfsc lcbuf,0 goto start ;エラーなのでブート movlw H'ff' call LCsendbyte btfsc lcbuf,0 goto start ;エラーなのでブート call LCstop ;書き込み命令完了 ;書き込み完了まで待つ writeNewEndp2 call LCstart movlw B'10100000' call LCsendbyte btfsc lcbuf,0 goto writeNewEndp2 ;書き込み未完 ;書き込み完了 ;ベリファイ ;値を読み取る call LCwriteRH btfsc lcbuf,0 goto start ;エラーなのでブート call LCreadbyte movwf readh call LCsendACK call LCreadbyte movwf readl call LCsendNOACK call LCstop ;値を検査する movf readh,W xorlw H'ff' btfss STATUS,Z goto writeNewEnd ;書き直し movf readl,W xorlw H'ff' btfss STATUS,Z goto writeNewEnd ;書き直し ;送信完了による区切り符号を書き込む writeNewfff0 movf stopadrh,W movwf adrh movf stopadrl,W movwf adrl call LCwriteWH btfsc lcbuf,0 goto start ;エラーなのでブート movlw H'ff' call LCsendbyte btfsc lcbuf,0 goto start ;エラーなのでブート movlw H'f0' call LCsendbyte btfsc lcbuf,0 goto start ;エラーなのでブート call LCstop ;書き込み命令完了 ;書き込み終了まで待つ writeNewfff0p2 call LCstart movlw B'10100000' call LCsendbyte btfsc lcbuf,0 goto writeNewfff0p2 ;書き込み未完 ;書き込み完了 ;ベリファイ ;値を読み取る call LCwriteRH btfsc lcbuf,0 goto start ;エラーなのでブート call LCreadbyte movwf readh call LCsendACK call LCreadbyte movwf readl call LCsendNOACK call LCstop ;値を検査する movf readh,W xorlw H'ff' btfss STATUS,Z goto writeNewfff0 ;書き直し movf readl,W xorlw H'f0' btfss STATUS,Z goto writeNewfff0 ;書き直し ;書き込みは正常に終了した call wait8ms ;24LC256の切り離し bcf PORTA,2 ;WPを上げる bcf PORTA,3 ;Clockを上げる bcf PORTB,2 ;電源Off call wait8ms ;アクセス要求の終了 bsf STATUS,RP0 ;Select Bank 1 bsf TRISB,0 ;B0を入力にする bcf STATUS,RP0 ;Select Bank 0 ;EIA-574は待機状態(1) bsf PORTA,0 ;行うことが全て終わったので ;赤と青を両方点灯した状態で ;リセット・ケーブル抜き取り待ち。 endloop call wait8ms bsf PORTB,5 ;青をつける bsf PORTB,6 ;赤をつける goto endloop goto endloop goto endloop ;---------------------- ; ここからサブルーチン ;---------------------- ; 24LC256に開始信号を送る ; A4を出力に切り替える ; クロックとデータが両方下がった状態で終了 LCstart bsf STATUS,RP0 ;Select Bank 1 bcf TRISA,4 ;A4を出力にする bcf STATUS,RP0 ;Select Bank 0 bsf PORTA,3 ;(反転)クロックを下ろす goto LCstartp2 LCstartp2 bsf PORTA,4 ;(正論理)データを上げる goto LCstartp3 LCstartp3 bcf PORTA,3 ;クロックを上げる goto LCstartp4 LCstartp4 bcf PORTA,4 ;データを下げる goto LCstartp5 LCstartp5 bsf PORTA,3 ;クロックを下げる return ; 24LC256に終了信号を送る。 ; A4を入力に切り替える ; クロックとデータが両方あがった状態で終了。 LCstop bsf PORTA,3 ;クロック(反転)を下ろす goto LCstopp2 LCstopp2 bcf PORTA,4 ;(正論理)データを下ろす goto LCstopp3 LCstopp3 bcf PORTA,3 ;クロックを上げる goto LCstopp4 LCstopp4 bsf PORTA,4 ;データを上げる bsf STATUS,RP0 ;Select Bank 1 bsf TRISA,4 ;A4を入力にする bcf STATUS,RP0 ;Select Bank 0 return ; Wレジスタで受けた値を1バイト送信。 ; ACKを受け取った場合lcbuf,W=0で返す。 ; ACKがないとlcbuf,W=ffで返す。 ; A4=出力、クロックが下がった状態で呼んでください。 ; クロックが下がった状態で終わる。 LCsendbyte movwf lcbuf movlw D'8' movwf lccount LCsendbytep2 btfss lcbuf,7 goto LCsendbyte3 bsf PORTA,4 ;1を出す場合 goto LCsendbyte4 LCsendbyte3 bcf PORTA,4 ;0を出す場合 goto LCsendbyte4 LCsendbyte4 bcf PORTA,3 ;クロックを上げる goto LCsendbyte5 LCsendbyte5 bsf PORTA,3 ;クロックを下げる rlf lcbuf,F ;1ビット左へずらす decfsz lccount,F goto LCsendbytep2 ;ACKのチェック bsf STATUS,RP0 ;Select Bank 1 bsf TRISA,4 ;A4を入力にする bcf STATUS,RP0 ;Select Bank 0 nop bcf PORTA,3 ;クロックを上げる nop movlw H'00' btfsc PORTA,4 ;ACKのチェック movlw H'ff' ;ACKがない場合 movwf lcbuf ;戻り値を書き込む bsf PORTA,3 ;クロックを下げる nop bsf STATUS,RP0 ;Select Bank 1 bcf TRISA,4 ;A4を出力にする bcf STATUS,RP0 ;Select Bank 0 return ; 1バイト読み取る ; 値はWレジスタに入れて返す ; lcbufにも入れる。 ; クロックが下がった状態で呼びます ; 終了時A4=出力となります。 ; ACK用のクロックは送りません。 LCreadbyte bsf STATUS,RP0 ;Select Bank 1 bsf TRISA,4 ;A4を入力にする bcf STATUS,RP0 ;Select Bank 0 movlw D'8' movwf lccount LCreadbytep2 bcf PORTA,3 ;クロックを上げる rlf lcbuf,F bsf lcbuf,0 btfss PORTA,4 bcf lcbuf,0 bsf PORTA,3 ;クロックを下げる decfsz lccount,F goto LCreadbytep2 bsf STATUS,RP0 ;Select Bank 1 bcf TRISA,4 ;A4を出力にする bcf STATUS,RP0 ;Select Bank 0 movf lcbuf,W ;呼んだ内容をWレジスタにも入れる return ; ACKを送る LCsendACK bcf PORTA,4 goto LCsendACKp2 LCsendACKp2 bcf PORTA,3 ;クロックを上げる goto LCsendACKp3 LCsendACKp3 bsf PORTA,3 ;クロックを下げる return ;NOACKを送る LCsendNOACK bsf PORTA,4 goto LCsendNOACKp2 LCsendNOACKp2 bcf PORTA,3 ;クロックを上げる goto LCsendNOACKp3 LCsendNOACKp3 bsf PORTA,3 ;クロックを下げる return ; adrh, adrlのアドレスに書き込み用 ; (ランダムアクセスリードと兼用)の ; コマンドを送る。 ; 続けて1バイト書けば書き込みになる。 ; 続けてStartとリードコマンドを送れば読み込みになる。 ; 正常終了でW,lcbuf=00となる。 ; 異常時はW,lcbuf=ffとなる。 LCwriteWH clrf lcwrflag ;書き込みヘッダだけ送る goto LCwrhead ; 書き込み用ヘッダに続けて読み取り用コマンドも送る。 ; 戻り値などは書き込みヘッダを送るだけの場合と同じ。 LCwriteRH movlw H'ff' movwf lcwrflag ;読み込みヘッダも送る設定 LCwrhead call LCstart ;スタートコード movlw B'10100000' ;コマンドコード call LCsendbyte btfsc lcbuf,0 return ;エラーだったらリターン movf adrh,W ;上位アドレス call LCsendbyte btfsc lcbuf,0 return movf adrl,W ;下位アドレス call LCsendbyte btfsc lcbuf,0 return ;読み取り用コマンドを送るかどうかの分岐 btfss lcwrflag,0 return ;書き込みモードなのでこれで終わる ;読み取り用コマンドも送る call LCstart ;スタートコード movlw B'10100001';読み取りコマンド call LCsendbyte return ; EIA-584に1バイト送る ; データはWレジスタから受け取る ; RTSタイムアウト(4秒)でffh ; 正常終了で00hを、Wレジスタとeibuf ; の両方に入れて戻る。 EIsendbyte movwf eibuf clrf eicount ;RTSがあがる(値が0になる)のを待つ btfss PORTA,1 ;送信OK? goto EIsendbyte3 ;はい。 ;いいえ。 EIsendbyte2 ;RTSがあがるまで最大4秒待つ call wait8ms call wait8ms btfss PORTA,1 ;送信OK? goto EIsendbyte3 ;はい。 ;いいえ。 decfsz eicount,F goto EIsendbyte2 ;RTSが上がらなかったので戻る movlw H'ff' movwf eibuf return EIsendbyte3 ;スタートビット(1bit=26サイクル) bcf PORTA,0 ;0 call wait10c call wait10c movlw D'8' movwf eicount ;22 ;1ビットずつ8回出す(LSB first) EIsendbyte4 btfsc eibuf,0 goto EIsendbyte5 nop bcf PORTA,0 ;0を出す 26 goto EIsendbyte6 EIsendbyte5 bsf PORTA,0 ;1を出す 26 goto EIsendbyte6 EIsendbyte6 rrf eibuf,F ;1ビットずらす ;3 call wait10c call wait6c ;19 decfsz eicount,F goto EIsendbyte4 ;ストップビット(1bit)を出す call wait4c bsf PORTA,0 ;26 call wait10c call wait7c call wait6c ;正常終了で戻る clrf eibuf retlw H'00' ;26 ; 16進数2桁でWレジスタの値を送る ; 00からffまで。 ; 正常終了と異常終了はeibufとWレジスタ ; で判断(EIsendbyteルーチンの出力そのまま) EIsendhex movwf eihexa ;上4bitsの出力 swapf eihexa,W andlw H'0f' addlw D'48' movwf eihexb movlw D'58' subwf eihexb,W ;コード - 58 movlw D'39' btfsc STATUS,C ;コード >= 58 だったら addwf eihexb,F ;さらに39を加える。 movf eihexb,W call EIsendbyte btfsc eibuf,0 ;エラー? return ;はい。帰る。 ;いいえ。 ;下4bitsを出力 movf eihexa,W andlw H'0f' addlw D'48' movwf eihexb movlw D'58' subwf eihexb,W ;コード - 58 movlw D'39' btfsc STATUS,C ;コード >= 58 だったら addwf eihexb,F ;さらに39を加える。 movf eihexb,W call EIsendbyte return ; adrl,adrhを次の位置に進める incadrby2 movlw D'2' addwf adrl,F ;2ずつ進む btfsc STATUS,Z incf adrh,F ;くりあがり処理 bcf adrh,7 ;最上位ビットを下ろす return ; 8ms待つ ; 8000命令サイクル回す wait8ms movlw D'11' movwf wlooph movlw D'97' movwf wloopl wait8msp3 decfsz wloopl,F goto wait8msp3 decfsz wlooph,F goto wait8msp3 return ;callとreturnを含め ;決めたサイクル数待つ wait10c nop wait9c nop wait8c nop wait7c nop wait6c nop wait5c nop wait4c return end