赤外線リモコン

ハードウェア

仕様

(NECの)テレビリモコンを使用して、チャンネルコードを受信します。 赤外線リモコンのコードは次のように NEC から公開されています。 http://www.necel.com/ja/faq/mi_com/__com_remo.html

赤外線センサーはGP3 に接続する。 また、GP4 が Low の時は出力信号はホールドされるが、 High のときは 1 秒だけホールドされ 0 に戻る(未実装)。

出力は GP5, GP2, GP1, GP0 の 4bit で出力します。

リモコンボタン、送信コード、出力の割り当ては以下のとおりです。

ボタンコード出力
118 E7 08 F71
218 E7 88 772
318 E7 48 B73
418 E7 C8 374
518 E7 28 D75
618 E7 A8 576
718 E7 68 977
818 E7 E8 178
918 E7 18 E79
1018 E7 98 67A
1118 E7 58 A7B
1218 E7 D8 27C
Vol+18 E7 40 BFD
Vol-18 E7 C0 3FE
電源18 E7 10 EFF
Ch+18 E7 00 FF未割当
Ch-18 E7 80 7F未割当

開発

12F629 は出力ピンが少ないため、互換性がそれなりにある 16F628A で開発を 行い、フィードバックを行う。 そのため、初期化と入出力の定義の部分だけ別にし、リモコンの処理自体は共 通ソースで開発する。

回路図

12F629

12F629用回路図

16F628A

16F628A用回路図

16F887

赤外線センサは RE3, スイッチは RE2, 状態出力は RE0,1, データ出力は RC とする。

ソフトウェア

動作の概要

リモコンの信号の解析は割り込み処理によって行い、データの出力は主プログ ラムで行う。 内部用の状態変数 irstatus と読み込みデータ変数 rcvdata[4] に対して、出 力が確定したときの出力用変数 iroutstatus、 rcvoutdata[4] を持つ。

主プログラムではこの iroutstatus と rcvoutdata[4] を適宜出力する。 NEC のフォーマットを読み込むと rcvoutdata[0] はメーカーコード、 rcvoutdata[1] はメーカーコードの反転、 rcvoutdata[2] は通信データ、 rcvoutdata[3] は通信データの反転である。 そのため、 rcvoutdata[2] を searchchdata サブルーチンによりデータ変換 をして出力ピンに出力する。

リモコン解析は割り込みを用いてタイミングを計測する。 まず、当初 Timer0 割り込みを通常のタイミングで用いていたが、それでは分 解能が低すぎるため、割り込みごとに Timer0 のカウンタを分解能が 4 倍に なるように設定して動作させている。

また、外部コントロール sw により、出力を数秒で 0 に戻すため、 Timer 1 を使用する。

内部状態は 5 状態ある。 各状態へ移行する際に ircounter を 0 にする。 割り込みのたびに ircounter を 1 ずつ増やし、対象の時間と比較する。

  1. 初期状態は 1 であり、この状態では OFF (受光開始) を検出する。 検出後は状態 2 に移行する。
  2. 状態 2 ではリーダーの OFF 部分 9ms を検出する。 時間間隔 LEADEROFFMIN と LEADEROFFMAX の間に ON になったら状態 3 に移行する。
  3. 状態 3 ではリーダの ON 部分 4.5ms を検出する 時間間隔 LEADRONMIN と LEADERONMAX の間になったら状態 4 に移行する。
  4. 状態 4 ではデータを読み込む 信号が ON→OFF になるタイミングを検出し、閾値 THRESH 以下であれば 0 を、 以上であれば 1 を読む。 これを 8bit ずつ rcvdata[numofdata] にデータとして蓄える。 蓄え終わったら 2 byte ずつパリティのチェックを行う。 0xff xor rcvdata[i] xor rcvdata[i+1] が 0 になるかどうかチェックする。 チェックが終了したら読み込んだデータを rcvoutdata にコピーし、 iroutstatus を Ok にし、状態 0 に移行する。 なお、外部コントロールが On の時は、Timer 1を始動する。
  5. 状態 0 ではなにもせず、irtotal カウンタがオーバーフローしたら状態 1 に 移行する。 状態 0 には正常な読み込み終了の他、エラー発生時にも遷移してくる。 ここでは、リモコンの最長信号間隔である 108ms 分だけなにもせずに待機を してから読み込みモードに復帰する。 そのため、状態 1 から 2 へ移る際、また、irtotal カウンタがオーバーフロー した際に irtotal カウンタをリセットする。 このカウンタ(16bit)は割り込みごとに 1 増える。
  6. Timer 1 の割り込みが生じたら、出力を 0 にする。 なお、 duration 変数により、 0 にするまでの時間を調整できる。

各エラー処理は次の通りである。

状態 2-4
irtotal がオーバーフローしたら timeouterr
状態 2
短いときは noise, 長いときは timeouterr
状態 3
短いときは noise, 長いときは timeouterr
状態 4
parity チェックがエラーの時に formaterr

なお、以上をふまえ、各状態ごとの処理の前の共通の処理は次のようになる。

  1. リモコンの受信値を計算する。irdata には前回の値と今回の値のビット がセットされる
  2. カウンタとして ircount と irtotal(16bit) が加算される
  3. irtotal の値がタイムアウト値になっていたら irtotal の値をリセットし、 irstatus が 0 でないなら iroutstatus に TIMEOUT を入れ、irstatus を 0 にする
  4. irstatus の値ごとに分岐

プログラム

共通部分

irheader.inc


; irhead.inc
IRTOTALMAX equ d'200' * d'4'
LEADEROFFMIN	equ d'17'*d'4' ; 9ms / 512us
LEADEROFFMAX	equ	d'20'*d'4'
LEADERONMIN	equ d'8'*d'4' ; 4.5ms
LEADERONMAX	equ	d'12'*d'4'
THRESH		equ	d'13' 
	; (1.125 + 2.25) /2 / 512us = 3.29
	; 1.125 / 512us = 2.19
	; 2.25 / 512us = 4.39
OK		equ d'1'
TIMEOUT	equ d'2'
FORMATERR	equ d'3'
;numofdata	set 3
;dataoffset	set 2
numofdata	set	4
dataoffset	set 2
duration 	set 5
	cblock
		irdata
		ircounter
		irtotallow
		irtotalhigh
		irstatus
		iroutstatus	
	endc

;	irtotal : little endian
	cblock
		irwork
	endc

	cblock
	index
	rcvdata:numofdata
	rcvcounter
	rcvoutdata:numofdata
	endc
ir_init	macro
	movlw	d'1'	; initial
	movwf	irstatus
	clrf	iroutstatus
	endm

irbody.inc



clrtotal	macro
	clrf	irtotallow
	clrf	irtotalhigh
	endm
inctotal	macro
	movlw	d'1'
	addwf	irtotallow,1
	btfsc	STATUS,C
	incf	irtotalhigh,1
	endm
testtotal	macro	x 	; x - irtotal , w is destroyed
	movlw	low x
	subwf	irtotallow,0	; irtotal - x
	movwf	irwork
	movlw	high x
	btfss	STATUS,C
	addlw	-d'1'		; w - 1
	subwf	irtotalhigh,0
	btfsc	STATUS,Z
	movf	irwork,1
	endm

timer01 
        movwf   savew
	movf    STATUS,0
	movwf   savest
    btfss   INTCON,T0IF
	goto    nottimer0
	movlw	256-256/4+5
	movwf	TMR0
	bcf     INTCON,T0IF
	call    ircontrol
nottimer0
    btfss   PIR1,TMR1IF
	goto    intend
	bcf     PIR1,TMR1IF
	call    blink
intend
    movf    savest,0
	movwf	STATUS
	movf    savew,0
    retfie






ircontrol
	receiveir
	goto	iroff
iron
	bsf		STATUS,C
	goto	calcir
iroff
	bcf		STATUS,C
calcir
	rlf		irdata,1
	movlw	b'00000011'
	andwf	irdata,1

	incf	ircounter,1 ; irtotal > 108ms でタイムアウト
irpoint
	inctotal
	testtotal	IRTOTALMAX
	btfss	STATUS,Z
	goto	irprocess
	clrtotal
	clrf	ircounter
	movlw	d'2'
	subwf	irstatus,0
	btfss	STATUS,C	; タイムアウトで irstatus が 0 でないなら
	goto	movetoinitialstate
	movlw	TIMEOUT		; iroutstatus ← TIMEOUT
	movwf	iroutstatus
movetoinitialstate
	movlw	d'1'		; initial
	movwf	irstatus
	goto	irprocess

irprocess
	movf	irstatus,0
	addwf	PCL,1
	goto	endprocess	; 0 wait for timeout
	goto	initial		; 1
	goto	leaderoff	; 2
	goto	leaderon	; 3
	goto	readdata	; 4


initial
	btfsc	irdata,0
	return				; RA5 = on ならそのまま
					; RA5 = off なら検出開始
	movlw	d'2'	; leader
	movwf	irstatus
	clrtotal		
	clrf	iroutstatus
	clrf	ircounter

	goto	endprocess




length	macro	cond,min,tooshort,max,toolong
	local change
	if cond == 1
	btfss	irdata,0
	else
	btfsc	irdata,0	
	endif
	goto	change		; RA5 = on なら off → on を検出
	movlw	max	; leader の off 長 > LEADERMAX ならタイムアウト
	subwf	ircounter,0
	btfss	STATUS,C
	goto	endprocess
	goto	toolong
change
	movlw	min	; leader の off 長 < LEADERMIN なら noise
	subwf	ircounter,0
	btfss	STATUS,C
	goto	tooshort
	endm
leaderoff
	length	0,LEADEROFFMIN,noise,LEADEROFFMAX,timeouterr
	movlw	d'3'	; leaderon
	movwf	irstatus
	clrf	ircounter
	goto	endprocess
leaderon
	length	1,LEADERONMIN,noise,LEADERONMAX,timeouterr
;	length	1,LEADERONMIN,formaterr,LEADERONMAX,timeouterr
	movlw	d'4'	; readdata
	movwf	irstatus




	clrf	ircounter
	clrf	index

	variable	i = 0
	while	i < numofdata
	clrf	rcvdata + i
	i ++
	endw

	movlw	d'8'
	movwf	rcvcounter
	goto	endprocess

readdata
	movlw	b'00000010'	;1→0の検出
	subwf	irdata,0
	btfss	STATUS,Z
	goto	endprocess


	movlw	rcvdata
	addwf	index,0
	movwf	FSR
	movlw	THRESH
	subwf	ircounter,0
	rlf		INDF,1
;	rlf		rcvdata,1
	clrf	ircounter
	decfsz	rcvcounter,1
	goto	endprocess
	movlw	d'8'
	movwf	rcvcounter
	incf	index,1
	movlw	numofdata
	subwf	index,0
	btfss	STATUS,Z
	goto	endprocess

	

; leader off part ok
paritycheck
	if	numofdata	<= 2
	movlw	0xff
	xorwf	rcvdata,0
	xorwf	rcvdata+1,0
	btfss	STATUS,Z
	goto	formaterr
	endif
	if	numofdata	<= 4
	movlw	0xff
	xorwf	rcvdata+2,0
	xorwf	rcvdata+3,0
	btfss	STATUS,Z
	goto	formaterr
	endif
	nop
	i = 0
	while	i < numofdata
	movf	rcvdata + i,0
	movwf	rcvoutdata + i
	i ++
	endw	

	clrf	irstatus
	movlw	OK
	movwf	iroutstatus

	cblock
	blinkcounter
	endc

	testctrl
	goto	endprocess
	movlw	duration
	movwf	blinkcounter
	starttimer1
	goto	endprocess	

endprocess
	return
noise
	movlw	d'0'
	movwf	iroutstatus
	goto	clrstatus
timeouterr
	movlw	TIMEOUT
	movwf	iroutstatus
	goto	clrstatus
formaterr
	movlw	FORMATERR
	movwf	iroutstatus
	goto	clrstatus
clrstatus
;	clrf	irtotal
	clrf	ircounter
	clrf	irstatus	; wait for timeout
	return


searchchdata
	; in: wreg : data
	; out: wreg : data
	cblock
	searchdata
	searchindex
	endc
	movwf	searchdata
	clrf	searchindex
loop
	movf	searchindex,0
	call	getchdata
	addlw	0x0		;test wreg
	btfsc	STATUS,Z
	retlw	0x0		; return 0
	subwf	searchdata,0
	btfss	STATUS,Z
	goto	notfound
	incf	searchindex,0
	return
notfound
	incf	searchindex,1
	goto	loop	

getchdata
	addwf	PCL,1
	retlw	0x08	;1
	retlw	0x88	;2
	retlw	0x48	;3
	retlw	0xc8	;4
	retlw	0x28	;5
	retlw	0xa8	;6
	retlw	0x68	;7
	retlw	0xe8	;8
	retlw	0x18	;9
	retlw	0x98	;10
	retlw	0x58	;11
	retlw	0xd8	;12
	retlw	0x40	;vol+
	retlw	0xc0	;vol-
	retlw	0x10	;pwr
	retlw	0x00	;end

blink
	testctrl
	return
	decfsz	blinkcounter,1
	return
	stoptimer1
	i = 0
	while	i < numofdata
	clrf	rcvoutdata + i
	i ++
	endw	
	return

12F629 部分

主プログラム ir629.asm


#include "sakamoto629.inc"
#include "irheader.inc"

	org	0x0000
	goto	start
	org	0x0004
	goto	timer01
	org	0x0008

start
	calibrate
	movlw	0x07
	movwf	CMCON
	banksel TRISIO
	movlw   b'00011000'
	movwf   TRISIO
	banksel GPIO
	clrf    GPIO
	ir_init
	timer01_init b'11010000',b'00110001' 
	; 0: 内部クロック, PS=1:2
	; 1: 内部クロック, PS=1:8
main
	cblock
		chdata
		outdata
	endc
	movf	rcvoutdata+dataoffset,0
	call	searchchdata
	movwf	chdata
	movlw	b'00000111'
	andwf	chdata,0
	movwf	outdata
	btfsc	chdata,3
	bsf		outdata,5

	movlw	b'11011000'
	iorwf	outdata,0
	andwf	GPIO,1
	movlw	b'00100111'
	andwf	outdata,0
	iorwf	GPIO,1
    goto    main

receiveir	macro
	btfss	GPIO,3
	endm
testctrl	macro
	btfss	GPIO,4
	endm

#include "irbody.inc"
	end

12F629 用マクロ集


; sakamoto629.inc
; sakamoto629 マクロ ver 1.0
; written by Naoshi SAKAMOTO [email protected]

;
;初期化
;

        list p=12f629
	#include p12f629.inc
	variable env
env = _CPD_OFF
env &= _CP_OFF
env &= _BODEN_OFF
env &= _MCLRE_OFF
env &= _PWRTE_OFF
env &= _WDT_OFF
env &= _INTRC_OSC_NOCLKOUT
	__config env
	cblock  0x20
	endc
	nolist


calibrate	macro
	bsf	STATUS,RP0
	call	0x3ff
	movwf	OSCCAL
	bcf	STATUS,RP0
	endm




;
; timer0 TIME0 割り込みの設定、取り扱い
;


timer0_init macro psmode
	cblock 
	 savew
	 savest
	endc
	clrwdt
	banksel OPTION_REG
	movlw   psmode
	movwf   OPTION_REG
	banksel INTCON
	bsf     INTCON,T0IE
	bcf	INTCON,T0IF
	bsf	INTCON,GIE
	endm

timer0_prg macro func
timer0 
        movwf   savew
	movf    STATUS,0
	movwf   savest
        btfss   INTCON,T0IF
	goto    nottimer0
	bcf     INTCON,T0IF
	call    func
nottimer0
        movf    savest,0
	movwf	STATUS
	movf    savew,0
        retfie
        endm

;
; postscaler 呼び出しを間引く
;


postscaler_init macro rate
        #define post_rate rate
	cblock
	 post_count
	endc
	movlw	post_rate
	movwf	post_count
	endm

postscaler_prg macro func
postscaler
	decfsz	post_count,1
	return
	movlw	post_rate
	movwf	post_count
	call    func
	return
	endm

;
; duty 呼び出されると二つのサブルーチンを特定の割合で交互に呼び出す
;

duty_init macro 
	 cblock
	 duty_ratio,duty_period,duty_counter
	 endc
	 endm

duty_prg macro func_off, func_on
duty
	movf    duty_counter,0
	subwf	duty_ratio,0
	btfsc	STATUS,C
	goto    duty_on
	call	func_off
	goto	duty_end
duty_on
	call    func_on
duty_end
	decfsz	duty_counter,1
	return 
	movf     duty_period,0
	movwf	duty_counter
	return
	endm

set_rate_by_counter_prg macro
set_rate_by_counter
        movf    counter,0
	call    getduty
	movwf	duty_ratio
	return
	endm
getduty_prg	macro
getduty
        addwf   PCL,1
startduty
;	retlw   d'128'
	retlw   d'64'
	retlw   d'32'
	retlw   d'16'
	retlw   d'8'
	retlw   d'4'
	retlw   d'2'
	retlw   d'1'
endduty
        endm

timer01_init macro timer0mode,timer1mode
	cblock 
	 savew
	 savest
	endc
	clrwdt
	movlw	timer1mode
	movwf	T1CON
	banksel OPTION_REG
	movlw   timer0mode
	movwf   OPTION_REG
	bsf		PIE1,TMR1IE
	banksel INTCON
	bsf     INTCON,T0IE
	bcf	INTCON,T0IF
	bcf	PIR1,TMR1IF
	bsf	INTCON,GIE
	endm

timer01_prg macro func0,func1
timer01 
    movwf   savew
	movf    STATUS,0
	movwf   savest
    btfss   INTCON,T0IF
	goto    nottimer0
	bcf     INTCON,T0IF
	call    func0
;	goto	intend
nottimer0
    btfss   PIR1,TMR1IF
	goto    intend
	bcf     PIR1,TMR1IF
	call    func1
intend
    movf    savest,0
	movwf	STATUS
	movf    savew,0
    retfie
	endm


starttimer1	macro
	clrf	TMR1H
	clrf	TMR1L
	bsf		T1CON,TMR1ON
	endm
stoptimer1	macro
	bcf		T1CON,TMR1ON
	endm



        list

16F628A部分

主プログラム ir628a.asm


#include "sakamoto628a.inc"
#include "irheader.inc"

	org	0x0000
	goto	start
	org	0x0004
	goto	timer01
	org	0x0008

start
	movlw	0x07
	movwf	CMCON
	banksel TRISA
	movlw   b'00110000'
	movwf   TRISA
	clrf	TRISB
	banksel PORTA
	clrf    PORTA
	clrf	PORTB
	ir_init
	timer01_init b'11010000',b'00110001' 
	; 0: 内部クロック、 PS=1:2
	; 1: 内部クロック, PS=1:8

main
		movf	iroutstatus,1
		btfsc	STATUS,Z
		goto	statusend
		movlw	b'11111100'
		iorwf	iroutstatus,0
		andwf	PORTA,1
		movlw	b'00000011'
		andwf	iroutstatus,0
		iorwf	PORTA,1
statusend
		movf	rcvoutdata + dataoffset,0
		call	searchchdata
		movwf	PORTB

        goto    main

receiveir	macro
	btfss	PORTA,5
	endm
testctrl	macro
	btfss	PORTA,4
	endm

#include "irbody.inc"
	end

16f628a 用マクロ集


; sakamoto628a.inc
; written by Naoshi SAKAMOTO [email protected]

    list p=16f628a
	#include p16f628a.inc
	variable env
env = _BOREN_OFF
env &= _CP_OFF
env &= _DATA_CP_OFF
env &= _PWRTE_OFF
env &= _WDT_OFF
env &= _LVP_OFF
env &= _MCLRE_OFF
env &= _INTOSC_OSC_NOCLKOUT
	__config env
	cblock  0x20
	endc
	nolist

enable_PB macro
	banksel TRISB
	clrf    TRISB
	banksel PORTB
	clrf    PORTB
	endm
enable_PAPB macro
	banksel TRISA
	movlw   b'0010000'
	movwf   TRISA
	clrf    TRISB
	banksel PORTA
	clrf    PORTA
	clrf	PORTB
	endm

;
; sw RA5 のスイッチが押された時サブルーチンを呼ぶマクロ
;

sw_init macro
    	cblock
		sw_prev
		endc
		clrf    sw_prev
	endm
sw_prg	macro func
sw_main
	btfsc	PORTA,5
	goto    sw_on
sw_off
        clrf    sw_prev
	goto    sw_main
sw_on
        movf    sw_prev,1
        btfss   STATUS,Z
	goto    sw_main
	movlw	d'1'
	movwf	sw_prev
	call    func
        goto    sw_main
	endm

;
; ビジーウェイト(初期化時に時定数を与える)
;

bwait_init macro _time
	#define	bwait_time _time
	cblock
	bwait_v0,bwait_v1,bwait_v2
	endc
	endm

bwait_prg macro
bwait	
	movlw	bwait_time
	movwf	bwait_v0
bwait0
	clrf    bwait_v1
bwait1
	clrf	bwait_v2
bwait2
		nop
	decfsz	bwait_v2,1
	goto	bwait2
	decfsz  bwait_v1,1
	goto    bwait1
	decfsz  bwait_v0,1
	goto    bwait0
	return
	endm

;
; counter カウンタを増やし(inccount)、値を表示する(dispcount)
; counter_prg にカウンタの上限値を与える(通常は pat_end-pat_start)
; 要 getpat 
;


counter_init macro
        cblock
	counter
        endc
        clrf   counter
	call	dispcounter
        endm
counter_prg macro limit
inccounter
	incf    counter,1
	movlw   limit
	subwf   counter,0
	btfsc   STATUS,Z
        clrf    counter

dispcounter
        movf    counter,0
	call	getpat
	movwf	PORTB
	return
	endm
;
; getpat W レジスタの値に応じた値を W レジスタに返す関数マクロ
; pat_end - pat_start が要素数になる。
; getpat_num_prg は 連続ビットパターン
; getpat_num_prg は 7 セグメント LED の表示パターン
;

getpat_bit_prg macro
getpat	
        addwf   PCL,1
pat_start
	retlw   b'00000000'
	retlw   b'00000001'
	retlw   b'00000011'
	retlw   b'00000111'
	retlw   b'00001111'
	retlw   b'00011111'
	retlw   b'00111111'
	retlw   b'01111111'
	retlw   b'11111111'
pat_end
        endm
getpat_num_prg macro
getpat	
        addwf   PCL,1
pat_start
	retlw   b'11111011' ; 0 このパターンは配線によって変わります
	retlw   b'10000010' ; 1
	retlw   b'11011101' ; 2
	retlw   b'11001110' ; 3
	retlw   b'10100111' ; 4
	retlw   b'01101110' ; 5
	retlw   b'01111111' ; 6
	retlw   b'11100010' ; 7
	retlw   b'11111111' ; 8
	retlw   b'11101110' ; 9
	retlw   b'11110111' ; A
	retlw   b'00111110' ; b
	retlw   b'01111001' ; C
	retlw   b'10011110' ; d
	retlw   b'01111101' ; E
	retlw   b'01110100' ; F
pat_end
        endm
timer0_init macro psmode
	cblock 
	 savew
	 savest
                savepclath
	endc
	clrwdt
	banksel OPTION_REG
	movlw   psmode
	movwf   OPTION_REG
	banksel INTCON
	bsf     INTCON,T0IE
	bcf	INTCON,T0IF
	bsf	INTCON,GIE
	endm

timer0_prg macro func
timer0 
        movwf   savew
	movf    STATUS,0
	movwf   savest
               movf    PCLATH,0
               movwf   savepclath
        btfss   INTCON,T0IF
	goto    nottimer0
	bcf     INTCON,T0IF
	call    func
nottimer0
        movf    savepclath,0
        movwf   PCLATH
        movf    savest,0
	movwf	STATUS
	movf    savew,0
        retfie
        endm
postscaler_init macro rate
        #define post_rate rate
	cblock
	 post_count
	endc
	movlw	post_rate
	movwf	post_count
	endm

postscaler_prg macro func
postscaler
	decfsz	post_count
	return
	movlw	post_rate
	movwf	post_count
	call    func
	return
	endm
duty_init macro 
	 cblock
	 duty_ratio,duty_period,duty_counter
	 endc
	 endm

duty_prg macro func_off, func_on
duty
	movf    duty_counter,0
	subwf	duty_ratio,0
	btfsc	STATUS,C
	goto    duty_on
	call	func_off
	goto	duty_end
duty_on
	call    func_on
duty_end
	decfsz	duty_counter
	return 
	movf     duty_period,0
	movwf	duty_counter
	return
	endm
set_rate_by_counter_prg macro
set_rate_by_counter
        movf    counter,0
	call    getduty
	movwf	duty_ratio
	return
	endm
getduty_prg macro
getduty
        addwf   PCL,1
startduty
;	retlw   d'128'
	retlw   d'64'
	retlw   d'32'
	retlw   d'16'
	retlw   d'8'
	retlw   d'4'
	retlw   d'2'
	retlw   d'1'
endduty
        endm
porta_init macro
	cblock
	patterna
	endc
	movlw	b'11111111'
	movwf	patterna
	endm
porta_prg macro
porta_on
        movf    patterna,0
	movwf	PORTA
	return
p
porta_off
	clrf	PORTA
	return
	endm

timer01_init macro timer0mode,timer1mode
	cblock 
	 savew
	 savest
                savepclath
	endc
	clrwdt
	movlw	timer1mode
	movwf	T1CON
	banksel OPTION_REG
	movlw   timer0mode
	movwf   OPTION_REG
	bsf		PIE1,TMR1IE
	banksel INTCON
	bsf     INTCON,T0IE
	bcf	INTCON,T0IF
	bcf	PIR1,TMR1IF
	bsf	INTCON,GIE
	endm

timer01_prg macro func0,func1
timer01 
    movwf   savew
	movf    STATUS,0
	movwf   savest
               movf    PALATH,0
               movwf   savepclath
    btfss   INTCON,T0IF
	goto    nottimer0
	bcf     INTCON,T0IF
	call    func0
;	goto	intend
nottimer0
    btfss   PIR1,TMR1IF
	goto    intend
	bcf     PIR1,TMR1IF
	call    func1
intend
               movf    pclath,0
               movwf   PCLATH
    movf    savest,0
	movwf	STATUS
	movf    savew,0
    retfie
	endm


starttimer1	macro
	clrf	TMR1H
	clrf	TMR1L
	bsf		T1CON,TMR1ON
	endm
stoptimer1	macro
	bcf		T1CON,TMR1ON
	endm



	list

16F887 部分

主プログラム ir887.asm


#include "sakamoto887.inc"
#include "irheader.inc"

	org	0x0000
	goto	start
	org	0x0004
	goto	timer01
	org	0x0008

start
	banksel	ANSEL
	clrf	ANSEL
	clrf	ANSELH
	banksel TRISC
	clrf	TRISC
	movlw   b'00001100'
	movwf   TRISE
	banksel PORTC
	clrf	PORTC
	clrf    PORTE
	ir_init
	timer01_init b'11010000',b'00110001' 
	; 0: 内部クロック、 PS=1:2
	; 1: 内部クロック, PS=1:8

main
		movf	iroutstatus,1
		btfsc	STATUS,Z
		goto	statusend
		movlw	b'11111100'
		iorwf	iroutstatus,0
		andwf	PORTE,1
		movlw	b'00000011'
		andwf	iroutstatus,0
		iorwf	PORTE,1
statusend
		movf	rcvoutdata + dataoffset,0
		call	searchchdata
		movwf	PORTC

        goto    main

receiveir	macro
	btfss	PORTE,3
	endm
testctrl	macro
	btfss	PORTE,2
	endm

#include "irbody.inc"
	end

16f887 用マクロ集 sakamoto887.inc


; written by Naoshi SAKAMOTO [email protected]

    list p=16f887
	#include p16f887.inc
	variable env1,env2
env1 = _DEBUG_OFF
env1 &= _LVP_OFF
env1 &= _FCMEN_OFF
env1 &= _IESO_OFF
env1 &= _BOR_OFF
env1 &= _CPD_OFF
env1 &= _CP_OFF
env1 &= _MCLRE_OFF
env1 &= _PWRTE_OFF
env1 &= _WDT_OFF
env1 &= _INTRC_OSC_NOCLKOUT

env2  = _WRT_OFF
env2 &= _BOR40V
	__config _CONFIG1,env1
	__config _CONFIG2,env2
	cblock  0x20
	endc
	nolist

enable_DIGITALPORT macro
	banksel PORTA
	clrf	PORTA
	clrf	PORTB
	clrf	PORTC
	clrf	PORTD
	clrf	PORTE
	banksel	ANSEL
	clrf	ANSEL
	clrf	ANSELH
	banksel TRISA
	clrf	TRISA
	clrf	TRISB
	clrf	TRISC
	clrf	TRISD
	movlw   b'00001000'
	movwf   TRISE
	endm



;
; counter カウンタを増やし(inccount)、値を表示する(dispcount)
; counter_prg にカウンタの上限値を与える(通常は pat_end-pat_start)
; 要 getpat 
;


counter_init macro
        cblock
	counter
        endc
        clrf   counter
	call	dispcounter
        endm
counter_prg macro limit
inccounter
	incf    counter,1
	movlw   limit
	subwf   counter,0
	btfsc   STATUS,Z
        clrf    counter

dispcounter
        movf    counter,0
	call	getpat
	movwf	PORTB
	return
	endm
;
; getpat W レジスタの値に応じた値を W レジスタに返す関数マクロ
; pat_end - pat_start が要素数になる。
; getpat_num_prg は 7 セグメント LED の表示パターン
;


getpat_num_prg macro
getpat	
        addwf   PCL,1
pat_start
	retlw   b'11111011' ; 0 このパターンは配線によって変わります
	retlw   b'10000010' ; 1
	retlw   b'11011101' ; 2
	retlw   b'11001110' ; 3
	retlw   b'10100111' ; 4
	retlw   b'01101110' ; 5
	retlw   b'01111111' ; 6
	retlw   b'11100010' ; 7
	retlw   b'11111111' ; 8
	retlw   b'11101110' ; 9
	retlw   b'11110111' ; A
	retlw   b'00111110' ; b
	retlw   b'01111001' ; C
	retlw   b'10011110' ; d
	retlw   b'01111101' ; E
	retlw   b'01110100' ; F
pat_end
        endm
timer0_init macro psmode
	cblock 
	 savew
	 savest
                savepclath
	endc
	clrwdt
	banksel OPTION_REG
	movlw   psmode
	movwf   OPTION_REG
	banksel INTCON
	bsf     INTCON,T0IE
	bcf	INTCON,T0IF
	bsf	INTCON,GIE
	endm

timer0_prg macro func
timer0 
        movwf   savew
	movf    STATUS,0
	movwf   savest
               movf    PCLATH,0
               movwf   savepclath
        btfss   INTCON,T0IF
	goto    nottimer0
	bcf     INTCON,T0IF
	call    func
nottimer0
        movf    savepclath,0
        movwf   PCLATH
        movf    savest,0
	movwf	STATUS
	movf    savew,0
        retfie
        endm
postscaler_init macro rate
        #define post_rate rate
	cblock
	 post_count
	endc
	movlw	post_rate
	movwf	post_count
	endm

postscaler_prg macro func
postscaler
	decfsz	post_count
	return
	movlw	post_rate
	movwf	post_count
	call    func
	return
	endm
duty_init macro 
	 cblock
	 duty_ratio,duty_period,duty_counter
	 endc
	 endm

duty_prg macro func_off, func_on
duty
	movf    duty_counter,0
	subwf	duty_ratio,0
	btfsc	STATUS,C
	goto    duty_on
	call	func_off
	goto	duty_end
duty_on
	call    func_on
duty_end
	decfsz	duty_counter
	return 
	movf     duty_period,0
	movwf	duty_counter
	return
	endm
set_rate_by_counter_prg macro
set_rate_by_counter
        movf    counter,0
	call    getduty
	movwf	duty_ratio
	return
	endm
getduty_prg macro
getduty
        addwf   PCL,1
startduty
;	retlw   d'128'
	retlw   d'64'
	retlw   d'32'
	retlw   d'16'
	retlw   d'8'
	retlw   d'4'
	retlw   d'2'
	retlw   d'1'
endduty
        endm
porta_init macro
	cblock
	patterna
	endc
	movlw	b'11111111'
	movwf	patterna
	endm
porta_prg macro
porta_on
        movf    patterna,0
	movwf	PORTA
	return

porta_off
	clrf	PORTA
	return
	endm

timer01_init macro timer0mode,timer1mode
	cblock 
	 savew
	 savest
                savepclath
	endc
	clrwdt
	movlw	timer1mode
	movwf	T1CON
	banksel OPTION_REG
	movlw   timer0mode
	movwf   OPTION_REG
	bsf		PIE1,TMR1IE
	banksel INTCON
	bsf     INTCON,T0IE
	bcf	INTCON,T0IF
	bcf	PIR1,TMR1IF
	bsf	INTCON,GIE
	endm

timer01_prg macro func0,func1
timer01 
    movwf   savew
	movf    STATUS,0
	movwf   savest
               movf    PCLATH,0
               movwf   savepclath
    btfss   INTCON,T0IF
	goto    nottimer0
	bcf     INTCON,T0IF
	call    func0
;	goto	intend
nottimer0
    btfss   PIR1,TMR1IF
	goto    intend
	bcf     PIR1,TMR1IF
	call    func1
intend
    movf    savepclath,0
    movwf   PCLATH
    movf    savest,0
	movwf	STATUS
	movf    savew,0
    retfie
	endm


starttimer1	macro
	clrf	TMR1H
	clrf	TMR1L
	bsf		T1CON,TMR1ON
	endm
stoptimer1	macro
	bcf		T1CON,TMR1ON
	endm



	list

開発メモ

会得したコツ

始めにやることは、リーダー部を検出するプログラムを作ること。 このとき、きちんとエラー処理のしかたも考える。 内部状態を出力できるようにして、理論値と比較する。

実際のリモコンのデータをディジタルオシロスコープで読み、実データからデ バッガ用のタイミングデータを作る。 MPLAB の Stimulus の pin/Register Actions にデータを再現する。 これで、読み込みプログラムが合っているかどうかの把握が容易になる。

本番回路の前に必ずデバッグ用の回路を制作する。 回路ごとに Project を作り、共通部分、個別部分の切り分けを行う。

テスト用プログラム

16F628A を使用したリーダの認識のみのプログラム


#include "sakamoto628a.inc"



IRTOTALMAX equ d'200'
LEADERMIN	equ d'17'
LEADERMAX	equ	d'20'
OK		equ d'1'
TIMEOUT	equ d'2'
FORMATERR	equ d'3'

	cblock
		irdata
		ircounter
		irtotal
		irstatus
		iroutstatus	
	endc





	org	0x0000
	goto	start
	org	0x0004
	goto	timer0
	org	0x0008

start
	movlw	0x07
	movwf	CMCON
	banksel TRISA
	movlw   b'00100000'
	movwf   TRISA
	banksel PORTA
	clrf    PORTA
	clrf	irstatus
	clrf	iroutstatus
	timer0_init b'11010000' ; 内部クロック、 PS=1:256

main
		movf	iroutstatus,1
		btfsc	STATUS,Z
		goto	main
		movlw	b'11111100'
		iorwf	iroutstatus,0
		andwf	PORTA,1
		movlw	b'00000011'
		andwf	iroutstatus,0
		iorwf	PORTA,1
        goto    main

	timer0_prg ircontrol





ircontrol
	btfss	PORTA,5
	goto	iroff
iron
	bsf		STATUS,C
	goto	calcir
iroff
	bcf		STATUS,C
calcir
	rlf		irdata,1
	movlw	b'00000011'
	andwf	irdata,1

	incf	ircounter,1 ; irtotal > 108ms でタイムアウト
	incf	irtotal,1
	movlw	IRTOTALMAX
	subwf	irtotal,0
	btfss	STATUS,C
	goto	irprocess
	clrf	irtotal
	clrf	ircounter
	movf	irstatus,1
	btfsc	STATUS,Z	; タイムアウトで irstatus が 0 でないなら
	goto	clearstatus
	movlw	TIMEOUT		; iroutstatus ← TIMEOUT
	movwf	iroutstatus
	goto	irprocess
clearstatus
	clrf	iroutstatus
irprocess
	movf	iroutstatus,1
	btfss	STATUS,Z
	goto	endprocess
	movf	irstatus,0
	addwf	PCL,1
	goto	initial
	goto	leader
;	goto	blanc
;	goto	datain

initial
	btfsc	irdata,0
	return				; RA5 = on ならそのまま
	clrf	irtotal		; RA5 = off なら検出開始
	clrf	iroutstatus
	clrf	ircounter
	movlw	d'1'	; leader
	movwf	irstatus
	goto	endprocess
leader					; leader 検出
	btfsc	irdata,0	
	goto	change		; RA5 = on なら off → on を検出
	movlw	LEADERMAX	; leader の off 長 > LEADERMAX ならタイムアウト
	subwf	ircounter,0
	btfss	STATUS,C
	goto	endprocess
	goto	timeouterr
change
	movlw	LEADERMIN	; leader の off 長 < LEADERMIN ならフォーマットエラー
	subwf	ircounter,0
	btfss	STATUS,C
	goto	formaterr
	clrf	ircounter

	movlw	d'0'	; initial
	movwf	irstatus
	movlw	OK
	movwf	iroutstatus
	goto	endprocess	

endprocess
	return

timeouterr
	movlw	TIMEOUT
	movwf	iroutstatus
	goto	errend
formaterr
	movlw	FORMATERR
	movwf	iroutstatus
errend
	clrf	irtotal
	clrf	ircounter
	clrf	irstatus
	return
	end

坂本直志 <[email protected]>
東京電機大学工学部情報通信工学科