;            プログラム名　   Ver.3
;
;　　　　　　　使用ワンチップマイコン　ＰＩＣ１７Ｃ７５６
;自作したアナログデータメモリコントロールプログラムである。
;
;        7/28   1999 （元となったバージョンの最終改訂日）
;        2/9    2000  改訂
;        4/21   2000　改訂　ＲＳ－２３２Ｃ送信で、データ間に時間幅の余裕を持たせる。
;        4/30   2000  改訂　4/21 の改訂を取り消し、８１９２データ（＝１６３８４バイト）を
;　　　　　　　　　　　　　　連続して１ブロックとして送信する。インターバル後、次のブロック
;　　　　　　　　　　　　　　そ送信する。これを１６ブロック分繰り返す。
;                            ８１９２データ／ブロック×１６ブロック＝１３１０７２データ
;　　　　　　　　　　　　　　インターバルは当面　０．５ｍ秒ぐらいとしておく。
;　　　　　　　　　　　　　　因みに　８１９２＝２５６×３２＝２進数１５ビット＋１
;              5/1 一応完成
;	6/21   2000  改訂　サンプリング時間設定をμＳにおいて21から999まで、
;			   mSにおいては1～999、Sにおいても1～999まで設定することに成功
;			 　今まではオフセットを含んだサンプリング時間だったが
;			 　それを取り除くことに成功。
;			   その結果を同フロッピーに付加する。
;
;
;
;      11/22         改訂　送信データとして、サンプリング時間（３バイト）と
;                          時間単位代表数値（１バイト）を先頭に付加することにした。
;      11/23         修正完了
;
;
;
;システムの動作の概要
;（１）アナログ正電圧（０．０Ｖ～＋５．０Ｖ）をサンプリングし、メモリに保持する。
;（２）サンプリングできるアナログチャンネルは１０個である。
;（３）サンプリング時間
;　　１秒～２５５秒、１ｍ秒～２５５ｍ秒、約２０マイクロ秒～２５５マイクロ秒
;　　の範囲で任意に指定できる。
;    が、 ２０マイクロ秒以下では,ＡＤ変換に要する時間が１０マイクロ秒以上あるので、５０％以上に
;    なることに注意。
;（４）サンプリング時、モニタリングができる。
;（５）システムの動作はキー入力で行える。
;（６）割り込みは「ワリコミ」ボタンを押したとき、ハンドラールーチンに分岐するようにする
;（７）１Ｍ（１３１０７２＊８ビット）メモリ使用時はアドレスカウンタの１８ビット目、
;　　　４Ｍ（５２４２８８＊８ビット）メモリ使用時はアドレスカウンタの２０ビット目をモニターして
;　　　このビットがＬからＨになった時点で、
;　　　メモリアドレスのオーバーフローをチェックし、測定終了とさせる。
;　　　なを、現時点では１Ｍメモリでは動作確認済み、４Ｍメモリでは未確認。
;（８）ＡＤ変換は１０ビットである。メモリは２つを用い、同じアドレス番地の片方に上位８ビットを
;　　　、他方に下位２ビットを記憶させる。　
;（９）電源投入時、リセット時にメモリはクリアされる。　
;（１０）オシロ等でモニターできるように設けたモニター出力端子からは、ＡＤ変換で得られた得られた
;　　　１０ビットのうち、上位８ビットをＤＡ変換した電圧が出力される。下位２ビットは省略している。
;      どうしても、下位２ビットをモニターしたければ、プログラム中の２カ所を変更することで
;　　　簡単にできる。プログラム中にその仕方を指示している。
;（１１）ＲＳ２３２Ｃの設定
;        ノーハンドシェイク、１９２００ボー、８データビット、１ストップビット
;（１２）ＲＳ２３２Ｃ出力端子からは、　　上位８ビット分、　　下位２ビット分、
;　　　　　　　　　　　　　　　　　　次の上位８ビット分、その下位２ビット分、
;                                その次の上位８ビット分、その下位２ビット分、 
;　　　　　　　　　　　　　　　　　　　以下同上　　　　　　以下同上
;　　　　のデータ順列で、記録されたデータが出力される。
;（１３）受信側の性能のため、送信される１３１０７２個のデータは、１６のブロックにぶんかつして
;　　　　送信している。ブロック間には約１２ｍ秒の時間インターバルを設けている。
;（１４）全データ送信時間はおよそ　２分１５秒。
;
;ＬＣＤ画面での操作の流れ
;
;      → → → → → → → → → → → → Data Memory
;     ↑                                      OK?
;     ↑                                      ↓(D)
;     ↑                                      ↓                                   
;     ↑                                Job Selection
;     ↑         （選択）( Measure ) → (Memory Out) → (RS232C OUT)→
;     ↑                     ↓      (A)      ↓     (A)    ↓
;     ↑                     ↓(D)            ↓(D)         ↓(D)
;     ↑                 Time Interval                      ↓
;     ↑                (   secont   )       同左           ↓
;     ↑        （選択）(  milisec   )                      ↓
;     ↑          (A)   (  microsec  )                      ↓
;     ↑                     ↓(D)            ↓(D)         ↓
;     ↑                     → → → → → →  ← ← ← ← ←
;     ↑                                      ↓
;     ↑                                    Start                   
;     ↑                                      ↓(D)                  
;     ↑                                    Execute               
;     ↑                                      ↓                     
;     ↑                                      ↓(D)                  
;     ↑                                    Measure              
;     ↑                                      ↓(W)                 
;     ↑                                      ↓                    
;     ↑                                     Stop
;     ↑                                      ↓(R)
;       ← ← ← ← ← ← ← ← ← ← ← ← ←
;
; 　(D)　キーパットのＤキー。処理決定
;   (A)　キーパットのＡキー。処理選択
;   (W)　割り込みスイッチ
;   (R)　リセットスイッチ

;アセンブル時の注意
;（１）定数はリテラル値扱いである。厳重に留意しておくこと。
;（２）変数の値をＷに取り込むときには  movfp を使用しなければならない。
;                                      movlw では実行時エラーとなる
;（３）予約語、ラベルが何バンクにあるか正確に把握しておくこと。
;（４） バンク０以外に移動したときは、処理後は直ぐバンク０に戻すようにする。
;（５）Radix は Decimal とする。暗黙数値は１０進数と見なす。
;（６）アセンブルした出力ファイルは　INHX32 形式に指定すべし

  LIST P=PIC17C756       ;使用するプロセッサを指定する
  #INCLUDE "P17C756.INC" ;上記プロセッサのためのインクルードファイルを
                         ;呼び出し結合する
;ＰＩＣの初期設定 
  __CONFIG  _MC_MODE & _WDT_OFF & _XT_OSC &_BODEN_ON
                        ;ＰＩＣはマイクロコントローラモード
                        ;これでポートＣその他の端子がＩ／Ｏポートとなる。
                        ;ウオッチドックタイマーはオフ
                        ;発振は４ＭＨｚクリスタル方式。７月４日から２０ＭＨｚに変更
                        ;ブラウンアウトはオン。規定電圧以下となるとリセットする。
;*********************************************************************************************** 
;キーパッド入力用変数	
       CBLOCK h'0020'      ;このディレクチブと下のENDCの間に使用する変数名を定義できる
                        ;数値は使用するプロセッサの一般目的レジスタの開始番地とする　　　　　　　　　　　　
            cols        ;マトリックスの行の変数
            key         ;入力されたキーパッドの判別用変数
;ＬＣＤ出力用変数
            temp0       ;一時的カウンタ変数
            temp1       ;
            temp2       ;
            temp3       ;
            counter     ;表示した文字数のカウンタ変数
            step        ;ステップ変数
            current     ;一時変数
            charnum     ;表示する文字数を入れる
;その他
            jobsel      ;処理の種類番号。測定＝０，メモリ出力＝１，ＲＳ２３２出力＝２
            figure      ;サンプリング時間間隔のための数値文字の桁数が入る
            figure1     ;同上の１桁目の文字数値が入る
            figure2     ;　　　２　
            figure3     ;　　　３
            timebase    ;秒（＝０）、ｍ秒（＝１）、マイクロ秒（２）の選択値が入る
            inttime     ;文字数値から得られたサンプリング時間間隔の入る変数
            numb0	;３桁目の数字が入る変数（ループnumberにて）
            numb1	;１，２桁目の数字が入る変数（ループnumberにて）
            uless0      ;サンプリング時間の調整（無駄時間）変数　その１
            uless1	;サンプリング時間の調整（無駄時間）変数　その２
            uless2	;サンプリング時間の調整（無駄時間）変数　その３
;ＲＳ－２３２用
            bcounter0   ;１ブロック＝８１９２データ（１６３８４バイト）分を
            bcounter1   ;カウントするための変数。８１９２＝３２×２５６
                        ;bcounter1（６ビット）+bcounter0（８ビット） で１６ビットカウンタを作る
                        ;１６ビットカウンタの最高位ビット（bcounter1のb5）を１フラッグとして使用
                        ;し、データ８１９２個の送信完了の印とする。
       ENDC
;
;***********************************************************************************************
;キーパッド入力用の各Ｉ／Ｏポートの割り当て。ポートＤの８ビットを使用
;キーパットは４行×４列の１６個のキーであり、
;ポートＤの０，１，２，３ビットはキーパットの１，２，３，４列に、
;ポートＤの４，５，６，７ビットはキーパットの１，２，３，４行に結線されている
keypad  equ  PORTD      ;Ｄポートにラベル名を付ける。バンク１にある。
row1    equ  4          ;Ｄポートの第４、５、６、７各ビットを指定するため、対応する
row2    equ  5          ;数値ではなく、役割を示すラベルを割り当て、プログラムを理解
row3    equ  6          ;し易くする
row4    equ  7

;ＬＣＤの制御用Ｉ／Ｏポートの割り当て。ポートＥの４ビットの内の３ビットを使用
contl   equ  PORTE      ;Ｅポートにラベル名を付ける。バンク１にある。
                        ;Ｅポートの第０，１，２，３各ビットを指定するため、対応する
                        ;数値ではなく、役割を示すラベルを割り当て、プログラムを理解
                        ;し易くする
e       =    0          ;０=ＬＣＤ不動作、    １=ＬＣＤ動作
rw      =    1          ;０=ＬＣＤへ書き込み　１=ＬＣＤから読み出し
rs      =    2          ;０=命令、            １=記号／バイト

;ＬＣＤのデータ用Ｉ／Ｏポートの割り当て。ポートＣの８ビットを使用
lcd_data    equ  PORTC  ;Ｃポートにラベル名を付ける。これはバンク１にある。
;
;ＬＣＤに転送する各命令のコードの定義
;使用するＬＣＤのテクニカルノートを参照すること
;                                ２進数　　　　　処理
clear     equ   1              ; 00000001　　表示をクリア
home      equ   2              ; 00000010　　カーソルをホームへ
shift_l   equ   24             ; 00011000　　表示を左へ移動
shift_r   equ   28             ; 00011100　　表示を右へ移動
crsr_l    equ   16             ; 00010000　　カーソルを左へ移動
crsr_r    equ   20             ; 00010100　　カーソルを右へ移動
crsr_e    equ   32             ; 00100000　　ファンクションをセット
blink_c   equ   11             ; 00001011　　表示オフ、カーソルオン、ブリンクオン
no_crsr   equ   8              ; 00001000　　表示オフ、カーソルオフ、ブリンクオフ
ret_bak   equ   192            ; 11000000　　改行とリターン

;ＡＤ変換を実行するアナログチャンネルを指定し、かつＡＤ変換器をオンする
channel1   equ   b'00000001'   ;ＡＮ０を選択
channel2   equ   b'00010001'   ;ＡＮ１を選択
channel3   equ   b'00100001'   ;ＡＮ２を選択
channel4   equ   b'00110001'   ;ＡＮ３を選択
channel5   equ   b'01000001'   ;ＡＮ４を選択
channel6   equ   b'01010001'   ;ＡＮ５を選択
channel7   equ   b'10000001'   ;ＡＮ８を選択
channel8   equ   b'10010001'   ;ＡＮ９を選択
channel9   equ   b'10100001'   ;ＡＮ１０を選択
channel10  equ   b'10110001'   ;ＡＮ１１を選択

;ＬＣＤに表示する各文字の文字数
devisenum   equ    12    ;' Data Memory'   スペースも入れている
oknum       equ    3     ;'OK?'の文字数
jobselnum   equ    13    ;'Job Selection'の文字数
measurenum  equ    7     ;'Measure'の文字数
memorynum   equ    10    ;'Memory Out'の文字数
RS232Cnum   equ    10    ;'RS232C Out'の文字数
stimenums   equ    14    ;'Sample Time(s)'　の文字数
stimenumm   equ    15    ;'Sample Time(ms)'　の文字数
stimenumu   equ    15    ;'Sample Time(us)'　の文字数
startnum    equ    5     ;'Start'の文字数
executenum  equ    7     ;'Execute'の文字数
stopnum     equ    4     ;'Stop'の文字数

;アドレス用定数  時間精度が上がるように数値の調整をすること
militime1   equ    59    ;ミリ秒時間遅延用
militime2   equ    28    ;同上
sectime1    equ    108   ;秒時間遅延用
sectime2    equ    60    ;同上

;****************************************************************************************
;****************************************************************************************
;
          org     0                ;スタートアドレス０番地
          goto    start

;****************************************************************************************
;*********** 割り込み処理 ***************************************************************
          org     8
handler
      ;当面、間違ったキー入力を取り消し、処理の選択画面に移らせるのに使用する
      ;割り込みを行うときまでに測定したデータをメモリから消さないで置くようにする
          call    wait_exe         ;少し待機
          call    port_initial     ;ポートを初期化する
          movlb   5                ;
          bsf     PORTG,5          ;上位ビット用メモリをスタンバイとする
          bsf     PORTG,6          ;下位ビット用メモリをスタンバイとする
          movlb   0
          call    address_initial  ;アドレスカウンタを初期化する
          call    LCD_initial      ;ＬＣＤを初期化する
          movlw   b'00101100'      ;１度割り込みが発生すると、CPUSTAのb4が自動的に１となり、
                                   ;それ以降の割り込みを禁止する
          movwf   CPUSTA           ;b4=0 として割り込みを再許可する 
          goto    main_repeat      ;処理選択ルーチンへ移る
          return
 
;****************************************************************************************
;*********** スタート *******************************************************************
start

     ;最初に割り込み条件を設定する
          movlw   b'00101100'      ;b4が全ての割り込みの制御ビット
          movwf   CPUSTA           ;b4=1 で全ての割り込みを不可、 
          movlw   b'00000001'      ;b0がRA0/INT での割り込みを決める
          movwf   INTSTA           ;b0=1 が可 b0=0 が不可
          movlw   b'00000000'      ;b7 が RA0/INT でのエッジ選択を決める
          movwf   T0STA            ;テーゼロ　b7=0 で立ち下がり  b7=1 で立ち上がり

     ;ポートの初期設定  
           call    port_initial
     ;ＬＣＤの初期設定   
          call    LCD_initial
     ;ＡＤの初期設定    
          call    AD_initial
     ;アドレスカウンタの初期設定 
          call   address_initial
     ;メモリの初期設定  
          call    memory_initial
     ;ＲＳ－２３２Ｃの初期設定
          call    RS_232C_initial
     ;ＬＣＤ画面に初期文章を表示 
          call   first_LCD

     ;測定／メモリ出力／ＲＳ２３２Ｃ出力の選択
main_repeat
          call   job_selection
     ;サンプリング時間間隔の読み込み 
          movlw    2               ;jobnum=2の時は、ＲＳ２３２Ｃ出力なので
          cpfseq   jobsel          ;サンプリング時間の設定は不用
          call   samplingtime_set  ;
     ;選択された処理に入る
       
          movlw    0               ;ジョブ番号が０の時には、測定を開始する
          cpfseq   jobsel          ;ジョブ番号が１の時には、メモリ出力を行う
          goto     jobjump1        ;ジョブ番号が２の時には、ＲＳ２３２出力を行う
          goto     measure_start   ;
jobjump1  movlw    1               ;
          cpfseq   jobsel          ;
          goto     RS232C_start    ;
          goto     memoryout_start ;

;**************************************************************************************
;*********  デバイスタイトル表示  *****************************************************
first_LCD
          movlb   1                ;Ｅポートはバンク１にある
          bsf     PORTE,0          ;ＬＣＤのＥ端子を１とし、ＬＣＤを動作させる  
          movlb   0                ;                       
       ;デバイスタイトル表示
          movlw    devisenum       ;デバイスタイトルの文字数をcharnumに取り込む
          movwf    charnum
          call     devise_out      ;１行目にタイトルを表示する
          call     careturn_out    ;改行する
          movlw    oknum           ;'OK?'の文字数を取り込む
          movwf    charnum         ;
          call     ok_out          ;ＬＣＤに表示する
          call     key_push        ;'D'キーが押されるまで待機
          call     clear_out       ;ＬＣＤ画面をクリア
          call     wait_exe        ;少し時間待機させる 
          movlw    jobselnum       ;'Job Selection'の文字数を取り込む
          movwf    charnum 
          call     jobsel_out      ;ＬＣＤに表示する
          call     careturn_out    ;改行する
          return

;***************************************************************************************
;*********  ジョブ選択  ****************************************************************
job_selection
       ;測定の文字を描写
measuresub
          call     clear_out       ;ＬＣＤ画面のクリア
          movlw    jobselnum       ;'Job Selection'の文字数を取り込む
          movwf    charnum 
          call     jobsel_out       ;ＬＣＤに表示する
          call     careturn_out    ;改行する
          movlw    measurenum      ;'Measure'の文字数を取り込む
          movwf    charnum 
          call     measure_out       ;ＬＣＤに表示する
          call     inkey           ;キー入力を読み込む
          call     wait_exe
          movlw    15              ;
          cpfseq   key             ;キー文字がＤ（１５）の時、スキップ
          goto     memorysub
          movlw    0               ;測定処理に０の番号をつける
          movwf    jobsel          ;
          return

       ;メモリからの出力を表示 
memorysub
          call     clear_out       ;ＬＣＤ画面のクリア
          movlw    jobselnum       ;'Job Selection'の文字数を取り込む
          movwf    charnum 
          call     jobsel_out       ;ＬＣＤに表示する
          call     careturn_out    ;改行する
          movlw    memorynum       ;'Memory Out'の文字数を取り込む
          movwf    charnum 
          call     memory_out       ;ＬＣＤに表示する
          call     inkey           ;キー入力を読み込む
          call     wait_exe
          movlw    15              ;
          cpfseq   key             ;キー文字がＤ（１５）の時、スキップ
          goto     RS232Csub
          movlw    1               ;メモリ出力の処理に１の番号をつける
          movwf    jobsel          ;
          return

       ;ＲＳ２３２送信を表示 
RS232Csub
          call     clear_out       ;ＬＣＤ画面のクリア
          movlw    jobselnum       ;'Job Selection'の文字数を取り込む
          movwf    charnum 
          call     jobsel_out       ;ＬＣＤに表示する
          call     careturn_out    ;改行する
          movlw    RS232Cnum       ;'RS232C Out'の文字数を取り込む
          movwf    charnum 
          call     RS232C_out       ;ＬＣＤに表示する
          call     inkey           ;キー入力を読み込む
          call     wait_exe
          movlw    15              ;
          cpfseq   key             ;キー文字がＤ（１５）の時、スキップ
          goto     measuresub
          movlw    2               ;ＲＳ２３２Ｃ送信の処理に２の番号をつける
          movwf    jobsel          ;
          return

;****************************************************************************************
;***********  サンプリング時間間隔の設定  ***********************************************
samplingtime_set
       ;時間間隔はメモリのアドレスをインクリメントする時間間隔を制御することで行う。
          clrf     figure          ;桁数を示す変数を０としておく
          clrf     figure1         ;各桁の文字の入る変数を０としておく
          clrf     figure2         ;
          clrf     figure3         ;
          movlw    1
          movwf    inttime         ;初期値を１としておく
       ;秒単位
secont    movlw    0
          movwf    timebase        ;timebase=0 とし、秒を表現
          call     clear_out       ;ＬＣＤ画面をクリアする
          movlw    stimenums       ;'Sample Time (s)'の文字数をcharnumに取り込む
          movwf    charnum
          call     stimes_out      ;ＬＣＤに表示する
          call     careturn_out    ;改行しておく
          call     inkey           ;キー入力を読み込む
          call     wait_exe
          movlw    12              ;キー文字がＡ（１２）の時は、画面をスクロールさせて
          cpfseq   key             ;ｍ秒単位の処理に移る
          goto     nextsec1        ;
          goto     milisec         ;
nextsec1  movlw    15              ;
          cpfseq   key             ;キー文字がｄ（１５）の時は、時間間隔の読み込み
          goto     nextsec         ;データを０とみなして測定に入る
          return                   ;このルーチンを終了する
nextsec   call     charassign      ;入力キー文字を数値に直すルーチンへ行く
          call     inkey
          call     wait_exe        ;待機
          movlw    15
          cpfseq   key             ;キー文字がＤ（１５）の時には、決定となり
          goto     nextsec         ;
          call     numerize        ;３桁数値の処理ルーチンへ行く
          return

       ;ｍ秒単位
milisec   movlw    1
          movwf    timebase        ;timebase=1 とし、ｍ秒を表現
          call     clear_out       ;ＬＣＤ画面をクリアする
          movlw    stimenumm       ;'Sample Time (ms)'の文字数をcharnumに取り込む
          movwf    charnum
          call     stimem_out      ;ＬＣＤに表示する
          call     careturn_out    ;改行しておく
          call     inkey           ;キー入力を読み込む
          call     wait_exe
          movlw    12              ;キー文字がＡ（１２）の時は、画面をスクロールさせて
          cpfseq   key             ;マイクロ秒単位の処理に移る
          goto     nextmil1        ;
          goto     microsec
nextmil1  movlw    15              ;
          cpfseq   key             ;キー文字がｄ（１５）の時は、時間間隔の読み込み
          goto     nextmil         ;データを０とみなして測定に入る
          return                   ;このルーチンを終了する
nextmil   call     charassign      ;入力キー文字を数値に直すルーチンへ行く
          call     inkey
          call     wait_exe
          movlw    15
          cpfseq   key             ;キー文字がＤ（１５）の時には、決定となり
          goto     nextmil         ;
          call     numerize        ;３桁の数値処理ルーチンへ行く   
          return

       ;マイクロ秒単位
microsec  movlw    2
          movwf    timebase        ;timebase=2 とし、マイクロ秒を表現
          call     clear_out       ;ＬＣＤ画面をクリアする
          movlw    stimenumu       ;'Sample Time (us)'の文字数をcharnumに取り込む
          movwf    charnum
          call     stimeu_out      ;ＬＣＤに表示する
          call     careturn_out    ;改行しておく
          call     inkey           ;キー入力を読み込む
          call     wait_exe
          movlw    12              ;キー文字がＡ（１２）の時は、画面をスクロールさせて
          cpfseq   key             ;秒単位の処理に移る
          goto     nextmic1        ;
          goto     secont
nextmic1  movlw    15              ;
          cpfseq   key             ;キー文字がｄ（１５）の時は、時間間隔の読み込み
          goto     nextmic         ;データを０とみなして測定に入る
          return                   ;このルーチンを終了する
nextmic   call     charassign      ;入力キー文字を数値に直すルーチンへ行く
          call     inkey
          call     wait_exe
          movlw    15
          cpfseq   key             ;キー文字がＤ（１５）の時には、決定となり
          goto     nextmic         ;
          call     numerize        ;３桁数値の処理ルーチンへ行く
          return

;キー入力した数値文字の整理
charassign
       ;キーパットのキーを押したときに発生するデータコードとキー文字とはアセンブラの
       ;コードとは一致していない。従って、まず数値キーを押したらアセンブラでその数値
       ;データとして扱えるようにする。対応表はルックアップテーブルを参照すること。
         movlw    0               ;
          cpfseq   key             ;keyが０なら（１のキー）ば、
          goto     next1           ;currentに１を代入
          movlw    1               ;
          movwf    current         ;
          goto     next10
next1     movlw    1
          cpfseq   key             ;keyが１なら（４のキー）ば、
          goto     next2           ;currentに４を代入
          movlw    4               ;
          movwf    current         ;
          goto     next10
next2     movlw    2
          cpfseq   key             ;keyが２なら（７のキー）ば、
          goto     next3           ;currentに７を代入
          movlw    7               ;
          movwf    current         ;
          goto     next10
next3     movlw    4
          cpfseq   key             ;keyが４なら（２のキー）ば、
          goto     next4           ;currentに２を代入
          movlw    2               ;
          movwf    current         ;
          goto     next10
next4     movlw    5
          cpfseq   key             ;keyが５なら（５のキー）ば、
          goto     next5           ;currentに５を代入
          movlw    5               ;
          movwf    current         ;
          goto     next10
next5     movlw    6
          cpfseq   key             ;keyが６なら（８のキー）ば、
          goto     next6           ;currentに８を代入
          movlw    8               ;
          movwf    current         ;
          goto     next10
next6     movlw    7
          cpfseq   key             ;keyが７なら（０のキー）ば、
          goto     next7           ;currentに０を代入
          movlw    0               ;
          movwf    current         ;
          goto     next10
next7     movlw    8
          cpfseq   key             ;keyが８なら（３のキー）ば、
          goto     next8           ;currentに３を代入
          movlw    3               ;
          movwf    current         ;
          goto     next10
next8     movlw    9
          cpfseq   key             ;keyが９なら（６のキー）ば、
          goto     next9           ;currentに６を代入
          movlw    6               ;
          movwf    current         ;
          goto     next10
next9     movlw    10
          cpfseq   key             ;keyが１０なら（９のキー）ば、
          goto     next10          ;currentに９を代入
          movlw    9               ;
          movwf    current         ;

next10    movfp    current,WREG
          movwf    key
      ;この時点で、keyにはキーパットの押したキーの表している数値に対応した
      ;プログラムで使用できる数値データが入った
          incf     figure,1        ;figureを＋１する
          movlw    1               ;
          cpfseq   figure          ;第１文字でなければ、ジャンプさせる     
          goto     double
single    movfp    key,WREG        ;キーの文字をfigure1に取り込む
          movwf    figure1         ;
          return                   ;戻る
double    movlw    2               ;
          cpfseq   figure          ;第２文字でなければ、ジャンプさせる
          goto     triple          ;
          movfp    figure1,WREG    ;figure1に１桁目を、
          movwf    figure2         ;figure2に２桁目を入れる
          movfp    key,WREG         ;
          movwf    figure1         ;
          return                   ;戻る
triple    movfp    figure2,WREG    ;
          movwf    figure3         ;figure1に１桁目を、
          movfp    figure1,WREG    ;figure2に２桁目を、
          movwf    figure2         ;figure3に３桁目を入れる
          movfp    key,WREG        ;
          movwf    figure1         ;
          return                   

;３桁の数値文字列から本物の数値を作る
numerize
;その後、実施のサンプリング時間間隔とキーイン時間数を合わせる。
          movfp    figure2,WREG    ;２桁目の数を取りだし、
          mullw    10              ;Ｗの値と１０を掛け算する。結果は１６ビットで
                                   ;バンクされていないレジスタPRODL,PRODHに入る
          movfp    PRODL,WREG      ;掛け算結果の下位８ビットを
          movwf    temp0           ;temp0に入れておく
          movfp    figure3,WREG    ;３桁目の数を取りだし、
          mullw    100             ;Ｗの値と１００を掛け算をする
          movfp    PRODL,WREG      ;
          addwf    temp0,0         ;Ｗの値とtemp0（２桁目）を加算し、結果はＷに入れる。
          addwf    figure1,0       ;Ｗの値とfigure1（１桁目）を加算し、結果はＷに。
          movwf    inttime         ;得られた値をinttimeに入れる。
          return
          
number    movfp    figure3,WREG		;３桁目の数字をnumb0にいれる
	  movwf    numb0		;
	  movfp    figure2,WREG		;figure2×10＋Figure1より２桁の数字を作り出す
	  mullw    10			;
	  movfp	   PRODL,WREG		;
	  addwf    figure1,0            ;addwf  figure1,WREG ではワーニングエラーが出るので変更（１１月２３日）
	  movwf    numb1		;２桁の数字をnumb1にいれる
	  movlw    20			;
	  cpfsgt   numb1		;num1が２０以上か比較する
	  goto     numberD		;２０以下だったらnumberＤへ
	  movlw    20			;２０以上だったらnumb1より２０を引く
	  subwf    numb1,F		;
	  movlw    0
	  cpfseq   numb1		;numb1が０かどうか調べる
	  goto     numberA		;≠０だったら、numberAへとぶ
	  goto     numberB		;＝０だったら、numberBへとぶ
numberA   nop
	  nop
	  decfsz   numb1,F		;numb1=0になるまで減算をする
	  goto     numberA		;
numberB   movlw    0			;numb0=0かどうか調べる
          cpfseq   numb0		;
          goto     numberC		;
          return			;
numberC   decf     numb0,F		;numb0-1する
	  movlw    99			;numb1に99を代入する
          movwf    numb1		;
          goto     numberA		;
numberD   movlw    0			;numb0（三桁の数字）が０でないが調べる
	  cpfseq   numb0		;numb0＝０ならばループを抜け出す
	  goto     numberE		;そうじゃなければnumb0-1してnumbに８０を加える
	  return			
numberE	  decf     numb0,F		;
	  movlw    80			;
	  addwf    numb1,F		;
	  goto     numberA		;
;numberループでサンプリング周期 100*numb0＋numb1より20を引いているのはAD変換に要する時間	 
;のために生じるサンプリング時間のオフセット分を取り除くためである
;オフセット時間は２０マイクロ秒であった。
;************************************************************************************
;*************  測定の実行  *********************************************************
measure_start
          call     clear_out       ;ＬＣＤ画面をクリアする         
          movlw    startnum        ;'Start'の文字数を読み込む
          movwf    charnum
          call     start_out       ;文字をＬＣＤに表示する
          call     key_push        ;'D'キーが押されるまで待機
       ;実行中を表示させておく
          call     clear_out       ;ＬＣＤが面をクリアする
          movlw    executenum      ;'Execute'の文字数を読み込む
          movwf    charnum
          call     execute_out     ;文字をＬＣＤに表示する
       ;ＡＤチャンネルの選択　ここの所で入力チャンネルを指定すればよい
       ;                      現時点ではチャンネル１だけを用いている     
          movlw   channel1         ;ＡＮ２を選択し、ＡＤ変換器をオンする
        ; movlw   channel5         ;ＡＮ６を選択し、ＡＤ変換器をオンする
          movlb   5
          movwf   ADCON0           ;ＡＤ制御レジスタADCON0の設定
          movlb   0
       ;サンプリングの開始
          movlb   1                ;Ｅポートはバンク１にある
          bcf     PORTE,0          ;ＬＣＤのＥ端子を０とし、ＬＣＤを不動作としておく
          movlb   5                ;Ｇポートはバンク５にある
          bcf     PORTG,7          ;メモリのＷＥ端子を０とし、メモリを書き込み可とする
                                   ;後は、アドレスを進める毎に、ＣＳ端子に接続している
          movlb   0                ;ＲＧ５をクロックすれば良い
sample_start
          movlb   5                ;
          bsf     ADCON0,GO        ;ＡＤ変換を開始させる
nodone    btfsc   ADCON0,GO        ;ＡＤ変換が完了するまで待機する
          goto    nodone           ;完了すると、GOビットは０となる
        ;上位８ビットのメモリへの書き込み
          movfp   ADRESH,WREG      ;１０ビットのうちの上位８ビットをＷに値を取り込む
          movlb   1                ;メモリへのデータ出力端子はバンク１のＣポートである。
          movwf   PORTC            ;メモリへデータを送り出す。
          movlb   5                ;上位ビット用メモリのＣＳ端子はバンク５のＲＧ５に接続している
          bcf     PORTG,5          ;メモリのＣＳ端子を０としてから、１にする
          bsf     PORTG,5          ;これでメモリへの書き込みが完了する
          movlb   0
          movwf   PORTB            ;得られたＡＤ変換値をＤＡ変換器より出力させる
        ;下位２ビットのメモリへの書き込み
          movlb   5                ;
          movfp   ADRESL,WREG      ;１０ビットのうちの下位２ビットをＷに値を取り込む
          movlb   1                ;メモリへのデータ出力端子はバンク１のＣポートである。
          movwf   PORTC            ;メモリへデータを送り出す。
          movlb   5                ;下位ビット用メモリのＣＳ端子はバンク５のＲＧ６に接続している
          bcf     PORTG,6          ;メモリのＣＳ端子を０としてから、１にする
          bsf     PORTG,6          ;これでメモリへの書き込みが完了する
               rrcf    WREG,1           ;ＷＲＥＧの値を右に１ビット送る
               rrcf    WREG,1           ;          同上
               rrcf    WREG,1           ;          同上
               rrcf    WREG,1           ;          同上
               movwf   PORTF            ;得られたＡＤ変換値下位２ビットをＤＡ変換器より出力させる
          movlb   0                ;
          
          btfsc   PORTA,1          ;メモリのアドレスカウンタがオーバーフローした時点で
          goto    job_end          ;測定を終了させる。ＡポートのＲＡ１が１になったら
                                   ;終了処理ルーチンへジャンプ
          movlw   2
          cpfseq  timebase         ;timebase=2 がマイクロ秒の処理
          goto    addnext1  
          call    address_up_micro ;マイクロ秒でのアドレスカのインクリメント
          goto    sample_start
addnext1  movlw   1
          cpfseq  timebase         ;timebase=1 がｍ秒の処理
          goto    addnext2  
          call    address_up_mili  ;ミリ秒でのアドレスのインクリメント
          goto    sample_start
addnext2  call    address_up_sec   ;秒でのアドレスのインクリメント
          goto    sample_start
          return

;****************************************************************************************
;************  上位８ビット用メモリからの出力  ******************************************
; 以下にある２つの注釈行を生かし、そのかわり各々の上のステートメントを注釈行とすれば、
; 一応、下位２ビットメモリのデータをモニター出力できる。
memoryout_start
          call     clear_out        ;ＬＣＤ画面をクリアする         
          movlw    startnum         ;'Start'の文字数を読み込む
          movwf    charnum
          call     start_out        ;'Start'文字をＬＣＤに表示する
          call     key_push         ;'D'キーが押されるまで待機
  ;実行中を表示させておく
          call     clear_out        ;ＬＣＤが面をクリアする
          movlw    executenum       ;'Execute'の文字数を読み込む
          movwf    charnum
          call     execute_out      ;'Execute'文字をＬＣＤに表示する
          movlb    1
          clrf     PORTC            ;バンク１のＣポートのラッチをクリアしておく
          movlw    b'11111111'      ;メモリからデータを取り込むため、
          movwf    DDRC             ;Ｃポート８ビットを全て入力とする。
          movlb    0
          call     address_initial  ;アドレスカウンタをリセットし、そしてカウント状態とする
          movlb    5                ;
          bsf      PORTG,7          ;メモリのＷＥ端子を１とし、読み出し可とする
mloop     movlb    5
          bcf      PORTG,5          ;上位８ビット用メモリのＣＳ端子を０とし、データを読み出す
      ;    bcf      PORTG,6          ;下位２ビット用メモリのＣＳ端子を０とし、データを読み出す
          movlb    1                ;          
          movfp    PORTC,WREG       ;バンク１にあるＣポートからデータをＷに取り込み、
          movlb    0                ;バンク０にあるＢポートに出力する
          movwf    PORTB
          movlb    5                ;
          bsf      PORTG,5          ;上位８ビット用メモリのＣＳ端子を１とし、メモリを不可とする
      ;    bsf      PORTG,6          ;下位２ビット用メモリのＣＳ端子を１とし、メモリを不可とする
      ;    movlb    0
               bcf      PORTG,6          ;下位２ビット用メモリのＣＳ端子を０とし、データを読み出す
               movlb    1                ;          
               movfp    PORTC,WREG       ;バンク１にあるＣポートからデータをＷに取り込み、
               movlb    5                ;バンク５にあるＦポートに出力する
               rrcf     WREG,1           ;ＷＲＥＧの値を右に１ビット送る
               rrcf     WREG,1           ;          同上
               rrcf     WREG,1           ;          同上
               rrcf     WREG,1           ;          同上
               movwf    PORTF
               bsf      PORTG,6          ;下位２ビット用メモリのＣＳ端子を１とし、メモリを不可とする
               movlb    0
          btfsc   PORTA,1           ;メモリのアドレスカウンタがオーバーフローした時点で
          goto    job_end           ;測定を終了させる。ＡポートのＲＡ１が１になったら
                                    ;終了処理ルーチンへジャンプ
          movlw   2
          cpfseq  timebase          ;timebase=2 がマイクロ秒の処理
          goto    memadd1  
          call    address_up_micro  ;マイクロ秒でのアドレスカのインクリメント
          goto    mloop
memadd1   movlw   1
          cpfseq  timebase          ;timebase=1 がｍ秒の処理
          goto    memadd2  
          call    address_up_mili   ;ミリ秒でのアドレスのインクリメント
          goto    mloop
memadd2   call    address_up_sec    ;timebase=0秒でのアドレスのインクリメント
          goto    mloop
          return 

;*****************************************************************************************
;************  ＲＳ２３２Ｃ出力を実行  ***************************************************
RS232C_start
          call    clear_out         ;ＬＣＤ画面をクリアする         
          movlw   startnum          ;'Start'の文字数を読み込む
          movwf   charnum
          call    start_out         ;文字をＬＣＤに表示する
          call    key_push          ;'D'キーが押されるまで待機
       ;実行中を表示させておく
          call    clear_out         ;ＬＣＤが面をクリアする
          movlw   executenum        ;'Execute'の文字数を読み込む
          movwf   charnum
          call    execute_out       ;文字をＬＣＤに表示する

       ;サンプリング時間数値の送信　３桁　１１月２３日付加する
          movfp   figure3,WREG      ;３桁目（百の位）をＷレジスタに取り込み、
          call    time_para         ;送信サブルーチンへ
          movfp   figure2,WREG      ;２桁目（十の位）
          call    time_para         ;
          movfp   figure1,WREG      ;１桁目（一の位）
          call    time_para         ;
          call    RS_interval       ;少し待機

       ;サンプリング時間単位の送信　　　　　１１月２３日付加する
          movfp   timebase,WREG     ;時間単位代表値をＷレジスタに取り込み、
          call    time_para         ;送信サブルーチンへ
　        call    RS_interval       ;少し待機

       ;メモリに記録して置いたデータの送信
          movlb   1
          clrf    PORTC             ;バンク１のＣポートのラッチをクリアしておく
          movlw   b'11111111'       ;メモリからデータを取り込むため、
          movwf   DDRC              ;Ｃポート８ビットを全て入力とする。
          movlb   0

          call    address_initial   ;ハードのアドレスカウンタ７４ＨＣ４０４０をリセットし、
                                    ;そしてカウント状態とする

blockloop
          call    RS_interval       ; 
          call    bcounter_initial  ;ブロックカウンタを初期値に戻す

    ;１データ＝２バイト分の送信
          movlb   5                 ;
          bsf     PORTG,7           ;メモリのＷＥ端子を１とし、読み出し可とする
RSloop1 ;先行１バイト（上位８ビット分）の送信
          movlb   5
          bcf     PORTG,5           ;上位８ビット用メモリのＣＳ端子を０とし、データを読み出す
          movlb   1                 ;          
          movfp   PORTC,WREG        ;メモリデータ線と結線しているＣポートからデータをＷに取り込み、
          movlb   0
          movwf   TXREG1            ;送信用レジスタにテータを入れる
          bsf     TXSTA1,TXEN       ;送信を可とする
          movlb   1                 ;
RSwait1   btfss   PIR1,TX1IF        ;TXREG1が空になるまで待機。１データの転送完了待ち
          goto    RSwait1           ;空になると、TX1IF=1となる 
          movlb   0                 ;モニターのためバンク０にあるＢポートに出力する
          movwf   PORTB
          movlb   5    
          bsf     PORTG,5           ;上位８ビット用メモリのＣＳ端子を１とし、メモリを不可とする
       ;後続１バイト（下位２ビット分）の送信 
          bcf     PORTG,6           ;下位２ビット用メモリのＣＳ端子を０とし、データを読み出す
          movlb   1                 ;          
          movfp   PORTC,WREG        ;メモリデータ線と結線しているＣポートからデータをＷに取り込み、
          movlb   0 
          movwf   TXREG1            ;送信用レジスタにテータを入れる
          bsf     TXSTA1,TXEN       ;送信を可とする
          movlb   1                 ;
RSwait2   btfss   PIR1,TX1IF        ;TXREG1が空になるまで待機。１データの転送完了待ち
          goto    RSwait2           ;空になると、TX1IF=1となる 
          movlb   0                 ;モニターのためバンク０にあるＢポートに出力する
          movwf   PORTB
          movlb   5    
          bsf     PORTG,6           ;下位２ビット用メモリのＣＳ端子を１とし、メモリを不可とする
          movlb   0

        ;ハードのアドレスカウンタ７４ＨＣ４０４０のアドレスを進める
          btfsc   PORTA,1           ;メモリのアドレスカウンタがオーバーフローした時点で
          goto    job_end           ;送信を終了させる。ＡポートのＲＡ１が１になったら
                                    ;終了ルーチンへジャンプ  
          movlb   5                 ;Ｇポートのあるバンク５に移る
          bsf     PORTG,4           ;アドレスカウンタのCLOCK端子に１クロックを送り、
          bcf     PORTG,4           ;アドレスを１つ進める
          movlb   0

          call    bcounter_inc      ;データを１つ送ったのでデータ数モニターカウンターを＋１する。
          btfss   bcounter1,5       ;bcounter1 のb5=1 の時は8192個データ送信したのでblockloop へ行き、
          goto    RSloop1           ;              =0 の時はまだなのでRSloop1 へ行き、繰り返す。
          goto    blockloop
          return

;*********************************************************
time_para         ;サンプリング時間に関するパラメータ送信ルーチン　１１月２３日付加する
          movwf   TXREG1            ;Ｗレジスタの値を送信専用レジスタに入れる
          bsf     TXSTA1,TXEN       ;送信を可とする
          movlb   1                 ;バンク１に移る
RSwait0   btfss   PIR1,TX1IF        ;送信完了まで待機
          goto    RSwait0
          movlb   0                 ;バンク０に戻す
          return

bcounter_initial  ;１ブロック中の送信データ数を設定するルーチン
          clrf    bcounter1         ;bcounter1（上位６ビット）＋bcounter0（下位８ビット）
          clrf    bcounter0         ;で、１６ビットカウンタとする。
                                    ;bcounter1の最高ビットb5はフラッグとして使用する。
          return                    ;８１９２をカウントすれば、b5=1 となる。

bcounter_inc      ;送信されたデータ件数カウンタのルーチン。１６ビットカウンタである。
          incfsz  bcounter0,1       ;低位８ビット分カウンタを＋１し、0000000とならなければ、
          return                    ;戻る。00000000となったならば、キャリーアップをする。
          incf    bcounter1,1       ;下位８ビットからのキャリーアップとして、＋１する。
          return

RS_interval  ;送信されるデータブロック間に適当な時間幅を持たせるためのルーチン
          movlw   0                 ;
          movwf   temp0             ;２５６×１０で約５００μ秒の時間幅となる
          movlw   0                 ;２５６×２５６では１２．５ｍ秒
          movwf   temp1             ;
rsinloop  decfsz  temp0,1           ;
          goto    rsinloop          ;
          decfsz  temp1,1           ;
          goto    rsinloop          ;
          return

;***********************************************************************************
;*************  終了処理  **********************************************************
job_end
       ;ポートを初期化する
          call     port_initial    ;
       ;ＬＣＤを能動とし、画面をクリアし、ストップを表示する
          movlb    5               ;バンク５にあるＧポートの第５ビットを１とし、
          bsf      PORTG,5         ;上位ビット用メモリをスタンバイとする
          bsf      PORTG,6         ;下位ビットメモリをスタンバイとする
          movlb    1               ;
          movlw    b'00000000'     ;バンク１にあるＣポートを出力とし、ＬＣＤ用データ線
          movwf    DDRC            ;とする。メモリデータ線と共用であることに注意
          bsf      PORTE,0         ;ＬＣＤのＥ端子を１とし、ＬＣＤを能動とする
          movlb    0               ;
          call     clear_out       ;ＬＣＤ画面をクリア
          movlw    stopnum         ;'Stop'の文字数を読み込む
          movwf    charnum
          call     stop_out        ;文字をＬＣＤに表示する
       ;アドレスカウンタをリセットし、すぐにカウント可能としておく
          movlb    1               ;バンク１に移る
          bsf      PORTE,3         ;アドレスカウンタのRESET端子を１とする
          bcf      PORTE,3         ;
          movlb    0
       ;ＲＳ２３２Ｃ送信は不可としておく
          bcf     TXSTA1,TXEN      ;送信を不可とする
       ;分岐の選択
end_rep   call     inkey           ;キー入力を読み込む
          call     wait_exe        ;少し待機
          movlw    15
          cpfseq   key             ;キー文字がＤ（１５）の時、
          goto     end_rep         ;再度処理を開始する
          goto     main_repeat     ;
          return
               
;***********************************************************************************
;*************　初期設定ルーチン集  ************************************************
;ポートの初期設定
port_initial 
       ;Ａポート（６ビット）には DDR は無い。RA0 と RA1 は入力機能のみ
       ;      ＲＡ０は外部割り込み用、ＲＡ１はメモリアドレス・オーバーフローチェック用
       ;Ｂポートは全て（８ビット）出力端子に指定する。バンク０にある。ＤＡ出力ポート。
          clrf    PORTB             ;PORTB のラッチデータをクリア
          movlw   b'00000000'       ;Ｗに２進数の00000000を入れる
          movwf   DDRB              ;Ｂポートのデータ方向管理レジスタDDRBに上の値を代入し、          
                                    ;Ｂポートを出力端子とする
       ;Ｃポートは全て（８ビット）出力端子に設定する。後で入力端子ともなる。ＬＣＤデータポート。
          movlb   1                 ;バンク1をへ移る
          clrf    lcd_data          ;PORTCのラッチデータをクリアする
          movlw   b'00000000'       ;Ｗに２進数の00000000を入れる
          movwf   DDRC              ;Ｃポートのデータ方向管理レジスタDDRCに上の値を代入し、
                                    ;Ｃポートを出力端子とする。
       ;Ｄポートは、上位４ビットを入力端子、下位４ビットを出力端子に設定。キーパットポート。
          movlb   1                 ;バンク１へ移る
          clrf    keypad            ;PORTDのラッチデータをクリアする
          movlw   b'11110000'       ;Ｗに２進数の11110000を入れる
          movwf   DDRD              ;Dポートのデータ方向管理レジスタDDRDに上の値を代入し、
                                    ;Dポートを上記の設定とする。
       ;Ｅポートを全て（４ビット）出力端子に設定。ＬＣＤ制御ポート。
          movlb   1                 ;バンク１を選択する（PORTEレジスタのあるところ）
          clrf    contl             ;PORTEのラッチデータをクリアする
          movlw   b'00000000'       ;Ｗに２進数の00000000を入れる
          movwf   DDRE              ;Ｗの値をＥポートのデータ方向管理レジスタDDREに代入し、
                                    ;Ｅポートを出力端子とする。
          movlb   0
       ;Ｆポートは全てアナログ入力。
          movlb   5                 ;バンク５にＦポートはある
          clrf    PORTF             ;
       ;  movlw   b'11111111'       ;端子をＡＤ変換器として使用するときには、DDRレジスタを
                                    ;入力モードに指定しておかなければならない
               movlw   b'11110011'       ;ＲＦ３とＲＦ２はデジタル出力端子として使用する
          movwf   DDRF
          movlb   0
       ;Ｇポートは上位４ビットはデジタル出力端子、下位４ビットはアナログ入力端子に設定
          movlb   5                 ;
          clrf    PORTG             ;
          movlw   b'00001111'       ;
          movwf   DDRG              ;
          movlb   0
          return

;ＬＣＤの初期設定（タイトル表示を含む） 
LCD_initial   
          movlb   0                 ;０バンク指定。
          clrf    counter           ;
          call    lcdwait           ;無駄時間ループﾟ 
       ;ＬＣＤの初期設定
          movlw   b'00111000'       ;Ｗレジスタの値を変数temp2に代入
          movlb   1                 ;バンク１へ移る
          movwf   lcd_data          ;データ長８ビット、デューティ比を１／１６、
                                    ;フォントサイズを５＊７にそれぞれ設定
          movlb   0                 ;
          call    lcd_comout        ;命令をＬＣＤに転送
       ;画面をクリアし、カーソルをホームへ戻す
          movlw   clear             ;
          movlb   1                 ;
          movwf   lcd_data          ;
          movlb   0                 ;
          call    lcd_comout        ;ＬＥＤの命令処理を実行する
          movlw   home              ;同上
          movlb   1                 ;
          movwf   lcd_data          ;
          movlb   0                 ;
          call    lcd_comout        ;
       ;ＬＣＤ画面でカーソルをブリンクさせる
          movlw   b'00001111'       ;
          movlb   1                 ;
          movwf   lcd_data          ;表示オン、カーソルオン、ブリンクオンに設定
          movlb   0                 ;
          call    lcd_comout        ;命令をＬＣＤに転送
       ;データの書き込み時カーソルをカーソルをインクリメントするように設定
          movlw   b'00000110'       ;
          movlb   1                 ;
          movwf   lcd_data          ;文字入力時にカーソルアドレスを＋１
          movlb   0                 ;
          call    lcd_comout        ;命令をＬＣＤに転送
          return

;ＡＤコンバータの初期設定
AD_initial   ;ＡＤコンバータはＦポートとＧポートの一部（共にバンク５）にある。
          movlb   5                ;バンク５に移る
      ;   movlw   b'00000000'      ;ＡＤ変換クロックFoscの ８分の１とする。(b7,b6)=(00)
                                   ;ＡＤ結果の書式。左揃えとする。b5=0
                                   ;ＡＮ０～ＡＮ１１全てアナログ入力とする。(b3-b1)=(000)
                                   ;ＡＤ変換基準電圧は Vref+ と Vref- とする。b0=1
                                   ;                   AVdd と AVss とする。b0=0
                                   ;詳細は７５６のテクニカルノートＰ１６８を参照
               movlw   b'00000100'      ;ＲＦ２とＲＦ３をモニター下位２ビット出力用の
                                        ;デジタルＩ／Ｏに設定する。(b3-b1)=(010)
          movwf   ADCON1           ;ＡＤ制御レジスタADCON1の設定
          movlb   0                ;
          return

;アドレスカウンタの初期設定
address_initial 
          movlb   5                ;バンク５にＧポートがある
          bcf     PORTG,4          ;カウンタのＣＬＯＣＫ端子に接続している端子を
                                   ;０としておく
          movlb   1                ;バンク１にＥポートがある
          bsf     PORTE,3          ;カウンタのＲＥＳＥＴ端子に接続している端子を
          bcf     PORTE,3          ;１とし、リセットさせ、直ぐ０とし、カウント状態とする
          movlb   0
          return

;メモリの初期設定
memory_initial   
       ;メモリの内容をクリアしておく
          movlb   1                ;Ｅポートはバンク１にある
          bcf     PORTE,0          ;ＬＣＤのＥ端子を０とし、ＬＣＤを不動作としておく
          movlb   5                ;Ｇポートはバンク５にある
          bcf     PORTG,7          ;メモリのＷＥ端子を０とし、メモリを書き込み可とする
                                   ;後は、アドレスを進める毎に、ＣＳ端子に接続している
          movlb   0                ;ＲＧ５、ＲＧ６をクロックすれば良い
clearloop              ;
        ;上位８ビットのメモリのクリア
          movlb   1                ;ＰＯＲＴＣはバンク１にある
          clrf    PORTC,1          ;メモリのデータ線に００００００００を送る
          movlb   5                ;上位ビット用メモリのＣＳ端子はバンク５のＲＧ５に接続している
          bcf     PORTG,5          ;メモリのＣＳ端子を０としてから、１にする
          bsf     PORTG,5          ;これでメモリへの書き込みが完了する
        ;下位２ビットのメモリのクリア
          bcf     PORTG,6          ;下位ビット用メモリのＣＳ端子を０としてから、１にする
          bsf     PORTG,6          ;これでメモリへの書き込みが完了する
          movlb   0                ;
          btfsc   PORTA,1          ;メモリのアドレスカウンタがオーバーフローした時点で
          goto    clear_end        ;終了させる。ＡポートのＲＡ１が１になったら終了。
        ;アドレスを進める
          movlb   5                ;バンク５にＧポートがある
          bsf     PORTG,4          ;１クロックパルスをカウンタに送る
          bcf     PORTG,4          ;アドレスを１つ進める
          goto    clearloop        ;
clear_end movlb    5               ;
          bsf      PORTG,5         ;上位ビット用メモリのＣＳ端子を１とし、スタンドバイとしておく
          bsf      PORTG,6         ;下位ビット用メモリのＣＳ端子を１とし、スタンドバイとしておく
          movlb    0
        ;メモリの初期化に使用したアドレスカウンタを初期化しておく
          call    address_initial
          return

;ＲＳ－２３２Ｃの初期設定
RS_232C_initial
          bsf     RCSTA1,SPEN       ;RA5/TX1/CK1 端子をシリアルポートとして設定
          bsf     TXSTA1,CSRC       ;クロックソースの選択ビット。０，１でも非同期時は無視される
          bcf     TXSTA1,TX9        ;送信データビット数の選択。＝０で８ビット送信
          bcf     TXSTA1,TXEN       ;＝０で送信ディセーブル
          bcf     TXSTA1,SYNC       ;USARTモード選択ビット。＝０で非同期モード
          movlw   15                ;ボーレートの設定。
          movwf   SPBRG1            ;２０Ｍクロック時、１９２００ボーに設定
          return

;*************************************************************************************
;**********　キーパットのスキャン　***************************************************
inkey 
          call    scankeys          ;scankeys 呼び出し。キーパッドの入力を読み取る。
          movlw   16                ;
          subwf   key,0             ;keyの値からＷレジスタの値を引く。結果はＷに保持
          btfsc   ALUSTA,Z          ;演算結果　０ならばＺ＝１，それ以外はＺ＝０
          goto    keydelay          ;
          call    key_output        ;キーが押されていれば、文字をＬＣＤに出力しに行く
          return
keydelay
          movlw   0                 ;キーの多重打ちを避けるための遅延ループ
          movwf   temp0
          movwf   temp1
kloop     decfsz  temp0,1
          goto    kloop
          decfsz  temp1,1
          goto    kloop
          goto    inkey             ;キーが押されるまでエンドレス
scankeys  clrf    key               ; key をクリア
          movlb   1                 ;keypadはバンク1にある
          clrf    keypad            ; keypad をクリア
          movlb   0                 ;
          movlw   4                 ;cols=4、４＊４キーパッドを指定
          movwf   cols              ;
          bsf     ALUSTA,C          ;キャリービットを１にセット
scan      movlb   1                 ;バンク1に移る
          rlcf    keypad,1          ;keypadを左回転。第０ビット目にキャリー（Ｃ）値が入る。
          bcf     ALUSTA,C          ;キャリービットを０にクリア
          btfsc   keypad,row1       ;row1(rb.4)=1ならば press へ
          goto    press             ;
          movlb   0                 ;バンク０に戻る
          incf    key,1             ;key=key+1
          movlb   1                 ;
          btfsc   keypad,row2       ;row2(rb.5)=1ならば pressへ
          goto    press             ;
          movlb   0                 ;
          incf    key,1             ;key=key+1
          movlb   1                 ;
          btfsc   keypad,row3       ;row3(rb.6)=1ならば press へ
          goto    press             ;
          movlb   0                 ;
          incf    key,1             ;key=key+1
          movlb   1                 ;
          btfsc   keypad,row4       ;row4(rb.7)=1ならば press へ
          goto    press             ; 
          movlb   0                 ;
          incf    key,1             ;key=key+1
          decfsz  cols,1            ;cols-1、０でなければ scan へ
          goto    scan              ;
press     movlb   0
          return   

;*************************************************************************************
;**********  ＬＣＤに文字列を表示する  ***********************************************
    ;デバイスタイトル、オーケー、ジョブ選択、サンプリング（秒）、サンプリング（ｍ秒）
    ;サンプリング（マイクロ秒）、測定、メモリ出力、スタート、実行、停止を表示
       ;デバイスタイトルを表示
devise_out
          call    inclear
devloop   movfp   current,WREG      ;
          call    devise_title      ;
          movlb   1
          movwf   lcd_data          ;ＬＣＤへ出力
          movlb   0
          call    lcd_sigout        ;ＬＣＤへ書き込み
          incf    current,1         ;currentを＋１する
          decfsz  charnum,1         ;charnumを－１し、結果が０の時、下の命令をスキップ 
          goto    devloop
          return

       ;オーケーを表示
ok_out
          call    inclear
okloop    movfp   current,WREG      ;
          call    ok_title          ;
          movlb   1                 ;
          movwf   lcd_data          ;ＬＣＤへ出力
          movlb   0
          call    lcd_sigout        ;ＬＣＤへ書き込み
          incf    current,1         ;currentを＋１する
          decfsz  charnum,1         ;charnumを－１し、結果が０の時、下の命令をスキップ      
          goto    okloop
          return

       ;ジョブ選択を表示
jobsel_out
          call    inclear
jobloop   movfp   current,WREG      ;
          call    jobsel_title      ;
          movlb   1                 ;
          movwf   lcd_data          ;ＬＣＤへ出力
          movlb   0
          call    lcd_sigout        ;ＬＣＤへ書き込み
          incf    current,1         ;currentを＋１する
          decfsz  charnum,1         ;charnumを－１し、結果が０の時、下の命令をスキップ      
          goto    jobloop
          return

       ;測定を表示
measure_out
          call    inclear
mealoop   movfp   current,WREG      ;
          call    measure_title     ;
          movlb   1                 ;
          movwf   lcd_data          ;ＬＣＤへ出力
          movlb   0
          call    lcd_sigout        ;ＬＣＤへ書き込み
          incf    current,1         ;currentを＋１する
          decfsz  charnum,1         ;charnumを－１し、結果が０の時、下の命令をスキップ      
          goto    mealoop
          return

       ;メモリ出力表示
memory_out
          call    inclear
memloop   movfp   current,WREG      ;
          call    memory_title      ;
          movlb   1                 ;
          movwf   lcd_data          ;ＬＣＤへ出力
          movlb   0
          call    lcd_sigout        ;ＬＣＤへ書き込み
          incf    current,1         ;currentを＋１する
          decfsz  charnum,1         ;charnumを－１し、結果が０の時、下の命令をスキップ      
          goto    memloop
          return

       ;ＲＳ２３２Ｃ出力表示
RS232C_out
          call    inclear
rsloop    movfp   current,WREG      ;
          call    RS232C_title      ;
          movlb   1                 ;
          movwf   lcd_data          ;ＬＣＤへ出力
          movlb   0
          call    lcd_sigout        ;ＬＣＤへ書き込み
          incf    current,1         ;currentを＋１する
          decfsz  charnum,1         ;charnumを－１し、結果が０の時、下の命令をスキップ      
          goto    rsloop
          return

       ;サンプリング時間　秒を表示
stimes_out
          call    inclear
stsloop   movfp   current,WREG      ;
          call    stimes_title          ;
          movlb   1                 ;
          movwf   lcd_data          ;ＬＣＤへ出力
          movlb   0
          call    lcd_sigout        ;ＬＣＤへ書き込み
          incf    current,1         ;currentを＋１する
          decfsz  charnum,1         ;charnumを－１し、結果が０の時、下の命令をスキップ      
          goto    stsloop
          return
       ;サンプリング時間　ｍ秒を表示
stimem_out
          call    inclear
stmloop   movfp   current,WREG      ;
          call    stimem_title      ;
          movlb   1                 ;
          movwf   lcd_data          ;ＬＣＤへ出力
          movlb   0
          call    lcd_sigout        ;ＬＣＤへ書き込み
          incf    current,1         ;currentを＋１する
          decfsz  charnum,1         ;charnumを－１し、結果が０の時、下の命令をスキップ      
          goto    stmloop
          return
       ;サンプリング時間　マイクロ秒を表示
stimeu_out
          call    inclear
stuloop   movfp   current,WREG      ;
          call    stimeu_title          ;
          movlb   1                 ;
          movwf   lcd_data          ;ＬＣＤへ出力
          movlb   0
          call    lcd_sigout        ;ＬＣＤへ書き込み
          incf    current,1         ;currentを＋１する
          decfsz  charnum,1         ;charnumを－１し、結果が０の時、下の命令をスキップ      
          goto    stuloop
          return

       ;スタートを表示
start_out
          call    inclear
staloop   movfp   current,WREG      ;
          call    start_title          ;
          movlb   1                 ;
          movwf   lcd_data          ;ＬＣＤへ出力
          movlb   0 
          call    lcd_sigout        ;ＬＣＤへ書き込み
          incf    current,1         ;currentを＋１する
          decfsz  charnum,1         ;charnumを－１し、結果が０の時、下の命令をスキップ
          goto    staloop
          return

       ;実行を表示
execute_out
          call    inclear
exeloop   movfp   current,WREG      ;
          call    execute_title      ;
          movlb   1                 ;
          movwf   lcd_data          ;ＬＣＤへ出力
          movlb   0
          call    lcd_sigout        ;ＬＣＤへ書き込み
          incf    current,1         ;currentを＋１する
          decfsz  charnum,1         ;charnumを－１し、結果が０の時、下の命令をスキップ
          goto    exeloop
          return

       ;停止を表示
stop_out
          call    inclear
stoloop   movfp   current,WREG      ;
          call    stop_title          ;
          movlb   1                 ;
          movwf   lcd_data          ;ＬＣＤへ出力
          movlb   0    
          call    lcd_sigout        ;ＬＣＤへ書き込み
          incf    current,1         ;currentを＋１する
          decfsz  charnum,1         ;charnumを－１し、結果が０の時、下の命令をスキップ
          goto    stoloop
          return

inclear   clrf    current           ;初期値を０にしておく
          clrf    WREG              ;初期値を０にしておく
          return

;********************************************************************************
;*************  ＬＣＤ制御用各種ルーチン  ***************************************
clear_out   ;ＬＣＤ画面のクリア
          movlw   clear             ;画面クリアのコードの取り込み
          movlb   1                 ;
          movwf   lcd_data          ;ＬＣＤへ送る
          movlb   0                 ;
          call    lcd_comout  
          return 
   
careturn_out   ;ＬＣＤに改行させる
          movlw   ret_bak           ;キャリッジリターンのコードを取り込み、
          movlb   1                 ;
          movwf   lcd_data          ;ＬＣＤへ送る
          movlb   0                 ;
          call    lcd_comout  
          return

lcd_comout   ;ＬＣＤへの命令の書き込みルーチン
          movlb   1
          bcf     contl,rs          ;rs=0として、命令コードの指定
          bcf     contl,rw          ;rw=0として、書き込みの指定
          bsf     contl,e           ;e =1として、ＬＣＤの動作起動
          nop
          bcf     contl,e           ;e =0として、ＬＣＤの動作停止
          movlb   0
          call    lcdwait           ;
          return

lcd_sigout   ;ＬＣＤへの記号の書き込みルーチン
          movlb   1
          bsf     contl,rs          ;rs=1として、記号コードの指定
          bcf     contl,rw          ;rw=0として、書き込みの指定
          bsf     contl,e           ;e =1として、ＬＣＤの動作起動
          nop
          bcf     contl,e           ;e =0として、ＬＣＤの動作停止
          movlb   0
          call    lcdwait           ;
          return

key_output   ;キーパッドにより入力された文字をＬＣＤへ出力させるためのルーチン
          movfp   key,WREG          ;keyの値をＷへ格納
          call    msg               ;キャラクターテーブルより、文字を受け取って戻る
          movlb   1                 ;バンク１に移る
          movwf   lcd_data          ;
          movlb   0                 ;
          call    lcd_sigout        ;文字をＬＣＤに転送する
          return  

lcdwait   ;ＬＣＤ表示時のディレイ用ルーチン
          movlw   0                 ;temp0=0,temp1=8では表示こぼしが発生する
          movwf   temp0             ;
          movlw   32
          movwf   temp1         
lcdloop   decfsz  temp0,1           ;
          goto    lcdloop           ;
          decfsz  temp1,1
          goto    lcdloop
          return   

;***************************************************************************
;************* アドレススキップルーチン  ***********************************
; アドレスのスキップに時間をかけ、必要なだけのサンプリング時間幅を作る 
address_up_sec
     ;秒でアドレスカウンタを＋１する
          movlb   5                ;バンク５にＧポートがある
          bsf     PORTG,4          ;１クロックパルスをカウンタに送る
          movlb   0
        ;時間幅設定
          call	  number2
          
          movlb   5
          bcf     PORTG,4
          movlb   0
          return

address_up_mili
     ;ｍ秒でアドレスカウンタを＋１する
          movlb   5                ;バンク５にＧポートがある
          bsf     PORTG,4          ;１クロックパルスをカウンタに送る
          movlb   0
        ;時間幅設定
          call    number1
          
          movlb   5
          bcf     PORTG,4
          movlb   0
          return

address_up_micro  
     ;マイクロ秒でアドレスカウンタを＋１する
     ;ＡＤ変換処理自体に１０マイクロ秒以上の時間を有するので、およそ２０マイクロ秒以下の
     ;設定時間では大幅な誤差がでることに留意しておくこと。
          movlb   5                ;バンク５にＧポートがある
          bsf     PORTG,4          ;１クロックパルスをカウンタに送る
          movlb   0
        ;時間幅設定
          call    number
          movlb   5
          bcf     PORTG,4
          movlb   0
          return

;***************************************************************************
;*************  その他  ****************************************************
key_push    ;'D'キーが押されるまで待機させる
          call     inkey           ;キー入力を調べる。文字’Ｄ’がキーイン
          movlw    15              ;された時を決定と見なす。
          cpfseq   key             ;文字Ｄは数値の１５に対応している
          goto     key_push        ;
          return       

wait_exe   ;プログラムの実行を少し待機させるためのルーチン
          movlw   0                 ;
          movwf   temp0             ;
          movwf   temp1
          movlw   4
          movwf   temp2         
waitloop  decfsz  temp0,1           ;
          goto    waitloop          ;
          decfsz  temp1,1
          goto    waitloop
          decfsz  temp2,1
          goto    waitloop
          return                    ;
     
;************************************************************************************
;********  キャラクターテーブル  ****************************************************
msg   ;キーパット用「キー対文字」対応表ルーチン
       addwf    PCL,1            ;addwf f,d  Ｗレジスタとｆの内容を加算し、
                                 ;d=1 の時、結果はｆに、d=0 の時、結果はＷに代入する。
       retlw    '1'              ;
       retlw    '4'              ;
       retlw    '7'              ;キーパットのキーに対応した各文字記号の設定
       retlw    '*'              ;
       retlw    '2'              ;リテラル値（即値）をＷレジスタに戻す。
       retlw    '5'       
       retlw    '8'              ;キーパットの文字はプルグラムでは数値に対応させている       
       retlw    '0'              ;１は０，４は１，７は２，＊は３，
       retlw    '3'              ;２は４，５は５，８は６，０は７，
       retlw    '6'              ;３は８，６は９，９は１０，＃は１１，
       retlw    '9'              ;Ａは１２，Ｂは１３，Ｃは１４，Ｄは１５
       retlw    '#'       
       retlw    'A'       	
       retlw    'B'       
       retlw    'C'       
       retlw    'D'
       return


devise_title   ;デバイスのタイトル文
       addwf    PCL,1
       dt       " Data Memory" 
       return 

ok_title   ;オーケーの文字列
       addwf    PCL,1           ;'OK?'
       retlw    'O'
       retlw    'K'
       retlw    '?'
       return

jobsel_title  ;ジョブ選択の文字列
       addwf    PCL,1  
       dt       "Job Selection"
       return

measure_title   ;測定の文字列
       addwf    PCL,1 
       dt       "Measure"
       return

memory_title   ;メモリ出力の文字列
       addwf    PCL,1  
       dt       "Memory Out"
       return

RS232C_title   ;ＲＳ２３２Ｃ出力の文字列
       addwf    PCL,1 
       dt       "RS232C Out"
       return
        nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
stimes_title   ;サンプリング時間の文字列
       addwf    PCL,1 
       dt       "Sample Time(s)"
       return
	
stimem_title
       addwf    PCL,1  
       dt       "Sample Time(ms)"
       return

       nop      ;ページ切り替えのため
       nop
       nop
       nop
       nop
       nop
       nop
       nop
       nop
       nop
       nop
       nop
 
stimeu_title
       addwf    PCL,1 
       dt       "Sample Time(us)"
       return

start_title   ;スタート文字列
       addwf    PCL,1          ;'Start'
       retlw    'S'
       retlw    't'
       retlw    'a'
       retlw    'r'
       retlw    't'
       return

execute_title   ;実行の文字列
       addwf    PCL,1  
       dt       "Execute"
       return

stop_title   ;ストップ文字列
       addwf    PCL,1   
       dt       "Stop"
       return

;msのサンプリングするためのカウンタ
number1
	  movfp    figure3,WREG		;３桁目の数字をnumb0にいれる
	  movwf    numb0		;
	  movfp    figure2,WREG		;figure2×10＋Figure1より２桁の数字を作り出す
	  mullw    10			;
	  movfp	   PRODL,WREG		;
	  addwf    figure1,0            ;addwf  figure1,WREG をワーニングエラーが出るので変更（１１月２３日）
          addwf    PRODL,0		;
	  movwf    numb1		;２桁の数字をnumb1にいれる
	  
	  movlw    0
	  cpfseq   numb1		;numb1が０かどうか調べる
	  goto     numberAm		;≠０だったら、numberAへとぶ
	  goto     numberBm		;＝０だったら、numberBへとぶ
numberAm  call     uless_lp

	  decfsz   numb1,F		;numb1=0になるまで減算をする
	  goto     numberAm		;
numberBm  movlw    0			;numb0=0かどうか調べる
          cpfseq   numb0		;
          goto     numberCm		;
          return			;
numberCm  decf     numb0,F		;numb0-1する
	  movlw    99			;numb1に99を代入する
          movwf    numb1		;
          goto     numberAm		;

;このuless_lpループは１０００回の無駄時間ループである。
;これによってｍ秒単位の時間ロープが出来上がる。
uless_lp  movlw    10			
          movwf    uless1
uless_lp1 movlw    100
          movwf    uless0
uless_lp2 nop
	  nop
	  decfsz   uless0,F
          goto     uless_lp2
          decfsz   uless1,F
          goto     uless_lp1
          return

;Sのサンプリングをするためのカウンタ
number2
	  movfp    figure3,WREG		;３桁目の数字をnumb0にいれる
	  movwf    numb0		;
	  movfp    figure2,WREG		;figure2×10＋Figure1より２桁の数字を作り出す
	  mullw    10			;
	  movfp	   PRODL,WREG		;
	  addwf    figure1,0            ;addwf  figure1,WREG　ではワーニングエラーが出るので変更（１１月２３日）
	  movwf    numb1		;２桁の数字をnumb1にいれる
	  
	  movlw    0
	  cpfseq   numb1		;numb1が０かどうか調べる
	  goto     numberAs		;≠０だったら、numberAへとぶ
	  goto     numberBs		;＝０だったら、numberBへとぶ
numberAs  call     uless_lps

	  decfsz   numb1,F		;numb1=0になるまで減算をする
	  goto     numberAs		;
numberBs  movlw    0			;numb0=0かどうか調べる
          cpfseq   numb0		;
          goto     numberCs		;
          return			;
numberCs  decf     numb0,F		;numb0-1する
	  movlw    99			;numb1に99を代入する
          movwf    numb1		;
          goto     numberAs		;

;このuless_upループは1000000回の無駄時間ループである。
;これによって秒単位の時間ループが出来上がる。
uless_lps 
          movlw    100
          movwf    uless1
uless_lps1
	  movlw    100
          movwf    uless0
uless_lps2 
	  movlw    100
	  movwf    uless2
uless_lps3
	  nop
	  nop
	  decfsz   uless2,F
	  goto     uless_lps3
	  decfsz   uless0,F
          goto     uless_lps2
          decfsz   uless1,F
          goto     uless_lps1
          return       

;****************************************************************************
       end
       

