; (c) 2002 Sugihara Toshio. ; All rights reserved. ; ; チャイムシステムプログラム[タイマー側] ; ;----------------------------------------------------------- ;ハード定義 include 16f84.h .osc LP .pwrt on .wdt off .protect off ;----------------------------------------------------------- ;変数定義 org 0ch ;保持する日時情報 week ds 1;曜日(0トキモスカケニ) hour ds 1;時(0-23) min ds 1;分(0-59) sec ds 1;秒(0-59) ;速度修正用変数 col ds 1;回(0-60) ;アラーム設定判定用変数 chnum ds 1;編集中のチャンネル chpoint ds 1;編集中のチャンネル先頭のEEPROMアドレス chweek ds 1;編集中の曜日 chhour ds 1;編集中の時 chmin ds 1;編集中の分 ;アラーム電源関係変数 alarmsec ds 1; アラーム電源残り秒数 alarmsw ds 1; アラームスイッチ押し続け秒数 ;conv10値2桁変換表示ルーチン ni ds 1;内部変数 n0 ds 1;出力値1の位 n1 ds 1;出力値10の位 ;曜日表示ルーチン用などバッファ変数 weekp ds 1;曜日表示用ダミー。EEPROM書き込みルーチンでも使用 ;アラーム曜日編集,判定用変数 weekmsk ds 1;曜日マスク weekcsr ds 1;編集用カーソル位置 ;停電管理 teiden ds 1;平常は0,停電中は1 ;出力バッファ outbuf ds 1;1バイト出力時のバッファ ;時間待ちルーチン用 timea ds 1;時間待ち制御用 ;----------------------------------------------------------- ;プログラム本体 boot org 0h goto start warikomi org 4h goto start ;ハードウエアの初期化 start movlw 00111000b ;バンク1を選択 movwf status ;すべての割り込みを禁止 startloop bcf intcon, 7 ;GIEビットを下げる btfsc intcon, 7 goto startloop clrf intcon ;割り込み管理ビットは全部off ;BポートプルアップOFF、TMR0のソースは命令サイクルクロック ;プリスケーラはTMR0で、分周比1:32に。1秒に1回オーバーフロー movlw 10000100b movwf option ;Aポートは1234が入力、0は出力とする movlw 00011110b movwf porta ;Bポートをすべて出力とする clrf portb ;バンク0を選択 bcf status, 5 ;I/O出力初期化 clrf porta ;アラームパルスを解除 clrf portb ;LCD出力を全て下げる ;電源オン直後状態 poweronloop ;タイマの初期化 clrf tmr0 bcf intcon,2 ;停電状態の調査 clrf teiden ;停電していないteiden=0 btfss porta,4 ;停電している teiden=1 incf teiden,1 ;ブートしたことを表示 btfsc teiden,0 ;停電中? goto powerbutton ;はい、表示せずにボタン待ちへ進む ;いいえ、表示開始 call initlcd ;液晶を初期化 movlw 192 call csrshow ;カーソルを2行目先頭に表示 movlw 'v' call putrs1 movlw '0' call putrs1 movlw '2' call putrs1 movlw ' ' call putrs1 movlw 'キ' call putrs1 movlw 'ト' call putrs1 movlw '゙' call putrs1 movlw 'ウ' call putrs1 clrf portb ;液晶出力を下げる ;青が押されるまで起動を待つ powerbutton btfss porta,3 ;SETUP(黄)ボタン押された? goto clockstart ;はい。時計をスタート ;いいえ。 btfss porta, 2 ;UP(青)ボタンが押された? goto clockstart ;はい。時計をスタート ;いいえ。 btfss porta, 1 ;ATEST(赤)ボタンが押された? goto clockstart ;はい。時計をスタート ;いいえ。 btfss intcon,2 ;タイマがあふれた? goto powerbutton ;いいえ。ボタン待ちを続ける goto start ;はい、はじめのループへ戻る ;時計機能の開始 clockstart ;変数の初期化 ;日時 clrf hour ;0時 clrf min ;0分 clrf sec ;0秒 movlw 00000001b ;日曜日 movwf week ;col値(EEPROMから読み込む) movlw 63 ;COL値のEEPROMアドレスは63とする movwf eeadr call eeread ;EEPROMデータをWレジスタに読む movwf col ;col値をセット ;アラーム電源関係変数 clrf alarmsec ;アラーム残り時間は0 clrf alarmsw ;ATEST秒数を0に初期化 ;時計のスタート clrf tmr0 ;秒未満を切り捨て bcf intcon,2 ;TMR0オーバーフローフラグを下げる ;通常の時計動作時ループ mainloop call initlcd ;液晶の初期化(カーソルが消える) call showtime ;時計の表示 call waits ;操作直後の待ち時間(カーソルが消えることも) mainloopnext btfss intcon,2 ;時計が進んだら goto mainloopb ;いいえ、進まないので次へ call susumu ;はい、susumuルーチンへ goto mainloopnext;ループへ帰る mainloopb btfsc porta,3 ;SETUPが押されていたら goto mainloopnext;いいえ、ループへ帰る ;はい、時のセットへ進む ;時の設定 sethoura call waits ;操作直後の待ち時間 sethour movlw 129 ;カーソルを1行め2文字めへ call csrshow sethournext btfss intcon,2 ;時計が進んだら goto sethourb ;いいえ、進まないので次へ call susumu ;はい、susumuルーチンへ goto sethour ;ループへ帰る sethourb btfsc porta,2 ;UPボタンが押されていたら goto sethourc ;いいえ、押されていないので次へ incf hour,1 ;はい、[時]を進めます movf hour,0 sublw 24 btfsc status,2 ;24時になったら0時に戻す clrf hour call showtime ;時刻を表示 goto sethoura ;ループへ帰る sethourc btfsc porta,3 ;SETUPボタンが押されていたら goto sethournext ;いいえ、ループへ帰る ;はい、分の設定へ進む ;分の設定 setmina call waits ;操作直後の待ち時間 setmin movlw 132 ;カーソルを1行め5文字めへ call csrshow setminnext btfss intcon,2 ;時計が進んだら goto setminb ;いいえ、進まないので次へ call susumu ;はい、susumuルーチンへ goto setmin ;ループへ帰る setminb btfsc porta,2 ;UPボタンが押されていたら goto setminc ;いいえ、押されていないので次へ incf min,1 ;はい、[分]を進めます movf min,0 sublw 60 btfsc status,2 ;60分になったら0分に戻す clrf min call showtime ;時刻を表示 goto setmina ;ループへ帰る setminc btfsc porta,3 ;SETUPボタンが押されていたら goto setminnext ;いいえ、ループへ帰る ;はい、秒の設定へ進む ;秒の設定 setseca call waits ;操作直後の待ち時間 setsec movlw 136 ;カーソルを1行め9文字めへ call csrshow setsecnext btfss intcon,2 ;時計が進んだら goto setsecb ;いいえ、進まないので次へ call susumu ;はい、susumuルーチンへ goto setsec ;ループへ帰る setsecb btfsc porta,2 ;UPボタンが押されていたら goto setsecc ;いいえ、押されていないので次へ ;はい、押されているので秒を設定 movlw 4 ;秒以下のタイミングを初期化 movwf tmr0 bcf intcon,2 movlw 30 ;30秒以上か以下かの判定と処理 subwf sec,0 ;W=s-30 btfsc status,0 ;現在は30秒以上? goto setsagari ;はい。30秒以上は繰り上がり処理 clrf sec ;いいえ、29秒以下は繰り下がり処理 call showtime goto setseca ;ループへ帰る setsagari movlw 59 movwf sec call susumu ;59秒にして進め、繰り上がりさせる goto setseca setsecc btfsc porta,3 ;SETUPボタンが押されていたら goto setsecnext ;いいえ、ループへ帰る ;はい、曜日の設定へ進む ;曜日の設定 setweeka call waits ;操作直後の待ち時間 setweek movlw 143 ;カーソルを1行め16文字めへ call csrshow setweeknext btfss intcon,2 ;時計が進んだら goto setweekb ;いいえ、進まないので次へ call susumu ;はい、susumuルーチンへ goto setweek ;ループへ帰る setweekb btfsc porta,2 ;UPボタンが押されていたら goto setweekc ;いいえ、押されていないので次へ ;はい、曜日を進める bcf status,0 ;Cフラグをクリア rlf week,1 ;曜日を進める btfss week,7 ;土曜日の次? goto setweekd ;いいえ、次へ movlw 00000001b ;はい、曜日を日曜日にする movwf week setweekd call showtime ;時刻を表示 goto setweeka ;ループへ帰る setweekc btfsc porta,3 ;SETUPボタンが押されていたら goto setweeknext;いいえ、ループへ帰る ;はい、col値の設定へ進む ;col値の設定 setcola call waits ;操作直後の待ち時間 setcol btfsc teiden,0 ;停電していたら goto setcolnext ;表示せずに次へ movlw 192 ;カーソルを2行め1文字めへ call putrs0 movlw 'c' ;col値を表示 call putrs1 movf col,0 call conv10 movlw 194 ;カーソルを2行3文字めへ call csrshow setcolnext btfss intcon,2 ;時計が進んだら goto setcolb ;いいえ、進まないので次へ call susumu ;はい、susumuルーチンへ goto setcol ;ループへ帰る setcolb btfsc porta,2 ;UPボタンが押されていたら goto setcolc ;いいえ、押されていないので次へ incf col,1 ;はい、col値を進めます movf col,0 sublw 61 btfsc status,2 ;61になったら0に戻す clrf col call showtime ;時刻を表示 goto setcola ;ループへ帰る setcolc btfsc porta,3 ;SETUPボタンが押されていたら goto setcolnext ;いいえ、ループへ帰る ;はい。EEPROMへ値を書き込みます。 movlw 63 ;col値のEEPROMアドレスをセット movwf eeadr movf col,0 ;書き込む値colをセット call eewrite ;(値が変更されていれば)書込み実行 ;チャイムの設定 ;アラームセットの初期化 setabegin clrf chnum ;編集するチャンネルを0(EXIT)にする clrf chpoint setanext call initlcd ;画面を初期化 call showtime ;時刻を再表示 ;既存EEPROMデータの読み込み setaload movf chpoint,0 ;先頭アドレスをロード btfsc status,2 ;先頭アドレスは0? goto setaloadend ;はい、読む必要はない movwf eeadr ;いいえ、読み込み開始 call eeread ;週を読み込み movwf chweek incf eeadr,1 ;次は時を読み込む call eeread movwf chhour incf eeadr,1 ;次は分を読み込む call eeread movwf chmin setaloadend ;次はchnumのセット ;chnumの選択 setchnuma call waits ;操作直後の待ち時間 setchnum call showalarm ;アラーム設定を表示 movlw 193 ;カーソルを2行2文字めへ call csrshow setchnumnext btfss intcon,2 ;時計が進んだら goto setchnumb ;いいえ、進まないので次へ call susumu ;はい、susumuルーチンへ goto setchnum ;ループへ帰る setchnumb btfsc porta,2 ;UPボタンが押されていたら goto setchnumc ;いいえ、押されていないので次へ incf chnum,1 ;はい、chnumを1進める movlw 3 ;chpointを3進める addwf chpoint,1 movf chnum,0 sublw 21 btfsc status,2 ;chnumは21? goto setabegin ;はい、chnumなどを0に初期化 goto setaload ;いいえ、新しいchnumでEEPROMをロード setchnumc btfsc porta,3 ;SETUPボタンが押されていたら goto setchnumnext ;いいえ、ループへ帰る ;はい、E/D設定またはmainloopに進む movf chnum,1 btfsc status,2 ;chnumは0? goto mainloop ;はい、メインループへ戻る ;いいえ、E/D設定へ進む ;E/D設定 seteda call waits ;操作直後の待ち時間 seted call showalarm ;アラーム設定を表示 movlw 194 ;カーソルを2行3文字めへ call csrshow setednext btfss intcon,2 ;時計が進んだら goto setedb ;いいえ、進まないので次へ call susumu ;はい、susumuルーチンへ goto seted ;ループへ帰る setedb btfsc porta,2 ;UPボタンが押されていたら goto setedc ;いいえ、押されていないので次へ movlw 10000000b ;はい、E/Dを変化させます xorwf chweek,1 ;chweekのビット7を反転 goto seteda ;ループへ帰る setedc btfsc porta,3 ;SETUPボタンが押されていたら goto setednext ;いいえ、ループへ帰る ;はい、アラーム時の設定へ進む ;アラーム時の設定 setchhoura call waits ;操作直後の待ち時間 setchhour call showalarm ;アラーム設定を表示 movlw 196 ;カーソルを2行5文字めへ call csrshow setchhournext btfss intcon,2 ;時計が進んだら goto setchhourb ;いいえ、進まないので次へ call susumu ;はい、susumuルーチンへ goto setchhour ;ループへ帰る setchhourb btfsc porta,2 ;UPボタンが押されていたら goto setchhourc ;いいえ、押されていないので次へ incf chhour,1 ;はい、[時]を進めます movf chhour,0 sublw 24 btfsc status,2 ;24時になったら0時に戻す clrf chhour goto setchhoura ;ループへ帰る setchhourc btfsc porta,3 ;SETUPボタンが押されていたら goto setchhournext;いいえ、ループへ帰る ;はい、アラーム分の設定へ進む ;アラーム分の設定 setchmina call waits ;操作直後の待ち時間 setchmin call showalarm ;アラーム設定を表示 movlw 199 ;カーソルを2行8文字めへ call csrshow setchminnext btfss intcon,2 ;時計が進んだら goto setchminb ;いいえ、進まないので次へ call susumu ;はい、susumuルーチンへ goto setchmin ;ループへ帰る setchminb btfsc porta,2 ;UPボタンが押されていたら goto setchminc ;いいえ、押されていないので次へ incf chmin,1 ;はい、[分]を進めます movf chmin,0 sublw 60 btfsc status,2 ;60分になったら0時に戻す clrf chmin goto setchmina ;ループへ帰る setchminc btfsc porta,3 ;SETUPボタンが押されていたら goto setchminnext ;いいえ、ループへ帰る ;はい、アラーム曜日の設定へ進む ;アラーム曜日の設定 ;初期設定 movlw 00000001b ;曜日マスクは日曜日 movwf weekmsk movlw 201 ;曜日設定カーソルも日曜の位置 movwf weekcsr setchweeka call waits ;操作直後の待ち時間 setchweek call showalarm ;アラーム設定を表示 movf weekcsr,0 ;カーソルをweekcsrで設定したところへ call csrshow setchweeknext btfss intcon,2 ;時計が進んだら goto setchweekb ;いいえ、進まないので次へ call susumu ;はい、susumuルーチンへ goto setchweek ;ループへ帰る setchweekb btfsc porta,2 ;UPボタンが押されていたら goto setchweekc ;いいえ、押されていないので次へ movf weekmsk,0 ;はい、曜日をトグルで選択 xorwf chweek,1 ;chweekの更新 goto setchweeka ;ループへ帰る setchweekc btfsc porta,3 ;SETUPボタンが押されていたら goto setchweeknext;いいえ、ループへ帰る ;はい、設定する曜日を進める bcf status,0 ;Cフラグをクリア rlf weekmsk,1 ;設定曜日を進める incf weekcsr,1 ;カーソル位置を進める btfss weekmsk,7 ;曜日マスクのbit7が1? goto setchweeka ;いいえ、ループに戻る ;はい、次はEEPROMへの書込み ;アラーム情報のEEPROMへの書込み movf chpoint,0 movwf eeadr ;chweekのアドレス書込み movf chweek,0 call eewrite ;chweekを書き込む incf eeadr,1 movf chhour,0 call eewrite ;chhourを書き込む incf eeadr,1 movf chmin,0 call eewrite ;chminを書き込む ;chnum選択画面へ戻る goto setanext ;時計を進める(1秒) susumu bcf intcon,2 ;TMR0オーバフローフラグを下げる ;秒を進める incf sec,1 movf sec,0 sublw 60 btfss status,2 ;分が進む? goto alarmend ;いいえ。進まないのでアラーム判定の次へ clrf sec ;はい。秒は0になる ;col値により時計を進める btfsc min,0 ;1時間あたり90回 incf tmr0,1 ;時計を1/256秒進める incf tmr0,1 movf col,0 ;col値の設定により時計をさらに進める subwf min,0 ;wレジスタ = min - col btfss status,0 ;min - col < 0 の場合 incf tmr0,1 ;時計をもう1/256秒進める ;teiden=1とすることで、停電復帰を模擬してLCD初期化を促す。 movlw 1 movwf teiden ;teiden = 1 ;ポートAとBの入出力設定を再実行 bsf status, 5 ;バンク1を選択 movlw 00011110b ;ポートAはA1,A2,A3,A4が入力 movwf porta clrf portb ;ポートBは全て出力 bcf status, 5 ;バンク0を選択 ;分を進める incf min,1 movf min,0 sublw 60 btfss status,2 ;時が進む? goto alarmcheck ;いいえ。アラーム検査ルーチンへ clrf min ;はい。分は0になる ;時を進める incf hour,1 movf hour,0 sublw 24 btfss status,2 ;曜日が進む? goto alarmcheck ;いいえ。アラーム検査ルーチンへ clrf hour ;はい。時は0になる ;曜日を進める bcf status,0 ;Cフラグをクリア rlf week,1 ;曜日を進める btfss week,7 ;土曜日の次? goto alarmcheck ;いいえ。アラーム検査ルーチンへ movlw 00000001b ;はい。曜日を日曜日にする movwf week ;チャイムを鳴らすかどうか判断 alarmcheck ;初期設定 movlw 3 ;EEPROMアドレスをWeek(1)にする movwf eeadr alarmnext call eeread ;アラーム曜日の読み込み btfss eedata,7 ;グローバルビットが1? goto alarmp1 ;いいえ、次のデータに移る ;はい(グローバルビットは整合) movf week,0 andwf eedata,0 ;これが0以外なら曜日はあっている btfsc status,2 ;結果は0? goto alarmp1 ;はい、次のデータに移る ;いいえ(曜日は整合) incf eeadr,1 call eeread ;アラーム時の読み込み subwf hour,0 ;W = hour - アラーム時 btfss status,2 ;hour=アラーム時? goto alarmp2 ;いいえ、次のデータに移る ;はい(時は整合) incf eeadr,1 call eeread ;アラーム分の読み込み subwf min,0 ;W = min - アラーム分 btfss status,2 ;min=アラーム分? goto alarmp3 ;いいえ、次のデータに移る ;はい(分は整合) ;だから、アラームを鳴らすと決定 movlw 45 movwf alarmsec ;鳴らす時間を45秒間に設定 goto alarmend ;判定完了 alarmp1 incf eeadr,1 ;hourを差す alarmp2 incf eeadr,1 ;minを差す alarmp3 incf eeadr,1 ;次のデータのアラーム曜日を差す movlw 63 subwf eeadr,0 ;W = eeadr - 63 btfss status,2 ;eeadr=63? goto alarmnext ;いいえ、次のデータを調査 ;はい、全てのデータで不一致、判定終了 ;アラーム判定処理の終了(susumuルーチン実行時は必ず来る) alarmend ;ATESTボタンの読みとり incf alarmsw,1 ;スイッチの秒数を上げる btfsc porta, 1 ;ATESTが押されていたら clrf alarmsw ;いいえ。秒数をクリア ;はい。 btfss alarmsw, 2 ;スイッチ秒数が4?(bit2が上がった?) goto teidenset ;いいえ。停電状態の更新へ ;はい。アラームを開始します。 movlw 45 movwf alarmsec ;残り45秒間に設定 ;停電状態の設定(復旧時の液晶初期化) teidenset btfsc teiden,0 ;teiden=1? goto teidenis1 ;はい。teidenis1へ飛ぶ ;いいえ。 ;teiden=0の場合 btfss porta,4 ;Vcc3が下がっている? incf teiden,1 ;はい。停電開始。(0 -> 1) ;いいえ。引き続き停電なし。(0 -> 0) goto teidensafe ;停電関連安全管理へ進む teidenis1 ;teiden=1の場合 btfss porta,4 ;Vcc3が下がっている? goto teidensafe ;はい、停電続行中。停電安全管理へ進む(1 -> 1) clrf teiden ;いいえ、停電から復旧。(1 -> 0) call initlcd ;液晶を初期化 teidensafe btfss teiden,0 ;停電していたら goto asecdec ;いいえ、アラーム電源カウントへ移る ;はい。アラーム関連の変数と全I/Oを0に clrf alarmsec ;アラーム残り時間を0に clrf alarmsw ;アラームスイッチ時間を0に clrf porta ;出力を0に(アラーム電源周り) clrf portb ;出力を0に(液晶周り) asecdec movf alarmsec, 1 ;アラームの残り時間と電源の操作 btfsc status, 2 ;アラーム残り時間は0? goto astop ;はい。アラーム電源を止める bsf porta, 0 ;いいえ、アラーム電源を入れる decf alarmsec, 1 ;残り時間を1減らす goto showtime astop clrf porta ;アラーム電源を停止 ;日時を表示(1行目を全て書き換える) showtime btfsc teiden,0 ;停電中なら return ;何もせずに戻る movlw 128 ;カーソルを1行目左へ call putrs0 movf hour,0 call conv10 movlw ':' call putrs1 movf min,0 call conv10 movlw ':' call putrs1 movf sec,0 call conv10 movlw ' ' call putrs1 movf week,0 ;曜日を表示して戻る ;曜日を7桁ニケカスモキトで表示。入力はwレジスタ showweek movwf weekp movlw 'ニ' btfss weekp,0 movlw ' ' call putrs1 movlw 'ケ' btfss weekp,1 movlw ' ' call putrs1 movlw 'カ' btfss weekp,2 movlw ' ' call putrs1 movlw 'ス' btfss weekp,3 movlw ' ' call putrs1 movlw 'モ' btfss weekp,4 movlw ' ' call putrs1 movlw 'キ' btfss weekp,5 movlw ' ' call putrs1 movlw 'ト' btfss weekp,6 movlw ' ' call putrs1 clrf portb ;液晶出力を下げる return ;アラーム設定を表示 showalarm btfsc teiden,0 ;停電中の場合は return ;何もせずに返す movlw 192 ;カーソルを2行目1文字目へ call putrs0 movf chnum,0 ;chnumを表示 call conv10 movf chnum,1 btfsc status,2 ;chnumは0? goto showexit ;はい、exitを表示して戻る ;いいえ、次はE/Dの表示 movlw 'D' ;グローバルイネーブルビットの表示 btfsc chweek,7 movlw 'E' call putrs1 movf chhour,0 ;アラームの時を表示 call conv10 movlw ':' call putrs1 movf chmin,0 ;アラームの分を表示 call conv10 movlw ' ' call putrs1 movf chweek,0 goto showweek ;アラーム曜日を表示して戻る ; EXITと表示して戻る showexit movlw ' ' call putrs1 movlw 'E' call putrs1 movlw 'X' call putrs1 movlw 'I' call putrs1 movlw 'T' call putrs1 clrf portb ;液晶出力を下げる return ;数値を2桁文字に変換して液晶に表示 ;入力値はWレジスタ ;n1=10の位 n0=1の位となる conv10 movwf ni ;入力値を保管 ;出力値の初期化 movlw '0' movwf n1 movwf n0 ;2桁のキャラクタコードに変換 movlw 10 convnext incf n1,1 subwf ni,1 btfsc status, 0 goto convnext addwf ni,1 ;ni = 1の位の数値 decf n1,1 ;n1 = 10の位のキャラクタコード movf ni, 0 addwf n0, 1;n0 = 1の位のキャラクタコード ;値を2桁で表示 movf n1, 0 call putrs1 movf n0, 0 call putrs1 return ;Wレジスタの位置にカーソルを移動して表示(カーソル点滅+下線) csrshow btfsc teiden,0 ;停電していたら? return ;何もせずに戻る ;カーソルを移動して表示 call putrs0 movlw 00001111b;カーソルを表示 call putrs0 clrf portb ;液晶出力を下げる return ;液晶表示装置を初期化(カーソル表示なし、画面をクリア) initlcd btfsc teiden,0 ;停電していたら? return ;初期化せずに戻る movlw 205 call waitw ;100ms待つ movlw 00000011b call puthalf movlw 10 call waitw ;4.5ms待つ movlw 00110011b call putrs0 movlw 00000010b call puthalf movlw 00101000b call putrs0 ;8bit 2lines 5x7dot movlw 00001000b call putrs0 movlw 00000001b call putrs0 movlw 3 call waitw ;約2ms待つ movlw 00000110b call putrs0 ;インクリメントする,シフトしない movlw 00001100b ;ディスプレイON カーソルoff カーソル点滅off call putrs0 ;LCDをオンにする clrf portb ;節電のため液晶出力を下げる return ;液晶装置にデータ転送(RS=0) ;Wレジスタに表示したい値を置く putrs0 movwf outbuf ;出力値の保管 movlw 00000000b ;E=0,RS=0をセット goto put4bit ;液晶装置にデータ転送(RS=1) ;Wレジスタに表示したい値を置く putrs1 movwf outbuf ;出力値の保管 movlw 00010000b ;E=0,RS=1をセット ;4ビット制御のLCDにデータを送信 put4bit movwf portb ;EとRSを出力 ;上4ビットの出力 swapf outbuf,0 ;上4ビットをWREGの下4ビットにする andlw 0fh ;下4ビットを取り出す iorwf portb,1 ;ポートへの出力 bsf portb,5 ;E=1 bcf portb,5 ;E=0 ;下4ビットをポートからクリア movlw 0f0h andwf portb,1 ;下4ビットの出力 putlowbits movf outbuf,0 andlw 0fh iorwf portb,1 ;下4ビットをポートへ出力 bsf portb,5 ;E=1 bcf portb,5 ;E=0 return ;LCDに下4ビットのみのデータを送信。ただしRS=0 puthalf movwf outbuf ;出力データを保管 movlw 00000000b ;E=0,RS=0をセット movwf portb ;EとRSを書き込む goto putlowbits ;Wレジスタに指定された回数ループして時間待ちする。 ;w=3->2ms 30->15ms 205->100ms waitw movwf timea ;待ち時間をtimeaへ書き込む waitwloop decf timea, 1;timeaをデクリメント btfss status,2;ゼロフラグが上がっていたらループ終了 goto waitwloop ;ゼロでなければ繰り返す return ;操作直後におよそ0.13秒時間待ちをする。 ;時計が進む場合は値を進めることができる。 waits movlw 180 ;待ち時間 movwf timea waitsloop btfsc intcon,2 ;タイマがオーバーフローしていたら call susumu ;時計を進める decf timea,1 btfss status,2 goto waitsloop return ;EEPROMの読み込み ;入力はeeadr,読んだ値はEEDATAとWレジスタに入る eeread bsf status, 5 ;バンク1を選択 bsf eecon1,0 ;読み込み指示 bcf status, 5 ;バンク0を選択 movf eedata,0 ;読んだ値をWレジスタにセット return ;EEPROMの書き込み ;入力はアドレスはeeadr,書く値はWレジスタに入れる eewrite movwf weekp ;入力値をバッファに保管 ;EEPROMを読む bsf status, 5 ;バンク1を選択 bsf eecon1,0 ;読み込み指示 bcf status, 5 ;バンク0を選択 ;書込み必要性の判定 subwf eedata,0 ;W = eedata(既存値) - weekp(入力値) btfsc status,2 ;eedataがweekpと等しい? return ;はい、書込み不要なので戻る ;いいえ、書込みに移る ;EEPROMへの書込み movf weekp,0 ;入力値をeedataにセット movwf eedata bsf status, 5 ;バンク1を選択 bcf eecon1,4 ;書き込み終了ビットをクリア bsf eecon1,2 ;EEPROM書き込み可能にする movlw 55h movwf eecon2 movlw 0aah movwf eecon2 bsf eecon1,1 ;書き込み指示 eewritewait btfss eecon1,4 ;書き込み終了ビット=1? goto eewritewait ;いいえ。待ちループを続ける ;はい。書き込み完了。 bcf eecon1,2 ;EEPROMを書き込み不能にする bcf status, 5 ;バンク0を選択 return