;****************************************************************************
;*ATtiny2313 LC meter based on ideas from: *
;*frequency meter (C)2002 by Richard Cappels sap@cappels.org *
;*;http://projects.cappels.org/ *
;*Math routines from Fred W. Krom PE0FK0 see http://home.ict.nl/~fredkrom *
;*the rest changed a lot by Rudi Drabek (C)2009 *
;*especially NEW calibrating routine to eliminate warmup drift ~3pF *
;*when used keep copyrights mentioned! *
;****************************************************************************
.include "tn2313def.inc"
.equ clock = 5000000 ;clock frequency
.equ baudrate = 9600 ;choose a baudrate
.equ baudconstant = 31 ;(clock/(16*baudrate))-1
;Fuses High = $DB, LOW = $EE
; ATtiny2313
; +--+-+--+ 2 Reedrelais:
; !RESET |1 |_|20| VCC 1 Lreed
; (RX)PD0 | | PB7(SCK) 2 Creed
; (TX)PD1 | | PB6(MISO)
; XTAL2 | | PB5(MOSI)
; XTAL1 | | PB4
; (INT0)PD2 | | PB3(OC1)
; (INT1)PD3 | | PB2
; (T0)PD4 | | PB1
; (T1)PD5 | | PB0
; GND |10 11| PD6
; +-------+
;
; PD0 I RX RS232 nicht benützt
; PD1 O TX RS232
; PD2 O C-reed off=Co on=Cx, immer off bei Lx
; PD3 O L-reed off=Lx on=Lo umgekehrt!! immer on bei Cx
; PD4 I L/C Schalter
; PD5 I Frequence input von LM319
; PD6 O nc
; PB0 I Display pin 11 D4 4bit mode, Display HMC16223SO von Pollin
; PB1 I Display pin 12 D5
; PB2 I Display pin 13 D6
; PB3 I Display pin 14 D7
; PB4 O Enable pin 6
; PB5 O RS pin 4
; PB6 O Gate LED
; PB7 nc
.macro storeX ;SRAM intermediate store
ldi ZL,byte1(@0)
rcall stx
.endmacro
.macro storeY ; <memory>
ldi ZL,byte1(@0)
rcall stY
.endmacro
.macro loadX ; <memory>
ldi ZL,byte1(@0)
rcall ldX
.endmacro
.macro loadY ; <memory>
ldi ZL,byte1(@0)
rcall ldY
.endmacro
.macro movXtoY
mov RY0,RX0
mov RY1,RX1
mov RY2,RX2
mov RY3,RX3
.endmacro
.macro movYtoX
mov RX0,RY0
mov RX1,RY1
mov RX2,RY2
mov RX3,RY3
.endmacro
;counter gatetime variables
.def presetloopmultiplier =r0
.def presetdelaycounter =r1
.def presetdelaycounter1 =r2
.def delaycounter =r3
.def delaycounter1 =r4
.def loopmultiplier =r5
;*********************************
;calculation varables
.def RY0 = r6
.def RY1 = r7
.def RY2 = r8
.def RY3 = r9
.def RR0 = r10
.def RR1 = r11
.def RR2 = r12
.def RR3 = r13
.def RR4 = r14
.def lcswitch=r15 ;check ob L oder C Messung
.def RX0 = r16 ; timer1 lo und fx^2
.def RX1 = r17 ; timer1 hi und fx^2
.def RX2 = r18 ; fx^2
.def RX3 = r19 ; fx^2
.def RX4 = r20 ; BCD value digits 0 and 1
.def RX5 = r21 ; BCD value digits 2 and 3
.def RX6 = r22 ; BCD value digits 4 and 5
.def RX7 = r23 ; BCD value digits 6 and 7 (MSD)
;allgemeine Variablen ;general purpose register
.def A = r24
.def B = r25
.def C = r29
.def mux = r26
.org $00
rjmp main
.org $0007 ;RXCIE Interrupt, Wird nicht verwendet,nur zur Vollständigkeit
;may be zur Kalibrierung verwenden.
.org $13
;constanten für die Cx Lx Berechnung
k1: ;von http://netzreport.googlepages.com onlineumrechner k=1/(4*pi^2*Lo)
.db $80, $d0, $c0, $6b, $52, $03; 69,35uH, 1020pf k=3,65253e(14-2), 0,1s gate!!
;k1 wird nicht verwendet bei fo^2/fx^2 Methode ACHTUNG
Cref:
.db $93,$03,00,00 ;die Basiskapazität 915 pF .Ein zweiter Referenzkondensator
;zur Co Kalibrierung ist auch nicht besser als der verwendete Styroflex.
;also wird die fo Drift herausgemessen und damit eliminiert. (C) Rudi Drabek
Lref:
.db $40, $19,$01,00 ;die Basisinduktivität 72000 nH,
_C: .db " C-Messung (pF)",00,00
_L: .db " L-Messung (nHy)",00,00
main:
ldi A,low(ramend)
out spl,A ;set Stackpointer
clr ZH ;ist ZH und immer 0
ldi ZL,k1*2 ;adressiere Konstanten bytewise
clr YH ;und verschiebe nach
ldi YL,kc ;Beginn SRAM bzw. .dseg
ldi mux,14
tabletr:lpm A,Z+
st Y+,A
dec mux
brne tabletr ;fertig
;init Port B und D
ldi A,255 ;alles output bei LCmeter
out DDRB,A ;B0....B5 Display, B6="Gate open" LED
;B7 ist unbeschaltet
ldi A,0b01001110;PortD0=RX, PD1=TX, PD2=Creed, PD3=Lreed,PD4=L/C switch,
;PD5=In Counter1 ;PD6= unbeschaltet PD7 gibts nicht
out DDRD,A
;via RS232 über PD1 gehen die Ergebnisse zum VFD-Display bzw.RS232 Empfänger
;für den Fall der weiteren Nutzung am z.B. PC
;init counter1
ldi A,$00 ;set TCCR1A
out TCCR1A,A ;Seite 108 "normal count operation" von Counter1
ldi A,$06 ;enable input to counter 1 Seite 111
out TCCR1B,A ;clock on falling edge, so nötig für 74F160
ldi A,$00 ;clear 16 bit counter
out tcnt1h,A
out tcnt1l,A
mov RX2,A ;RX0...3 NULL setzen
mov RX3,A
ldi A,$70 ;setzt Bits 4,5 und 6 auf 1 : 74F160 und LED aktiv
out PortB,A ;jetzt
;RS232_init
cli ;disable Interrupt during setup of USART
clr A
out UBRRH,A ;baudrate 9600 bei 4 Mhz aus Tabelle
ldi A,baudconstant
out UBRRL,A
ldi A,0b0000110 ;8N1 setzen
out UCSRC,A
ldi A,0b10011000; RX und TX enable, RXCIE interrupt enable
out UCSRB,A ;
;sei ;enable Interrupt, bleibt gesperrt
;set 0,1s Messzeit sodass Timer 1 innerhalb 16 bit Ergebnis bleibt
ldi A,25 ;(19949+51 codecycles)*25 -1= 499999 cycles
mov presetloopmultiplier,A ; +2 cycles "cbi instr." in total 500001
ldi A,98 ;(4 cycles) * 98 -1=391 cycles
mov presetdelaycounter,A
ldi A,50 ;(391+8)*50 -1=19949
mov presetdelaycounter1,A
;**************LCD Init
lcd_init:
ldi C,$FF ;PortB alle auf Output Seite50
out DDRB,C
;clr C ;geht net wieso? WEGEN enable Puls
out PortB,C ;definierter Status fürs Display
ldi B,100 ;n x 2ms delay
wait_display: ;t2313 ist fertg, display auch
rcall delay2ms ;lass alles zur Ruhe kommen
dec B
brne wait_display
; Display DB [7:4] liegt auf PortB [3:0]
; sonst könnte man nicht RS = PB5, Enable = PB4
; im 4 bit mode vom PortB aus bedienen
ldi C,0b00000011 ;8bit mode,
out LCD_PORTB, C ;
rcall lcd_enable ;1,
rcall delay2ms
rcall delay2ms
rcall lcd_enable ;2
rcall delay2ms
rcall lcd_enable ;3
rcall delay2ms ;Display ist jetzt eindeutig im 8bit mode
;LCD: function set
ldi C,0b00000010;4bit-Mode, noch im 8 bit mode gesendet
out LCD_PORTB, C
rcall lcd_enable
rcall delay2ms ;Display ist jetzt im 4bit mode
; ab nun kann das Byte jeden Wert haben, da es in 2 nibbles aufgeteilt
; wird, die via PB[3:0] kommend, an das Display DB[7:4] gelangen.
funcset:ldi C, 0b00101000 ;4bit, 2 Zeilen, 5x7 dots + cursor
rcall lcd_cmd
disp_on:ldi C, 0b00001100 ;Display on, Cursor off, blink off
rcall lcd_cmd
dispclr:ldi C, 0b00000001 ;clear Display,Cursor home,
rcall lcd_cmd ;executiontime 1,52 ms
rcall delay2ms ;deshalb delay
entmode:ldi C, 0b00000110 ;increment, Cursor move
rcall lcd_cmd
;********************
;* MEASURE FREQUENCY*
;********************
measurefreq:
; L oder C-Messung?
in lcswitch,pinD ;wie steht der L/C Auswahlschalter
sbrs lcswitch,4
rjmp messC ;bit clear = false, also messe C
;L-messung gefragt
cbi portD,2 ;C-Reed immer offen --> Cx hat keinen Einfluss
rjmp gocount ;gehe zu Frequenz feststellen
messC: sbi portD,3 ;L-Reed immer geschlossen
;**Jetzt noch 1. Zeile Display ausgeben***************
gocount:clr ZH ;Text in Zeile1 schreiben
ldi ZL,_C * 2 ;byte adresse
in lcswitch,pinD ;wie steht der L/C Auswahlschalter
sbrc lcswitch,4
subi ZL, -18 ;L-Messung gefragt
ldi C,0 ; C-Messung Zeile1 Pos1
rcall lcd_flash_string ;benützt den Befehl lpm
ldi A,$00 ;clear 16 bit counter
out TCNT1H,A
out TCNT1L,A
mov RX2,A ;clear RX0...3
mov RX3,A
mov loopmultiplier,presetloopmultiplier ;grösste Loop laden
sbi PORTB,6 ;LED Counting indicator on
ldi A,6 ;select ext. clock source
out TCCR1B,A ;start counting
bigloop:mov delaycounter,presetdelaycounter ;1; innerste loop laden
mov delaycounter1,presetdelaycounter1 ;1 mittlere loop laden
dealylooproutine: ; 5 millisecond delay loop
dec delaycounter ;1
nop ;1
brne dealylooproutine ;2;1;in Summe 392-1
mov delaycounter,presetdelaycounter ;1;reload innerste loop
dec delaycounter1 ;1;werde später fractured loop
nop ;1;wie im Original machen
nop ;1
nop ;1
brne dealylooproutine ;2;1; in Summe 19950-1
;die LoCo Werte werden so eingestellt, dass timer1 auf max.62000 zählt
in A,TIFR ;check auf Überlauf ;1;
sbrs A,7 ;Seite 82 TOV1 = bit7 ;2;1;
rjmp nooverflow ;2;
inc RX2 ;ja, also SWcounter hinaufzählen ;1;
ori A,128 ;setze Bit 7, damit TOV1 Flag gelöscht wird.;1;
out TIFR,A ; ;1;
rjmp goon ;2;
nooverflow:nop ;;Zeitausgleich für overflowhandling ;1;
nop ;muss ja gleich lang sein, sonst ist die ;1;
nop ;1 sec Messzeit="gate open" verschieden lang;1;
goon: ldi A,9 ;extra Zeit damit die Messzeit 0,1 sec ist;1;in Summe 8
goon1: dec A ;1;jeder Zweig
nop ;1;
brne goon1 ;2;1;in Summe 36-1
nop ;1;
nop ;1;
dec loopmultiplier ;1;
brne bigloop ;2;1;in Summe 6
;jetzt ist die gatetime abgelaufen, bis hierher dauert es in Summe 499999 cycles
out TCCR1B,ZH ;stop counting Timer1 = no clock source set
cbi PortB,5 ;Rest von 120 MHz Zähler stört nicht
cbi PortB,6 ;set port d bit 6 low (turn LED off)
;hole die Ergenisse timer1
in RX0,TCNT1L;move counter contents to input for number conversion
in RX1,TCNT1H;RX2 und RX3 bleiben ja NULL;
;**************************************************************************
;* Cx = (Co*fo^2)/fx^2 - Co ;genau so ausführen wegen Auflösung
;* bei kleinen Cx Werten !!!
;**************************************************************************
in lcswitch,pinD ;wie steht der L/C Auswahlschalter
sbrs lcswitch,4
rjmp isC
isL: sbic portD,3 ;wie steht Lreed?
rjmp countfo ;Lreed "on" , Lo messen
sbi portD,3 ;Lreed ist "off", also "on" für nächste fo Messung
rjmp goLC
isC: sbis portD,2 ;wie steht Creed
rjmp countfo ;Creed "off", Co messen
cbi portD,2 ;Creed ist "on", for next measurecycle auf "off"
goLC: movXtoY ;copy counter from RXn to RYn for fx^2
rcall mul32 ;ergibt nur 32 bit fx^2 da ja timer1 in 16bit bleibt
storeX fx2 ;fx^2 speichern
loadY fo2 ;fo^2 holen ;könnte man ausbauen z.B. 20 bit
;L oder C Messung?
in lcswitch,pinD ;wie steht der L/C Auswahlschalter
sbrs lcswitch,4
rjmp getc
loadX Lo
rjmp gocalc
getc: loadX Co
gocalc:
rcall mul32 ;Co * fo^2
loadY fx2
rcall div48 ;so, C ist berechnet Ergebnis max 256e3= 16,7 mio pF
in lcswitch,pinD ;wie steht der L/C Auswahlschalter
sbrs lcswitch,4
rjmp cmess
loadY Lo ;jetzt noch das reale Lo der Schaltung abziehen
rjmp abziehen
cmess: loadY Co
abziehen:rcall sub32 ; ohne Cx sollte jetzt 00000000 da stehen, real 1pF
;Messwert ausgeben
; in BCD wandeln, aber vorher "L" oder "C" ausgeben für RS232 only
in lcswitch,pinD ;wie steht der L/C Auswahlschalter
sbrs lcswitch,4
rjmp is_C
ldi A,'L' ;bit 4 set also Spule
rjmp is_LC
is_C: ldi A,'C' ;bit 4 clear, also Kondensator
is_LC: rcall WrCOM
rcall millisec ;jetzt die 8 Stellen des Ergebnisses
;**Display Zeile 2 löschen und Cursor auf Position 6 = 64 + 6 =70
rcall clrline2
ldi C,70 ;Cursor auf Position 7 in Zeile 2
rcall set_cur
rcall Bin3BCD16 ;in ASCII ausgeben
ldi mux,4 ;RX7 bis RX4 ausgeben
clr ZH ;Z auf RX7 setzen
ldi ZL,24 ;um 1 höher wegen "ld -Z" Befehl
bcdout: ld A,-Z ;hoechste Stelle =r23= BCD8 und 7 zuerst raus
swap A
andi A, 15 ;hi nibble maskieren
ori A,$30 ;in ASCII
rcall WrCOM ; an RS232
;und ans Display senden
mov C,A ;Wert nach C weil lcd_data das will
rcall lcd_data
rcall millisec ;1 Byte braucht ja 1,04 ms, no handshake
ld A,Z ;also Wartezeit von ca 1,2 ms einführen
andi A, 15 ;lo nibble detto
ori A,$30 ;in ASCII
rcall WrCOM ; an RS232
;und ans Display senden
mov C,A ;Wert nach C weil lcd_data das will
rcall lcd_data
rcall millisec
dec mux
brne bcdout ;4 Bytes mit den 8 Stellen ausgegeben
premea: clr A ;extra delay ca 1/3 sec damit display
mov loopmultiplier,A;mit 0,1 sec gatetime nicht so flackert.
disp3: rcall millisec
dec loopmultiplier
brne disp3
rjmp measurefreq
;
;die Induktivität stabil zu bekommen war nicht einfach
;jedenfalls darf man keine "bead choke" verwenden.
countfo: ;bei offenem Reedrelais wird das eingebaute C ermittelt
in lcswitch,pinD ;wie steht der L/C Auswahlschalter
sbrs lcswitch,4
rjmp isCo
isLo: cbi portD,3 ;Lreed ist "on", für next cycle = fx "off"
rjmp countfo1
isCo: sbi portD,2 ;Creed ist "off", for next measurecycle auf "on"
countfo1:movXtoY ;copy counter from RXn to RYn for fo^2
rcall mul32 ;ergibt nur 32 bit fo^2 da ja timer1 in 16bit bleibt
storeX fo2 ;das ist jetzt das aktuelle fo^2
rjmp premea ;das reed soll ausgeprellt haben
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; LCD-Routinen für HMC16223 Display ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.equ LCD_PORTB = PORTB ;define the Ports / IOs
.equ LCD_DDRB = DDRB
.equ PIN_RS =PB5 ;Config for display RS und Enable
.equ PIN_E =PB4
;send text pointed by source=Z und destination=C from flasch to LCD
lcd_flash_string:
rcall set_cur ;set display, DDRAM address
lcd_flash_1:
lpm C, Z+ ;pointed char nach C
cpi C, 00 ;Stringende = 0
breq lcd_flash_2
rcall lcd_data
rjmp lcd_flash_1
lcd_flash_2:ret
;send a data byte in C to the LCD, RS = high, changes C
lcd_data:
push C ;copy the data byte for later
swap C ;hi nibble zuerst senden
andi C, 0b00001111 ;clear ehemals low nibble
sbr C, 1<<PIN_RS ;es sind Daten RS=1
out LCD_PORTB, C ;prepare LCD port for write
rcall lcd_enable ;LCD enable writes now + 50us
pop C ;process now low nibble
andi C, 0b00001111
sbr C, 1<<PIN_RS ;es sind Daten RS=1
out LCD_PORTB, C ;
rcall lcd_enable
ret
;send a command in C to the LCD, RS = low changes C
;bis auf RS kein Unterschied zu lcd_data
lcd_cmd:push C ;copy the command byte for later
swap C ;hi nibble zuerst senden
andi C, 0b00001111 ;clear ehemals low nibble und RS=0
out LCD_PORTB, C ;prepare LCD port for write
rcall lcd_enable ;LCD enable writes now + 50us
pop C ;process now low nibble
andi C, 0b00001111 ;RS ist damit automatisch 0
out LCD_PORTB, C ;
rcall lcd_enable
ret
clrline2:ldi C,64 ;lösche Zeile2 des Displays
rcall set_cur
ldi A,15
clr1: ldi C,' '
rcall lcd_data
dec A
brne clr1
ret
;create enable pulse 5 cycles auf 1 macht 0,75 us ändert kein Register
;mit fallender Flanke werden Daten übernommen
lcd_enable:
sbi LCD_PORTB, PIN_E ;2; Enable high
nop
nop
nop
cbi LCD_PORTB, PIN_E ;2; Enable low
rcall delay50us ;ab H>L Enable braucht das Display 38 us
ret ;bis es wieder bereit ist
; set cursor to DDRAM position in C, changes C
; 1. line [C]= 0.....15d
; 2. line [C]= 64d...79d
set_cur:ori C, $80 ;Befehl selbst
rcall lcd_cmd
rcall delay50us ;50 us sollte an sich genügen
ret
; > 38 us delay, ändert kein Register
delay50us:push A
ldi A, 50
delay50us_:dec A ;(5*50-1+7)*0,2 = 51,2 us
nop
nop
brne delay50us_
pop A
ret
; > 1,52 ms delay for lcd_clr und lcd_home ändert kein Register
delay2ms:push C
push B
ldi C, 32
w2ms0: ldi B, 125
w2ms1: dec B ;delay 3*B -1 Takte ~75 uS
brne w2ms1
dec C ;+1
brne w2ms0 ;(375*32 +10)*0,2
pop B
pop C
ret ;= 2402 uS
;--------------------------------------------------------------------
;-- RX[64] = RX[32] * RY[32]
;-- bei LCcalc bleibt das Ergebnis aber innerhalb 32 bit.
;die Genauigkeit des LC-meters ist bei 16 bit timer 1, selbst bei
;Zählerstand 1000 innerhalb 1%o, also eine Messzeitanpassung, damit
;der Zähler immer nah am maxcount liegt ist eine Fleissaufgabe
;--------------------------------------------------------------------
mul32: clr RX7
clr RX6
clr RX5
sub RX4,RX4 ; RX4=0, C=0
ldi A,32+1
mnxtb: brcc mnoadd
add RX4,RY0
adc RX5,RY1
adc RX6,RY2
adc RX7,RY3
mnoadd: ror RX7
ror RX6
ror RX5
ror RX4
ror RX3
ror RX2
ror RX1
ror RX0
dec A
brne mnxtb
ret
;--------------------------------------------------------------------
;-- RX[48] = RX[48] / RY[32]
;--------------------------------------------------------------------
div48: ldi A,48+1 ; init loop counter
clr RR0 ; clear remainder Low byte
clr RR1
clr RR2
clr RR3
sub RR4,RR4 ; clear remainder High byte and carry
div1: rol RX0
rol RX1
rol RX2
rol RX3
rol RX4
rol RX5
dec A
brne div3
ret
div3: rol RR0
rol RR1
rol RR2
rol RR3
rol RR4
sub RR0,RY0 ;remainder = remainder - divisor
sbc RR1,RY1
sbc RR2,RY2
sbc RR3,RY3
sbc RR4,ZH
brcc div2 ;if result negative
add RR0,RY0 ; restore remainder
adc RR1,RY1
adc RR2,RY2
adc RR3,RY3
adc RR4,ZH ;
clc ; clear carry to be shifted into result
rjmp div1 ;else
div2: sec ; set carry to be shifted into result
rjmp div1
;--------------------------------------------------------------------
;-- RX[32] = RX[32] - RY[32]
;--------------------------------------------------------------------
sub32: sub RX0,RY0
sbc RX1,RY1
sbc RX2,RY2
sbc RX3,RY3
ret
;--------------------------------------------------------------------
;-- Store and load X & Y from SRAM
;--------------------------------------------------------------------
stx: st Z+,RX0
st Z+,RX1
st Z+,RX2
st Z+,RX3
ret
sty: st Z+,RY0
st Z+,RY1
st Z+,RY2
st Z+,RY3
ret
ldX: ld RX0,Z+ ;
ld RX1,Z+
ld RX2,Z+
ld RX3,Z+
ret
ldy: ld RY0,Z+
ld RY1,Z+
ld RY2,Z+
ld RY3,Z+
ret
;Delay für RS232. Da kein Handshake verwendet wird
;muss der Sender fürs timing sorgen
millisec:clr A ;(256*3*8 -1 +7)*0,20 uS=1,23 ms
ldi B,9 ;wenn A nicht mit 0 geladen wird, dann ist der
millis: dec A ;1. Durchlauf eben entsprechend. Der 2. aber mit
brne millis ;256 , so kann man "fractured loops" bauen
dec B ;und gut sehr genau auf die gewünschte Zeit kommen.
brne millis
ret
;-----> wird nicht verwendet
;Empfange Zeichen via Interruptsteuerung. Kopie der Routine vom VFD-Display
RdCom: clr YH
ldi YL,$60
ldi mux,8 ;jetzt das ganze Display um eine Stelle nach links
d_shift:ldd B,Y+1 ;hole Stelle+1, speichere 1 Stelle links davon
st Y+,B ;dann nächste Stelle rechts adressieren
dec mux ;8x das ganze
brne d_shift
in A,UDR ;hole USART empfangenes Byte ab
rcall WrCom ;Echo out
andi A,15 ;in Zahl wandeln, falls nötig
ldi YL,$68 ;und
st Y,A ;ins Display rechtsbündig schreiben
reti ;nicht vergessen "i"
;max 9 Zeichen dürfen gesendet werden, das Display kann nicht mehr darstellen
WrCOM: sbis UCSRA,UDRE ;wait for empty transmit buffer
rjmp WrCom
out UDR,A ;sende Byte in A
ret
;***************************************************************************
;* Bin3BCD == 24-bit Binary to BCD conversion
;*
;* RX0:RX1:RX2 >>> RX4:RX5:RX6:RX7
;* hex dec
;* r16r17r18 >>> r20r21r22r23
;* see AVR200 bis MATH32X application notes, http://avr-asm.tripod.com
;* sehr gute Seite ist auch http://elm-chan.org u.a. Wurzel ziehen
;***************************************************************************
;.def RX0 =r16 ; binary value byte 0 (LSB)
;.def RX1 =r17 ; binary value byte 1
;.def RX2 =r18 ; binary value byte 2 (MSB)
;.def RX3 =r19 ; ist für diese Routine nicht nötig
;.def RX4 =r20 ; BCD value digits 0 and 1
;.def RX5 =r21 ; BCD value digits 2 and 3
;.def RX6 =r22 ; BCD value digits 4 and 5
;.def RX7 =r23 ; BCD value digits 6 and 7 (MSD)
Bin3BCD16: ldi RX7,0xfa ;initialize digits 7 and 6
binbcd_107: subi RX7,-0x10 ;
subi RX0,byte1(10000*1000) ;subit fbin,10^7
sbci RX1,byte2(10000*1000) ;
sbci RX2,byte3(10000*1000) ;
brcc binbcd_107 ;
binbcd_106: dec RX7 ;
subi RX0,byte1(-10000*100) ;addit fbin,10^6
sbci RX1,byte2(-10000*100) ;
sbci RX2,byte3(-10000*100) ;
brcs binbcd_106 ;
ldi RX6,0xfa ;initialize digits 5 and 4
binbcd_105: subi RX6,-0x10 ;
subi RX0,byte1(10000*10) ;subit fbin,10^5
sbci RX1,byte2(10000*10) ;
sbci RX2,byte3(10000*10) ;
brcc binbcd_105 ;
binbcd_104: dec RX6 ;
subi RX0,byte1(-10000) ;addit fbin,10^4
sbci RX1,byte2(-10000) ;
sbci RX2,byte3(-10000) ;
brcs binbcd_104 ;
ldi RX5,0xfa ;initialize digits 3 and 2
binbcd_103: subi RX5,-0x10 ;
subi RX0,byte1(1000) ;subiw fbin,10^3
sbci RX1,byte2(1000) ;
brcc binbcd_103 ;
binbcd_102: dec RX5 ;
subi RX0,byte1(-100) ;addiw fbin,10^2
sbci RX1,byte2(-100) ;
brcs binbcd_102 ;
ldi RX4,0xfa ;initialize digits 1 and 0
binbcd_101: subi RX4,-0x10 ;
subi RX0,10 ;subi fbin,10^1
brcc binbcd_101 ;
add RX4,RX0 ;LSD
ret ;
;--------------------------------------------------------------------
;-- SRAM variablen
;--------------------------------------------------------------------
.dseg
kc: .byte 6 ; Konstante für C-Rechnung
Co: .byte 4 ; C reference
Lo: .byte 4 ; L reference
fo2: .byte 4 ; f0 ohne Cx
fx2: .byte 4 ; fx mit zu messendem Cx, Lx
kl: .byte 6 ; Constant L calculation
; ursprünglich wollte ich fo ersetzen durch kc bzw kl für die Cx und Lx
; Messung. Aber die aktuelle fo Messung und die Autocalibratroutine
; (jede 2. Messung stellt fo fest) ist einfacher, da fo nicht aus Lo
; bzw Co errechnet wird. Auch ist Lo und Co nicht ausreichend konstant über
; Temperatur. Das ist die einzige Quelle, neben dem LM319 für Unstabilität