;            プログラム名　　Receive.asm
;
;ラジコンのサーボモータを利用したシステムの受信側のＰＩＣの制御プログラムである。
;     　　　　　　　　　　　　　　　　　　　　　　　　　　　   2000,3/24～　　金野
;　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　2000,4/6    完成　　
;母プログラムは　jusin　である。
;　　　　　サ－ボモータ駆動パルスは４チャンネル同時出力方式としている。
;　　　　　送信側の４個のスイッチ状態は１つの変数の第０ビット～３ビット目に入れる。
;
;回路での設定条件
;（１）使用する発振素子はセラミックオシレータ１０．０ＭＨｚとする。
;（２）データの受信端子はＲＢ０／ＩＮＴを使用する。
;（３）サーボモータは規格として、入力パルス幅が１．５ｍ秒でニュートラル位置。
;　　　入力パルス幅が１．５ｍ秒±０．５ｍ秒で左右に±６０°位回転する。
;　　実際サーボモータを駆動してみると、許容できる入力パルス幅は０．４ｍ秒から２．５ｍ秒と広く、
;　　左右に±９０°も回転してくれる。
;
;プログラムの流れの概要
;（１）１０ＭＨｚクロックでは、一命令の実行時間は約０．４マイクロ秒（多分４サイクル）
;（２）データの送信側からは、一定時間間隔毎に、ＲＳ＿２３２Ｃ規格準拠のデータが４バイト（チャンネル分）
;　　　送信されてくる。
;（３）１バイトデータ（１０ビット長）の送信時間長は凡そ２７マイクロ秒である。送信側と一致させること。
;       １ビット長　約２．７マイクロ秒。
;　　　順序　１スタートビット＋ビット０＋ビット１＋・・・・＋ビット７＋１ストップビット
;（４）ＲＢ０／ＩＮＴ端子の入力レベルがＨになった時、割り込みを発生させる。
;（５）シリアルデータを取り込み、パラレル８ビットデータに復帰させる。これを４回繰り返し、
;　　　４バイトのデータを個々の変数に代入して、受信を完了させる。
;（６）それらの各値に従い、各サーボモータ駆動用の１．５ｍ秒±０．５ｍ秒のパルスを形成し、
;　　　ＲＢポートの各端子からそれを出力し、サーボモータを駆動する。
;　　　（１）各端子に下駄分のＨパルスを同時に出力する。
;　　　（２）その後、各データ値を１ずつ減じて、負になったチャンネルからＬレベルとする。
;　　　（３）全てのチャンネルがＬレベルとなった時、
;（７）割り込みを解消し、（４）の受信状態とする。後は繰り返し。
;
;アセンブル時の注意
;（１）定数はリテラル値扱いである。厳重に留意しておくこと。
;（２）Radix は Decimal とする。暗黙数値は１０進数と見なす。
;（３）アセンブルした出力ファイルは　INHX32 形式に指定すべし

  LIST P=PIC16C711       ;使用するプロセッサを指定する
  #INCLUDE "P16C711.INC" ;上記プロセッサのためのインクルードファイルを
                         ;呼び出し結合する
;ＰＩＣの初期設定 
  __CONFIG  _WDT_OFF & _XT_OSC &_BODEN_OFF
                          ;ＰＩＣはマイクロコントローラモード
                          ;これでポートＣその他の端子がＩ／Ｏポートとなる。
                          ;ウオッチドックタイマーはオフ
                          ;発振はクリスタル方式
                          ;ブラウンアウトはオフ。（オンでは規定電圧以下となるとリセット）

;************************************************************************************************ 
;変数	
   CBLOCK h'000C'     ;このディレクチブと下のENDCの間に使用する変数名を定義できる
                      ;数値は使用するプロセッサの一般目的レジスタの開始番地とする　　
        temp0         ;一時的カウンタ変数
        temp1         ;
        temp2         ;
        temp3         ;
        VR1_data      ;１番目の可変抵抗の受信した電圧値データの入る変数
        VR2_data      ;２番目の　　　　　同上
        VR3_data      ;３番目の　　　　　同上
        VR4_data      ;４番目の　　　　　同上
        max_data      ;電圧値の最大値のはいる変数
        Sw_data       ;４個のスイッチ状態を示す変数。第０ビット～３ビット目に入っている。
        cur_data      ;電圧値の入るカレント変数
        bit_cntr      ;受信したビット数
        rcv_byte      ;受信時に受信ビットデータ列の入る変数
   ENDC

  ;各使用端子に名称を定義する。
   #define   servo1       PORTA,0  ;１番目のサーボモータ駆動パルスを出力する端子の命名
   #define   servo2       PORTA,1  ;２番目　　　同上
   #define   servo3       PORTA,2  ;３番目　　　同上
   #define   servo4       PORTA,3  ;４番目　　　同上

   #define   RS_232C_in   PORTB,0  ;ＲＳ＿２３２Ｃ規格の信号を入力する端子の命名 
   #define   Trigger      PORTB,1  ;トリガー信号出力端子として使用 
   #define   LED_out      PORTB,2  ;シリアルデータ受信状況モニター用ＬＥＤドライブ端子の命名

   #define   Monitor1     PORTB,7  ;送信側の１番目のスイッチの状態モニター出力端子の命名
   #define   Monitor2     PORTB,6  ;送信側の２番目の　　　同上
   #define   Monitor3     PORTB,5  ;送信側の３番目の　　　同上
   #define   Monitor4     PORTB,4  ;送信側の４番目の　　　同上




;定数
bit_const     equ       8 ;データはビット長
;以下の３つの値を適当に調整して、可変抵抗の回転と同期して、サーボモータが回転するようにする。
offset_width  equ      10 ;下の値と組になって、オフセット分とする。
offset_para   equ      20 ;

;************************************************************************************************
          org     0  
          goto    start

;********** 割り込み処理 *************************************************
          org     4      ;割り込み処理番地の指定
handler  ;スタートビットが届くと、同時に、割り込みもかかる。

          bsf      Trigger       ;モニター用トリガパルス出力端子をＨレベルとする。    
          bcf     INTCON,GIE     ;割り込みを禁止する。
      ;ＡＤ変換値の受信　４バイト分
        ;１バイト目の受信
          call    data_receive   ;シリアルデータを受信し、８ビットデータを復元する。
          movf    rcv_byte,0     ;データを
          movwf   VR1_data       ;変数に代入する
          call    pulse_wait     ;次のスタートパルスが来るまで待機。
        ;２バイト目の受信
          call    data_receive   ;同上
          movf    rcv_byte,0     ;
          movwf   VR2_data       ;
          call    pulse_wait     ;       
        ;３バイト目の受信
          call    data_receive   ;同上
          movf    rcv_byte,0     ;
          movwf   VR3_data       ;
          call    pulse_wait     ;
        ;４バイト目の受信
          call    data_receive   ;同上
          movf    rcv_byte,0     ;
          movwf   VR4_data       ;
          call    pulse_wait     ;

      ;スイッチの状態データの受信　１バイトの第０～３ビット
          call    data_receive   ;同上
          movf    rcv_byte,0     ;
          movwf   Sw_data        ;

　        bcf      Trigger       ;モニター用トリガパルス出力端子をＬレベルとする。

     ;最初に、送信機側のスイッチの状態に対応した出力を行う。
     ;　　スイッチがＨレベルならば、出力はＨ、Ｌレベルならば、出力はＬとする。
          btfsc   Sw_data,0      ;Sw_data の第０ビット目が１ならば、
          bsf     Monitor1       ;Monitor1 の出力はＨレベルとする。
          btfss   Sw_data,0      ;　　　　　　　　　　　　０ならば、
          bcf     Monitor1       ; 　　　　　　　　Ｌレベルとする。　
          btfsc   Sw_data,1      ;Sw_data の第１ビット目が１ならば、　　　
          bsf     Monitor2       ;Monitor2 の出力はＨレベルとする。
          btfss   Sw_data,1      ;　　　　　　　　　　　　０ならば、
          bcf     Monitor2       ; 　　　　　　　　Ｌレベルとする。　
          btfsc   Sw_data,2      ;Sw_data の第２ビット目が１ならば、　　　
          bsf     Monitor3       ;Monitor3 の出力はＨレベルとする。
          btfss   Sw_data,2      ;　　　　　　　　　　　　０ならば、
          bcf     Monitor3       ; 　　　　　　　　Ｌレベルとする。　
          btfsc   Sw_data,3      ;Sw_data の第３ビット目が１ならば、　　　
          bsf     Monitor4       ;Monitor4 の出力はＨレベルとする。
          btfss   Sw_data,3      ;　　　　　　　　　　　　０ならば、
          bcf     Monitor4       ; 　　　　　　　　Ｌレベルとする。　

     ;電圧値の最大値探索
          movf    VR1_data,0     ;VR1_data を
          movwf   max_data       ;max_data に代入。
          subwf   VR2_data,0     ;VR2_data-VR1_data の計算。
          btfss   STATUS,C       ;VR2_data<VR1_data の時、 
          goto    sort1          ;max_data に
          movf    VR2_data,0     ;VR2_data を
          movwf   max_data       ;代入する。
sort1     movf    max_data,0     ;
          subwf   VR3_data,0     ;
          btfss   STATUS,C       ;
          goto    sort2          ;
          movf    VR3_data,0     ;
          movwf   max_data       ;
sort2     movf    max_data,0     ;
          subwf   VR4_data,0     ;
          btfss   STATUS,C       ;
          goto    sort3          ;
          movf    VR4_data,0     ;
          movwf   max_data       ;
sort3
       
        ;サーボモータを駆動する。同時駆動方式としてみる。
          bsf     servo1         ;servo1 端子をＨとし、１番目のサーボモータにＨレベルを出力。
          bsf     servo2         ;servo2 端子に関して。同上
          bsf     servo3         ;servo3 端子に関して。同上
          bsf     servo4         ;servo4 端子に関して。同上
           ;ループをさせておいて、逐次値を比較させ、値が一致したサーボからＬレベルとする。
           ;サーボモータ制御パルス幅形成ルーチン
           ;パルス幅は（１）＋（２）で形成する。
pulse_width
           ;（１）オフセット分    
           movlw    offset_width  ;
           movwf    temp0         ;
           movlw    offset_para   ;
           movwf    temp1         ;
loop_pw1   decfsz   temp0,1        ;
           goto     loop_pw1      ;
           movlw    offset_width  ;
           movwf    temp0         ;
           decfsz   temp1,1       ;
           goto     loop_pw1      ;
   ;（２）比例分
   ;　　　各電圧値を順次－１し、０になったら、該当する出力をＬレベルとする。
loop_pw2   decf     VR1_data,1    ;VR1_data を－１し、
           nop
           btfsc    STATUS,Z      ;０になったら（Ｚ＝１）、
           bcf      servo1        ;サーボモータへの出力パルスをＬレベルとする。

           decf     VR2_data,1    ;VR2_data を－１
           nop
           btfsc    STATUS,Z      ;
           bcf      servo2        ;

           decf     VR3_data,1    ;VR3_data を－１
           nop
           btfsc    STATUS,Z      ;
           bcf      servo3        ;

           decf     VR4_data,1    ;VR4_data を－１
           nop
           btfsc    STATUS,Z      ;
           bcf      servo4        ;

           decfsz   max_data,1    ;最大電圧値を－１する。
           goto     loop_pw2      ;０になったらループを終了させる。

handend   bcf     INTCON,INTF    ;INTF=0 として、割り込み要因を解消させ、
          bsf     INTCON,GIE     ;割り込みを許可する

          retfie                 ;終了した後、割り込みがかかった時点にプログラムは復帰する              

;********* 正規のプログラムジョブの開始 **********************************
start
     ;各ポートの初期設定  
          call     port_initial
          bcf      Monitor1       ;モニター出力の初期値はＬレベル としておく。
          bcf      Monitor2       ;
          bcf      Monitor3       ;
          bcf      Monitor4       ;

     ;割り込み条件の設定
          call     inte_initial

execute  
          goto     execute       ;割り込みを待たせる。 
   
;****** 各種サブルーチン *************************
;シリアルデータの受信のルーチン
data_receive
          movlw   bit_const      ;ビット長数を
          movwf   bit_cntr       ;bit_cntr に代入する
          clrf    rcv_byte       ;シリアル受信データ列を入れる変数をクリアしておく。
          nop                    ;時間調整用ｎｏｐ命令。スタートビットをやり過ごす。
          nop
          nop
          nop
          nop
          nop
rep_receive
          bsf     LED_out        ;ＬＥＤを点灯する。この命令を取り消す時は、ｎｏｐ命令で置き換える。
          btfss   RS_232C_in     ;以下の４行で、シリアル受信端子への入力レベルを
          bcf     STATUS,C       ;ステータスレジスタのキャリービットに代入する。
          btfsc   RS_232C_in     ;RS_232C_in を　C に代入する。
          bsf     STATUS,C       ;
          rrf     rcv_byte,1     ;rcv_byte へ C の内容を右回転で代入する。        
          bcf     LED_out        ;ＬＥＤ消灯。この命令を取り消すときには、ｎｏｐ命令で置き換える。
          nop                    ;時間調整用ｎｏｐ命令
          nop
          nop
          nop
          decfsz  bit_cntr,1     ;８ビットすむまで、受信を繰り返す。
          goto    rep_receive    ;
          movf    rcv_byte,0     ;rcv_byte の内容をＷレジスタに取り込む。
          return

;*****************************************************
;次のスタートパルスが来るまで待機させる
pulse_wait
          movlw   30             ;最初に、　　３０から５０以上がよいかもしれない
          movwf   temp0          ;１ビットの時間以上長く遅らせて、
w_loop1   decfsz  temp0,1        ;Ｌレベルのストップビット以降に位置させる。
          goto    w_loop1        ;

w_loop2   btfss   RS_232C_in     ;次のスタートパルス（Ｈレベル）が来るまで
          goto    w_loop2        ;待機。
          return

;*************　初期設定ルーチン集  **************************************************************
;ポートの初期設定
port_initial 
  ;ＲＡポートの設定。全てデジタル入力端子に設定
  ;　　ＲＡ０　　１番目のサーボモータ駆動パルス出力端子として使用
  ;　　ＲＡ１　　２番目の　　　　同上
  ;　　ＲＡ２　　３番目の　　　　同上
  ;　　ＲＡ３　　４番目の　　　　同上
  ;　　ＲＡ４　　未使用
          bsf     STATUS,RP0        ;バンク１に移る
          movlw   b'11'             ;これでＲＡ０～ＲＡ４端子をＤ端子として
          movwf   ADCON1            ;設定することになる。
          movlw   b'00000'          ;ＲＡ０～ＲＡ４を出力端子 
          movwf   TRISA             ;として設定。
          bcf     STATUS,RP0        ;バンク０に戻る

  ;ＲＢポートの設定。全てデジタル出力端子として使用
  ;　　ＲＢ０　　入力　ＲＳ＿２３２Ｃ規格入力端子として使用。割り込み機能も許可する。
  ;　　ＲＢ１　　出力　トリガー出力端子として使用。
  ;　　ＲＢ２　　出力　未使用　
  ;　　ＲＢ３　　出力　未使用　
  ;　　ＲＢ４　　出力　４番目のスイッチのモニター出力端子として使用
  ;　　ＲＢ５　　出力　３番目の　　　同上
  ;　　ＲＢ６　　出力　２番目の　　　同上
  ;　　ＲＢ７　　出力　１番目の　　　同上
          clrf    PORTB             ;PORTB のラッチデータをクリア
          bsf     STATUS,RP0        ;バンク選択ビットを１とし、バンク１に移る
          movlw   b'00000001'       ;Ｗに２進数の 00000000 を入れる
          movwf   TRISB             ;ＢポートのステータスレジスタTRISBに上の値を代入。
                                    ;上記設定となる。
          bcf     STATUS,RP0        ;バンク０に戻しておく。
          return

;割り込み条件の初期設定
inte_initial   ;関係レジスタ　ＩＮＴＣＯＮ，ＯＰＴＩＯＮ＿ＲＥＧ
               ;ＲＢ０／ＩＮＴポートがＬからＨになった時、割り込みを発生させる。
         movlw   b'10010000'  ;INTCON=(GIE,ADIE,TOIE,INTE,RBIE,TOIF,INTF,RBIF)
         movwf   INTCON       ;  GIE=1   割り込みを許可する。　　　　　　従って１とする。
                              ; ADIE=1   ＡＤ割り込みを許可する。　　　　従って０とする。
                              ; TOIE=1   タイマー割り込みを許可する。　　従って０とする。
                              ; INTE=1   RB0/INT での外部割り込みを許可する。　　従って１とする。
                              ; RBIE=1   ＲＢポートでの状態変化割り込みを許可する。従って０とする。
                              ; TOIF=1   TMR0　のオーバーフローフラッグ。１ではオーバーフローした。　　
                              ; INTF=1   RB0/INT での外部割り込みフラッグ。１では割り込みが発生した。
                              ; RBIF=1   ＲＢポートでの割り込みフラッグ。１では割り込みが発生した。
         bsf     STATUS,RP0   ;バンク１に移る。
         movlw   b'01000000'  ;OPTION_REG=(RBPU,INTEDG,TOCS,TOSE,PSA,PS2,PS1,PS0)
         movwf   OPTION_REG   ;  RBPU=1  ＲＢポートプルアップ許可ビット。よってここでは無関係。
                              ;INTEDG=1  RB0/INT での割り込みエッジの選択枝。１で立ち上がりで割り込み。
                              ;  TOCS=1  TMR0 のクロックソースの選択枝。よってここでは無関係。
                              ;  TOSE=1  TMR0 のパルスのアップ、ダウンの選択枝。よってここでは、無関係。
                              ;   PSA=1  プリスケーラの設置選択枝。よってここでは無関係。
                              ;   PS2=1  下の２つと共になってプリスケーラの割合選択枝。今は無関係。                               ;   PS1=1
                              ;   PS0=1

         bcf     STATUS,RP0   ;バンク０に戻す。
         return

;************************************************************************************************ 

         END




