目次>8章.機能が豊富なPICを使う(PIC16F88)>汎用PWMコントローラ>ソース
更新日2009.6.27
以下のソースを取り込んで、アセンブル→PIC書き込み→実行して下さい。
; ========================== ここから ============================== ; ファイル名 AD_PWM88.asm ; 作成日 2009.6.14 ; 作成者 mit.ueno ; バージョン 1.0 ; ; PIC PIC16F88 ; クロック INTRC 1,2,4,8MHz ; 概要 ; PIC16F88のPWM機能を使った汎用装置 ; 2つの可変抵抗の電圧をA/D変換し、PWMの周期とパルス幅にする ; クロックは内部クロックで、1,2,4,8MHzをスイッチで切り替え ; 使用ポート ; RB4 LCD DB4 ; RB5 LCD DB5 ; RB6 LCD DB6 ; RB7 LCD DB7 ; RA0 LCD RS (4:Register Select) ; RA1 LCD E (6:Enable Signal) ; ; RA2 スイッチ ; RA3/AN3 可変抵抗 ; RA4/AN4 可変抵抗 ; ; RB3/CCP LED(PWM) ; LIST P=16F88 INCLUDE P16F88.INC __CONFIG _CONFIG1, _WDT_OFF & _BODEN_ON & _PWRTE_ON & _INTRC_IO & _CCP1_RB3 & _LVP_OFF CBLOCK 020h ;GPR(汎用RAM)定義 clock ;1:1MHz,2:2MHz,3:4MHz,4:8MHz sw_stat ;bit0:スイッチ状態(0:OFF,1:ON) WORK_0 ;一時的ワーク CNT50us CNT50us_i ;50uSカウンタ初期値(clockにより変更) CNT05ms CNT05ms_i ;500uSカウンタ初期値(clockにより変更) CNT1ms CNT5ms CNT10ms CNT01s char ;LCD出力データ ENDC RS EQU 00h E EQU 01h ; ----------------------------------------------------- ORG 0 GOTO init ; ----------------------------------------------------- ; 割込み処理(未使用) ORG 4 ;割込みの入口 RETFIE ; ----------------------------------------------------- ; 初期処理 init CALL pic_init ; ----------------------------------------------------- ; メイン処理 main CALL AD_PWM ;A/D変換を行いPWMの周期とパルス幅を設定 ; == スイッチ == BTFSC PORTA,2 ;スイッチON? GOTO main10 ; No CALL wait10ms BTFSC PORTA,2 ;スイッチ本当にON? GOTO main10 ; No CALL sw_on GOTO main11 main10 BCF sw_stat,0 ;スイッチはOFF main11 GOTO main ;============= PICの初期化 ================================== pic_init ; <クロック&ポート設定> BSF STATUS,RP0 ;■バンク1に切替え MOVLW 070h MOVWF OSCCON ; CLOCK=8MHz MOVLW 0FCh MOVWF TRISA ; RA0-1は出力 MOVLW 006h MOVWF TRISB ; RB0,3-7は出力 BCF STATUS,RP0 ;■バンク0に切替え CLRF PORTA CLRF PORTB MOVLW 004h MOVWF clock ; CLOCK=8MHz ; <A/D設定> MOVLW 059h MOVWF ADCON0 ;16Tosc,CH3,ADON BSF STATUS,RP0 ;■バンク1に切替え MOVLW 040h MOVWF ADCON1 ;16Tosc,左詰め,Vref=Vdd MOVLW 018h MOVWF ANSEL ;AN3/4使用 BCF STATUS,RP0 ;■バンク0に切替え ; <PWM設定> MOVLW 07h MOVWF T2CON ;T2_on,Prescaler:16,Postscale:1 MOVLW 00Fh MOVWF CCP1CON ;PWM mode ; <その他の設定> MOVLW d'25' MOVWF CNT50us_i MOVLW d'249' MOVWF CNT05ms_i CALL LCD_init ;LCD初期化 CALL LCD_disp_init ;LCD固定表示の出力 CLRF sw_stat ;スイッチ状態初期化(OFF) RETURN ;======== 2チャネルのA/D変換を行いPWM設定 ============ AD_PWM ; == AN3 == MOVF ADCON0,W ANDLW 0C0h IORLW 019h MOVWF ADCON0 ;CH3,ADON CALL wait50us ;50μS待つ(アクイジション時間) BSF ADCON0,GO ;AD変換開始 AD_PWM3 BTFSC ADCON0,GO ;AD変換完了? GOTO AD_PWM3 ; NO MOVF ADRESH,W ;A/D変換結果を BSF STATUS,RP0 ;■バンク1に切替え MOVWF PR2 ; PWMの周期にセット BCF STATUS,RP0 ;■バンク0に切替え MOVLW 082 ;1行3桁 CALL LCD_command MOVF ADRESH,W ;A/D変換結果を CALL LCD_hex ; LCDに16進表示 ; == AN4 == MOVF ADCON0,W ANDLW 0C0h IORLW 021h MOVWF ADCON0 ;CH4,ADON CALL wait50us ;50μS待つ(アクイジション時間) BSF ADCON0,GO ;AD変換開始 AD_PWM4 BTFSC ADCON0,GO ;AD変換完了? GOTO AD_PWM4 ; NO MOVF ADRESH,W ;A/D変換結果を MOVWF CCPR1L ; PWMのパルス幅にセット MOVLW 0C2 ;2行3桁 CALL LCD_command MOVF ADRESH,W ;A/D変換結果を CALL LCD_hex ; LCDに16進表示 RETURN ;============= スイッチが押された時の処理 =================== sw_on BTFSC sw_stat,0 ;スイッチは今までOFF? GOTO sw_on99 ; No BSF sw_stat,0 ;スイッチがOFFからONになった MOVLW 0CCh ;2行13桁 CALL LCD_command DECF clock,F MOVF clock,W ADDWF PCL,F GOTO sw_on0 ;(→8MHz) GOTO sw_on1 ;1MHz GOTO sw_on2 ;2MHz GOTO sw_on3 ;4MHz GOTO sw_on4 ;8MHz sw_on0 MOVLW 04h MOVWF clock GOTO sw_on4 ;8MHz sw_on1 ;== クロックを1MHzへ切り替え == MOVLW d'4' MOVWF CNT50us_i ;50uSカウンタの初期値 MOVLW d'32' MOVWF CNT05ms_i ;500uSカウンタの初期値 BCF ADCON0,6 ;2Tosc BSF STATUS,RP0 ;■バンク1に切替え BCF ADCON1,6 ;2Tosc MOVLW 040h MOVWF OSCCON ; CLOCK=1MHz BCF STATUS,RP0 ;■バンク0に切替え MOVLW '1' CALL LCD_write GOTO sw_on99 sw_on2 ;== クロックを2MHzへ切り替え == MOVLW d'7' MOVWF CNT50us_i ;50uSカウンタの初期値 MOVLW d'63' MOVWF CNT05ms_i ;500uSカウンタの初期値 BCF ADCON0,6 ;4Tosc BSF STATUS,RP0 ;■バンク1に切替え BSF ADCON1,6 ;4Tosc MOVLW 050h MOVWF OSCCON ; CLOCK=2MHz BCF STATUS,RP0 ;■バンク0に切替え MOVLW '2' CALL LCD_write GOTO sw_on99 sw_on3 ;== クロックを4MHzへ切り替え == MOVLW d'13' MOVWF CNT50us_i ;50uSカウンタの初期値 MOVLW d'125' MOVWF CNT05ms_i ;500uSカウンタの初期値 BSF ADCON0,6 ;8Tosc BSF STATUS,RP0 ;■バンク1に切替え BCF ADCON1,6 ;8Tosc MOVLW 060h MOVWF OSCCON ; CLOCK=4MHz BCF STATUS,RP0 ;■バンク0に切替え MOVLW '4' CALL LCD_write GOTO sw_on99 sw_on4 ;== クロックを8MHzへ切り替え == MOVLW d'25' MOVWF CNT50us_i ;50uSカウンタの初期値 MOVLW d'249' MOVWF CNT05ms_i ;500uSカウンタの初期値 BSF ADCON0,6 ;16Tosc BSF STATUS,RP0 ;■バンク1に切替え BSF ADCON1,6 ;16Tosc MOVLW 070h MOVWF OSCCON ; CLOCK=8MHz BCF STATUS,RP0 ;■バンク0に切替え MOVLW '8' CALL LCD_write GOTO sw_on99 sw_on99 RETURN ;=========== LCDに8ビットを16進数で表示 =============== LCD_hex MOVWF WORK_0 SWAPF WORK_0,W ANDLW 00Fh ;上位4ビットを CALL bin2hex ;16進数で CALL LCD_write ;LCDに表示 MOVF WORK_0,W ANDLW 00Fh ;下位4ビットを CALL bin2hex ;16進数で CALL LCD_write ;LCDに表示 RETURN ;=========== LCDに下位4ビットを16進数で表示 =========== LCD_hex4 ANDLW 00Fh ;下位4ビットを CALL bin2hex ;16進数で CALL LCD_write ;LCDに表示 RETURN ; ----------------------------------------------------- ; バイナリ4ビットをLCD表示用16進数に変換 ; 0100hバウンダリに注意! bin2hex ADDWF PCL,F RETLW '0' ;0 RETLW '1' ;1 RETLW '2' ;2 RETLW '3' ;3 RETLW '4' ;4 RETLW '5' ;5 RETLW '6' ;6 RETLW '7' ;7 RETLW '8' ;8 RETLW '9' ;9 RETLW 'A' ;A RETLW 'B' ;b RETLW 'C' ;C RETLW 'D' ;d RETLW 'E' ;E RETLW 'F' ;F ;================= LCDに初期表示 ========================= LCD_disp_init MOVLW 'P' CALL LCD_write ; MOVLW 086h ;1行7桁 ; CALL LCD_command ; MOVLW 'm' ; CALL LCD_write ; MOVLW 'S' ; CALL LCD_write MOVLW 08Ch ;1行13桁 CALL LCD_command MOVLW 'ク' CALL LCD_write MOVLW 'ロ' CALL LCD_write MOVLW 'ッ' CALL LCD_write MOVLW 'ク' CALL LCD_write CALL LCD_2line MOVLW 'W' CALL LCD_write ; MOVLW 0C6h ;2行7桁 ; CALL LCD_command ; MOVLW 'm' ; CALL LCD_write ; MOVLW 'S' ; CALL LCD_write MOVLW 0CCh ;2行14桁 CALL LCD_command MOVLW '8' CALL LCD_write MOVLW 'M' CALL LCD_write MOVLW 'H' CALL LCD_write MOVLW 'z' CALL LCD_write RETURN ;================= LCD表示をクリアする =================== LCD_clear MOVLW 01h CALL LCD_command CALL wait5ms ;LCDのBFをチェックしないので1.53mS以上待つ 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 00Fh ;PORTBの上位4ビットを ANDWF PORTB,F ; クリア MOVF char,W ;上位 ANDLW 0F0h ;4ビットを IORWF PORTB,F ;PORTB(4-7)にセット(PORTB(0-3)はそのまま) BSF PORTA,E ;LCDにデータ書き込み NOP BCF PORTA,E MOVLW 00Fh ;PORTBの上位4ビットを ANDWF PORTB,F ; クリア SWAPF char,W ;下位 ANDLW 0F0h ;4ビットを IORWF PORTB,F ;PORTB(4-7)にセット(PORTB(0-3)はそのまま) 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 00Fh ;PORTBの上位4ビットを ANDWF PORTB,F ; クリア MOVF char,W ;上位 ANDLW 0F0h ;4ビットを IORWF PORTB,F ;PORTB(4-7)にセット(PORTB(0-3)はそのまま) BSF PORTA,E ;LCDにデータ書き込み NOP BCF PORTA,E MOVLW 00Fh ;PORTBの上位4ビットを ANDWF PORTB,F ; クリア SWAPF char,W ;下位 ANDLW 0F0h ;4ビットを IORWF PORTB,F ;PORTB(4-7)にセット(PORTB(0-3)はそのまま) 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 030h ;上位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 020h ;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 ; ******** タイマルーチン ***************************** ; ******** 100msタイマ ******** wait01s MOVLW d'200' MOVWF CNT01s wait01sL CALL wait05ms DECFSZ CNT01s,F GOTO wait01sL RETURN ; ******** 10msタイマ ******** wait10ms MOVLW d'20' MOVWF CNT10ms wait10msL CALL wait05ms DECFSZ CNT10ms,F GOTO wait10msL RETURN ; ******** 5msタイマ ******** wait5ms MOVLW d'10' MOVWF CNT5ms wait5msL CALL wait05ms DECFSZ CNT5ms,F GOTO wait5msL RETURN ; ******** 1msタイマ ******** wait1ms MOVLW d'2' MOVWF CNT1ms wait1msL CALL wait05ms DECFSZ CNT1ms,F GOTO wait1msL RETURN ; ******** 0.5msタイマ ******** wait05ms MOVF CNT05ms_i,W MOVWF CNT05ms wait05msL NOP DECFSZ CNT05ms,F GOTO wait05msL RETURN ; ******** 50usタイマ ******** wait50us MOVF CNT50us_i,W MOVWF CNT50us wait50usL NOP DECFSZ CNT50us,F GOTO wait50usL RETURN END ; =========================== ここまで ===============================