M´kay, nachdem jetzt der Empfänger abgehandelt ist,
wollen wir uns mal der Generierung des Sendesingnales zuwenden.
Bei dem ersten Blick, fälllt bereits auf, dass es hier etwas wüster zugeht,
als im Empfänger.
Als Kern der eigentlichen Senderroutine wird hier der Comparematch mit dem OCR2 Register
zur Pulsweiten Variation genutzt. Dazu an gegebener Stelle mehr.
Der erste Teil in der Mainschleife soll den Befehl aufnehemen,
der gesendet werden soll. In diesem ersten Prog ist das nur einmal das Bitmuster
00010001 oder 00010010. Der eine Befehl schaltet eine Lampe ein, der andere aus.
Es ist auf jeden Fall ratsam, immer min. zwei BIT´s 1 zu setzen, um eine gewisse
Störsicherheit zu erreichen. Jedoch reicht auch das auf längere Zeit nicht. Ich werde
daher dazu übergehen, 16 BIT´s zu kodieren.
Nach diesem ersten Teil wird getestet, ob der neue Befehl auch tatsächlich neu ist und nicht
bereits gesendet wurde, wovon abhängt, ob dann überhaupt gesendet wird. Da muss man sich aber
überlegen, ob das nötig ist. Z.B. würden erhöhende und erniedrigende Befehle
auch mehrmals Sinn machen.
Nachdem das alles abgehandlet ist, wird der PIN, an dem der Sender hängt HIGH gesetz,
und eine Warteschleife aufgerufen, die bis TCNT2 = 250 dauert. An dieser Stelle ist
der Interrupt Enable für OCR2 noch inaktiv.
Nach dieser Funktion wird der zu sendende Befehl in einem zweiten Register zum späteren
vergleichen abgespeichert.
Darauf folgt die INIT Funktion, in welcher der Interrupt des Comparematches aktiv wird, der TNCT2
wird null gesetzt, an OCR2 der Wert 60 übergeben und der zu sendede Befehl in das shift Register shf
kopiert. Auf dieses wird später die LSL Operation angewendet.
Nun kommt endlich der interessante Teil, die eigentliche Senderoutine.
In diese ist eine Schleife progammiert, die elf mal durchlaufen wird.
In shfc wird festgehalten, wie oft die ISR aufgerufen wurde.
mehr1:
cpi shfc,11 (aus irgendeinem Grund
brlo mehr1 ist die doppelte abfrage
cpi shfc,11 nötig, sonst wird die Schleife
brlo mehr1 einen Zyklus zu früh verlassen -
ldi shfc,0 hat was mit einem der Statusbits zu tun)
Die Erklärung für die elf Mal
findet sich in der Erläuterung des Empfangprog´s.
Diese Schleife kann erst nach dem senden aller Datenbits verlassen werden. Vorher
wird sie mit der Verarbeitungsgeschwindigkeit wiederholt. Unterbrochen wird das nur
durch einen Comparematch mit OCR2, also beim ersten Mal bei TCNT2 = 60.
Daraufhin wird die ISR "hitvalue" aufgerufen.
Dort wird als erstes der logische Pegel, an dem der Sender sitzt, ivertiert. Das geht
Hand in Hand mit der Einstellung des Empfängers, der bei einem logischen Wechsel an INT1
interruptet.
Als zweites wird geprüft, ob die ISR im ersten Durchlauf ist, denn dann war der Interrupt zum
initialisieren des Empfängers.
Ist es jedoch mindestens der zweite Durchlauf, wird in Abhängigkeit des M(ost) S(inificant) B(it)
von shf die nächste Pulsdauer bestimmt und die besagte LSL Op auf shf gemacht.
ldi dauer,60
sbrs shf,7
ldi dauer,30
lsl shf
Als letztes wird shfc um eins erhöht.
Dann wird über reti wieder in die Schleife der Funktion senden1
cpi shfc,11
brlo mehr1
cpi shfc,11
brlo mehr1
zurückgesprungen.
Sind die elf Mal erreicht, wird der Interrupt durch OCR2 wieder deaktiviert und eine Warteschleife
auf Basis von TCNT0 bis 30 ausgeführt.
Danach wird der PIN wierder LOW gesetzt und nach MAIN zurückgekehrt.
Die Ganze Fummelei mit dem TIMSK könnte man im Prinzip auch mit sei; und cli machen, aber villeicht will man ja mal noch andere Interrupte nutzten, Tastermatrix z.B.
Kommentar:Code:.include "m8def.inc" .def shf = r17 .def shfc = r18 .def dauer = r19 .def zwischen = r20 .def tmp = r21 .def timermaskon = r22 .def timermaskoff = r23 .def befehl = r24 .def t = r25 .org 0x0000 rjmp reset .org OC2addr ; OCR2 Interrupt Vector Address rjmp hitvalue reset: ;Stack wird bei Interrupts benötigt! ldi r16,HIGH(RAMEND) out SPH,r16 ldi r16,LOW(RAMEND) out SPL,r16 ldi r16,0b01100000 ;internal Vref - Channel 0 out ADMUX,r16 ldi r16,0b10001110 ;singleconversion - prescaler 32 - int.enable out ADCSRA,r16 ldi r16,0b11111110 out DDRC,r16 ;out PORTC,r16 ldi r16,0b11110111 out DDRD,r16 ldi r16,0b00000011 out TCCR0,r16 ldi timermaskoff,0 ldi tmp,0b00001100 ;interuppt on comparematch - presc 128 out TCCR2,tmp ;ldi r16,255 ;out OCR2,r16 ldi timermaskon,0b10000000 sei mainloop: wdr sbic PIND,3 rjmp open sbis PINB,5 ldi befehl,0b00010001 sbis PINB,4 ldi befehl,0b00010010 open: cp zwischen,befehl breq unten ldi tmp,255 out PORTC,tmp rcall pause mov zwischen,befehl rcall init rcall senden1 ldi t,0 hoch: sbic PIND,3 rjmp hoch unten: rjmp mainloop pause: ldi tmp,0 out TCNT0,tmp warten: in tmp,TCNT0 cpi tmp,250 brlo warten ldi tmp,0 out TCNT0,tmp ret init: ldi tmp,0 out TCNT2,tmp ldi tmp,60 out OCR2,tmp mov shf,befehl out TIMSK,timermaskon ret senden1: mehr1: cpi shfc,11 brlo mehr1 cpi shfc,11 brlo mehr1 ldi shfc,0 out TCNT0,shfc out TIMSK,timermaskoff warten2: in tmp,TCNT0 cpi tmp,30 brlo warten2 ldi tmp,0 out TCNT0,tmp ldi tmp,0 out PORTC,tmp ret hitvalue: in tmp,PORTC com tmp out PORTC,tmp cpi shfc,1 brlo senden ldi dauer,60 sbrs shf,7 ldi dauer,30 lsl shf out PORTD,dauer out OCR2,dauer senden: inc shfc reti
Nch dem schreiben sind mir einoge Dinge aufgefallen, die noch nicht perfekt sind. Zum ersten kann ich sicher das erste INIT Bit schon als Datenbit nutzten und zum anderen in der senden1 Funktion die Warteschleife mit dem TCNT0 müsste auch wie zuvor über den Interrupt gehen.
Und wenn jemand weiß, woran das liegt, das ich die elfer Schleife zweimal brauche, bin ich dankbar für eine Erklärung.
Wenn ich dann mal die Zeit habe, mache ich mal eine Schaltungsskizze.
The Man
Lesezeichen