;### DTMF_EXCEL_OUT ### ;###################################### ;### ### ;### AUSGABE FÜR EXCEL-AUSWERTUNG ### ;### ### ;###################################### ;ERKLÄRUNGEN: ; - mit 16bit-Zähler mit 1MHz (RC-Zähltakt) ; - es wird in uSec_H:L die Zeit gemessen (in µsec), ; die für 30 Wellenberge notwendig ist ; - mit differential input gainx20 (left adjust) ; - der ADC misst mit 250KHz sehr schnell ; - der ATtiny26L war bei der Verstärkung weniger stabil ; als der ATtiny26 ; - mit Ausgabemodul für Min-/Max-Werte(ausgeschaltet) ; - Berechnungen ergaben, dass 30 Berge eine hinreichend ; genaue und möglichst schnelle Frequenzmessung gestatten ; - Die Genauigkeit nimmt bei ca. 2KHz ab, liegt also ; im gewünschten Messbereich ??? ; - Formel: ; 30 ; f(Messung) = --------------------- x 1E6 ; (uSec_Hx256 + uSec_L) ; ; - Die obere Frequenz (1209/1336/1477Hz) wird ohne Trennung ; gut erkannt, wenn Toleranz hoch genug gewählt wird. ; - ggf. ADC-Frequenz noch senken (Mehr Zeit für Programm!) ; ; - Signalspeicherung der 30 Berge und 29 Täler ; ; - U-PRG: SIGNAL_CHECK: ; - 1. Berge UND Täler werden erkannt (insges. 59 Werte) ; - 2. DC-Anteil wird vom AC-Anteil entfert: ; Der Wert wird von allen Messwerten subtrahiert ; - 3. Ggf. wird Vorvergrösserung der Signale durchgeführt ; - 4. Durch Multiplikation mit dem sog. Faktor werden alle ; Messwerte in einen optimal aufgeweiteten Bereich ; zwischen 0 und 255 angehoben ; ; - JETZT: Optimierung des Systems ; ;----------------------------------------------------------- .include "tn26def.inc" ;### FÜR EIGENES STATUSREGISTER ### .equ Flag_1 = 1 .equ Flag_2 = 2 .equ Flag_3 = 4 ;für SBRS-Tests .equ Bit_Flag_1 = 0 .equ Bit_Flag_2 = 1 .equ Bit_Flag_3 = 2 ;### DEFINITION DER AUSGÄNGE ### ;portb (hohe Frquenzen) .equ GRUEN_b = 3 ;LED für 1477Hz .equ ORANGE_b = 4 ;LED für 1336Hz .equ GELB_b = 5 ;LED für 1209Hz .equ ROT_b = 6 ;Alarm: Signal zu stark/schwach! ;port a (niedrige Frequenzen) .equ ROT_a = 0 ;LED für 697Hz .equ ORANGE_a = 1 ;LED für 770Hz .equ GELB_a = 2 ;LED für 852Hz .equ GRUEN_a = 4 ;LED für 941Hz ;### DEFINITION DER EINGÄNGE ### .equ SWITCH_a = 5 ;Taster zur Wertausgabe ;### DEFINITION FÜR WRCOM ### .equ Del_1 = 30 ;Delay für WrCOM .equ Del_15 = 48 ;Port B .equ TXD = 1 ;für WrCOM ;### WEITERE DEFINITIONEN ### ;### FÜR OBERTONERKENNUNG ### .equ F1209_H = 96 ;errechnet gem. og. Formel .equ F1209_L = 237 .equ F1336_H = 87 .equ F1336_L = 182 .equ F1477_H = 79 .equ F1477_L = 87 .equ HF_NOT = 0 ;Kodierung von High_Freq .equ HF_1209 = 1 .equ HF_1336 = 2 .equ HF_1477 = 3 .equ Toleranz_H = 1 ;für 16bit-Toleranzwert (m:k) .equ Toleranz_L = 125 ;(Toleranz_H x 256 + Toleranz_L) ;### VARIABLEN-DEFINITIONEN ### .def Sicher_1 = r0 ;für U-Programme .def Sicher_ITR1 = r1 ;für ITR's .def Sicher_ITR2 = r2 .def Richtung = r3 ;1 --> Kurve geht hoch ;0 --> Kurve geht runter .def Max = r4 .def Min = r5 .def ADC_H = r6 ;ADC .def ADC_H_alt = r7 ;ADC von Vormessung .def uSec_H = r8 ;uSec_H:L als 16bit-Zähler .def uSec_L = r9 .def uSec_H_ITR = r10 ;dauernder High-Byte-Zähler .def High_Freq = r11 ;enthält kodierten Obertonwert .def Faktor = r12 ;Zykluszahl Obertonerkennung .def i = r16 ;Hilfsregister .def j = r17 .def k = r18 .def m = r19 .def n = r20 .def p = r21 .def StatReg = r22 ;Eigenes Status-Register .def Delay = r23 ;für WrCOM .def Count = r24 .def Count2 = r25 .def BergZahl = r26 ;Zählt die Wellenberge ;für YH:YL = r29:r28 reserviert!!! ;für ZH:ZL = r31:r30 reserviert!!! ;######################################################### rjmp ANFANG .org 0x0006 ;Timer0 overflow rjmp TIM0_OVF .org 0x000B ;ADC Conversion complete rjmp ADC_COMPLETE ANFANG: cli ldi i,LOW(RAMEND) ;setze Stackpointer out SP,i ;PB4 und PB5 frei für Quarz!! ;port b sbi ddrb,TXD ;Datenrichtung TXD für WrCOM sbi ddrb,ROT_b ;LED für Signalstärke sbi ddrb,GRUEN_b ;LEDs für hohe Frequenzen sbi ddrb,ORANGE_b sbi ddrb,GELB_b ;porta sbi ddra,ROT_a ;LEDs für niedrige Frequenzen sbi ddra,GRUEN_a sbi ddra,ORANGE_a sbi ddra,GELB_a sbi porta,SWITCH_a ;Taster mit PullUp rcall ADC_START ;ADC (free running) einschalten rcall RESTART_uSEC ;Zähler an! sei LOOP: ;eigentliches Hauptprogramm nop rjmp LOOP ;============================================================= ADC_START: in Sicher_1,SREG ;76543210 ldi i,0b11101010 out ADCSRA,i ;b7=1(ADEN) :ADC enable ein ! ;b6=1(ADSC) :Start first Conv. ;b5=1(ADFR) :free running ein! ;b4=0(ADIF) :ADC-ITR-Flag(read) ;b3=1(ADIE) :ADC-ITR-Enable ein! ;b2..0=010 :1MHz/4=250kHz ;76543210 ldi i,0b00110111 out ADMUX,i ;b7=0 & b6=0: AVCC 5,0V stab. ;b5(ADLAR)=1: left adjust AN! ;b4..0=10111: ; ADC6(PA7)=pos. diff. input x20 ; ADC5(PA6)=neg. diff. input x20 out SREG,Sicher_1 ret ;---------------------------------------------------------- ADC_COMPLETE: ;Übergabevariable: ADCH in Sicher_ITR1,SREG in uSec_L,TCNT0 ;aktuelle Werte sichern mov uSec_H,uSec_H_ITR ;(uSec_H dient als Puffer) in ADC_H,ADCH ;HighByte = ADCH ;U[V] = (Vin x 1024) / Vref sei ;wieder an wegen Timer0! SIGNAL_TEST: ;zur Arbeitspunkteinstellung .. ldi i,255 ;ADC_H = 255 ? cp ADC_H,i brne NICHT_UEBER sbi portb,ROT_b ;Rote LED: Signal zu hoch (=255)! NICHT_UEBER: ldi i,2 cp ADC_H,i brsh NICHT_UNTER sbi portb,ROT_b ;Rote LED: Signal zu tief (<2)! NICHT_UNTER: ;RICHTUNGS-TEST (HOCH/RUNTER) tst Richtung brne HOCH RUNTER: cp ADC_H,Min brsh TAL_TEST ;Min-Wert nach unten hin mov Min,ADC_H ;aktualisieren TAL_TEST: cp ADC_H_alt,ADC_H brlo TAL ;dh. Tal erkannt mov ADC_H_alt,ADC_H rjmp ENDE_ADC_RELAIS TAL: clr Richtung ;Richtung <- 1 (=hoch) inc Richtung ;früher: PIEZO an! mov ADC_H_alt,ADC_H ;SPEICHERUNG TAL-WERT im SRAM: st Y+,ADC_H ;(Y) <- ADC_H, Y <- Y + 1 rjmp ENDE_ADC_RELAIS ;----- HOCH: cp Max,ADC_H brsh BERG_TEST ;Max-Wert nach oben hin mov Max,ADC_H ;aktualisieren BERG_TEST: cp ADC_H,ADC_H_alt brlo BERG ;dh. Berg erkannt mov ADC_H_alt,ADC_H rjmp ENDE_ADC_RELAIS BERG: clr Richtung ;Richtung <- 0 (=runter) ;früher:PIEZO aus! mov ADC_H_alt,ADC_H ;BERG-ZAHL-TEST: cbi portb,ROT_b ;Rote LED aus (Signalstärke)! inc BergZahl ;BergZahl <- BergZahl+1 ;SPEICHERUNG BERG-WERT im SRAM: st Y+,ADC_H ;(Y) <- ADC_H, Y <- Y + 1 ;SIND 30 BERGE GEZÄHLT? cpi BergZahl,30 ;dh. 30 Berge gezählt brlo ENDE_ADC_RELAIS ;weiter, wenn zu wenig Berge ;30 BERGE SIND GEZÄHLT! cli ;TIMER0 AUSSCHALTEN! ;76543210 ldi i,0b00000000 ;Timer0 stop! out TCCR0,i ;76543210 ldi i,0b00000000 ;Timer0 OVF ITR disable! out TIMSK,i ;------------------------- rjmp RELAIS_ENDE ;Verkürzung für relative branch ENDE_ADC_RELAIS: rjmp ENDE_ADC_COMPLETE RELAIS_ENDE: ;------------------------- ;##### VERGLEICH MIT OBERTON ##### ldi k,Toleranz_L ;Toleranzwert einlesen ldi m,Toleranz_H ldi ZL,LOW(HIGH_TONE*2) ;Adresse von Label HIGH_TONE ldi ZH,HIGH(HIGH_TONE*2) LOOP_LED: lpm High_Freq,Z ;Kodierter Oberton tst High_Freq ;bei 0 => keine Freq. gefunden! breq VAR_RESET adiw ZL,1 lpm i,Z ;Low-Byte Referenzfrequenz adiw ZL,1 lpm j,Z ;High-Byte Referenzfrequenz adiw ZL,1 lpm n,Z ;LED-Farbe adiw ZL,1 rcall Freq_Check tst High_Freq ;High_Freq von U-Prg. ggf. geändert! breq LOOP_LED ;bei 0 => nächster Freq.-Test ;OBERTON GEFUNDEN: in i,portb ;LED für hohe Frequenz an! or i,n out portb,i ;- - - - - - - - - - - - - - - - - - - - - - - - - - ;- - sbic pina,SWITCH_a ;wenn low => Taster gedrückt rjmp OUTPUT_ENDE WAIT_SWITCH: sbis pina,SWITCH_a ;warten, bis Taster wieder frei rjmp WAIT_SWITCH rcall SIGNAL_CHECK ;Berechnung "Interferenz-Muster" ;AUSGABE DER 59 BERG-/TAL- WERTE, nur wenn High_Freg <> 0 ! ;insges. 59 Werte aufgezeichnet clr j ldi YH,HIGH(0x0061) ldi YL,LOW(0x0061) LOOP_BERG: inc j ;j <- j + 1 ld i,Y+ ;i <- (Y), Y <- Y + 1 rcall WrCOM cpi j,59 brlo LOOP_BERG ;- - ;- - - - - - - - - - - - - - - - - - - - - - - - - - ;ldi i,0 ;rcall WrCOM ;mov i,High_Freq ;Codierte Frequenz ;rcall WrCOM ;ZUM TESTEN DES ARBEITSPUNKTS: ;mov i,Max ; Max (8bit) %%%% ;rcall WrCOM ;mov i,Min ; Min (8bit) ;rcall WrCOM OUTPUT_ENDE: ;ADC-ITR WIEDER AN! ; ;76543210 ;ldi i,0b11101XXX ;out ADCSRA,i ;b7=1(ADEN) :ADC enable ein ! ;b6=1(ADSC) :Start first Conv. ;b5=1(ADFR) :free running ein! ;b4=0(ADIF) :ADC-ITR-Flag(read) ;b3=1(ADIE) :ADC-ITR-Enable ein! VAR_RESET: cbi portb,GRUEN_b cbi portb,ORANGE_b cbi portb,GELB_b rcall RESTART_uSEC ;Timer0 wieder hochzählen ENDE_ADC_COMPLETE: out SREG,Sicher_ITR1 reti ;---------------------------------------------------------- WrCOM: in Sicher_1,SREG sbi portb,TXD ;Senden (Übergabewert i) ldi Delay,Del_1 D4: dec Delay brne D4 ldi Count,8 L2: sbrc i,0 rjmp OFF rjmp ON ON : sbi portb,TXD rjmp BitD OFF: cbi portb,TXD rjmp BitD BitD: ldi Delay,Del_1 D5: dec Delay brne D5 lsr i dec Count brne L2 cbi PORTB,TXD ldi Delay,Del_1 D6: dec Delay brne D6 out SREG,Sicher_1 ret ;----------------------------------------------------------- TIM0_OVF: ;Zählt High-Byte von uSec_H:L hoch in Sicher_ITR2,SREG inc uSec_H_ITR out SREG,Sicher_ITR2 reti ;----------------------------------------------------------- RESTART_uSEC: ;bereitet für neue Zählung von ;X Frequenz-Bergen vor in Sicher_1,SREG clr ADC_H_alt ;Reset ADC clr Richtung clr BergZahl ldi YH,HIGH(0x0061) ;Reset Berg-Wert-Speicher im SRAM ldi YL,LOW(0x0061) ldi i,1 ;Reset Timer-Werte out TCNT0,i clr uSec_L clr uSec_H clr uSec_H_ITR clr Max ;Max <- 0 ldi i,255 ;Min <- 255 mov Min,i ;TIMER0 WIEDER STARTEN! ;76543210 ldi i,0b00000001 ;bit2..0=001 0=> Takt=CK(1MHz) out TCCR0,i ;76543210 ldi i,0b00000010 ;bit1 =1 => Timer0 OVF ITR enable out TIMSK,i out SREG,Sicher_1 ret ;----------------------------------------------------------- FREQ_CHECK: ;Übergabevariablen: ;rein: FREQUENZVORGABE: ; j(High-Byte):i(Low-Byte) ; TOLERANZWERT: ; m(High-Byte):k(Low-Byte) ;raus: High_Freq in Sicher_1,SREG add i,k ;[j:i] <- [j:i] + [m:k] adc j,m cp uSec_L,i cpc uSec_H,j brsh NO_FREQ sub i,k ;[j:i] <- [j:i] - [m:k] sbc j,m sub i,k ;[j:i] <- [j:i] - [m:k] sbc j,m cp uSec_L,i cpc uSec_H,j brlo NO_FREQ ;FREQUENZ GEFUNDEN! rjmp FREQ_CHECK_ENDE NO_FREQ: clr High_Freq FREQ_CHECK_ENDE: out SREG,Sicher_1 ret ;----------------------------------------------------------- HIGH_TONE: .db HF_1209,F1209_L,F1209_H,32 ;8,16,32 codieren die LEDs .db HF_1336,F1336_L,F1336_H,16 ;für Befehl .db HF_1477,F1477_L,F1477_H,8 .db 0,0 ;----------------------------------------------------------- SIGNAL_CHECK: ;Signal-Modifikationen in Sicher_1,SREG ;AC-ANTEIL SELEKTIEREN: ;Signal wird von DC-Anteil befreit clr j ;übrig bleibt AC-Anteil clr Max ;Max neu definiert: Max. AC-Anteil ldi YH,HIGH(0x0061) ldi YL,LOW(0x0061) LOOP_SUB_MIN: inc j ld i,Y ;i <- (Y) sub i,Min ;i <- i-Min cp Max,i brsh SAVE_AC mov Max,i ;Max <- i SAVE_AC: st Y+,i ;(Y) <- i, Y <- Y+1 cpi j,59 brlo LOOP_SUB_MIN ;### MAX MINDESTENS 100! ### LOOP_PRE_ZOOM: ldi i,100 ;um den Faktor mit 8bit zu reali- cp Max,i ;sieren, dürfen nur Werte zwischen brsh FIND_FAKTOR ;100 .. 255 verwendet werden! clr j ldi YH,HIGH(0x0061) ldi YL,LOW(0x0061) ADD Max,Max ;Max <- 2 x Max PRE_ZOOM: inc j ld i,Y ;i <- (Y) add i,i ;i <- i+i (= 2xi ) st Y+,i ;(Y) <- (Y)+i (= 2x (Y)) cpi j,59 brlo PRE_ZOOM rjmp LOOP_PRE_ZOOM ;### WERTE AUF 0..255 AUFWEITEN ### FIND_FAKTOR: ;mit Faktor = 25500 / Max ldi j,0x63 ldi i,0x9C ;[j:i] <- 25500 (255 x 100) clr Faktor clr m ;für [m:Max] LOOP_FAKTOR: ;Faktor <- 0x639C / Max cp i,Max cpc j,m ;[j:i] < [m:Max] ? brlo ENDE_LOOP_FAKTOR inc Faktor sub i,Max sbc j,m ;[j:i] <- [j:i] - [m:Max] rjmp LOOP_FAKTOR ENDE_LOOP_FAKTOR: ;Faktor ist gefunden ldi YH,HIGH(0x0061) ldi YL,LOW(0x0061) clr p FAKTOR_MULTIP: clr i ;zuerst (Y) x Faktor rechnen clr j clr k clr n inc p cpi p,60 ;nur 59 mal durchlaufen! brsh ENDE_FAKTOR_MULTIP ld m,Y ;m <- (Y) LOOP_MULTIP: ;Einfaches Multiplikationsprogramm: cp k,Faktor ;[j:i] <- m x Faktor brsh FAKTOR_DIVIS inc k add i,m ;[j:i] <- [j:i] + m adc j,n rjmp LOOP_MULTIP FAKTOR_DIVIS: ;Einfaches Divisionsprogramm: ldi m,100 ;[j:i] <- [j:i] / 100 ([n:m]) clr n clr k LOOP_DIVIS: cpi j,0 brne DIVIS_1 cpi i,100 brsh DIVIS_1 rjmp STORE_DIVIS ;wenn: [j:i] < 100 ! DIVIS_1: inc k ;k = Ergebnis der Division sub i,m ;[j:i] <- [j:i] - 100 sbc j,n rjmp LOOP_DIVIS STORE_DIVIS: st Y+,k ;(Y) <- k, Y <- Y + 1 rjmp FAKTOR_MULTIP ENDE_FAKTOR_MULTIP: out SREG,Sicher_1 ret