Pfad: Home => AVR-Übersicht => IR-Steuerungen => Analyse IR-Transmitter

Analyse von IR-Fernsteuerungen mit AVR ATmega8



;
; **********************************************
; * Measure signal durations for IR receivers  *
; * Version 1 as of October 2010               *
; * (C)2010 by http://www.avr-asm-tutorial.net *
; **********************************************
;
; Included header file for target AVR type
.NOLIST
.INCLUDE "m8def.inc" ; Header for ATMEGA8
.LIST
;
; ============================================
; D E B E U G G I N G   I N F O R M A T I O N
; ============================================
;
.equ debug = 0 ; enable debugging infos over PORTB
;
; ============================================
;   H A R D W A R E   I N F O R M A T I O N   
; ============================================
;
; Receive and send over the RS232 interface
;   PD0 is RXD input (Pin 2)
;   PD1 is TXD output (Pin 3)
;
; Time measurement over INT0
;   PD2 is input for the time measurements (Pin 4)
;
; Output signal
;   1 second duration on PD3 (Pin 5)
;
; ============================================
;      P O R T S   A N D   P I N S 
; ============================================
;
; External interrupt measure pulse durations
.equ pExt0I = PIND
.equ pbExt0I = PIND2
; TxD and RxD in UART communication
.equ pTxdD = DDRD
.equ pbTxdD = DDD1
.equ pRxdD = DDRD
.equ pbRxdD = DDD0
; Time signal 1 s
.equ pOutD = DDRD
.equ pbOutD = DDD3
.equ pOutP = PORTD
.equ pbOutP = PORTD3
;
; ============================================
;    C O N S T A N T S   T O   C H A N G E 
; ============================================
;
.equ cClock = 9830400 ; Xtal clock @ 9.8304 MHz
.equ cBaud = 38400 ; Baudrate for RS232 TX and RX
;
; ============================================
;  F I X + D E R I V E D   C O N S T A N T S 
; ============================================
;
.equ cBaudDiv = cClock / 16 / cBaud - 1 ; Baudrate generator
.equ c10us = cClock / 100000 - 1 ; time bases
.equ c100us = cClock / 10000 - 1
.equ c1ms = cClock / 1000 - 1
.equ c10ms = cClock / 100 / 8 - 1
.equ cSec = cClock / 256 / 256
;
; ============================================
;   R E G I S T E R   D E F I N I T I O N S
; ============================================
;
; R0 used for lpm operations
.def rRes0 = R1 ; result bytes transfer from ext int
.def rRes1 = R2
.def rRes2 = R3
.def rD0 = R4 ; decimal subtractor bytes
.def rD1 = R5
.def rD2 = R6
.def rV0 = R7 ; binary to decimal conversion
.def rV1 = R8
.def rV2 = R9
; free: R10
.def rRBInL = R11 ; result buffer in pointer
.def rRBInH = R12
.def rRBOutL= R13 ; result buffer out pointer
.def rRBOutH= R14
.def rSreg = R15 ; save/restore SREG inside ints
.def rmp = R16 ; Multipurpose register outside ints
.def rimp = R17 ; Multipurpose register inside ints
.def rFlag = R18 ; Flag register
	.equ bMode0 = 0 ; Mode bit 0
	.equ bMode1 = 1 ; Mode bit 1
	.equ bMOn = 2 ; Measuring on
	.equ bXfer = 3 ; transfer of result ready
	.equ bTxData = 4 ; transmit data results
	.equ bTxBusy = 5 ; RS232 TX is busy
	.equ bRxLine = 6 ; RS232 end of line
; free: R19..R21
.def rSec = R22 ; Counter for second pulse
.def rCnt2 = R23 ; counter byte 2
.def rCnt0 = R24 ; counter byte 0
.def rCnt1 = R25 ; counter byte 1
; used: X as buffer pointer for RS232 transmit
; used: Y pointer outside int
; used: Z pointer outside int (inside int: restored)
;
; ============================================
;       S R A M   D E F I N I T I O N S
; ============================================
;
.DSEG
.ORG  0x0060 ; Start of SRAM
;
sRxBPtr: ; RS232 RX buffer pointer
.byte 2
sRxBSta: ; RS232 RX buffer start
.byte 8
sRxBEnd: ; RS232 RX buffer end
;
sTxBSta: ; RS232 TX buffer start
.byte 11
sTxBEnd: ; RS232 TX buffer end
;
sRBSta: ; Result buffer
.equ nResults = (RAMEND-sRBSta-20) / 3 ; number of packs
.byte 3*nResults
sRBEnd:
;
; Format: Label: .BYTE N ; reserve N Bytes from Label:
;
; ============================================
;   R E S E T   A N D   I N T   V E C T O R S
; ============================================
;
.CSEG
.ORG $0000
;
	rjmp Main ; Reset vector
	rjmp Int0Isr ; INT0 External Interrupt Request 0
	reti ; INT1 External Interrupt Request 1
	reti ; TIMER2 COMP Timer/Counter2 Compare Match
	reti ; TIMER2 OVF Timer/Counter2 Overflow
	rjmp Tc1C ; TIMER1 CAPT Timer/Counter1 Capture Event
	reti ; TIMER1 COMPA Timer/Counter1 Compare Match A
	reti ; TIMER1 COMPB Timer/Counter1 Compare Match B
	reti ; TIMER1 OVF Timer/Counter1 Overflow
	rjmp Tc0Isr ; TIMER0 OVF Timer/Counter0 Overflow
	reti ; SPI, STC Serial Transfer Complete
	rjmp IntRx ; USART, RXC USART, Rx Complete
	rjmp IntDre ; USART, UDRE USART Data Register Empty
	rjmp IntTxC ; USART, TXC USART, Tx Complete
	reti ; ADC ADC Conversion Complete
	reti ; EE_RDY EEPROM Ready
	reti ; ANA_COMP Analog Comparator
	reti ; TWI Two-wire Serial Interface
	reti ; SPM_RDY Store Program Memory Ready
;
; ============================================
;     I N T E R R U P T   S E R V I C E S
; ============================================
;
; Int0 service routine, low/high transition
Int0Isr:
	in rSreg,SREG ; save SREG
	sbis pExt0I,pbExt0I ; if input is low
	sbr rCnt2,0x40 ; set High-bit
	sbrc rFlag,bXfer ; transfer bit clear
	sbr rCnt2,0xC0 ; set X error
	sbr rFlag,1<<bXfer ; set transfer flag
	mov rRes2,rCnt2 ; copy result to transfer
	mov rRes1,rCnt1
	mov rRes0,rCnt0
	clr rCnt2 ; clear counter
	clr rCnt1
	clr rCnt0
.if debug == 1
	sbic PORTB,0
	rjmp Int0Isr1
	sbi PORTB,0
	rjmp Int0Isr2
Int0Isr1:
	cbi PORTB,0
Int0Isr2:
	.endif
	out SREG,rSreg ; restore SREG
	reti
;
; Timer/Counter Capture Event service routine
Tc1C:
	in rSreg,SREG ; save SREG
	adiw rCnt0,1 ; inc counter
	brne Tc1C1
	inc rCnt2 ; increase msb
	cpi rCnt2,0xC0 ; overflow?
	brcs Tc1C1
	ldi rCnt2,0x80 ; signal overflow
	mov rRes2,rCnt2 ; set transfer register
	clr rCnt2
	clr rRes1
	clr rRes0
	sbr rFlag,1<<bXfer ; set transfer bit
Tc1C1:
	out SREG,rSreg
	reti
; TC0 interrupt service routine
Tc0Isr:
	in rSreg,SREG ; save SREG
	dec rSec ; decrease counter
	brne Tc0Isr2
	ldi rSec,cSec ; restart counter
	sbic pOutP,pbOutP ; output zero?
	rjmp Tc0Isr1
	sbi pOutP,pbOutP ; set one
	rjmp Tc0Isr2
Tc0Isr1:
	cbi pOutP,pbOutP ; set zero
Tc0Isr2:
	out SREG,rSreg ; restore SREG
	reti
; RS232 RX service routine
IntRx:
	in rSreg,SREG ; save SREG
	in rimp,UCSRA ; read error flag
	andi rimp,(1<<FE)|(1<<DOR)|(1<<PE) ; check
	in rimp,UDR ; read data
	breq IntRx1 ; no error
	ldi rimp,'?' ; signal an error
IntRx1:
	out UDR,rimp ; echo character
	push ZH ; save Z
	push ZL
	lds ZL,sRxBPtr ; read RX buffer pointer
	lds ZH,sRxBPtr+1
	cpi rimp,0x08 ; backspace?
	brne IntRx2 ; no
	cpi ZL,LOW(sRxBSta) ; first buffer position?
	breq IntRx4 ; yes, ignore
	sbiw ZL,1 ; back one space
	rjmp IntRx3 ; save pointer
IntRx2:
	st Z+,rimp ; store character
	cpi ZL,LOW(sRxBEnd) ; beyond buffer end?
	brcc IntRx4 ; pointer beyond end
IntRx3:
	sts sRxBPtr,ZL ; save pointer
	sts sRxBPtr+1,ZH
IntRx4:
	pop ZL ; restore Z
	pop ZH
	cpi rimp,$0D ; new line?
	brne IntRx5
	sbr rFlag,1<<bRxLine
IntRx5:
	out SREG,rSreg
	reti
; RS232 UDRE service routine
IntDre:
	in rSreg,SREG
	ld rimp,X+ ; read next char
	out UDR,rimp ; sent character
.if debug == 1
	sbi PORTB,2
		.endif
	cpi rimp,0x0A ; last character?
	brne IntDre1 ; no
	ldi rimp,(1<<RXCIE)|(1<<TXCIE)|(1<<RXEN)|(1<<TXEN) ; enable TXC int
	out UCSRB,rimp
IntDre1:
	out SREG,rSreg ; restore SREG
	reti
; RS232 TX sent service routine
IntTxC:
	in rSreg,SREG
	cbr rFlag,1<<bTxBusy ; clear busy flag
	ldi rimp,(1<<RXCIE)|(1<<RXEN)|(1<<TXEN) ; disable TXC int
	out UCSRB,rimp
.if debug == 1
	cbi PORTB,1
	cbi PORTB,2
	.endif
	out SREG,rSreg
	reti
;
; ============================================
;     M A I N    P R O G R A M    I N I T
; ============================================
;
Main:
; Init stack
	ldi rmp, HIGH(RAMEND) ; Init MSB stack
	out SPH,rmp
	ldi rmp, LOW(RAMEND) ; Init LSB stack
	out SPL,rmp
; Clear flag bits
	clr rFlag ; set mode 10 us
; Init result buffer pointers
	ldi rmp,HIGH(sRBSta) ; set buffer pointers
	mov rRBInH,rmp
	mov rRBOutH,rmp
	ldi rmp,LOW(sRBSta)
	mov rRBInL,rmp
	mov rRBOutH,rmp
; Init RS232 receive buffer
	ldi rmp,HIGH(sRxBSta) ; Init buffer pointer
	sts sRxBPtr+1,rmp
	ldi rmp,LOW(sRxBSta)
	sts sRxBPtr,rmp
; Init Port for RS232
	sbi pTxdD,pbTxdD ; TX output
	cbi pRxdD,pbRxdD ; RX input
; Init RS232 hardware
	ldi rmp,HIGH(cBaudDiv) ; set baud rate
	out UBRRH,rmp
	ldi rmp,LOW(cBaudDiv)
	out UBRRL,rmp
	ldi rmp,(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0) ; Mode 8N1
	out UCSRC,rmp
	ldi rmp,(1<<RXEN)|(1<<TXEN)|(1<<RXCIE) ; RX and Int Enable
	out UCSRB,rmp
; Send characters over RS232
	rcall sendmenue
; Debugging info
.if debug == 1
	ldi rmp,0xFF ; Port B is output
	out DDRB,rmp
	.endif
; Init Timer 0
	sbi pOutD,pbOutD ; Port Bit for signal out
	ldi rmp,1<<CS02 ; prescaler = 256, start timer
	out TCCR0,rmp
; Init Timer 1
	ldi rmp,HIGH(c10us) ; set CTC value
	out ICR1H,rmp
	ldi rmp,LOW(c10us)
	out ICR1L,rmp
	; switch timer off
	clr rmp ; set mode timer/counter 1
	out TCCR1A,rmp
	ldi rmp,(1<<WGM13)|(1<<WGM12) ; stop timer
	out TCCR1B,rmp
	ldi rmp,1<<TOIE0 ; enable ints TC0, disable ints TC1
	out TIMSK,rmp
; Init general int control
	clr rmp ; external ints off
	out GICR,rmp
; Enable sleep mode idle
	ldi rmp,(1<<ISC00)|(1<<SE) ; sleep enable and external ints both edges on
	out MCUCR,rmp
	sei
;
; ============================================
;         P R O G R A M    L O O P
; ============================================
;
Loop:
	sleep ; go to sleep
	nop ; dummy for wake up
	sbrc rFlag,bXfer ; transfer of data?
	rcall Xfer
	sbrc rFlag,bRxLine ; RX line complete?
	rcall RxLine
	sbrc rFlag,bTxData ; data to transfer?
	rcall TxData
	rjmp loop ; go back to loop
;
; Transfer a result
;
Xfer:
	cli ; stop interrupts
	mov rD2,rRes2 ; copy result
	mov rD1,rRes1
	mov rD0,rRes0
	cbr rFlag,1<<bXfer ; clear transfer bit
	sei ; enable interrupts
.if debug == 1
	sbi PORTB,3
	.endif
	mov rmp,rFlag ; read flags
	andi rmp,0x03
	cpi rmp,0x03
	brne Xfer1
	mov rmp,rD2 ; copy upper error bits
	andi rmp,0xC0 ; isolate error bits
	mov R0,rmp ; store error bits
	ldi rmp,0x3F ; clear error bits
	and rD2,rmp
	lsr rD2 ; div by 8
	ror rD1
	ror rD0
	lsr rD2
	ror rD1
	ror rD0
	lsr rD2
	ror rD1
	ror rD0
	or rD2,R0
Xfer1:
	mov ZH,rRBInH ; copy in-pointer
	mov ZL,rRBInL
	st Z+,rD0 ; copy result to next buffer
	st Z+,rD1
	st Z+,rD2
	rcall Adjust
	mov rRBInH,ZH ; set pointer
	mov rRBInL,ZL
	sbr rFlag,1<<bTxData ; set flag
TxData:
	sbrc rFlag,bTxBusy ; Transmitter not busy
	ret
	cp rRBOutL,rRBInL ; In/Out pointer equal?
	brne TxData1
	cp rRBOutH,rRBInH
	brne TxData1
	cbr rFlag,1<<bTxData ; clear TX data flag
	ret
TxData1:
	mov ZH,rRBOutH ; pointer to output
	mov ZL,rRBOutL
	ld rV0,Z+ ; read value from buffer to register
	ld rV1,Z+
	ld rmp,Z+
	rcall Adjust ; correct buffer pointer
	mov rRBOutH,ZH ; store output pointer
	mov rRBOutL,ZL
	sbrc rmp,7 ; error flag?
	rjmp TxData3
	sbrc rmp,6 ; High/Low flag?
	rjmp TxData2
	mov rV2,rmp ; copy to result byte
	ldi rmp,'L' ; set low char
	rjmp TxData5
TxData2:
	andi rmp,0x3F ; clear high bit
	mov rV2,rmp
	ldi rmp,'H' ; set high char
	rjmp TxData5
TxData3:
	sbrc rmp,6 ; V or X error?
	rjmp TxData4
	andi rmp,0x3F
	mov rV2,rmp
	ldi rmp,'V' ; set overflow error
	rjmp TxData5
TxData4:
	andi rmp,0x3F ; clear high bits
	mov rV2,rmp
	ldi rmp,'X' ; set data missed error
TxData5:
	ldi YH,HIGH(sTxBSta) ; pointer to TX buffer
	ldi YL,LOW(sTxBSta)
	st Y+,rmp ; write first char to buffer
	set ; T flag is leading zero suppression
	tst rV2 ; check if Byte3 = 0
	breq TxData11 ; skip triples
	ldi ZH,HIGH(2*DecTab3) ; point to decimal table
	ldi ZL,LOW(2*DecTab3)
TxData6:
	lpm rD0,Z+ ; read decimal value from table
	tst rD0 ; zero?
	breq TxData10 ; end of triple conversion
	lpm rD1,Z+
	lpm rD2,Z+
	ldi rmp,'0' ; counter
TxData7:
	sub rV0,rD0 ; subtract
	sbc rV1,rD1
	sbc rV2,rD2
	brcs TxData8 ; carry
	inc rmp ; count on
	rjmp TxData7
TxData8:
	add rV0,rD0 ; add again
	adc rV1,rD1
	adc rV2,rD2
	brtc TxData9
	cpi rmp,'0' ; leading zero?
	breq TxData6
TxData9:
	st Y+,rmp
	clt ; no leading zeroes any more
	rjmp TxData6
TxData10:
	ldi ZH,HIGH(2*DecTab1) ; next with 1.000
	ldi ZL,LOW(2*DecTab1)
	rjmp TxData12
TxData11:
	ldi ZH,HIGH(2*DecTab2) ; next with 10.000
	ldi ZL,LOW(2*DecTab2)
TxData12:
	lpm rD0,Z+ ; read decimal
	tst rD0 ; already at end?
	breq TxData16
	lpm rD1,Z+
	ldi rmp,'0'
TxData13:
	sub rV0,rD0 ; subtract
	sbc rV1,rD1
	brcs TxData14
	inc rmp
	rjmp TxData13
TxData14:
	add rV0,rD0 ; add again
	adc rV1,rD1
	brtc TxData15
	cpi rmp,'0'
	breq TxData12
TxData15:
Bin2Dec25:
	st Y+,rmp
	clt
	rjmp TxData12
TxData16:
	ldi rmp,'0' ; last digit
	add rmp,rV0
	st Y+,rmp
	ldi rmp,0x0D ; add ch/lf
	st Y+,rmp
	ldi rmp,0x0A
	st Y+,rmp
	ldi XH,HIGH(sTxBSta) ; point to start
	ldi XL,LOW(sTxBSta)
	ld rmp,X+ ; read first character
	out UDR,rmp ; send first character
	sbr rFlag,1<<bTxBusy ; set busy flag
	nop
	ldi rmp,(1<<RXCIE)|(1<<UDRIE)|(1<<RXEN)|(1<<TXEN) ; enable UDRE ints
	out UCSRB,rmp
.if debug == 1
	sbi PORTB,1
	.endif
	ret
;
; decimal table
DecTab3:
.db 0x40,0x42,0x0F,0xA0,0x86,0x01,0x10,0x27,0x00,0x00 ; 1.000.000, 100.000 and 10.000
DecTab2:
.db 0x10,0x27 ; 10.000
DecTab1:
.db 0xE8,0x03,0x64,0x00,0x0A,0x00 ; 1.000, 100, 10
.db 0x00,0x00
;
; Adjust the buffer address in Z
;
Adjust:
	cpi ZL,LOW(sRBEnd) ; compare LSB
	brcc Adjust1
	cpi ZH,HIGH(sRBEnd)-1 ; carry, compare MSB
	brcs Adjust3 ; dont adjust
	rjmp Adjust2 ; start from beginning
Adjust1:
	cpi ZH,HIGH(sRBEnd) ; no carry, compare MSB
	brcs Adjust3 ; don't adjust
Adjust2:
	ldi ZH,HIGH(sRBSta) ; start new
	ldi ZL,LOW(sRBSta)
Adjust3:
	ret
;
; Received a line over UART
;
RxLine:
	cbr rFlag,1<<bRxLine ; clear flag
	ldi ZH,HIGH(sRxBSta) ; reset pointer
	ldi ZL,LOW(sRxBSta)
	cli ; disable ints
	sts sRxBPtr+1,ZH
	sts sRxBPtr,ZL
	ld rmp,Z ; read first char
	sei ; enable ints
	cpi rmp,'?' ; help?
	brne RxLine0
	rjmp sendmenue
RxLine0:
	cpi rmp,'a' ; Mode 1?
	brne RxLine1
	andi rFlag,0xFC ; clear mode bits
	ldi rmp,HIGH(c10us) ; set CTC value
	out ICR1H,rmp
	ldi rmp,LOW(c10us)
	out ICR1L,rmp
	rjmp RxLine7
RxLine1:
	cpi rmp,'b' ; Mode 2?
	brne RxLine2
	andi rFlag,0xFC
	ori rFlag,1<<bMode0
	ldi rmp,HIGH(c100us) ; set CTC value
	out ICR1H,rmp
	ldi rmp,LOW(c100us)
	out ICR1L,rmp
	rjmp RxLine7
RxLine2:
	cpi rmp,'c' ; Mode 3?
	brne RxLine3
	andi rFlag,0xFC
	ori rFlag,1<<bMode1
	ldi rmp,HIGH(c1ms) ; set CTC value
	out ICR1H,rmp
	ldi rmp,LOW(c1ms)
	out ICR1L,rmp
	rjmp RxLine7
RxLine3:
	cpi rmp,'d' ; Mode 4?
	brne RxLine4
	andi rFlag,0xFC
	ori rFlag,(1<<bMode1)|(1<<bMode0)
	ldi rmp,HIGH(c10ms) ; set CTC value
	out ICR1H,rmp
	ldi rmp,LOW(c10ms)
	out ICR1L,rmp
	rjmp RxLine7
RxLine4:
	cpi rmp,'0' ; Off?
	brne RxLine5
	cbr rFlag,1<<bMOn
	; switch timer off
	ldi rmp,(1<<WGM13)|(1<<WGM12) ; stop timer
	out TCCR1B,rmp
	ldi rmp,1<<TOIE0 ; disable TC1 timer interrupts
	out TIMSK,rmp
	clr rmp ; external ints off
	out GICR,rmp
	rjmp RxLine7
RxLine5:
	cpi rmp,'1' ; On?
	brne RxLine7
	ori rFlag,1<<bMOn ; set On flag
	rcall sendmenue2
	ldi rmp,0x0D
	rcall sendrmp
	ldi rmp,0x0A
	rcall sendrmp
	; switch timer on
	clr rCnt2 ; clear counter
	clr rCnt1
	clr rCnt0
	mov rmp,rFlag ; read mode
	andi rmp,0x03 ; mode bits both 1?
	cpi rmp,0x03
	ldi rmp,(1<<WGM13)|(1<<WGM12)|(1<<CS10) ; prescale =1
	brne RxLine6
	ldi rmp,(1<<WGM13)|(1<<WGM12)|(1<<CS11) ; prescale =8
RxLine6:
	out TCCR1B,rmp
	ldi rmp,(1<<TICIE1)|(1<<TOIE0) ; enable ICP interrupts
	out TIMSK,rmp
	ldi rmp,1<<INT0 ; enable INT0
	out GICR,rmp
	ret
RxLine7:
	rjmp sendmenue2
;
; Send Menu over RS232
;
sendmenue:
	ldi ZH,HIGH(2*sendmenuetext) ; Point to text
	ldi ZL,LOW(2*sendmenuetext)
sendmenue1:
	lpm rmp,Z+
	tst rmp ; end of text?
	breq sendmenue2
	rcall sendrmp ; send character
	rjmp sendmenue1
sendmenue2:
	ldi rmp,0x0D
	rcall sendrmp
	ldi rmp,0x0A
	rcall sendrmp
	mov rmp,rFlag ; read flag
	andi rmp,0x03 ; isolate mode
	subi rmp,-'A'
	sbrs rFlag,bMOn ; is off?
	subi rmp,-0x20
	rcall sendrmp
	ldi rmp,'>'
	rjmp sendrmp
;
; Send character in rmp over UART
;
SendRmp:
	sbis UCSRA,UDRE ; wait until buffer clear
	rjmp SendRmp
	out UDR,rmp ; send char in rmp
	ret


; Menue Text
sendmenuetext:
;.db 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55
;.db 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55
;.db 0x00,0x00
;.db "                                   ",0x00
.db 0x0C, 0x0D,0x0A,0x0D,0x0A,"Measuring device for pulse length",0x0D,0x0A
.db "------- (C)2010 by DG4FAC ------- ",0x0D,0x0A
.db "? = this menue",0x0D,0x0A
.db "0 = switch measurement off",0x0D,0x0A
.db "1 = switch measurement on ",0x0D,0x0A
.db "a = time base = 10 us ",0x0D,0x0A
.db "b = time base = 100 us",0x0D,0x0A
.db "c = time base = 1 ms",0x0D,0x0A
.db "d = time base = 10 ms",0x00
;
; End of source code
;



An den Seitenanfang

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