list p=16f877a ; PIC16F877A 用のプログラムであることを宣言 #include p16f877a.inc ; PIC16F877A 用のヘッダ・ファイルを読み込む __config _HS_OSC & _CP_OFF & _PWRTE_ON & _WDT_OFF & _LVP_OFF #define LCD_E PORTD,0 #define LCD_RS PORTD,1 #define LCD_RW PORTD,2 #define LCD_PORT PORTB #define LCD_PORT_ PORTB_ TRISB_LCD_OUT equ B'00001111' TRISB_LCD_IN equ B'11111111' ;*************************************************************************** TMP equ 0x20 STR_LOOP equ 0x21 CT_DELAY100US equ 0x22 CT_DELAY1MS equ 0x23 LCD_DAT equ 0x24 LCD_TMP equ 0x25 LCD_PORT_TMP equ 0x26 LCD_RDAT equ 0x27 HEX_TMP equ 0x28 PORTB_ equ 0x29 ;*************************************************************************** ; 初期化ルーチン org 0x000 Start bcf STATUS, RP0 bcf STATUS, RP1 clrf INTCON ; 割り込み禁止 clrf PORTA clrf PORTB clrf PORTC ; LED が点灯しないように clrf PORTD ; 出力は0にしておく clrf PORTE ; 出力は0にしておく movlw B'10010000' ; シリアルの設定 movwf RCSTA bsf STATUS, RP0 movlw B'00000111' ; PORTB のウィーク・プルアップを有効に ; プリスケーラはタイマに割り当て ; プリスケーラは1/256にする movwf OPTION_REG movlw TRISB_LCD_OUT movwf TRISB movlw B'10000000' movwf TRISC ; RXピン(ビット7)以外を出力に clrf TRISD ; 全ピン出力に movlw B'00100110' ; シリアルの設定 movwf TXSTA movlw D'64' ; ボーレートの設定 movwf SPBRG bcf STATUS, RP0 call LCD_INI ; 液晶の初期化 ; スタートアップルーチン call LCD_CLR ; 画面のクリア call PRT_STR ; 液晶に HELLO を表示 call SEND_STR ; シリアルにHELLO\r\nを送る ; メイン・ルーチン MAIN_Z call RXCHR call TXCHR ; エコーバック movwf TMP sublw 0x01 ; コマンド解釈 btfsc STATUS, Z goto MAINL_1 ;; コマンドでない場合にはデータ(RS=1)として扱う movfw TMP call LCD_DATA goto MAIN_Z MAINL_1 ; 液晶にコマンド(RS=0)を送る call RXCHR call TXCHR ; エコーバック call LCD_CMD goto MAIN_Z ;*************************************************************************** ;; シリアルにHELLO\r\nを送るサブルーチン SEND_STR clrf STR_LOOP SEND_STR_0 movfw STR_LOOP call STR_CHAR addlw 0 ; 0かどうかのチェック btfsc STATUS, Z return ; 0なら戻る call TXCHR incf STR_LOOP, f goto SEND_STR_0 ;*************************************************************************** ;; 液晶にHELLOを表示するサブルーチン PRT_STR clrf STR_LOOP PRT_STR_0 movfw STR_LOOP call STR_CHAR movwf TMP sublw '\r' ; \rと一致するかチェック btfsc STATUS, Z return ; \rなら戻る movfw TMP call LCD_DATA incf STR_LOOP, f goto PRT_STR_0 ;; 液晶の表示をクリアするサブルーチン LCD_CLR movlw 01H ;clear command call LCD_CMD return ;; 1バイト受信サブルーチン RXCHR btfss PIR1, RCIF ;@受信データがあるかチェック goto $-1 ;Aなければ受信するまでチェックを繰り返す ; エラーかチェックする btfss RCSTA, OERR ;Bオーバラン・エラーか? goto CHK_FERR ;Cオーバラン・エラーではない bcf RCSTA, CREN ;Dオーバラン・エラーを消す bsf RCSTA, CREN ; goto RXCHR ;Eもう一度受信する CHK_FERR btfss RCSTA, FERR ;Fフレーミング・エラーか? goto RCV_END ;Gフレーミング・エラーではない movfw RCREG ;Hフレーミング・エラーを消して、次の受信を行う goto RXCHR ;Eもう一度受信する RCV_END movfw RCREG ;受信データをwレジスタへ代入 return TXCHR btfss PIR1, TXIF ; @データが送信済みかチェックする goto $-1 ; Aそうでなければ、終わるまでチェックを繰り返す movwf TXREG ; B送信する return ;*************************************************** ; 液晶関連サブルーチン ;*************************************************** ; 初期化サブルーチン LCD_INI bcf LCD_E bcf LCD_RW ;R/W (write) bcf LCD_RS ;RS (CMD) call delay5ms ; 5[ms]待つ call delay5ms ; 5[ms]待つ call delay5ms ; 5[ms]待つ movlw 0x30 ;Function set 8bits call LCD_8BIT_SEND_NOCHK call delay5ms ; 5[ms]待つ movlw 0x30 ;Function reset 8bits call LCD_8BIT_SEND_NOCHK call delay100us ; 100[us]待つ movlw 0x30 ;Function reset 8bits call LCD_8BIT_SEND_NOCHK call delay100us ; 100[us]待つ movlw 0x20 ;Function set 4bits mode call LCD_8BIT_SEND_NOCHK ;From here 4bits mode ;; ここではBUSYチェックをしてはいけない call delay100us movlw 0x2C ;function DL=0 4bit mode call LCD_CMD_NOCHK ;; ここからはBUSYチェックあり movlw 0x08 ;Display off D=C=B=0 call LCD_CMD movlw 0x0f ;Display on D=1 C=B=0 call LCD_CMD movlw 0x06 ;Entry I/D=1 S=0 call LCD_CMD return ;; データを書く(RS=1) LCD_DATA movwf LCD_DAT ; wレジスタの内容を保存 call LCD_BUSY bsf LCD_RS ;RS high (DATA) goto LCD_SEND_BYTE ;; コマンドを書く(RS=0)、ビジー・チェックなし LCD_CMD_NOCHK movwf LCD_DAT ; wレジスタの内容を保存 bcf LCD_RS ;RS low (CMD) goto LCD_SEND_BYTE ;; コマンドを書く(RS=0)、ビジー・チェックあり LCD_CMD movwf LCD_DAT ; wレジスタの内容を保存 call LCD_BUSY bcf LCD_RS ;RS low (CMD) ;; 4ビット・モードで1バイト送る LCD_SEND_BYTE movfw LCD_DAT ; 上位4ビットを送る call LCD_SEND_4BITS; swapf LCD_DAT, w ; 下位4ビットを送る call LCD_SEND_4BITS; return ;; 液晶にwレジスタの上位4ビットを送る LCD_8BIT_SEND_NOCHK LCD_SEND_4BITS ;; W register の内容を LCD_PORT へ書く ;; STB(E)、R/S、RWやほかのデバイスなどの出力ビットのつながったポートと ;; LCD_PORT が同じ時に、それらを壊さないよう内部レジスタを読んで書く andlw B'11110000' ; 下位4ビットは0にする movwf LCD_PORT_TMP movfw LCD_PORT_ ; 現在のポート出力を読む andlw B'00001111' ; 上位4ビットを0にする iorwf LCD_PORT_TMP, w ; 上位と下位を結合する movwf LCD_PORT ; ポートに書く bsf LCD_E ; E high bcf LCD_E ; E low return ;; 液晶から1バイト読む LCD_READ movlw B'11110000' ; 下位4ビットを0にするため bsf LCD_E ;E high andwf LCD_PORT, w ; 上位4ビットを読む bcf LCD_E ;E low movwf LCD_RDAT bsf LCD_E ;E high swapf LCD_PORT, w ; 下位4ビットを読む bcf LCD_E ;E low andlw B'00001111' ; 上位4ビットを0にする iorwf LCD_RDAT, f ; 上位と下位を結合する return ;; 液晶のビジー・チェック・サブルーチン LCD_BUSY bsf STATUS,RP0 ;バンク 1 movlw TRISB_LCD_IN ; D5からD7のつながったピンを入力にする movwf TRISB bcf STATUS,RP0 ;バンク0 bcf LCD_RS ;RS low (CMD) bsf LCD_RW ;R/W high (read) LCD_BUSY_1 call LCD_READ BTFSC LCD_RDAT,7 ;ビジー・フラグのチェック goto LCD_BUSY_1 ;ビジーなので再読み込み bcf LCD_RW ;R/W low (write) bsf STATUS,RP0 ;バンク1 movlw TRISB_LCD_OUT ; D5からD7のつながったピンを出力にする movwf TRISB ;LCD_PORT bcf STATUS,RP0 ;バンク0 return ;; 10[us]待ちサブルーチン delay10us: goto $+1 ; 2 goto $+1 ; 2 goto $+1 ; 2 goto $+1 ; 2 goto $+1 ; 2 goto $+1 ; 2 goto $+1 ; 2 goto $+1 ; 2 goto $+1 ; 2 goto $+1 ; 2 nop ; 1 return ; 2 ;; 100[us]待ちサブルーチン delay100us: movlw D'9' movwf CT_DELAY100US T_LP1 call delay10us ;2+(25+3)*9−1=253 decfsz CT_DELAY100US, f goto T_LP1 return ;254*0.4=100[us] ;; 1[ms]待ちサブルーチン delay1ms: movlw D'89' ; 1 movwf CT_DELAY1MS ; 1 delay1msl1: call delay10us decfsz CT_DELAY1MS, f ; 1(次の行を実行)、2(次の行はとばす) goto delay1msl1 ; 2 nop ; 1 goto $+1 ; 2 return ; 2 ;; 5[ms]待ちサブルーチン delay5ms: call delay1ms call delay1ms call delay1ms call delay1ms call delay1ms return ;; テーブル・ルックアップでHELLO\r\n\0を返すサブルーチン org 0x300 STR_CHAR clrf PCLATH bsf PCLATH, 0 bsf PCLATH, 1 addwf PCL, f retlw 'H' retlw 'E' retlw 'L' retlw 'L' retlw 'O' retlw '\r' retlw '\n' retlw 0 end リスト5-12 Copyright 2005 Noriaki Mitsunaga