目次>5章 第2ステップ(色々な実験)> (22)DCモータの制御(正転/逆転,スピード制御)> ソース

DCモータの制御
− 正転/逆転,スピード制御 −

更新日2008.11.9

以下のソースを取り込んで、アセンブル→PIC書き込み→実行して下さい。

; ========================== ここから ==============================
;	ファイル名	TA_motor2.asm
;	作成日		2008.9.27
;	作成者		mit.ueno
;	バージョン	1.0
;	PIC		PIC16F84A
;	クロック	20MHz
;	概要
;		TA7291PによるDCモータの正転・逆転制御
;		簡易A/D変換を行い、PWM制御でDCモータの
;		スピード制御
;		A/D変換結果などはLCDに表示する
;	使用ポート
;		RB0	RB0/INT(積分結果入力)
;		RB2	DCモータ(TA7291P-IN1)
;		RB3	DCモータ(TA7291P-IN2)
;		RB4	LCD DB4
;		RB5	LCD DB5
;		RB6	LCD DB6
;		RB7	LCD DB7
;
;		RA0	LCD RS	(4:Register Select)
;		RA1	LCD E	(5:Enable Signal)
;		RA2	プッシュボタンスイッチ
;		RA3	矩形波出力 → 積分回路

;	TMR0(409.6uS)
;		プリスケーラ	8
;		TMR0	256(フリーラン)
;		割込み周期	(1/20MHz)*4*8*256=409.6uS
;
;	LCDフォーマット
;		0123456789012345
;		A/D=xx PWM=xx  +
;		Max=xx dif=xx
;
	LIST	P=PIC16F84A
	INCLUDE	P16F84A.INC
	__CONFIG	_HS_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF


	CBLOCK	0Ch
	save_w		;Wreg save area
	save_st		;STATUS save area
	AD_counter	;AD変換ワーク
	AD_max		;AD変換最大値
	AD_max_diff	;0FFh - AD変換最大値
	flag		;bit0:INT割込みフラグ
			;bit1:スイッチON
	char		;LCD表示データ
	CNT50uS		;50uS用カウンタ
	CNT1mS		;1mS用カウンタ
	CNT5mS		;5mS用カウンタ
	CNT15mS		;15mS用カウンタ
	PWM_cycle	;PWMの1サイクルカウンタ
	PWM_width	;PWMのパルス幅カウンタ
	PWM_width_i	;PWMのパルス幅
	PWM_bit		;PWM制御するビット位置
	WORK_0		;計算一時ワーク
	pattern		;TA7291Pの制御パターン(順番)
	ENDC

f_int	EQU	0	;INT割込みフラグ( flag[0] )
SW_on	EQU	1	;スイッチ状態フラグ( flag[1] )

RS	EQU	00h	;LCD Register Select
E	EQU	01h	;LCD Enable


	ORG	0
	GOTO	init

; =========== 割り込み処理 (RB0/INT,TMR0) ==========
	ORG	4		;割込みの入口

	MOVWF	save_w		;W-regセーブ
	SWAPF	STATUS,W
	MOVWF	save_st		;STATUSレジスタセーブ

	BTFSC	INTCON,INTF	;INT割込み?
	GOTO	int_INT		; Yes

; ==== TMR0割込み ====
int_TMR0
	BCF	INTCON,T0IF

	DECFSZ	PWM_cycle,F	;PWM 1サイクル終了?
	GOTO	int_T0_10	; No

	MOVLW	d'31'
	MOVWF	PWM_cycle	;PWMサイクル初期化

	MOVF	PWM_width_i,W	;PWMパルス幅は
	BTFSC	STATUS,Z	;0?
	GOTO	int_T0_05	; Yes

	MOVF	PWM_bit,W	;PWM制御ビットでPORTBとORし
	IORWF	PORTB,F		;モーターON
int_T0_05
	MOVF	PWM_width_i,W
	MOVWF	PWM_width	;PWMパルス幅初期化
	GOTO	int_exit
int_T0_10
	DECFSZ	PWM_width,F	;PWMパルスON時間経過?
	GOTO	int_exit	; No
	COMF	PWM_bit,W	;PWM制御ビットを反転してPORTBとANDし
	ANDWF	PORTB,F		;モーターOFF
	GOTO	int_exit

; ==== INT割込み ====
int_INT
	BCF	INTCON,INTF
	BSF	flag,f_int	;INT割込みフラグON

; ==== exit ====
int_exit
	SWAPF	save_st,W
	MOVWF	STATUS		;STATUSレジスタロード
	SWAPF	save_w,F
	SWAPF	save_w,W	;W-regロード
	RETFIE			;割込み許可リターン

; ======================= 初期処理 ==================
init
	CLRF	flag
	BSF	STATUS,RP0	;■バンク1に切替え
	MOVLW	0F4h		;
	MOVWF	TRISA		;RA0,1,3は出力
	MOVLW	003h		;
	MOVWF	TRISB		;RB2-7は出力
	MOVLW	0C2h		;プリスケーラ:8,プルアップなし,RB0/INT立ち上がり
	MOVWF	OPTION_REG
	BCF	STATUS,RP0	;■バンク0に切替え

	BSF	INTCON,GIE

	CLRF	PORTA		;PORTAをクリア
	CLRF	PORTB		;PORTBをクリア

	CALL	LCD_init	;LCD初期化
	CALL	LCD_init_disp	;LCD初期表示

	CALL	AD_1st		;初回A/D変換(最大値)

	MOVLW	d'31'
	MOVWF	PWM_cycle
	CLRF	PWM_width

	MOVLW	d'6'
	MOVWF	pattern		;制御パターン初期化

	CALL	wait1ms

; ===================== メイン処理 =================
main
	CALL	AD_proc		;簡易A/D変換&PWMパルス幅設定
	CALL	AD_LCD		;A/D変換結果&PWMパルス幅をLCD表示

	BTFSC	PORTA,2		;スイッチOFF?
	BCF	flag,SW_on	; Yes スイッチ状態OFF

	BTFSS	PORTA,2		;スイッチON?
	CALL	SW_CHK		; Yes パターン切り替え&設定

	CALL	wait1ms		;コンデンサの放電完了待ち(最低200uS)

	GOTO	main

; ================= A/D変換処理 ================
AD_proc
	BCF	flag,f_int	;INT割込みフラグOFF
	BSF	INTCON,INTE	;RB0/INT割込み許可
	CLRF	AD_counter	;AD変換結果クリア
	BSF	PORTA,3		;AD開始
AD_proc3
	INCF	AD_counter,F
	BTFSS	flag,f_int	;INT割込み(A/D変換終了)?
	GOTO	AD_proc3

	BCF	INTCON,INTE	;RB0/INT割込み禁止
	BCF	PORTA,3

	; A/D変換結果を最大値(0FFh)に換算し、上位5ビットを取り出す
	MOVF	AD_counter,W
	ADDWF	AD_max_diff,W	;最大値換算
	MOVWF	WORK_0
	BCF	STATUS,C	;上位5ビットを取り出す
	RRF	WORK_0,F	;
	BCF	STATUS,C	;
	RRF	WORK_0,F	;
	BCF	STATUS,C	;
	RRF	WORK_0,W	;
	MOVWF	PWM_width_i	;PWMのパルス幅にセット

	RETURN

; =========== A/D変換結果&PWMパルス幅をLCD表示 =====
AD_LCD
	MOVLW	084h		;LCD表示位置を4桁目に
	CALL	LCD_command
	MOVF	AD_counter,W
	CALL	LCD_hex		;A/D変換結果をLCDに16進表示

	MOVLW	08Bh		;LCD表示位置を11桁目に
	CALL	LCD_command
	MOVF	PWM_width_i,W
	CALL	LCD_hex		;PWMパルス幅をLCDに16進表示

	RETURN

; ============= スイッチON確認 ===================
SW_CHK
	BTFSC	flag,SW_on	;既にON?
	GOTO	SW_CHK90	; Yes
	CALL	wait15ms	;チャタリングキャンセル待ち
	BTFSC	PORTA,2		;スイッチON?
	GOTO	SW_CHK90	; No
	BSF	flag,SW_on	;→スイッチONに変化した

	DECFSZ	pattern,F	;制御パターン1サイクル終了?
	GOTO	SW_CHK10
	MOVLW	d'6'
	MOVWF	pattern		;制御パターン初期化
SW_CHK10
	CALL	PTN_set		;patternからRB2/RB3を設定

SW_CHK90
	RETURN

;================= パターンセット ==================
;	pattern(モータ制御パターン)により
;	・RB2/RB3およびPWM制御ビットを設定
;	・PWM制御のためのTMR0割込み設定
;	・状態をLCDに表示
PTN_set
	MOVLW	08Fh		;LCD表示位置を15桁目に設定
	CALL	LCD_command

	; patternにより処理を選択
	MOVF	pattern,W
	ADDWF	PCL,F
	NOP
	GOTO	PTN_01		;1 逆転
	GOTO	PTN_11		;2 ブレーキ
	GOTO	PTN_00		;3 ストップ
	GOTO	PTN_10		;4 正転
	GOTO	PTN_11		;5 ブレーキ
	GOTO	PTN_00		;6 ストップ

PTN_00			;ストップ
	BCF	INTCON,T0IE	;TMR0割込み禁止
	BCF	PORTB,2
	BCF	PORTB,3
	MOVLW	'P'
	CALL	LCD_write
	GOTO	PTN_90
PTN_11			;ブレーキ
	BCF	INTCON,T0IE	;TMR0割込み禁止
	BSF	PORTB,2
	BSF	PORTB,3
	MOVLW	'B'
	CALL	LCD_write
	GOTO	PTN_90
PTN_01			;逆転
	BCF	PORTB,2
	BSF	PORTB,3
	MOVLW	'-'
	CALL	LCD_write
	MOVLW	08h
	MOVWF	PWM_bit		;PWM制御ビット設定
	GOTO	PTN_80
PTN_10			;正転
	BSF	PORTB,2
	BCF	PORTB,3
	MOVLW	'+'
	CALL	LCD_write
	MOVLW	04h
	MOVWF	PWM_bit		;PWM制御ビット設定
;	GOTO	PTN_80
PTN_80
	CLRF	TMR0
	BSF	INTCON,T0IE	;TMR0割込み有効
PTN_90
	RETURN

;================= 初回A/D変換 ==================
AD_1st
	; A/D変換の最大値と0FFhとの差を求める
	CALL	AD_proc
	MOVF	AD_counter,W
	SUBLW	0FFh
	MOVWF	AD_max_diff	;0FFh - AD_max

	MOVLW	0C4h		;LCD表示位置を2行4桁目に
	CALL	LCD_command
	MOVF	AD_counter,W
	CALL	LCD_hex		;A/D変換最大値をLCDに16進表示

	MOVLW	0CBh		;LCD表示位置を2行11桁目に
	CALL	LCD_command
	MOVF	AD_max_diff,W
	CALL	LCD_hex		;A/D変換最大値と0FFhの差をLCD表示

	RETURN

;================= LCDの初期表示 ================
LCD_init_disp
	MOVLW	'A'
	CALL	LCD_write
	MOVLW	'/'
	CALL	LCD_write
	MOVLW	'D'
	CALL	LCD_write
	MOVLW	'='
	CALL	LCD_write

	MOVLW	087h		;LCD表示位置を7桁目に
	CALL	LCD_command
	MOVLW	'P'
	CALL	LCD_write
	MOVLW	'W'
	CALL	LCD_write
	MOVLW	'M'
	CALL	LCD_write
	MOVLW	'='
	CALL	LCD_write

	MOVLW	0C0h		;LCD表示位置を2行0桁目に
	CALL	LCD_command
	MOVLW	'M'
	CALL	LCD_write
	MOVLW	'a'
	CALL	LCD_write
	MOVLW	'x'
	CALL	LCD_write
	MOVLW	'='
	CALL	LCD_write

	MOVLW	0C7h		;LCD表示位置を2行7桁目に
	CALL	LCD_command
	MOVLW	'd'
	CALL	LCD_write
	MOVLW	'i'
	CALL	LCD_write
	MOVLW	'f'
	CALL	LCD_write
	MOVLW	'='
	CALL	LCD_write
	RETURN

; ==================================================
; バイナリ4ビットをLCD表示用16進数に変換
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に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表示をクリアする ==============
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	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
	CALL	wait5ms		;5mS待つ

	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


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