第20週
;16F877 USART受送信
;*********************************************
        LIST        P=PIC16F877   ;
        INCLUDE     "P16f877.inc" ;標準ヘッダ定義ファイル
        __CONFIG    _HS_OSC & _PWRTE_ON & _WDT_OFF & _LVP_OFF 
 
;*********************************************
WTEMP   EQU     021H            ;Wレジスタ待避
INTTMCT EQU     022H            ;割り込みタイマ設定値
TIMCNT  EQU     023H            ;タイマ用カウンタ
TIM2CNT EQU     024H
TIM5CNT EQU     025H
TIM1CNT EQU     026H
LCDDT   EQU     027H            ;LCD表示データ格納
LCDINST EQU     028H            ;LCDインストラクション格納
LOOPCNT EQU     029H            ;受信データクリア用カウンタ
SENDCNT EQU     02AH            ;送信文字数
TBPOINT EQU     02BH            ;テーブル処理ポインタ
;***********************
;  メインルーチン
;***********************
        ORG     0               ;Reset Start
;*********************************************************
;初期処理
        BSF     STATUS,RP0      ;バンク1へ切替
        BCF     INTCON,GIE      ;割り込み禁止
        MOVLW   07H
        MOVWF   ADCON1          ;A/D割り当て用ピンはすべてデジタル
        MOVLW   01H
        MOVWF   TRISA           ;とりあえずポートAをRA0入力、他は出力モード設定
        CLRF    TRISB           ;とりあえずポートBを出力モードに設定
        CLRF    TRISD           ;とりあえずポートDを出力モードに設定
        CLRF    TRISE           ;とりあえずポートEを出力モードに設定
        MOVLW   080H
        MOVWF   TRISC           ;ポートC RC7を入力、他を出力モードに設定(*2001-1-7 下記に追記)
        
        MOVLW   024H            ;8ビット、送信イネーブル、非同期
                                ;高速ボーレート選択
        MOVWF   TXSTA           ;
        MOVLW   081H            ;SPBRG=129(9600)
        MOVWF   SPBRG
        BCF     STATUS,RP0      ;バンク0に戻す
        MOVLW   090H            ;シリアルピン、8ビット、連続受信
        MOVWF   RCSTA
        
;LCD初期化
        CALL    TIM5            ;まず15msec以上待ち
        CALL    TIM5
        CALL    TIM5
        CALL    TIM5 
        MOVLW   030H
        MOVWF   PORTB
        BCF     PORTE,1         ;R/WをWに
        BCF     PORTE,2         ;RSをインストラクションに
        BSF     PORTE,0         ;E
        NOP
        BCF     PORTE,0

        CALL    TIM5            ;4.1msec以上待ち
        MOVLW   030H
        MOVWF   PORTB
        BCF     PORTE,1         ;R/WをWに
        BCF     PORTE,2         ;RSをインストラクションに
        BSF     PORTE,0         ;E
        NOP
        BCF     PORTE,0

        CALL    TIM02           ;100μsec以上待ち
        CALL    TIM02
        MOVLW   030H
        MOVWF   PORTB
        BCF     PORTE,1         ;R/WをWに
        BCF     PORTE,2         ;RSをインストラクションに
        BSF     PORTE,0         ;E
        NOP
        BCF     PORTE,0

        CALL    TIM02
        CALL    TIM02
        MOVLW   038H            ;Function Set 8ビット 2行 5×7ドット
        CALL    LCDCMD
        MOVLW   01H             ;表示クリア
        CALL    LCDCMD        
        MOVLW   06H             ;エントリーモード                
        CALL    LCDCMD
        MOVLW   0CH             ;表示ON
        CALL    LCDCMD

        CALL    LCDCLR          ;表示クリア

MAIN
        MOVLW   0A0H            ;バッファ先頭
        MOVWF   FSR             ;ポインタ初期化
        MOVLW   32              ;LCD表示は32文字表示
        MOVWF   LOOPCNT
SPLOOP  MOVLW   020H            ;SP文字
        MOVWF   INDF
        INCF    FSR,F
        DECFSZ  LOOPCNT,F
        GOTO    SPLOOP
        
        MOVLW   0A0H            ;バッファ先頭
        MOVWF   FSR             ;ポインタ初期化
        MOVLW   32              ;LCD表示は32文字表示
        MOVWF   LOOPCNT        
;受信
RCV     BTFSS   PIR1,RCIF       ;受信レジスタチェック
        GOTO    RCV                              
;エラーチェック
        BTFSC   RCSTA,FERR      ;フレーミングエラーチェック
        GOTO    ERR1
        BTFSC   RCSTA,OERR      ;オーバーランエラーチェック
        GOTO    ERR2
;データ格納
        MOVF    RCREG,W         ;RCREG読み込み
        MOVWF   WTEMP           ;W 待避
        SUBLW   0DH             ;CRチェック
        BTFSC   STATUS,Z
        GOTO    DPLY            ;CRならLCD表示へ(CRは表示しない)

        MOVF    WTEMP,W         ;W 復帰
        MOVWF   INDF            ;INDIRECT REG 書き込み(ポインタ処理)
        
CKBUFF  INCF    FSR,F           ;ポインタ+1
        DECFSZ  LOOPCNT,F
        GOTO    RCV
        GOTO    DPLY

SPLP    MOVLW   020H            ;SP文字
        MOVWF   INDF
        INCF    FSR,F
        DECFSZ  LOOPCNT,F
        GOTO    SPLP

        
;エラー処理        
ERR1                            ;フレーミングエラー
        MOVF    RCREG,W         ;RCREG読み込みで更新(FERRリセット)
        MOVLW   '.'             ;エラー文字
        MOVWF   INDF
        GOTO    CKBUFF

ERR2                            ;オーバーランエラー
        BCF     RCSTA,CREN      ;CRENクリアでリセット
        BSF     RCSTA,CREN      ;戻しておく
        MOVLW   '.'             ;エラー文字
        MOVWF   INDF
        GOTO    CKBUFF

;LCD表示        
DPLY    CALL    LCDCLR          ;LCD表示クリア
        
        MOVLW   0A0H            ;表示データ用汎用レジスタ先頭
        MOVWF   FSR
        MOVLW   010H            ;1行分16バイト
        MOVWF   LOOPCNT

LCDLOOP MOVF    INDF,W
        CALL    LCDDTW          ;LCDデータ書き込み

        INCF    FSR,F
        DECFSZ  LOOPCNT,F
        GOTO    LCDLOOP

        MOVLW   010H            ;2行目分16バイト
        MOVWF   LOOPCNT

        CALL    LCD2L           ;2行目先頭へ
LCDLP2  MOVF    INDF,W
        CALL    LCDDTW

        INCF    FSR,F
        DECFSZ  LOOPCNT,F
        GOTO    LCDLP2

;アンサー
SND                             ;テーブル上の文字を順次送信
        CLRF    TBPOINT
        MOVLW   4
        MOVWF   SENDCNT         ;送信文字数カウンタ(4文字)
LPSND   MOVF    TBPOINT,W
        CALL    TABLE
        CALL    SEND
        INCF    TBPOINT,F
        DECFSZ  SENDCNT,F
        GOTO    LPSND
        
        GOTO    MAIN
        
TABLE   ADDWF   PCL,F
        RETLW   'O'
        RETLW   'K'
        RETLW   '!'
        RETLW   0DH             ;CR
        
;***********************
;サブルーチン
;***********************
;***************************************************
;送信
SEND
        MOVWF   WTEMP           ;待避
        BSF     STATUS,RP0      ;BANK1
LPSEND  BTFSS   TXSTA,TRMT      ;TSR空チェック
        GOTO    LPSEND
        
        BCF     STATUS,RP0      ;BANK0
        MOVF    WTEMP,W
        MOVWF   TXREG
        RETURN
        
;***************************************************

;LCDデータ書き込み
LCDDTW                          ;Wに書き込まれたデータ(1文字)を表示
        MOVWF   PORTB
        BCF     PORTE,1         ;R/WをW
        BSF     PORTE,2         ;RSをデータに
        BSF     PORTE,0         ;E
        NOP
        BCF     PORTE,0
        CALL    LCDBUSY         ;BUSYチェック
        RETURN

LCDCMD                          ;LCDインストラクション書き込み
                                ;Wレジスタに書き込まれたコマンドをLCDへ
        MOVWF   PORTB
        BCF     PORTE,1         ;R/WをW
        BCF     PORTE,2         ;RSをインストラクションに
        BSF     PORTE,0         ;E
        NOP
        BCF     PORTE,0
        CALL    LCDBUSY         ;BUSYチェック
        RETURN

LCDCLR                          ;LCD表示クリア
        MOVLW   01H
        CALL    LCDCMD
        RETURN
LCD2L                           ;2行目へ
;◎データシートによると1行目と2行目はアドレスが連続していないで
;2行目の第1文字目は40(H)番地
;(b'1*******'が表示アドレス書き込み  *******を1000000として2行目先頭指令)
        MOVLW   0C0H
        CALL    LCDCMD
        RETURN

LCDBUSY                         ;LCD BUSYチェック
                                ;やっかいなことにいちいちPORTBを入力に変えて
                                ;さらにOPTIONレジスタで弱プルアップに設定
        BSF     STATUS,RP0      ;バンク1へ切替
        MOVLW   0FFH            ;ポートBを入力モードに設定
        MOVWF   TRISB
        BCF     STATUS,RP0      ;バンク0に戻す
        BCF     PORTE,2         ;RSをインストラクションに
        BSF     PORTE,1         ;R/WをR
        BSF     PORTE,0         ;E
        NOP
        BCF     PORTE,0
        MOVF    PORTB,W
        MOVWF   LCDINST
        BTFSC   LCDINST,7       ;BUSYフラグチェック
        GOTO    LCDBUSY

        BCF     PORTE,1         ;R/WをWに戻しておく
        BSF     STATUS,RP0      ;バンク1へ切替
        CLRF    TRISB           ;ポートBを出力モードに設定
        BCF     STATUS,RP0      ;バンク0に戻す
        RETURN

;************************************************************
;タイマ
TIM20                           ;約20μSECタイマ
        MOVLW   012H
        MOVWF   TIMCNT
TIMLP   
        DECFSZ  TIMCNT,F
        GOTO    TIMLP
        RETURN
TIM02   RETURN ;デバッグ用!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                          ;約0.2mSECタイマ
        MOVLW   0FFH
        MOVWF   TIM2CNT
TIM2LP  NOP
        DECFSZ  TIM2CNT,F
        GOTO    TIM2LP
        RETURN
TIM5    RETURN  ;デバッグ用!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                          ;約5msecタイマ
        MOVLW   01AH
        MOVWF   TIM5CNT
TIM5LP  CALL    TIM02
        DECFSZ  TIM5CNT,F
        GOTO    TIM5LP
        RETURN

;*********************************************************

        END

追記
 シリアル入力となるRC7ピンはわざわざ入力設定しなくともRCSTAレジスタでシリアルポートイネーブルに設定すれば
 RC6、RC7ともシリアルポートピンとして機能するようです。