list p=16f877a ; PIC16F877A 用のプログラムであることを宣言 #include p16f877a.inc ; PIC16F877A 用のヘッダ・ファイルを読み込む __config _HS_OSC & _CP_OFF & _PWRTE_ON & _WDT_OFF & _LVP_OFF PORTC_ equ 0x20 TMP equ 0x21 TMP_CHK equ 0x22 TMP_HEXL equ 0x23 TMP_HEXH equ 0x24 MSG_LOOP equ 0x25 MYFLAGS equ 0x26 DUTY equ 0x27 ;; MYFLAGSへの割り当て MOTOR_ON equ 0 ; PWMを出力する1, 出力しない0 PWM_2 equ 1 ; PWM1を出力する0, PWM2を出力する1 org 0x0 start: ; 初期設定をする bcf STATUS, RP0 ; この2行でバンク0にする bcf STATUS, RP1 clrf INTCON ; 割り込み禁止 clrf PORTC ; LEDが点灯しない, モータが回転しないように clrf PORTD ; 出力は0にしておく clrf PORTE ; 出力は0にしておく ; タイマ2の設定 movlw B'0000110' ; bit 6-3 ポストスケーラ 1:1 '0000' ; bit 2 タイマ2オン 1 ; bit 1-0 プリスケーラ 1:16 '1x' movwf T2CON clrf TMR2 ; PWM1のための設定 clrf CCPR1L ; デューティ比の上位8ビットを0にする movlw B'001100' ; bit 5-4 デューティ比の下位2ビット: '00' ; bit 3-0 PWMモード: '1100' movwf CCP1CON ; PWM2のための設定 clrf CCPR2L ; デューティ比の上位8ビットを0にする movlw B'001100' ; bit 5-4 デューティ比の下位2ビット: '00' ; bit 3-0 PWMモード: '1100' movwf CCP2CON movlw B'10010000' ; シリアルの設定 movwf RCSTA bsf STATUS, RP0 ; バンク1にする movlw 0xff movwf TRISB ; ポートBはディジタル入力 movlw B'00000111' ; PORTBのウィーク・プルアップを有効に ; プリスケーラはタイマに割り当て ; プリスケーラは1/256にする movwf OPTION_REG movlw B'10000000' movwf TRISC ; RXピン(ビット7)以外を出力に clrf TRISD ; 全ピン出力に movlw 0x3f ; PWM period movwf PR2 movlw B'00100110' ; シリアルの設定 movwf TXSTA movlw D'64' ; ボーレートの設定 movwf SPBRG bcf STATUS, RP0 ; バンク0にする clrf PORTC_ clrf DUTY ; PWMデューティは0に clrf MYFLAGS ; 初期設定は終了 ; 電源を入れたときにメッセージを出す call bootmsg ;; メイン・ルーチン main call RCVCHR ; 1文字受信(エコーバックつき) movwf TMP ; 受信した文字をTMPに書いておく ; parse command to ADC sublw '?' ; '?'を受信したら btfsc STATUS, Z call bootmsg ; 起動時のメッセージを出す movfw TMP sublw 'a' ; 'a'を受信したら btfsc STATUS, Z call enable_pwm1 ; PWM1を送ることにし、モータ回転 movfw TMP sublw 'b' ; 'b'を受信したら btfsc STATUS, Z call enable_pwm2 ; PWM2を送ることにし、モータ回転 movfw TMP sublw 's' btfsc STATUS, Z call motor_stop ; モータ・ストップ movfw TMP sublw 'S' btfsc STATUS, Z call motor_start ; モータ回転 movfw TMP sublw 'v' ; 'v' を受信したら btfsc STATUS, Z call motor_duty ; 速度コマンド goto main ;; メイン・ルーチンはここまで ;; PWM1のデューティが可変となるようフラグを変える enable_pwm1 bcf MYFLAGS, PWM_2 call motor_stop call motor_start return ;; PWM2のデューティが可変となるようフラグを変える enable_pwm2 bsf MYFLAGS, PWM_2 call motor_stop call motor_start return ;; モータを止める motor_stop ;; PWM1, PWM2共にデューティ比を0にする clrf CCPR1L clrf CCPR2L movlw B'001100' ; ビット5,4は0に、 ; ビット3-0をPWMモードを指定する設定にする movwf CCP1CON movwf CCP2CON bcf MYFLAGS, MOTOR_ON ; モータ・オン・フラグをクリア return ;; デューティ比を設定する motor_start bsf MYFLAGS, MOTOR_ON ; モータ・オン・フラグをセット btfsc MYFLAGS, PWM_2 ; PWM1を出力するかPWM2を出力するかチェック goto motor_start2 ; PWM2を出力 ;; PWM1 を出力 rrf DUTY, w ; 指令値を2ビット右にシフトする movwf TMP rrf TMP, w andlw 0x3f movwf CCPR1L ; 2ビット・シフトしたものを代入する swapf DUTY, w ; 指令値の下位2ビットをビット5、4に移す andlw 0x30 ; ビット5、4以外をマスク iorlw B'1100' ; ビット3-0をPWMモードを指定する設定にする movwf CCP1CON return motor_start2 ;; PWM2 を出力 rrf DUTY, w ; 指令値を2ビット右にシフトする movwf TMP rrf TMP, w andlw 0x3f movwf CCPR2L ; 2ビット・シフトしたものを代入する swapf DUTY, w ; 指令値の下位2ビットをビット5、4に移す andlw 0x30 ; ビット5。4以外をマスク iorlw B'1100' ; ビット3-0をPWMモードを指定する設定にする movwf CCP2CON return ;; デューティ比を受け取る motor_duty call RCV_HEX ; 2文字16進数として受信する btfsc STATUS, Z return ; zフラグが0ならエラー movwf DUTY ; zフラグが0ならエラーでないのでデューティ比を更新 btfsc MYFLAGS, MOTOR_ON ; PWMを出力しているかチェック call motor_start ; 出力しているならデューティ比を更新する return ;; 2文字受信し16進数として解釈する RCV_HEX ;; 上位バイトを受信 call RCVCHR call CHK_02F movwf TMP_HEXH sublw 0xff ; 0xffかチェック btfsc STATUS, Z return ; 0xffならエラー swapf TMP_HEXH, f ; 下位4ビットを上位4ビットへ移動 ;; 下位バイトを受信 call RCVCHR call CHK_02F movwf TMP_HEXL sublw 0xff ; 0xff かチェック btfsc STATUS, Z return ; 0xff ならエラー movfw TMP_HEXL iorwf TMP_HEXH, w ; 前に受信した上位4ビットと下位4ビットをあわせる bcf STATUS, Z ; ちゃんと受信した印にzフラグを0にする return ;; wレジスタが'0'から'f'なら0xfをwレジスタに返し、 ;; それ以外なら0xffをwレジスタに返すチェック・ルーチン CHK_02F movwf TMP_CHK addlw D'255' - '9' addlw '9' - '0' +1 btfss STATUS, C goto CHK_02F_1 ; W<'0' か W>'9' ; W は、'0' -> 0, '1' -> 1,..., '9' -> 9となっている return CHK_02F_1 movfw TMP_CHK addlw D'255' - 'f' addlw 'f' - 'a' + 1 btfss STATUS, C retlw 0xff ; '0' から 'f' でないのでエラー ; W は、'a' -> 0, 'b' -> 1,..., 'f' -> 5となっている addlw 0xa ; 'a' -> 0xa, 'b'->0xb,..., 'f' -> 0xf return ;; 1文字受信してエコーバックするサブルーチン ;; 受信した文字はwレジスタで返す RCVCHR call RCVCHR1 movfw RCREG call TXCHR return ;; 1文字受信サブルーチン ;; 受信した文字はRCREGレジスタを読む RCVCHR1 ; 1バイト受信するまで待つ btfss PIR1, RCIF goto $-1 ; エラーかチェックする btfss RCSTA, OERR goto CHK_FERR bcf RCSTA, CREN ; オーバラン・エラーを消す bsf RCSTA, CREN goto RCVCHR1 CHK_FERR btfss RCSTA, FERR return ; 正常に受信したので戻る movfw RCREG ; フレーミング・エラーを消して、次の受信を行う goto RCVCHR1 ;; 1文字送信サブルーチン TXCHR btfss PIR1, TXIF ; Check if the buffer is empty goto $-1 movwf TXREG return ;; メッセージを送るサブルーチン bootmsg clrf MSG_LOOP bootmsg_0 movfw MSG_LOOP call MSG0 addlw 0 btfsc STATUS, Z return call TXCHR incf MSG_LOOP, f goto bootmsg_0 org 0x300 ;; メッセージ中の1文字を返すサブルーチン MSG0 clrf PCLATH bsf PCLATH, 0 bsf PCLATH, 1 addwf PCL, f retlw 'm' retlw 'o' retlw 't' retlw 'o' retlw 'r' retlw '\r' retlw '\n' retlw 0 end リスト6-3 Copyright 2005 Noriaki Mitsunaga