Assembler code for the ATtiny13 IR receiver and switch

;
; ***************************************
; * IR-Switch 3-Channel with ATtiny13   *
; * (C)2016 by www.avr-asm-tutorial.net *
; ***************************************
;
; -------- Switches -------------
.equ cActiveH = 0 ; 1 = Outputs Aktive High
;
.NOLIST
.INCLUDE "tn13def.inc"
.LIST
;
; Hardware: ATtiny13
;                _________
;               /         |
;   +5V/10k o--|Reset  VCC|--o +5V
;              |          |
;       Key o--|PB3    PB2|--o Output ye
;              |          |
; Output gn o--|PB4    PB1|--o TSOP1740
;              |          |
;        0V o--|GND    PB0|--o Output rd
;              |__________|
;
; -------- Ports, Portpins ----------
	; Ports
	.equ pOut = PORTB ; Output port tn13
	.equ pDir = DDRB ; Direction port tn13
	.equ pIn  = PINB ; Input port tn13
	; Portbits
	.equ bIrO = PORTB1 ; IR-Receiver Output
	.equ bIrD = DDB1 ; IR-Receiver Direction
	.equ bIrI = PINB1 ; IR-Receiver Input
	.equ bRdO = PORTB0 ; Switch output red
	.equ bRdD = DDB0 ; Direction red
	.equ bYeO = PORTB2 ; Switch output yellow
	.equ bGeD = DDB2 ; Direction yellow
	.equ bGnO = PORTB4 ; Switch output green
	.equ bGnD = DDB4 ; Direction green
	.equ bKyO = PORTB3 ; Key Input Pullup
	.equ bKyI = PINB3 ; Key Input pin
;
; -------- Timing, IR-Signals -------
	; Clock:              1200000 Hz
	; TC0-Prescale             64
	; TC0-Tick             18,750 cs/s  
	;                          53.33 us 
	; TC0-Overflow         13,563 us
	.equ cTcTick = 53
	;
;
; Zero/One-Level:
.equ cOne = 868/cTcTick ; tn13:16
; Header/Data-Level:
.equ cHeader = 4*cOne ; tn13:48 
; Delay pause after last received bit:
.equ cChk = 1
; Half Second, MSB
.equ cSekH = 500000/cTcTick / 256 ; tn13: 36
; 
; -------- Registers -----------------
; R0 not used
.def rBits= R5 ; Received bits
.def rBitsO=R6 ; Received bits, display
.def rOne= R7 ; Zero/One-level
.def rI1L = R8 ; prelast bit burst, LSB
.def rI1H = R9 ; dto., MSB
.def rI0L = R10 ; last bit burst, LSB
.def rI0H = R11 ; dto., MSB
.def rIRL = R12 ; current bit burst, LSB
.def rIRH = R13 ; dto., MSB
.def rCntH= R14 ; MSB TC0-counter
.def rSreg= R15 ; SREG Status
.def rmp  = R16 ; Multi-purpose register
.def rimp = R17 ; dto., Interrupts
.def rFlag= R18 ; Flags
	.equ bOvf = 0 ; Overflow, check signal
	.equ bAdj = 1 ; Learning mode active
	.equ bSec = 2 ; End of half second
	.equ bLng = 3 ; Long confirmation
	.equ bTwo = 4 ; Second measuring
	.equ bEqu = 5 ; Equal burst 1 and 2
	.equ bDbl = 6 ; Double received
	.equ bErr = 7 ; Not equal
.def rSel = R19 ; 0: Red on, 1: Red off
; 2: Yellow on, 3: Yellow off, 4: Green on, 5: Green off
.def rCtr = R20 ; Counter EEPROM/Input
.def rmo = R21 ; for LED control
; R22 .. R25 ; unused
; Used: X for pointer operations
; Used: Y for Storing in SRAM
; Used: Z for diverse purposes
;
; -------- SRAM -------------
.DSEG
.ORG 0x0060
sBuffer: ; Data storage for averaging
.Byte 16 ; Zero and One duration
sBufferEnd:
;
sCodes:
.Byte 4 ; Detection code Red, On/Off
.Byte 4 ; dto., Yellow, On/Off
.Byte 4 ; dto., Green, On/Off
sCodesKeyEnd:
sCodesOne:
.Byte 1 ; Zero/One-level
sCodesEnd:
;
; -------- Reset- and Int-Vectors ---
.CSEG
.ORG 0x0000
	rjmp Start ; RESET-Vektor
	rjmp Int0Isr ; INT0 Ext. Int Request 0
	reti ; PCINT0 Pin Change Int Request 0
	rjmp TC0OIsr ; TIM0_OVF TC0 Overflow
	reti ; EE_RDY EEPROM Ready
	reti ; ANA_COMP Analog Comparator
	reti ; TIM0_COMPA TC0 Compare Match A
	reti ; TIM0_COMPB TC0 Compare Match B
	reti ; WDT Watchdog Time-out
	reti ; ADC ADC Conversion Complete
;
; -------- Int Service routines ------
; Analyze pulse from IR-receiver
Int0Isr: ; ATtiny13 INT0-Interrupt
	in rSreg,SREG ; Save SREG
	tst rCntH ; Long signal?
	brne Int0IsrLong
	in rimp,TCNT0
	cpi rimp,cHeader ; longer than header
	brcs Int0IsrShort
	; Header signal received, start new
Int0IsrLong:
	clr rimp ; restart counter
	out TCNT0,rimp
	clr rCntH ; clear MSB counter byte
	mov rBitsO,rBits
	clr rBits ; received bits to 0
	clr rIRL ; clear bit sampler register
	clr rIRH
	out SREG,rSreg ; done
	reti
Int0IsrShort:
	; Short data  signal
	in rimp,TCNT0 ; read timer
	st Y+,rimp ; store in SRAM
	cp rOne,rimp ; compare with zero/one level
	rol rIRL ; shift bit into sample registers
	rol rIRH
	inc rBits ; increase number of bits
	cpi YL,Low(sBufferEnd) ; pointer end?
	brne Int0IsrRet ; not beyond
	ldi YH,High(sBuffer) ; New start,
	ldi YL,Low(sBuffer) ; to the buffer start
Int0IsrRet:
	; Return from short signal
	clr rimp ; clear timer
	out TCNT0,rimp
	out SREG,rSreg ; restore SREG
	reti
;
; Analyze counter overflows
TC0OIsr:
	in rSreg,SREG ; save SREG
	inc rCntH ; count overflows
	mov rimp,rCntH ; longer pause?
	cpi rimp,cSekH ; half second over?
	brne TC0OIsr1
	sbr rFlag,1<<bSec ; set second flag
	clr rCntH
	rjmp TC0OIsrRet
TC0OIsr1:
	cpi rimp,cChk ; check?
	brne TC0OIsrRet
	tst rBits
	breq TC0OIsrRet
	mov rI0H,rIRH ; save received bits
	mov rI0L,rIRL ; into zero storage
	mov rBitsO,rBits ; Copy number of bits
	clr rBits
TC0OIsrRet:
	out SREG,rSreg ; restore SREG
	reti
;
; -------- Start, Init ------
Start:
	; Init stack
	ldi rmp,LOW(RAMEND)
	out SPL,rmp
	; Init port directions
	sbi pDir,bRdD ; Outputs, Direction
	sbi pDir,bGeD
	sbi pDir,bGnD
	; Port outputs inactive
.if cActiveH == 1
	cbi pOut,bRdO ; Outputs, start values
	cbi pOut,bYeO
	cbi pOut,bGnO
	.else
	sbi pOut,bRdO
	sbi pOut,bYeO
	sbi pOut,bGnO
	.endif
	; Init key and IR receiver input
	sbi pOut,bIrO ; Pullup IR receiver
	; Clear flags
	clr rFlag
	; Pre value zero/one level
	ldi rmp,cOne
	mov rOne,rmp
	; Buffer pointer for value storage
	ldi YH,High(sBuffer)
	ldi YL,Low(sBuffer)
	; Read detection values from EEPROM
	rcall ReadCodes
	lds rOne,sCodesOne
	; If key active adjust
	nop ; wait a while
	nop
	sbis pIn,bKyI ; if key input inactive
	sbr rFlag,1<<bAdj ; switch into learning mode
	; Start timer TC0
	ldi rmp,(1<<CS01)|(1<<CS00) ; Prescale by 64
	out TCCR0B,rmp
	ldi rmp,1<<TOIE0 ; Overflow Int
	out TIMSK0,rmp
	; Sleep mode idle, INT0/PCINT0 IR signals
	ldi rmp,(1<<SE)|(1<<ISC01)
	out MCUCR,rmp
	ldi rmp,1<<INT0 ; INT0-Interrupts
	out GIMSK,rmp
	; Interrupts enable
	sei
Loop:
	sleep ; Sleep
	nop ; wake up
	sbrc rFlag,bOvf ; Analyze overflow?
	rcall Overflow ; yes
	sbrc rFlag,bSec ; Second clock?
	rcall Second ; yes
	rjmp Loop
;
Second:
	; Half second over
	cbr rFlag,1<<bSec
	; Only in Adjust mode
	sbrs rFlag,bAdj
	ret ; not adjust
	; Long On phase?
	sbrs rFlag,bLng ; Confirmation?
	rjmp LedBlink ; No
	; Long On phase ending?
	dec rCtr ; Count five seconds
	brne SecondRet ; No
	; Long On phase ending
	cbr rFlag,1<<bLng ; Flag clear
	; Next input position
	rcall LedOff ; current LED off
	subi rSel,-2 ; add two
	cpi rSel,6 ; until rSel = 6
	brcs LedBlink ; not yet
	brne SecondEnd ; all adjusted
	ldi rSel,1 ; go on with Off codes
	rjmp LedBlink ; blink
SecondEnd:
	; all channels adjusted
	rcall WriteCodes ; Write codes to EEPROM
	clr rSel ; Restart with channel Zero
	cbr rFlag,1<<bAdj ; Clear adjust
	; All outputs off
.if cActiveH == 1
	cbi pOut,bRdO ; Output low
	cbi pOut,bYeO
	cbi pOut,bGnO
	.else
	sbi pOut,bRdO ; Output high
	sbi pOut,bYeO
	sbi pOut,bGnO
	.endif
SecondRet:
	ret
;
; Blink LED in rSel
LedBlink:
	rcall GetOutPin ; Aktive pin to rmp
	in rmo,pOut ; Read pins
	eor rmp,rmo ; Reverse polarity
	out pOut,rmp ; Write pins
	ret
;
; LED rSel on
LedOn:
	rcall GetOutPin ; Aktive pin to rmp
	in rmo,pOut ; Read pins
.if cActiveH == 1
	or rmp,rmo ; Activate pin
	.else
	com rmp ; invert
	and rmp,rmo ; Pin to zero
	.endif
	out pOut,rmp ; Write pins
	ret
;
; LED rSel off
LedOff:
	rcall GetOutPin ; Aktive pin to rmp
	in rmo,pOut ; Read pins
.if cActiveH == 1
	com rmp ; invert
	and rmp,rmo ; Pin to zero
	.else
	or rmp,rmo ; Pin to one
	.endif
	out pOut,rmp ; Write pins
	ret
;
; Read current output to rmp
GetOutPin:
	mov rmp,rSel ; Current position
	lsr rmp ; Shift out On/Off bit
	cpi rmp,1 ; Yellow LED active?
	brcs GetOutPinRt ; no, red
	brne GetOutPinGn ; no, green
	ldi rmp,1<<bYeO ; Yellow
	ret
GetOutPinRt:
	ldi rmp,1<<bRdO ; Red
	ret
GetOutPinGn:
	ldi rmp,1<<bGnO ; Green
	ret
;
; Overflow of timer, output result
;
Overflow:
	cbr rFlag,1<<bOvf ; Flagge clear
	; Check if learning mode
	sbrs rFlag,bAdj
	rjmp OverflowCheck ; no
	; From here learning mode
OverflowCalc:
	clr rmp ; Ints off
	out GIMSK,rmp
	out TIMSK0,rmp
	; Average duration of the last 16 data bits
	ldi ZH,High(sBuffer) ; Buffer start
	ldi ZL,Low(sBuffer)
	clr XH ; X is sum
	clr XL
OverflowSum:
	ld rmp,Z+ ; Byte from buffer
	add XL,rmp ; add
	ldi rmp,0 ; Overflow treatment
	adc XH,rmp
	cpi ZL,LOW(sBufferEnd) ; End?
	brne OverflowSum ; no, go on
	lsr XH ; div by 2
	ror XL
	lsr XH ; div by 4
	ror XL
	lsr XH ; div by 8
	ror XL
	lsr XH ; div by 16
	ror XL
	mov rOne,XL ; to detection register
	sts sCodesOne,XL ; and to SRAM
	; Compare two measurements
	sbrc rFlag,bTwo ; Second burst?
	rjmp OverflowZwei ; Compare both
	sbr rFlag,1<<bTwo ; Set flag
	mov rI1L,rI0L ; Copy value
	mov rI1H,rI0H
	rjmp OverflowNormal
OverflowZwei:
	; Compare second burst
	cbr rFlag,(1<<bTwo)|(1<<bEqu)
	cp rI1L,rI0L ; Compare LSB
	brne OverflowNormal ; unequal
	cp rI1H,rI0H ; Compare MSB
	brne OverflowNormal ; unequal
	; Equal, check already defined
	sbr rFlag,1<<bEqu ; Equal flag
	ldi XH,High(sCodes) ; X on codes
	ldi XL,Low(sCodes) ; in SRAM
OverflowDoppel:
	cpi XL,Low(sCodesKeyEnd)
	breq OverflowTasteOk ; Compare end of list
	ld rmp,X+ ; Read LSB
	cp rmp,rI1L ; compare LSB
	ld rmp,X+ ; Read MSB
	brne OverflowDoppel ; Already in list
	cp rmp,rI1H ; compare MSB
	brne OverflowDoppel ; 
	sbr rFlag,1<<bDbl ; Double flag
	rjmp OverflowNormal
	; Store Code, start long pause
OverflowTasteOk:
	ldi XH,High(sCodes) ; To code start
	ldi XL,Low(sCodes)
	mov rmp,rSel ; active output
	lsl rmp ; multiplied by two
	add XL,rmp ; Add to pointer
	ldi rmp,0 ; Overflow treatment
	adc XH,rmp
	st X+,rI1L ; Store value
	st X,rI1H
	rcall LedOn ; LED on
	ldi rCtr,5 ; long pause
	sbr rFlag,(1<<bEqu)|(1<<bLng)
	rjmp OverflowNormal
OverflowCheck:
	; Check received data set
	ldi XH,High(sCodes) ; Pointer to codes
	ldi XL,Low(sCodes)
	ser rSel ; Start witt 0xFF
OverflowCheck1:
	inc rSel ; Next value
	cpi rSel,6 ; End reached?
	brcc OverflowNf ; yes
	ld rmp,X+ ; Read value from SRAM
	cp rmp,rI0L ; Compare LSB
	ld rmp,X+ ; Read MSB
	brne OverflowCheck1 ; unequal
	cp rmp,rI0H ; Compare MSB
	brne OverflowCheck1 ; unequal
	; Correct code received
	cbr rFlag,(1<<bErr)|(1<<bDbl)
	sbrs rSel,0 ; Pin to on?
	rcall LedOn ; Pin on
	sbrc rSel,0 ; Pin off?
	rcall LedOff ; Pin off
	mov rI1H,rI0H ; Copy value
	mov rI1L,rI0L
	rjmp OverflowNormal
OverflowNf:
	; No match found
	clr rSel ; Set zero
	sbr rFlag,1<<bErr ; Set flag
OverflowNormal:
	; Enable interrupts
	clr rCntH
	ldi rmp,1<<TOIE0 ; Timer Int
	out TIMSK0,rmp
	ldi rmp,1<<INT0 ; INT0-Interrupts
	out GIMSK,rmp
	ret
;
; Read codes from EEPROM
ReadCodes:
	ldi ZH,0 ; Pointer to EEPROM address
	ldi ZL,0
	ldi XH,High(sCodes) ; Pointer to SRAM
	ldi XL,Low(sCodes)
	ldi rmp,sCodesEnd-sCodes ; Number
	mov rCtr,rmp
ReadCodes1:
	sbic EECR,EEPE ; wait until ready
	rjmp ReadCodes1
	out EEARL,ZL ; Address counter
	sbi EECR,EERE ; Read enable
	in rmp,EEDR ; Read byte
	st X+,rmp ; store in SRAM
	adiw ZL,1 ; Next address
	dec rCtr ; Counter
	brne ReadCodes1 ; Read on
	cpi rmp,0x00 ; Zero/One at zero?
	breq ReadCodes2 ; yes, data is corrupt
	cpi rmp,0xFF ; Zero/One on FF?
	brne ReadCodes3 ; Yes, data is corrupt
ReadCodes2:
	rjmp StartInput ; Data corrupt, start new
ReadCodes3: ; Data is ok
	ret
;
; Write codes to EEPROM
WriteCodes:
	ldi ZH,0 ; Pointer to EEPROM address
	ldi ZL,0
	ldi XH,High(sCodes) ; Pointer to SRAM
	ldi XL,Low(sCodes)
	ldi rmp,sCodesEnd-sCodes
	mov rCtr,rmp
WriteCodes1:
	sbic EECR,EEPE ; Wait until ready
	rjmp WriteCodes1 ; Wait on
	clr rmp ; Erase and write
	out EECR,rmp
	out EEARL,ZL ; Address write
	ld rmp,X+ ; Read byte from SRAM
	out EEDR,rmp ; to EEPROM data register
	cli ; disable ints to avoid timeout
	sbi EECR, EEMPE ; Master Program Enable
	sbi EECR, EEPE ; Program enable
	sei ; enable Interrupts
	adiw ZL,1 ; Increase address
	dec rCtr ; Byte counter
	brne WriteCodes1 ; go on
	ret
;
; Delete all codes
; Set default Zero/One level
; Channel zero
; Set adjust flag
StartInput:
	ldi ZH,High(sCodes) ; Pointer
	ldi ZL,Low(sCodes)
	clr rmp ; Zero
StartInput1:
	st Z+,rmp ; Delete codes
	cpi ZL,Low(sCodesEnd) ; End?
	brne StartInput1 ; continue
	ldi rmp,cOne ; Default Zero/One
	sts sCodesOne,rmp ; to SRAM
	mov rOne,rmp ; And in register
	clr rSel ; Restart
	sbr rFlag,1<<bAdj ; Lerning mode
	ret
;
; Presetting of codes
; (Example TV remote control)
.ESEG
.ORG 0x00
EeBeg:
 ; red, key 1 on, key 4 off
  .DW 0x0835,0xC8F5
 ; yellow, key 2 on, key 5 off
  .DW 0x88B5,0x2815
 ; green, key 3 on, key 6 off
  .DW 0x4875,0xA895
  ; Zero/One level
  .DB cOne
EeEnd:
;
; End of source code
;



©2016 by http://www.avr-asm-tutorial.net