; Copyright 2005 Yasuhiro Kanzaki ; f877A102.asm AD変換テスト・プログラム2 リスト12-4 ; リスト12-2,12-3のサブルーチンもこのリストに含まれています list p=16f877A ; プロセッサを定義する #include ; インクルード・ファイルを読み込む __CONFIG _CP_OFF & _WDT_OFF & _HS_OSC & _LVP_OFF & _DEBUG_OFF & _CPD_OFF ; 変数定義域 ;***** LCD 変数の定義域 b2a_tmp equ 20h ;  count_str equ 21h LCDPORT equ PORTE RS equ 0 RW equ 1 E equ 2 ;******************************************************* t_work3 equ 022h ; 20μsタイマ用ワーク b_bcdi equ 023h ; BCD変換用のワーク 1桁目がセット b_bcdo equ 024h ; BCD変換用のワーク 2桁目がセット b_bcdo1 equ 025h ; BCD変換用のワーク 3桁目がセット 0から2 work1 equ 026h ; バイナリ・データの一時保存ワーク count equ 027h ; b2_bcdの変数 16回の回数カウンタ temp equ 028h ; b2_bcdの変数 比較値一時保存データ h_byte equ 029h ; b2_bcdの変数 入力 上位バイト l_byte equ 02Ah ; b2_bcdの変数 入力 下位バイト r2 equ 02Bh ; b2_bcdの変数 出力 5桁目 r1 equ 02Ch ; b2_bcdの変数 出力 3,4桁目 r0 equ 02Dh ; b2_bcdの変数 出力 1,2桁目 ORG 000h ; リセット時の開始位置 goto main ; org 01ch main: ;タイマ0の初期化 bsf STATUS,RP0 ; バンク1を選択 bcf OPTION_REG,T0CS ; タイマ0 プリスケーラ256 bcf OPTION_REG,PSA ; プリスケーラはタイマ0 bcf OPTION_REG,NOT_RBPU;ポートBプルアップ ; movlw b'11101011' movwf CVRCON clrf TRISD ; ポートDは出力 clrf TRISE ; ポートEは出力 bcf STATUS,RP0 ; バンク0を選択 movlw b'10000011' ; 右詰 AN3が+リファレンス btfss PORTB,1 ; PORTBはバンク0 movlw b'00000011' ; 左詰 AN3が+リファレンス bsf STATUS,RP0 ; ADCON1はバンク1 movwf ADCON1 ; アナログ・ポートの構成をセット bcf STATUS,RP0 ; 以上で初期設定 完了 call inilcd8 ; LCDドライバの初期化 ;タイマ1初期化 movlw 0Bh ;プリスケーラ1:1 32.768kHz ,外部クロック,同期 movwf T1CON ; タイマ1構成セット及びタイマ1オン ;表示処理 movlw 01h ; LCDのクリア call cmdwrt ; コマンド書き込み movlw 80h+4dh ; ADCは4dhにセット call cmdwrt ; コマンド DDRAMアドレスセット2行目 movlw 'V' ; V プログラム・バージョンのV call dtawrt ; データ書き出し movlw 04h ; プログラムの改訂ナンバセット call b2asub ; データ書き出し movlw 80h ; LCDの表示アドレスセット call cmdwrt ; movlw tbl3-tbl1 ; 開始メッセージを表示 call lcdstr1 ; movlw 80h+41h ; 入力位置を2行目の2桁めに設定 call cmdwrt ; ;A-D変換器の処理についての初期化 movlw b'10000001' ; ADCS1〜ADCS0 10 ADON=1 movwf ADCON0 ; ADコンバータ起動,32Tosc,チャンネル0 loop bcf ADCON0,CHS0 ; チャンネル0を指定するためクリア btfss PORTB,0 ; DIPスイッチの入力チェック bsf ADCON0,CHS0 ; チャネル1を選択 call dtm20 ; データ・アクイジション時間待ち bsf ADCON0,GO ; AD変換開始 dloop2: btfsc ADCON0,GO ; AD変換完了を待つ goto dloop2 ; btfsc PORTB,2 ; ADRESH,ADRESLの選択をDIPスイッチで確認 goto adh ; banksel ADRESL ; ADRESLはバンク1にあるのでバンクの切替が必要 movf ADRESL,W ; 下位ADRESLの変換データを取り出す banksel PORTD ; バンク0に設定 goto adout ; adh movf ADRESH,W ; ADRESHの変換データを取り出す adout movwf work1 ; 変換データを保存 btfss PORTB,3 ;  call datalc10 ; 10ビット変換データをLCD表示 btfsc PORTB,3 call datalcd ; 8ビット変換データをLCD表示 movf work1,w ; ポートDに結果表示 movwf PORTD ; LEDで表示する ; 表示のインターバルを取るため タイマ1による時間待ち処理 movlw 0C0h ;  movwf TMR1H ; bcf PIR1,TMR1IF ; rt btfss PIR1,TMR1IF ; goto rt ; 時間待ち完了 goto loop ; 繰り返す dtm20 movlw d'30' ; アクイジション時間待ちルーチン movwf t_work3 ; dloop: decfsz t_work3,f ; 20μsが最小時間なので少し余裕を持った goto dloop ; return ; LCDへdata表示サブルーチン datalcd movwf work1 ; 元のデータを一時保存 call binbcd ; Wレジスタの値をBCDに変換 movf b_bcdo1,W ; 最上位ビットの表示できるように call bacon ; キャラクタ・コードに変換する call dtawrt ; 変換された文字コードを表示 movf b_bcdi,W ; 2桁の変換結果を表示 call b2asub ; HEXデータの表示ルーチンが流用できる movlw 80h+41h ; 表示位置をセットする call cmdwrt ; LCDコントローラにコマンドとしてセットする return ; LCDへ10ビットdata表示サブルーチン datalc10 bcf STATUS,RP0 movwf l_byte ; ADRESLの値をl_byteに設定 movf ADRESH,W ; 上位のバイト読み込み movwf h_byte ; h_byteに設定 call b2_bcd ; 変換処理ルーチンを呼び出す movf r1,W ; 上位の桁から表示 call b2asub ; HEXデータの表示ルーチンが流用できる movf r0,W ; 下位の桁を表示 call b2asub ; HEXデータの表示ルーチンが流用できる movlw 80h+41h ; 表示位置をセットする call cmdwrt ; LCDコントローラにコマンドとしてセットする return ; ;タイマ処理サブルーチン0.1ms 255 tm01 bcf INTCON,T0IF ; フラグをクリア sublw 0FFh ; カウント値を計算する movwf TMR0 ; タイマ0レジスタに0ff-カウント値をセット stmlp btfss INTCON,T0IF ; オーバ・フローを待つ goto stmlp ;   bcf INTCON,T0IF ; フラグをクリア return ; ; 0からFの4ビットの値を文字コードに変換する bacon andlw 0Fh ; 上位のビットのクリアする addwf PCL,f ;  dt "0123456789ABCDEF" ; 文字列の表示サブルーチン lcdstr1 movwf count_str strlp1 movf count_str,W call str010 andlw 0FFH btfsc STATUS,Z return call dtawrt incf count_str,f goto strlp1 str010 addwf PCL,F tbl1 dt "LCD TEST Pgm",0h tbl2 dt "debug mode",00h tbl3 dt "LM35Z TEST",00h ; 12章のテストの表示 ; バイナリデータをBCD3桁 変換処理 binbcd clrf b_bcdo1 ; 3桁目の値が入る clrf b_bcdo ; 2桁目の値をカウントするワーク・エリア movwf b_bcdi ; バイナリ・データをセットする movlw d'10' ; 10進数の10をセット blp1 subwf b_bcdi,f; 10の引き算の数をカウント btfss STATUS,C; 引き算の場合桁下がりでC=0 goto bcde ; 引けなくなったのでループを抜ける incf b_bcdo,f ; 引き算の数をカウント goto blp1 ; 繰り返す bcde addwf b_bcdi,f; 最後の引き算のマイナスその補正 bcdl2 subwf b_bcdo,f; 2桁目の値算出のための引き算 btfss STATUS,C; 引き算の場合桁下がりでC=0 goto bcde2 ; 引けなくなったのでループを抜ける incf b_bcdo1,f ; 3桁目の値算出のための引き算 goto bcdl2 ; 繰り返す bcde2 addwf b_bcdo,f; 最後の引き算のマイナスその補正 swapf b_bcdo,w ; 2桁目値を上位4ビットに移動 iorwf b_bcdi,f; BCD 2桁が算出 movf b_bcdi,w; return ;LCDドライバーの初期化8ビットポート inilcd8 movlw d'150' ; call tm01 ; 電源立ち上げ後15ms以上確保するため movlw 30h ; コマンド 30hを出力 call cmdwrtw ; コマンド 30hを出力 movlw d'41' ; call tm01 ; 4.1msの時間待ち movlw 30h ; call cmdwrtw ; コマンド 30hを出力 movlw 1 ; call tm01 ; 100μsの待ち movlw 30h ; コマンド 30hを出力 call cmdwrtw ; movlw 1 ; call tm01 ; 100μsの待ち movlw b'00111000' ; function set 8bit 2line call cmdwrt movlw b'00001100' ; display on/off on call cmdwrt movlw b'00000001' ; clears display call cmdwrt movlw b'00000110' ; entry mode set call cmdwrt return ; busy check LCDドライバの処理中のチェック bsychk bsf STATUS,RP0 ; バンク1を設定 comf TRISD,f ; ポートDを入力に設定のコード bcf STATUS,RP0 ; バンク0 を設定 bsf LCDPORT,RW ; コマンド読み取りなのでRでHにする bsyrp: bcf LCDPORT,RS ; コマンドなのでLでクリアする bcf LCDPORT,E ; ループで戻った時Lにするため bsf LCDPORT,E ; E信号をHにする nop ; 時間待ち btfsc PORTD,7 ; Busy フラグのチェック goto bsyrp ; フラグがオンの時繰り返す bcf LCDPORT,E ; E信号をLにする bcf LCDPORT,RW ; WRITEに変更 bsf STATUS,RP0 ; バンク1を設定 clrf TRISD ; ポートDを出力に設定 bcf STATUS,RP0 ; バンク0 を設定 return ; 一バイトデータの値をHEX表示でLCDに書き込む b2asub movwf b2a_tmp ; 表示データを保存 swapf b2a_tmp,w ; 上下のニブルを入れ替え call bacon ; 下位4ビットを 文字コードに変換 call dtawrt ; 変換されたデータをLCDに出力 movf b2a_tmp,w ; 保存したデータをWレジスタにセット call bacon ; 下位4ビットを 文字コードに変換 call dtawrt ; 変換されたデータをLCDに出力 return ; ;コマンド書き込みルーチン cmdwrt call bsychk ; Busyフラグがオフまで待つ cmdwrtw bcf LCDPORT,RW ; WRITEでL bcf LCDPORT,RS ; コマンドでRSはL movwf PORTD ; ポートDにコマンドを出力 bsf LCDPORT,E ; Eをオン bcf LCDPORT,E ; Eをオフ return ; ; 文字コードをデータとしてLCDに書き込む,文字が表示される dtawrt: call bsychk ; Busyフラグがオフまで待つ bcf LCDPORT,RW ; WRITEでL bsf LCDPORT,RS ; データでRSはH movwf PORTD ; データを出力 bsf LCDPORT,E ; Eをオン bcf LCDPORT,E ; Eをオフ return ; 二バイトのバイナリデータをBCD5桁に変換するサブルーチン b2_bcd bcf STATUS,C ; クリア キャリービット movlw .16 ; シフトしながらBCDの補正を行う movwf count ; 2バイト分16ビットシフトする clrf r2 ; 結果のエリアをクリア 最上位バイト 下位ニブルにのみセット clrf r1 ; 中間のバイト clrf r0 ; 下位バイト loop16 rlf l_byte,f; l_byteからr0までバイト間はキャリ・ビットで連続して rlf h_byte,f; 16ビット分のシフトされる rlf r0,f ; rlf r1,f ; rlf r2,f ; decfsz count,f; 16回繰り返すと終わる goto adjdec retlw 0 adjdec movlw r0 ; r0の変数のアドレスをWレジスタにセットする movwf FSR ; FSRはR0のアドレスを示す call adjbcd ; BCDの補正を行うルーチンへ movlw r1 ; 間接アドレス指定してのため,r0,r1,r2のアドレスを movwf FSR ; 渡せば同じサブルーチンでそれぞれのレジスタに適切な処理を call adjbcd ; 行う. movlw r2 ; r2は最上位で下位に飲みデータがセットされる movwf FSR ;  call adjbcd ; goto loop16 ; adjbcd movlw 3 ; Wレジスタに3をセット addwf INDF,W; rxの内容と3を加算,結果をWレジスタに movwf temp ; 結果をtempレジスタに btfsc temp,3; b3のオンをチェック movwf INDF ; 間接アドレスで movlw 30h ; 上位のニブル処理を行う addwf INDF,W movwf temp btfsc temp,7 movwf INDF retlw 0h END