;***************************************************************************** ; ; Program HDTEST.ASM ; Author Wim de Vree, pe1grl@amsat.org ; ; Revision history ; ; 2009-06-12 Initial setup for an IR controller program to skip ads on ; a Stein (Yakuma HDD recorder). The length of the ad-block is ; about 330 seconds so send a sequence of commands to get through ; this. ; 2009-06-13 Real World experiments done ; Now uses sleep mode, changed CONFIG to minimize current drawn ; 2009-06-20 Port to 12F683 (no 12F629 available at this time) ; 2009-06-21 Rewrite for 1 button operation (I could not find two matching ; buttons. The one-button version uses GPIO bit 5) ;============================================================================= LIST P=PIC12F683, F=INHX8M __CONFIG _CP_OFF & _WDT_OFF & _INTRC_OSC_CLKOUT & _BOD_OFF & 0x31FF include include "../inc/macros.inc" ;***************************************************************************** ; Equates, I/O, vars ;***************************************************************************** RESET_V EQU 0x0000 ; Address of RESET Vector ISR_V EQU 0x0004 ; Address of Interrupt Vector CLOCKFREQ EQU .4000 ; Some time constants for NEC IR protocol ; '0' – a 562.5µs pulse followed by a 562.5µs space, total transmit time of 1.125ms ; '1' – a 562.5µs pulse followed by a 1687.5us space, total transmit time of 2.25ms ; ; Transmission block: ; - a 9ms leading pulse burst (16 times the pulse burst length used for a logical data bit) ; - a 4.5ms space ; - the 8-bit HI address for the receiving device (Extended NEC protocol) ; - the 8-bit LO address for the receiving device ; - the 8-bit command ; - the 8-bit logical inverse of the command T_9000 equ (.65538-.9000) ; 9 milliseconds leading burst T_4500 equ (.65538-.4500) ; 4.5 milliseconds leading delay T_562 equ (.65538- .562) ; Burst / Idle for '0's T_1125 equ (.65538-.1125) ; Additional Idle for '1's LO_TONE equ .1573 ; 1200 Hz (20u) HI_TONE equ .2883 ; 2200 Hz (20u) DDS_CNT equ .99 ; 20 Mhz / 4 HDREC_ADDRHI equ 0xE8 ; 11101000 HDREC_ADDRLO equ 0x96 ; 10010110 HDREC_PLAY equ 0xD8 ; 11011000 HDREC_FASTFWD equ 0xAA ; 10101010 #define LED GPIO,2 #define SWITCH GPIO,5 ; Smart switch ; pressed < .4sec : 1 minute skip ; pressed > .4sec : 7 minute skip ;***************************************************************************** ; Variable definitions ;***************************************************************************** CBLOCK 0x20 IRCommand ; Command to send IRByte ; Byte to send BitCount LoopCount d1,d2,d3 ENDC ;***************************************************************************** ; Program start ;***************************************************************************** ORG RESET_V ; RESET vector location RESET GOTO START ;***************************************************************************** ; BEGIN OF MAIN CODE ;***************************************************************************** START: ; POWER_ON Reset (Beginning of program) clrf STATUS ; Do initialization, Select bank 0 clrf INTCON ; Clear int-flags, Disable interrupts clrf PCLATH ; Keep in lower 2KByte clrf GPIO ; ALL PORT output should output Low. movlw 0x07 movwf CMCON0 ; Disable comparators clrf ADCON0 ; A/D off BANK1 clrf VRCON ; Vref off clrf ANSEL MOVLW b'11111011' MOVWF TRISIO bsf OPTION_REG,NOT_GPPU movlw b'00110011' ; Enable weak pullups on inputs movwf WPU movlw b'00100000' ; Enable int_on_change on 5 movwf IOC ; movlw b'00011111' ; If fine tuning is needed uncomment ; movwf OSCTUNE ; these lines and test for best value BANK0 bsf INTCON,GPIE ; Enable int_on_change for WakeUp MainCode: movfw GPIO ; Dummy Read to clr RBIF bcf INTCON,GPIF clrf T1CON ; Timer1 off clrwdt sleep ; Reduce power requirement nop btfss SWITCH ; "Smart" Switch call DoSkipSmart goto MainCode ;----------------------------------------------------------------------------- ; Skip time is determined by the length the button is pressed. ; < 0.4 second: Skip 1 minute ; > 0.4 second: Skip 6 minutes DoSkipSmart: call Delay200ms call Delay200ms btfss SWITCH ; Still pressed ? goto DoSkip6Mins ; Yes, Long skip goto DoSkip1Min ; No, short skip ;----------------------------------------------------------------------------- ; Tuned to give a little longer delay than 6 minutes, ; for my HDD recorder about 7 minutes. ; (Commercial breaks are from 6m30s to 8m15s) DoSkip6Mins: movlw HDREC_FASTFWD call SendIRCommand ; Speed x2 call Delay500ms ; Sending commands too fast will movlw HDREC_FASTFWD ; crash the HDD software !!! call SendIRCommand ; Speed x4 call Delay500ms movlw HDREC_FASTFWD call SendIRCommand ; Speed x8 call Delay500ms movlw HDREC_FASTFWD call SendIRCommand ; Speed x16 call Delay500ms movlw HDREC_FASTFWD call SendIRCommand ; Speed x30 call Delay500ms movlw HDREC_FASTFWD call SendIRCommand ; Speed x60 call Delay500ms call Delay200ms ; Fine tuning, want a little bit longer movlw HDREC_FASTFWD call SendIRCommand ; Speed x100 movlw .16 ; Experimental determined value movwf LoopCount ; for a proper skip (abt 6min30s) call Delay200ms ; decfsz LoopCount,F ; goto $-2 movlw HDREC_PLAY call SendIRCommand return ;----------------------------------------------------------------------------- DoSkip1Min: movlw HDREC_FASTFWD call SendIRCommand ; Speed x2 call Delay500ms ; Sending commands too fast will movlw HDREC_FASTFWD ; crash the HDD software !!! call SendIRCommand ; Speed x4 call Delay500ms movlw HDREC_FASTFWD call SendIRCommand ; Speed x8 call Delay500ms movlw HDREC_FASTFWD call SendIRCommand ; Speed x16 call Delay500ms movlw HDREC_FASTFWD call SendIRCommand ; Speed x30 movlw .6 ; Experimental determined value movwf LoopCount ; for a proper skip (abt. 1min05s) call Delay200ms decfsz LoopCount,F goto $-2 movlw HDREC_PLAY ; Back to Play call SendIRCommand return ;----------------------------------------------------------------------------- SendIRCommand: movwf IRCommand movlw high T_9000 ; Load 9 millisecond Leading pulse movwf TMR1H movlw low T_9000 movwf TMR1L bsf T1CON,TMR1ON ; turn on TMR1 bcf PIR1,TMR1IF ; clear flag call SendBurst movlw high T_4500 ; 4.5 msec Idle Time movwf TMR1H movlw low T_4500 addwf TMR1L,F ; add already expired time skpnc incf TMR1H,F ; if carry, inc. tmrhi bcf PIR1,TMR1IF ; clear tmr overrun flag btfss PIR1,TMR1IF ; Time expired ? goto $-1 movlw HDREC_ADDRHI call SendByte movlw HDREC_ADDRLO call SendByte movf IRCommand,W ; Send selected COMMAND call SendByte comf IRCommand,W ; and its COMPLEMENT call SendByte call SendBitBurst ; Signify end of transmission return ;----------------------------------------------------------------------------- SendByte: movwf IRByte movlw .8 ; 8 bits to do movwf BitCount _nextBit call SendBitBurst ; 562 usec active call Do_0_Delay ; 0 = 562 usec idle rlf IRByte,F skpnc call Do_Add1_Delay ; 1 = 1867 usec idle decfsz BitCount,F goto _nextBit return ;----------------------------------------------------------------------------- Do_0_Delay movlw high T_562 ; 562 usec idle time movwf TMR1H movlw low T_562 addwf TMR1L,F ; add already expired time skpnc incf TMR1H,F ; if carry, inc. tmrhi bcf PIR1,TMR1IF ; clear tmr overrun flag btfss PIR1,TMR1IF ; Time expired ? goto $-1 return ;----------------------------------------------------------------------------- Do_Add1_Delay movlw high T_1125 ; 562+1125 usec idle time movwf TMR1H movlw low T_1125 addwf TMR1L,F ; add already expired time skpnc incf TMR1H,F ; if carry, inc. tmrhi bcf PIR1,TMR1IF ; clear tmr overrun flag btfss PIR1,TMR1IF ; Time expired ? goto $-1 return ;----------------------------------------------------------------------------- ; Transmit the active part (562 usec) of each bit SendBitBurst: movlw high T_562 ; 4.5 msec Idle Time movwf TMR1H movlw low T_562 addwf TMR1L,F ; add already expired time skpnc incf TMR1H,F ; if carry, inc. tmrhi bcf PIR1,TMR1IF ; clear tmr overrun flag SendBurst: bsf LED ; Emit an IR signal until TMR1 expires btfsc PIR1,TMR1IF ; Check if time is expired goto _burstDone ; Waste a total of 13 cycles btfsc PIR1,TMR1IF ; in the LED ON state goto _burstDone btfsc PIR1,TMR1IF goto _burstDone btfsc PIR1,TMR1IF goto _burstDone btfsc PIR1,TMR1IF goto _burstDone btfsc PIR1,TMR1IF goto _burstDone bcf LED btfsc PIR1,TMR1IF ; Check if time is expired goto _burstDone ; Waste a total of 13 cycles btfsc PIR1,TMR1IF ; in the LED OFF state goto _burstDone btfsc PIR1,TMR1IF goto _burstDone btfsc PIR1,TMR1IF goto _burstDone btfsc PIR1,TMR1IF goto _burstDone goto SendBurst _burstDone bcf LED ; Make sure its off return ;----------------------------------------------------------------------------- Delay200ms movlw 0x3E ;199993 cycles movwf d1 movlw 0x9D movwf d2 Delay200ms_0 decfsz d1, f goto $+2 decfsz d2, f goto Delay200ms_0 goto $+1 ;3 cycles nop return ;4 cycles (including call) Delay500ms movlw 0x03 ;499994 cycles ;----------------------------------------------------------------------------- movwf d1 movlw 0x18 movwf d2 movlw 0x02 movwf d3 Delay500ms_0 decfsz d1, f goto $+2 decfsz d2, f goto $+2 decfsz d3, f goto Delay500ms_0 goto $+1 ;2 cycles return ;4 cycles (including call) END