目次8章.機能が豊富なPICを使う(PIC16F88)汎用PWMコントローラ>ソース

汎用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
; =========================== ここまで ===============================