目次>5章 第2ステップ(色々な実験)> (25)超音波を扱う(距離を測定)> ソース
超音波を扱う
− 距離を測定 −
更新日2008.7.5
以下のソースを取り込んで、アセンブル→PIC書き込み→実行して下さい。
; ========================== ここから ============================== ; clock:20MHz ; ; 超音波による距離測定 ; ; ; PICのピン接続 ; RB0 LCD DB4 ; RB1 LCD DB5 ; RB2 LCD DB6 ; RB3 LCD DB7 ; RB4 超音波受信器の増幅信号 ; ; RA0,1 超音波送信器(TMR0割込み毎にON/OFFする) ; RA2 LCD RS (4:Register Select) ; RA3 LCD E (5:Enable Signal) ; ; 使用タイマ(プログラムループ) ; 15mS LCDパワーオンリセット待ち ; 5mS LCD初期化&writeルーチン ; 1mS LCD初期化ルーチン ; 50uS LCDwriteルーチン ; ; TMR0割込み ; プリスケーラ なし ; TMR0 256-63+12(12.6uS : 40KHzの波長の半分) ; ; LIST P=PIC16F84A INCLUDE P16F84A.INC __CONFIG _HS_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF CBLOCK 0Ch save_st ;STATUSのセーブ save_w ;W-regのセーブ flag ;状態 ; bit0 : 1 wav ON ; bit1 : 1 TMR0割込み256回(7.3728mS) ; bit2 : 1 PORTBピン変化割込み有り T0cnt ;超音波送信中 256 - 63 + 12 ;超音波非送信 256 - 144 + 12 wav_cnt ;1回当たりの超音波サイクル数 dista1 ;距離カウンタ下位バイト dista2 ;距離カウンタ上位バイト CNT7mS ;TMR0割込み256回カウンタ CNT50mS ;50mSカウンタ(TMR0割込み256回を7回) CNT50uS ;50μS Loop カウンタ CNT1mS ;1mS Loop カウンタ CNT5mS ;5mS Loop カウンタ CNT15mS ;15mS Loop カウンタ char ;LCD表示文字 BCDwk1 ;BCD変換ワーク BCDwk2 ;BCD変換ワーク binH ;BCD変換ワーク binL ;BCD変換ワーク BCD3 ;BCD変換結果(百の位) BCD2 ;BCD変換結果(十の位) BCD1 ;BCD変換結果(一の位) ENDC wav_val EQU d'40' ;超音波パルス数(20)×2 wav_ON EQU 0 ;超音波送信中フラグ(flag[0]) T7mFlag EQU 1 ;TMR0割込み256回(7.3728mS)フラグ(flag[1]) RB4_on EQU 2 ;PORTBピン変化割込み有り CNT50_i EQU d'7' RS EQU 02h ;LCD Register Select E EQU 03h ;LCD Enable ; ===================== リセットベクタ ===================== ORG 0 GOTO init ; ===================== 割込みルーチン ===================== ORG 4 ;割込みの入口 MOVWF save_w ;W-regセーブ SWAPF STATUS,W MOVWF save_st ;STATUSセーブ BTFSS INTCON,T0IF ;割込み? GOTO int_RB ; ========= TMR0割込み ============= int_T0 BCF INTCON,T0IF ;割込みフラグクリア MOVF T0cnt,W MOVWF TMR0 ;TMR0初期化 BTFSS flag,wav_ON ;超音波送信中? GOTO int_T0_2 ; No MOVLW 03h XORWF PORTA,F ;超音波送信 DECFSZ wav_cnt,F ;超音波送信1回分終了? GOTO int_exit ; No BCF flag,wav_ON ;超音波送信中フラグOFF MOVLW wav_val MOVWF wav_cnt ;1回当たりの超音波サイクル数 MOVLW d'256' - d'144' + d'12' ;12はオーバヘッド MOVWF T0cnt MOVWF TMR0 CLRF CNT7mS CLRF dista1 ;距離カウンタ下位バイト初期化 CLRF dista2 ;距離カウンタ上位バイト初期化 MOVF PORTB,W BCF INTCON,RBIF BSF INTCON,RBIE ;ピン変化割込み許可 GOTO int_exit int_T0_2 INCF dista1,F ;距離カウンタ+1 BTFSC STATUS,Z INCF dista2,F DECFSZ CNT7mS,F GOTO int_exit BSF flag,T7mFlag ;TMR0割込み256回(7.3728mS)フラグセット GOTO int_exit ; ========= PORTBピン変化割込み ============= int_RB BTFSS PORTB,4 GOTO int_RB_2 BSF flag,RB4_on ;PORTBピン変化割込み有り BCF INTCON,RBIE ;ピン変化割込み禁止 int_RB_2 BCF INTCON,RBIF int_exit SWAPF save_st,W MOVWF STATUS ;STATUSロード SWAPF save_w,F SWAPF save_w,W ;W-regロード RETFIE ;割込み許可リターン ; ===================== 初期化ルーチン ===================== init CALL wait15ms ;LCD電源ON後15mS待つ BSF STATUS,RP0 ;■バンク1に切替え MOVLW 0F0h ; MOVWF TRISA ;RA0-3は出力 MOVLW 0F0h ; MOVWF TRISB ;RB0-3は出力 MOVLW 88h ;TMR0プリスケーラ未使用,PORTBプルアップなし MOVWF OPTION_REG ; BCF STATUS,RP0 ;■バンク0に切替え CALL LCD_init ;LCD初期化 CALL LCD_i_disp ;LCD初期表示 CLRF flag BSF flag,wav_ON ;超音波送信中 MOVLW wav_val MOVWF wav_cnt ;1回当たりの超音波サイクル数 MOVLW CNT50_i MOVWF CNT50mS ;50mSカウンタ初期化 MOVLW 01h MOVWF PORTA ;RA0のみON MOVLW d'256' - d'63' + d'12' ;12はオーバヘッド MOVWF T0cnt MOVWF TMR0 ;TMR0初期化 BSF INTCON,T0IE ;タイマ割込み許可 BSF INTCON,GIE ;全体割込み許可 ; ===================== メインルーチン ===================== main BTFSC flag,wav_ON ;超音波送信中? GOTO main ; Yes (超音波送信に専念する) BTFSS flag,T7mFlag ;TMR0割込み256回(7.3728mS)? GOTO main10 ; No BCF flag,T7mFlag ;TMR0割込み256回(7.3728mS)フラグクリア DECFSZ CNT50mS,F ;50mS経過? GOTO main10 ; No MOVLW CNT50_i MOVWF CNT50mS ;50mSカウンタ初期化 BSF flag,wav_ON ;超音波送信中フラグセット MOVLW d'256' - d'63' + d'12' ;12はオーバヘッド MOVWF T0cnt MOVWF TMR0 GOTO main main10 BTFSC flag,RB4_on ;PORTBピン変化割込み有り? CALL distance ;距離計算&LCD表示 GOTO main ; ================= 距離計算&LCD表示 =================== distance BCF flag,RB4_on ;ピン変化割込みフラグクリア BCF STATUS,C RRF dista2,F ;距離カウンタ/2 (往復なので) RRF dista1,F MOVLW d'7' ;7cm補正 ADDWF dista1,F BTFSC STATUS,C INCF dista2 CALL bin2BCD MOVLW 088h ;1行9桁 CALL LCD_command MOVF BCD3,W ;百の位を IORLW 030h ; ASCII変換し CALL LCD_write ; LCDに表示 MOVF BCD2,W ;十の位 IORLW 030h CALL LCD_write MOVF BCD1,W ;一の位 IORLW 030h CALL LCD_write RETURN ; ====================================================== ; バイナリ10ビット(dista2,dista1)をBCDに変換 bin2BCD MOVF dista2,W MOVWF binH MOVF dista1,W MOVWF binL MOVLW 0FFh MOVWF BCD3 ; -1をセット MOVWF BCD2 ; -1をセット ; binLの下位2ビット → BCDwk2 MOVF binL,W ANDLW 03h MOVWF BCDwk2 ; binH・binL ÷ 4 → BCDwk1 ; 下位2ビットは一旦切り捨て(後で復活) BCF STATUS,C RRF binH,F RRF binL,F ; 1/2する BCF STATUS,C RRF binH,F RRF binL,W ; もう一度1/2する(合計1/4)。 MOVWF BCDwk1 ; 百の位(BCD3)を算出 MOVLW d'25' ; 1/4にしたので、25で割れば100の位が計算できる。 bin2BCD3 INCF BCD3,F SUBWF BCDwk1,F BTFSC STATUS,C ; BCDwk1 < 25 (C=0) GOTO bin2BCD3 ADDWF BCDwk1,F ; 十の位(BCD2)を算出 BCF STATUS,C RLF BCDwk1,F ; 2倍する RLF BCDwk1,F ; もう一度2倍する(合計4倍)。前で1/4したものを戻す。 MOVF BCDwk2,W ADDWF BCDwk1,F ; 前で切り捨てた下位2ビットを加算 MOVLW d'10' ; 10で割って10の位を計算。 bin2BCD2 INCF BCD2,F SUBWF BCDwk1,F BTFSC STATUS,C ; BCDwk1 < 10 (C=0) GOTO bin2BCD2 ADDWF BCDwk1,F ; 一の位(BCD1)を算出 MOVF BCDwk1,W MOVWF BCD1 RETURN ;================= LCD初期表示 ========================== LCD_i_disp MOVLW 084h ;1行5桁 CALL LCD_command MOVLW 'キ' CALL LCD_write MOVLW 'ョ' CALL LCD_write MOVLW 'リ' CALL LCD_write MOVLW 08Bh ;1行12桁 CALL LCD_command MOVLW 'c' CALL LCD_write MOVLW 'm' CALL LCD_write RETURN ;================= LCD表示をクリアする =================== LCD_clear MOVLW 01h CALL LCD_command CALL wait5ms ;LCDのBFをチェックしないので1.64mS以上待つ RETURN ;================= LCDのカーソル位置を先頭に戻す ========= LCD_home MOVLW 080h CALL LCD_command RETURN ;================= LCDのカーソル位置を2行目の先頭に ===== LCD_2line MOVLW 0C0h CALL LCD_command RETURN ;================= LCDのディスプレイをONにする ========= LCD_on MOVLW 0Ch CALL LCD_command RETURN ;================= LCDのディスプレイとカーソルをONにする == LCD_on_cur MOVLW 0Eh CALL LCD_command RETURN ;================= LCDのディスプレイをOFFにする ======= LCD_off MOVLW 08h CALL LCD_command RETURN ;================= LCDにデータを送る ===================== LCD_write MOVWF char BSF PORTA,RS ;RS=1(Data) MOVLW 0F0h ;PORTBの下位4ビットを ANDWF PORTB,F ; クリア SWAPF char,W ;上位 ANDLW 0Fh ;4ビットを IORWF PORTB,F ;PORTB(3-0)にセット(PORTB(7-4)はそのまま) BSF PORTA,E ;LCDにデータ書き込み NOP BCF PORTA,E MOVLW 0F0h ;PORTBの下位4ビットを ANDWF PORTB,F ; クリア MOVF char,W ;下位 ANDLW 0Fh ;4ビットを IORWF PORTB,F ;PORTB(3-0)にセット(PORTB(7-4)はそのまま) BSF PORTA,E ;LCDにデータ書き込み NOP BCF PORTA,E CALL wait50us ;LCDのBFをチェックしないので50uS待つ RETURN ;================= LCDにコマンドを送る =================== LCD_command MOVWF char BCF PORTA,RS ;RS=0(Command) MOVLW 0F0h ;PORTBの下位4ビットを ANDWF PORTB,F ; クリア SWAPF char,W ;上位 ANDLW 0Fh ;4ビットを IORWF PORTB,F ;PORTB(3-0)にセット(PORTB(7-4)はそのまま) BSF PORTA,E ;LCDにデータ書き込み NOP BCF PORTA,E MOVLW 0F0h ;PORTBの下位4ビットを ANDWF PORTB,F ; クリア MOVF char,W ;下位 ANDLW 0Fh ;4ビットを IORWF PORTB,F ;PORTB(3-0)にセット(PORTB(7-4)はそのまま) BSF PORTA,E ;LCDにデータ書き込み NOP BCF PORTA,E CALL wait50us ;LCDのBFをチェックしないので50uS待つ RETURN ;================= LCD初期化 ================================ LCD_init BCF PORTA,RS ;RS=0 BCF PORTA,E ;E=0 MOVLW 03h ;下位4ビットに'3'をセット MOVWF PORTB BSF PORTA,E ;ファンクションセット(1回目) NOP BCF PORTA,E CALL wait5ms ;5mS待つ BSF PORTA,E ;ファンクションセット(2回目) NOP BCF PORTA,E CALL wait5ms ;5mS待つ BSF PORTA,E ;ファンクションセット(3回目) NOP BCF PORTA,E CALL wait5ms ;5mS待つ MOVLW 02h ;4ビットモード MOVWF PORTB ;に BSF PORTA,E ;設定 NOP BCF PORTA,E CALL wait1ms ;1mS待つ MOVLW 028h ;4ビットモード,2行表示,7ドット CALL LCD_command CALL LCD_off ;ディスプレイOFF CALL LCD_clear ;LCDクリア MOVLW 06h ; CALL LCD_command ;カーソルモードセット (Increment) CALL LCD_on ;ディスプレイON,カーソルOFF RETURN ;================= 15mS WAIT ================================ wait15ms MOVLW d'3' MOVWF CNT15mS wait15ms_loop CALL wait5ms DECFSZ CNT15mS,F GOTO wait15ms_loop RETURN ;================= 5mS WAIT ================================= wait5ms MOVLW d'100' MOVWF CNT5mS wait5ms_loop CALL wait50us DECFSZ CNT5mS,F GOTO wait5ms_loop RETURN ;================= 1mS WAIT ================================= wait1ms MOVLW d'20' MOVWF CNT1mS wait1ms_loop CALL wait50us DECFSZ CNT1mS,F GOTO wait1ms_loop RETURN ;================= 50μS WAIT =============================== wait50us ; 1サイクル(4クロック):0.2μS ; 50μS=0.2μS×250サイクル MOVLW d'82' ;1 MOVWF CNT50uS ;1 wait50us_loop DECFSZ CNT50uS,F ;1 GOTO wait50us_loop ;2 RETURN ;2+1 END ; ========================== ここまで ==============================