/* * Fernbedienung.asm * * Created: 08.10.2015 14:35:11 * Author: Erich */ .INCLUDE "tn24def.inc" .EQU sbuff0, 0 ; serieller Puffer 0 bis .EQU sbuff1, 1 .EQU sbuff2, 2 .EQU sbuff3, 3 .EQU sbuff4, 4 ; 4 .EQU lastB, 5 ; letzter Zustand von PINB .EQU lt1p0l, 6 ; letzte Flankenposition PINB0 (Timer 1) low .EQU lt1p0h, 7 ; dito high .EQU lt1p1l, 8 ; dito PINB1 low .EQU lt1p1h, 9 ; dito high .EQU bcnt0, 10 ; Bitzähler PINB0 .EQU bcnt1, 11 ; Bitzähler PINB1 .EQU t1moml, 12 ; momentane Position Timer 1 low .EQU t1momh, 13 ; dito high .EQU aender, 14 ; Änderungen in PINB rjmp RESET reti reti reti reti reti reti reti reti rjmp TIMER0COMPA ; Timer0 Compare Match A reti reti reti reti reti reti reti RESET: ldi r16,lo8(RAMEND) ; Stackpointer initialisieren out SPL,r16 ldi r16,0x80 out CLKPR,r16 ldi r16,0x00 out CLKPR,r16 ; System-Vorteiler auf 1 ldi r16,0x03 out PRR,r16 ; Clocks: Timer/Counter 1 an, Timer/Counter 0 an, USI aus, ADC aus ... zum Stromsparen ldi r16,0x00 out WDTCSR,r16 ; Watchdog aus ldi r16,0x02 out PORTA,r16 ; 6x n.d., PORTA1 high (RS232-Sender), kein Pull-up an PORTA0 (RS232-Empfänger) ldi r16,0x00 out PORTB,r16 ; 2x n.d., kein Pull-up an PORTB1 (IR-Empfänger 1) & PORTB0 (IR-Empfänger 0) ldi r16,0x06 out DDRA,r16 ; Ausgänge: PORTA1 (RS232-Sender), PORTA2 (Test) ldi r16,0x00 out DDRB,r16 ; keine Ausgänge auf PORTB ldi r16,0x02 ; Timer0 Compare-Match-A Interrupt an out TIMSK0,r16 ldi r16,104 out OCR0A,r16 ldi r16,0x02 ; CTC-Modus: Periode = OCR0A = 104 -> 9600 baud out TCCR0A,r16 ldi r16,0x02 ; Vorteiler 8 für Timer 0 out TCCR0B,r16 ldi r16,0x02 ; Vorteiler 8 für Timer 1 out TCCR1B,r16 ldi r16,0x21 ; Start-Bit und mov sbuff0,r16 ldi r16,0x15 ; 0x48 ('H') und Start-Bit und mov sbuff1,r16 ldi r16,0x56 ; 0x61 ('a') und Start-Bit und mov sbuff2,r16 ldi r16,0x48 ; 0x21 ('!') und Start-Bit mov sbuff3,r16 ldi r16,0x0d ; und 0x0d (CR) mov sbuff4,r16 in lt1p0l,TCNT1L in lt1p0h,TCNT1H movw lt1p1l,lt1p0l in lastB,PINB ldi r16,0x03 and lastB,r16 sei MAINLOOP: in r16,PINB andi r16,0x03 eor r16,lastB breq MAINLOOP ; keine Änderung eor lastB,r16 ; Änderung übernehmen mov aender,r16 ; Änderungen merken in t1moml,TCNT1L in t1momh,TCNT1H ; Zählerstand holen movw r16,t1moml ; und kopieren sbrs aender,0 rjmp PIN0WACKELTNICHT sub r16,lt1p0l sbc r17,lt1p0h ; r17:r16 = TimeDiff movw lt1p0l,t1moml ; aktuellen Zählerstand als alten setzen subi r16,0xb1 sbci r17,0x01 ; - 865/2 = 0x01b1 = halbes Bit brcs RESET0 ; zu kurzes Bit -> Fehler! subi r16,0x61 sbci r17,0x03 ; - 865 = 0x0361 = kurzes Bit brcc KEINKURZESBIT0 clr r16 ; wird einfach gespeichert! inc bcnt0 rjmp WEITER0 KEINKURZESBIT0: subi r16,0x61 sbci r17,0x03 ; - 865 = 0x0361 = (noch ein) kurzes Bit (= langes Bit) brcc RESET0 ; zu langes Bit -> Fehler inc bcnt0 inc bcnt0 ldi r16,0x01 ; wird doppelt gespeichert! WEITER0: clc sbrs lastB,0 ; alten Pinzustand sec ; nach C lds r17,(0x0060) ; das erste der insgesamt vier Bytes von empfangenen Bits rol r17 sts (0x0060),r17 lds r17,(0x0061) rol r17 sts (0x0061),r17 lds r17,(0x0062) rol r17 sts (0x0062),r17 lds r17,(0x0063) rol r17 sts (0x0063),r17 brcs RESET0 ; es kamen mehr als 32 Bits an -> Fehler! subi r16,0x01 brcc WEITER0 ldi r16,0x1a cp bcnt0,r16 brcs ENDE0 ; noch keine 26 klein-Bits angekommen -> Ende ldi r16,0x1c cp bcnt0,r16 brcc RESET0 ; mehr als 27 klein-Bits angekommen -> Fehler! sbrs lastB,0 ; jetziger Zustand ist high? rjmp ENDE0 ; nein -> dann ist es auch nicht fertig! lds r16,(0x0063) ; das letzte Byte ori r16,0x40 ; die übrigen Bits (also die Bits, die eben nicht empfangen wurden) sts (0x0063),r16 ; des zuerst "empfangenen" Bytes werden alternierend auf 1 gesetzt ldi r26,0x60 ldi r27,0x00 ; Startadresse in den Speicher, mov r16,bcnt0 ; Bitanzahl in r16 rcall VERSENDEN ; und ab durch die serielle Schnittstelle RESET0: ldi r16,0x05 ; Startbit + '01'=0 (also 0. Empfänger) sts (0x0060),r16 ldi r16,0x00 sts (0x0061),r16 sts (0x0062),r16 sts (0x0063),r16 ; empfangene Bits initialisieren clr bcnt0 ; Bit-Zähler auf 0 setzen ENDE0: PIN0WACKELTNICHT: sbrs aender,1 rjmp MAINLOOP movw r16,t1moml ; Zählerstand rücksichern sub r16,lt1p1l sbc r17,lt1p1h ; r17:r16 = TimeDiff movw lt1p1l,t1moml ; aktuellen Zählerstand als alten setzen subi r16,0xb1 sbci r17,0x01 ; - 865/2 = 0x01b1 = halbes Bit brcs RESET1 ; zu kurzes Bit -> Fehler! subi r16,0x61 sbci r17,0x03 ; - 865 = 0x0361 = kurzes Bit brcc KEINKURZESBIT1 clr r16 ; wird einfach gespeichert! inc bcnt1 rjmp WEITER1 KEINKURZESBIT1: subi r16,0x61 sbci r17,0x03 ; - 865 = 0x0361 = (noch ein) kurzes Bit (= langes Bit) brcc RESET1 ; zu langes Bit -> Fehler inc bcnt1 inc bcnt1 ldi r16,0x01 ; wird doppelt gespeichert! WEITER1: clc sbrs lastB,1 ; alten Pinzustand sec ; nach C lds r17,(0x0064) ; das erste der insgesamt vier Bytes von empfangenen Bits rol r17 sts (0x0064),r17 lds r17,(0x0065) rol r17 sts (0x0065),r17 lds r17,(0x0066) rol r17 sts (0x0066),r17 lds r17,(0x0067) rol r17 sts (0x0067),r17 brcs RESET1 ; es kamen mehr als 32 Bits an -> Fehler! subi r16,0x01 brcc WEITER1 ldi r16,0x1a cp bcnt1,r16 brcs ENDE1 ; noch keine 26 klein-Bits angekommen -> Ende ldi r16,0x1c cp bcnt1,r16 brcc RESET1 ; mehr als 27 klein-Bits angekommen -> Fehler! sbrs lastB,1 ; jetziger Zustand ist high? rjmp ENDE1 ; nein -> dann ist es auch nicht fertig! lds r16,(0x0067) ; das letzte Byte ori r16,0x40 ; die übrigen Bits (also die Bits, die eben nicht empfangen wurden) sts (0x0067),r16 ; des zuerst "empfangenen" Bytes werden alternierend auf 1 gesetzt ldi r26,0x64 ldi r27,0x00 ; Startadresse in den Speicher, mov r16,bcnt1 ; Bitanzahl in r16 rcall VERSENDEN ; und ab durch die serielle Schnittstelle RESET1: ldi r16,0x03 ; Startbit + '10'=0 (also 1. Empfänger) sts (0x0064),r16 ldi r16,0x00 sts (0x0065),r16 sts (0x0066),r16 sts (0x0067),r16 ; empfangene Bits initialisieren clr bcnt1 ; Bit-Zähler auf 0 setzen ENDE1: PIN1WACKELTNICHT: rjmp MAINLOOP TIMER0COMPA: push r16 in r16,SREG push r16 sbrc sbuff0,0 sbi PORTA,1 sbrs sbuff0,0 cbi PORTA,1 ; clc ; so werden die Daten zyklisch gesendet ; sbrc r0,0 sec ror sbuff4 ror sbuff3 ror sbuff2 ror sbuff1 ror sbuff0 pop r16 out SREG,r16 pop r16 reti ; TIMER0COMPA WARTEAUFSENDBUFFER: ; wartet, bis der Sende-Puffer leer ist ldi r16,0xff cp sbuff4,r16 brne WARTEAUFSENDBUFFER cp sbuff3,r16 brne WARTEAUFSENDBUFFER cp sbuff2,r16 brne WARTEAUFSENDBUFFER cp sbuff1,r16 brne WARTEAUFSENDBUFFER cp sbuff0,r16 brne WARTEAUFSENDBUFFER ret ; WARTEAUFSENDBUFFER VERSENDEN: ; versendet r16/2+1 Bit Manchester-kodierte Daten ; aus DRAM, Adresse r27:r26 (=X), base64-kodiert movw r18,r26 ; Speicheradresse merken sbrc r16,0 rjmp VERSENDENNICHTSCHIEBEN sec ld r17,X rol r17 st X+,r17 ld r17,X rol r17 st X+,r17 ld r17,X rol r17 st X+,r17 ld r17,X rol r17 st X+,r17 movw r26,r18 VERSENDENNICHTSCHIEBEN: lsr r16 ldi r17,0x0d cpse r16,r17 ; nicht 26 halb-Bits? ret ; -> Fehler! ; ld r18,X+ ; ld r18,X+ ; ld r18,X+ ; ld r17,X+ ; clr r16 ; rjmp AUSLESESCHLEIFENENDE ldi r20,0x03 ALTERNIERENDTESTSCHLEIFE: ld r16,X+ mov r17,r16 lsr r16 eor r16,r17 andi r16,0x55 ldi r17,0x55 cpse r16,r17 ; Bits alternierend? ret ; nein -> Ende! subi r20,0x01 brcs ALTERNIERENDTESTSCHLEIFEENDE rjmp ALTERNIERENDTESTSCHLEIFE ALTERNIERENDTESTSCHLEIFEENDE: movw r26,r18 clr r18 clr r17 clr r16 ldi r19,0x10 ; 16 Bits zu lesen (13 reale Bits + 3 Geistbits) AUSZENSCHLEIFE: ld r20,X+ ldi r21,0x04 ; 4 Bits je Byte INNENSCHLEIFE: ror r20 ror r20 rol r18 rol r17 rol r16 subi r19,0x01 breq AUSLESESCHLEIFENENDE subi r21,0x01 brne INNENSCHLEIFE rjmp AUSZENSCHLEIFE AUSLESESCHLEIFENENDE: ; die zu sendenden 18 Bit Informationen liegen in r16(2):r17(8):r18(8) rol r18 rol r17 rol r16 rol r18 rol r17 rol r16 lsr r18 lsr r18 rol r17 rol r16 rol r17 rol r16 lsr r17 lsr r17 rcall TOBASE64 push r16 mov r16,r17 rcall TOBASE64 push r16 mov r16,r18 rcall TOBASE64 push r16 ; die zu sendenden Zeichen liegen auf dem Stack (3., 2., 1.) rcall WARTEAUFSENDBUFFER cli clc ; aus logistischen Gründen füllen wir den Puffer von hinten nach vorne ldi r16,0x0d ; 0x0d (CR) mov sbuff4,r16 pop r17 ldi r16,0x40 sec ror r17 ror r16 ror r17 ror r16 mov sbuff3,r17 pop r17 swap r17 mov r18,r17 andi r18,0x0f or r16,r18 mov sbuff2,r16 andi r17,0xf0 ori r17,0x04 pop r18 clr r16 clc rol r18 rol r16 sec rol r18 rol r16 or r16,r17 mov sbuff1,r16 mov sbuff0,r18 sei VERSENDENENDE: ret ; VERSENDEN TOBASE64: ; konvertiert Bit 0-5 von r16 in base64 ; 0-25: A-Z: +0x41 (=-0xbf) ; 26-51: a-z: +0x47 (=-0xb9) ; 52-61: 0-9: -0x04 ; 62: +: -0x13 ; 63: /: -0x10 andi r16,0x3f ; zur Sicherheit cpi r16,26 brcc NICHT0BIS25 subi r16,0xbf ret ; TOBASE64 NICHT0BIS25: cpi r16,52 brcc NICHT26BIS51 subi r16,0xb9 ret ; TOBASE64 NICHT26BIS51: cpi r16,62 brcc NICHT52BIS61 subi r16,0x04 ret ; TOBASE64 NICHT52BIS61: cpi r16,63 brcc NICHT62 subi r16,0x13 ret ; TOBASE64 NICHT62: subi r16,0x10 ret ; TOBASE64