(NECの)テレビリモコンを使用して、チャンネルコードを受信します。 赤外線リモコンのコードは次のように NEC から公開されています。 http://www.necel.com/ja/faq/mi_com/__com_remo.html
赤外線センサーはGP3 に接続する。 また、GP4 が Low の時は出力信号はホールドされるが、 High のときは 1 秒だけホールドされ 0 に戻る(未実装)。
出力は GP5, GP2, GP1, GP0 の 4bit で出力します。
リモコンボタン、送信コード、出力の割り当ては以下のとおりです。
ボタン | コード | 出力 |
---|---|---|
1 | 18 E7 08 F7 | 1 |
2 | 18 E7 88 77 | 2 |
3 | 18 E7 48 B7 | 3 |
4 | 18 E7 C8 37 | 4 |
5 | 18 E7 28 D7 | 5 |
6 | 18 E7 A8 57 | 6 |
7 | 18 E7 68 97 | 7 |
8 | 18 E7 E8 17 | 8 |
9 | 18 E7 18 E7 | 9 |
10 | 18 E7 98 67 | A |
11 | 18 E7 58 A7 | B |
12 | 18 E7 D8 27 | C |
Vol+ | 18 E7 40 BF | D |
Vol- | 18 E7 C0 3F | E |
電源 | 18 E7 10 EF | F |
Ch+ | 18 E7 00 FF | 未割当 |
Ch- | 18 E7 80 7F | 未割当 |
12F629 は出力ピンが少ないため、互換性がそれなりにある 16F628A で開発を 行い、フィードバックを行う。 そのため、初期化と入出力の定義の部分だけ別にし、リモコンの処理自体は共 通ソースで開発する。
赤外線センサは 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 ずつ増やし、対象の時間と比較する。
各エラー処理は次の通りである。
なお、以上をふまえ、各状態ごとの処理の前の共通の処理は次のようになる。
; 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
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
#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
; sakamoto629.inc
; sakamoto629 マクロ ver 1.0
; written by Naoshi SAKAMOTO sakamoto@c.dendai.ac.jp
;
;初期化
;
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
#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
; sakamoto628a.inc
; written by Naoshi SAKAMOTO sakamoto@c.dendai.ac.jp
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
#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
; written by Naoshi SAKAMOTO sakamoto@c.dendai.ac.jp
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