;Impuls-Korrektur für AVR Tiny15 zum Einsatz im Modellbau. ;Es wird aus einem Kanalimpuls ein neuer Kanalimpuls erzeugt, ;dessen Neutralpunkt und "Ausschlag" in weiten Grenzen separat ;manipuliert werden kann, sogar bis zur Impulsumkehr. ;Die Manipulation erfolgt durch 2 analoge Steuerspannungen (Trimmpotis). ;Das Modul hat einen Impulseingang (0,8ms...2,2ms), ;ein Poti zum Trimmen des neuen Neutralpunktes (1,2...1,8ms), ;ein Poti zum Trimmen der Verstärkung (Gain) des Ausschlags vom Neutralpunkt (-2...+2), ;einen Impulsausgang für den neu berechneten Impuls, ;einen Error-Ausgang, der bei Impulserkennungsfehlern H wird. ;Der 15. empfangenen Impuls (300ms nach dem Einschalten) wird als Neutralpunkt gewertet. ;Erst danach werden Ausgangsimpulse generiert. ;Das Erzeugen der Ausgangsimpulse erfolgt zeitversetzt, also erst nachdem der ;Eingangsimpuls beendet ist und die Korrektur berechnet wurde... ;Der Begriff "Verstärkung" ist so zu verstehen: ;Der "Ausschalg", also die Abweichung vom Neutralpunkt kann mittels ;des Trimmpotis abgeschwächt oder verstärkt werden. Dabei ist die Verstärkung ;stufenlos (naja: feinstufig) zwischen 0 (Mittelstellung des Potis) ;und doppelter Abweichung des Eingangsimpulses (Endstellung des Potis) ;einstellbar. Abhängig von der gewählten Bereichshälfte des Potis wird der ;Impuls ggf. invertiert, also aus einem langen ein kurzer gemacht und umgekehrt. ; (c) 08/2004 by ...HanneS... ;Anschlussbelegung des Tiny15: ;Pin 1: Reset (über R an +5V) ;Pin 2: Trimmeingang für Gain (Analogeingang) ;Pin 3: Trimmeingang für Neutralpunkt (Analogeingang) ;Pin 4: GND ;Pin 5: Error-Ausgang (H-Pegel bei Impuls-Error) ;Pin 6: Impulsausgang ;Pin 7: Impulseingang ;Pin 8: +5V ;Die Trimmpotis sind zwischen GND und Betriebsspannung zu schalten, ;mit Schleifer am Trimmeingang (C gegen Masse)... ;Damit die Kalibration des internen RC-Oszillators auf 1,6MHz funktionieren kann, ;muss das "Calibrationsbyte" mittels eines ISP-Programms aus dem Signature-Bereich ;des Tiny15 gelesen werden und in die letzten beiden Bytes des Flash-Speicherbereiches ;eingetragen werden. (eigentlich nur in das L-Byte der letzten Word-Zelle) ;Wird das versäumt, stimmt das Timing nicht!!! ;Funktionsbeschreibung (grob): ;- Steigende Flanke am Impulseingang (Eingangsimpulsanfang) ; * setzt Timer1 auf 0 und startet ihn mit 100kHz, ; * liest Neutraltrimmwert aus Poti (analog) ;- Fallende Flanke am Impulseingang (Eingangsimpulsende) ; * liest Timer1 aus (Eingangsimpulsbreite), ; * sorgt dafür, dass die ersten 14 empfangenen Impulse verworfen werden und ; der 15. Impuls als Neutralpunkt des Senders interpretiert wird, ; * erst ab 16.Impuls nach dem Einschalten Ausgangsimpulse generiert werden. ; * stoppt Timer1 erstmal, ; * liest Gaintrimmwert aus Poti (analog), ; * prüft Impulsbreite auf Gültigkeit, ; * prüft Impulsabstand auf Minimalwert, ; * schaltet ggf. Errorausgang ein/aus, ; * berechnet aus Eingangsimpuls, Neutral-Trimm und Gain-Trimm neuen Impuls-Sollwert, ; * lässt diesem den Istwert mit Hysterese nachlaufen, ; * setzt Timer0 auf Startwert (25,6ms vor Timeout), ; * setzt Timer1 mit neu berechnetem Impuls-Istwert, ; * setzt Impulsausgang auf H (Sendeimpulsbeginn), ; * aktiviert Timer1 mit 100kHz. ;- Timer1-Überlauf (Sende-Impulsende, Überlauf bei Impulsmessung wegen zu langem Impuls) ; * deaktiviert Timer1, (gemessener Impulswert ist dann 0, also illegal), ; * setzt Impulsausgang auf L. (ist bei Messung sowiso L). ;- Timer0-Überlauf (Timeout vermisster Eingangsimpuls) ; * setzt Timer0 auf Startwert (25,6ms vor Timeout), ; * setzt Error-Ausgang auf H, ; * setzt Ausgangsimpulswert auf Error-Impulswert (Konstante, definierbar) ; * setzt Timer1 mit neu berechnetem Impulswert, ; * setzt Impulsausgang auf H (Sendeimpulsbeginn), ; * aktiviert Timer1 mit 100kHz. ;- Reset-Routine ; * initialisiert beim Einschalten alle benötigten Ressourcen... ;- Hauptprogramm ; * schickt den AVR in den Schlafmodus, von dem er von einem der auftretenden Interrupts ; geweckt wird. Dies erhöht die Genauigkeit der Timer, was aber hier keine Rolle spielt. ;------------------------------------------------------------------------------ ;Ressourcen: ;Timer0: Impulsabstandmessung für Error ;Timer0-Überlauf: Impulsausfall-Timeout ;Timer1: Impulsbreitenmessung Eingangsimpuls ;Timer1-Überlauf: Impulserzeugung (Impulsende) ;Ext.Interrupt, steigende Flanke: Beginn Impulsmessung, ADC-Scan Neutral-Trimm ;Ext.Interrupt, fallende Flanke: Ende Impulsmessung, ADC-Scan Gain-Trimm, Beginn Berechnung und Impulsausgabe ;ADC: freilaufend ohne Interrupt, Auslesen per Eingangsimpuls ;Konstanten (Anpassung in sinnvollen Grenzen erlaubt): .equ tsw=96 ;Timer0-Startwert für 25,6ms Timeout-Error (Impulsausfall) .equ tmin=tsw+90 ;Timer0-Vergleichswert für minimalen Impulsabstand (14,4ms) .equ imin=70 ;Minimale Impulsbreite für Error (0,7ms) .equ imax=231 ;Maximale Impulsbreite für Error (2,3ms) .equ errw=150 ;Error-Wert, wird bei fehlendem Eingangsimpuls gesendet (1,5ms) ;------------------------------------------------------------------------------ ;untere Register: .def null=r1 ;Wert Null .def gasmux=r2 ;ADMUX-Wert für Gas-Trimm-Eingang .def trimux=r3 ;ADMUX-Wert für Neutral-Trimm-Eingang .def timaus=r4 ;Timer-Interruptfreigabe abgeschaltet .def timein=r5 ;Timer-Interruptfreigabe Timer1 .def t1vt16=r6 ;Timer1 Vorteiler 1:16 (Wert 9) .def startz=r7 ;Start-Zähler .def neut=r8 ;Neutralpunkt Empfangsimpuls ;obere Register: .def tmp=r16 ;temporäres Register .def iw=r17 ;empfangener Impulswert .def nlw=r18 ;Nachlaufwert für zu sendenden Kanalimpuls .def ntrim=r19 ;Trimmwert Neutralstellung .def atrim=r20 ;Trimmwert Abweichung (Gas) .def flags=r21 ;Einige Flags .equ tneg=0 ;Trimmung (Abweichung, Gas) ist negativ .equ ineg=1 ;Eingangsimpuls ist negativ (kürzer als neutral) .def niw=r22 ;neuer Impulswert .def sw=r23 ;Scanwert .include"tn15def.inc" .org 0 ;Startadresse ;Vektoren (Sprungtabelle) rjmp RESET ; Reset handler rjmp EXT_INT0 ; IRQ0 handler reti ;rjmp PIN_CHANGE ; Pin change handler reti ;rjmp TIM1_CMP ; Timer1 compare match rjmp TIM1_OVF ; Timer1 overflow handler (Impulsbreite) rjmp TIM0_OVF ; Timer0 overflow handler (alle 10ms) reti ;rjmp EE_RDY ; EEPROM Ready handler reti ;rjmp ANA_COMP ; Analog Comparator handler reti ;rjmp ADC ; ADC Conversion Handler ; ;------------------------------------------------------------------------------ ;Interrupt-Service-Routinen: ext_int0: ;Kanalimpuls... ;reines ISR-Programm ohne Hauptprogramm, daher keine SREG-Sicherung... sbis pinb,pb2 ;steigende Flanke (Impulsanfang)? rjmp fallend ;nein, fallende... out tcnt1,null ;ja, Impuls-Beginn, Timer1 für Impulsmessung löschen out tccr1,t1vt16 ;Timer1 für Impulsmessung starten out timsk,timein ;Int Timer1 aktivieren in tmp,admux ;prüfen, ob ADC-Quelle stimmt cpse tmp,trimux ;Neutral-Trimm? reti ;nein, nicht auswerten... in ntrim,adcl ;Neutral-Trimmung... ADC-Dummy lesen (untere 2 Bits, werden verworfen) in ntrim,adch ;ADC-Byte lesen (obere 8 Bits, also 0...255 bei 0...5V) lsr ntrim ;Scannwert (0...255) durch 4 teilen lsr ntrim ;(0...63, 32 in Mittelstellung des Trimmpotis) (Auflösung verringern) subi ntrim,-118 ;Trimmung zum Basisimpuls addieren (Zielwert: 150) out admux,gasmux ;ADC für nächste Messung auf Gas-Trimm-Eingang umschalten reti ;fertig... fallend: ;fallende Flanke... (Impulsende) in sw,tcnt1 ;Impulsbreite aus Timer lesen out tcnt1,null ;Timer1 stoppen sbrc startz,3 ;Startsequenz abgelaufen (15 Impulse)? rjmp fallend1 ;ja... mov neut,sw ;nein, Empfangswert als Netralpunkt merken inc startz ;Startzähler erhöhen out admux,trimux ;ADC für nächste Messung auf Neutral-Trimm-Eingang umschalten reti ;fertig fallend1: ;Startsequenz abgelaufen (Hauptbetrieb) cpi sw,imin ;Impuls kleiner Minwert? brlo fallend2 ;ja, Error... cpi sw,imax ;Impuls größer Maxwert? brsh fallend2 ;ja, Error... in tmp,tcnt0 ;Impulsabstand kleiner cpi tmp,tmin ;als erlaubt? brlo fallend2 ;ja, Error mov iw,sw ;nein, gemessener Impuls ist gültig cbi portb,0 ;Error-Ausgang löschen rjmp fallend3 ;weiter... fallend2: ;Error, gemessenen Impuls verwerfen, da ungültig sbi portb,0 ;Error-Ausgang setzen fallend3: ldi tmp,tsw ;Timeout auf Startwert out tcnt0,tmp ;setzen sub iw,neut ;Impulswert auf signed Char mit 0 in der Mitte wandeln brsh fallend4 ;negativ (kürzer als Neutral)? sbr flags,1<0 Int aus) out timsk,timein ;Int Timer1 aktivieren out tccr1, t1vt16 ;Timer1 mit Vorteiler 16 starten (100kHz, 10µs pro Wert) sbi portb,1 ;Impuls auf H setzen reti minus3: ;Hysterese/Nachlauf dec nlw ;Nachlauf- dec nlw ;Wert minus1: dec nlw ;reduzieren rjmp fertig plus3: inc nlw ;Nachlauf- inc nlw ;Wert plus1: inc nlw ;erhöhen rjmp fertig tim1_ovf: ;Impuls abschalten, Zeit abgelaufen... ;reines ISR-Programm ohne Hauptprogramm, daher keine SREG-Sicherung... cbi portb,1 ;Impulsausgang auf L zurück out timsk,timaus ;Timer1-INT deaktivieren out tccr1,null ;Timer1 stoppen reti ;fertig... tim0_ovf: ;Timeout Impulsausfall... ;reines ISR-Programm ohne Hauptprogramm, daher keine SREG-Sicherung... ldi tmp,tsw ;Timeout auf Startwert out tcnt0,tmp ;setzen ldi niw,errw ;Impulswert durch Errorwert ersetzen sbi portb,0 ;Error-Ausgang setzen rjmp nachlauf ;Impuls ausgeben... ;------------------------------------------------------------------------------ ;Programmstart: reset: ;Initialisierung ldi zl,low(1022) ;Pointer auf ldi zh,high(1022) ;Kalibrationsbyte lpm ;nach r0 holen ldi tmp,255 ;Referenz cpse tmp,r0 ;Kalibrationsbyte gültig (<>$ff)? out osccal,r0 ;ja, kalibrieren ldi tmp,0 ;Pull-Up aus out portb,tmp ;und L-Pegel an Impulsausgang ldi tmp,3 ;PB0 und PB1 als out ddrb,tmp ;Ausgang ldi nlw,150 ;bei 1,5ms starten ldi tmp,(1<