;********************************* ;Lazy guy's resonant frequency meter for L and C measurement ;Copyright(C)2002,2003 by Richard Cappels projects@cappels.org ;http://www.projects.cappels.org ;Uses AT90S2313 or similar operating at 4 MHz. ;Input is D5 ;LED output is D6 - goes low during frequency measurements and high while sending data. ;********************************* .include "2313def.inc" .equ clock = 4000000 ;clock frequency .equ baudrate = 9600 ;choose a baudrate .equ baudconstant = (clock/(16*baudrate))-1 ;***** 16 bit binary-to-packed-BDC Subroutine Register Variables .equ AtBCD0 =13 ;address of tBCD0 .equ AtBCD2 =15 ;address of tBCD1 ;***** other register assignments for frequency meter .def reallybigloopcounter =r1 .def presetreallybigloopcounter =r2 ;1, $0A number of seconds when loopmultiplier is = $64 .def presetloopmultiplier =r3 ;$64, $01 number of 10 ms increments .def presetdelaycounter =r4 ;$F4 at all times (for 4 MHz) .def presetdelaycounter1 =r5 ;$27 st all times (for 4 MHz) .def dacvalue =r6 ;Actuall pulse amplitude for pulse generator. .def daczero =r7 .def tBCD0 =r13 ;BCD value digits 1 and 0 .def tBCD1 =r14 ;BCD value digits 3 and 2 .def tBCD2 =r15 ;BCD value digit 4 .def fbinL =r16 ;binary value Low byte .def fbinH =r17 ;binary value High byte .def cnt16a =r18 ;loop counter .def tmp16a =r19 ;temporary value .def inbyteh =r20 ;higher byte for asci-hex conversion .def temp =r21 ;general purpose register .def delaycounter =r22 .def delaycounter1 =r23 .def loopmultiplier =r24 .def inchar =r25 ;char destined to go out the uart ;.def XL =r26 ;char coming in from the uart ;.def XH =r27 ;lower byte for asci-hex conversion .org $00 rjmp reset rjmp reset rjmp reset rjmp reset rjmp reset rjmp reset rjmp reset rjmp reset rjmp reset rjmp reset rjmp reset hellomessage: .db "LGM031227I 100ms" crlfmessage: .db $0A,$0D .db 00,00 kilohertz: .db " KHz" .db 00,00 reset: ldi temp,low(ramend) out spl,temp ;set spl ldi temp,baudconstant out ubrr,temp ;load baudrate ldi temp,$FF ;Weak pullups on all pins on PORTD out portd,temp ldi temp,$40 ;Make D6 an output out ddrd,temp rcall delaystart ;One second delay for display to start up. rcall TypeGreeting ;Display greeting. rcall delaystart rcall set100ms ;Measurement period measurefreuqency: ;Measeure and send forever. rcall measurefreq rjmp measurefreuqency set10ms: ldi temp,$01 mov presetreallybigloopcounter,temp ldi temp,$01 mov presetloopmultiplier,temp ldi temp,$F4 mov presetdelaycounter,temp ldi temp,$27 mov presetdelaycounter1,temp ret set100ms: ldi temp,$01 mov presetreallybigloopcounter,temp ldi temp,$0A mov presetloopmultiplier,temp ldi temp,$F4 mov presetdelaycounter,temp ldi temp,$27 mov presetdelaycounter1,temp ret set1s: ldi temp,$01 mov presetreallybigloopcounter,temp ldi temp,$64 mov presetloopmultiplier,temp ldi temp,$F4 mov presetdelaycounter,temp ldi temp,$27 mov presetdelaycounter1,temp ret rs_send: sbi ucr,txen ;set sender bit sbis usr,udre ;wait till register is cleared rjmp rs_send out udr,XL ;send the byte cbi ucr,txen ;clear sender bit ret ;go back crlf: ;send carriage return and line feed. ldi ZH,high(2*crlfmessage) ;Load high part of byte address into ZH ldi ZL,low(2*crlfmessage) ;Load low part of byte address into ZL rcall sendstring ret sendstring: ;call with location of string in Z lpm ;Load byte from program memory into r0 tst r0 ;Check if we've reached the end of the message breq finishsendstering ;If so, return mov XL,r0 rcall rs_send adiw ZL,1 ;Increment Z registers rjmp sendstring finishsendstering: ret sendline: ;send a string terminated in cariage return and line feed ;call with location of start of string in Z rcall sendstring rcall crlf ret TypeKHz: ldi ZH,high(2*kilohertz) ;Load high part of byte address into ZH ldi ZL,low(2*kilohertz) ;Load low part of byte address into ZL rcall sendstring ;sent it. ret TypeGreeting: ldi ZH,high(2*hellomessage) ;Load high part of byte address into ZH ldi ZL,low(2*hellomessage) ;Load low part of byte address into ZL rcall sendline ;sent it. ret byte_to_asciihex: ;convert byte in XH to ascii in inbyteh,nbytel mov inbyteh,XH lsr inbyteh ;convert the high nybble to ascii byte lsr inbyteh lsr inbyteh lsr inbyteh subi inbyteh,$D0 ;add $30 cpi inbyteh,$3A brlo PC+2 ;If less than 9 skip next instruction subi inbyteh,$F9 ;add 8 to ASCII (if data greater than 9) ; byte in inbyteh represents upper nybble that was in XH at start andi XH,0b00001111 ;convert the lower nybble to ascii byte subi XH,$D0 ;add $30 cpi XH,$3A brlo PC+2 ;If less than 9 skip next instruction subi XH,$F9 ;add 8 to ASCII (if data greater than 9) ret ;byte in inbyteh represents upper nybble that was in XH at start sendbyte: ;send byte contained in XH to terminal rcall byte_to_asciihex mov XL,inbyteh rcall rs_send mov XL,XH rcall rs_send ret sendbinarybyte: ldi temp,$08 stillsendingbinary: ;rotate byte through carry; send 0 or 1 depending on carry bit ldi XL,$30 rol XH brcc dontsendone ldi XL,$31 dontsendone: rcall rs_send dec temp brne stillsendingbinary ret ;******************* ;******************* ;******************* MEASURE FREQUENCY ;******************* ;******************* measurefreq: ldi temp,$90 ;enable uart interrupts -disabled when executed out ucr,temp sei ldi temp,$00 ;set tccr1a (contorl of 16 bit counter) to all zeros out tccr1a,temp ldi temp,$00 ;clear 16 bit counter out tcnt1h,temp out tcnt1l,temp ldi temp,$06 ;enable input to counter 1 out tccr1b,temp mov reallybigloopcounter,presetreallybigloopcounter cbi PORTD,6 ;set portD bit 6 low (LED Counting indicator on) reallybigloop: mov loopmultiplier,presetloopmultiplier ;****10 ms = $01, 100 ms = $0A, 1 second = $64 bigloop: mov delaycounter,presetdelaycounter ; set values for delay of 10 ms. delaycounter = $F4, delaycounter1 = $27 mov delaycounter1,presetdelaycounter1 dealylooproutine: ; 10 millisecond dealy loop dec delaycounter cpi delaycounter,$00 brne dealylooproutine dec delaycounter1 cpi delaycounter1,$00 brne dealylooproutine nop nop dec loopmultiplier brne bigloop dec reallybigloopcounter brne reallybigloop ldi temp,$00 ;stop 16 bit counter out tccr1b,temp cli ;disable interrupts sbi PORTD,6 ;set port d bit 6 high (turn LED off) displaythedata: ;Display the data in fbinL,tcnt1l ;move counter contents to input for number conversion in fbinH,tcnt1h rcall bin2BCD16 ;Convert to 2.5-byte packed BCD format rcall crlf mov XL,tBCD2 ldi temp,$30 add XL,temp rcall rs_send mov XH,tBCD1 rcall sendbyte ldi XL,'.' ;Put decimal point after first three digits rcall rs_send mov XH,tBCD0 ;since leading digit on high byte is always zero, dont' sent it. rcall sendbyte rcall TypeKHz ;Write "Khz" after the frequency. ret ;return to calling routine to eventually go back to loop ;**** A P P L I C A T I O N N O T E A V R 2 0 4 ************************ ;* Title: BCD Arithmetics ;* Version: 1.1 ;* Last updated: 97.07.04 ;* Target: AT90Sxxxx (All AVR Devices) ;* ;* Support E-mail: avr@atmel.com ;* ;* DESCRIPTION ;* This Application Note lists subroutines for the following Binary Coded ;* Decimal arithmetic applications: ;* ;* Binary 16 to BCD Conversion (special considerations for AT90Sxx0x) ;***** Code bin2BCD16: ldi cnt16a,16 ;Init loop counter clr tBCD2 ;clear result (3 bytes) clr tBCD1 clr tBCD0 clr ZH ;clear ZH (not needed for AT90Sxx0x) bBCDx_1:lsl fbinL ;shift input value rol fbinH ;through all bytes rol tBCD0 ; rol tBCD1 rol tBCD2 dec cnt16a ;decrement loop counter brne bBCDx_2 ;if counter not zero ret ; return bBCDx_2:ldi r30,AtBCD2+1 ;Z points to result MSB + 1 bBCDx_3: ld tmp16a,-Z ;get (Z) with pre-decrement ;---------------------------------------------------------------- ;For AT90Sxx0x, substitute the above line with: ; ; dec ZL ; ld tmp16a,Z ; ;---------------------------------------------------------------- subi tmp16a,-$03 ;add 0x03 sbrc tmp16a,3 ;if bit 3 not clear st Z,tmp16a ; store back ld tmp16a,Z ;get (Z) subi tmp16a,-$30 ;add 0x30 sbrc tmp16a,7 ;if bit 7 not clear st Z,tmp16a ; store back cpi ZL,AtBCD0 ;done all three? brne bBCDx_3 ;loop again if not rjmp bBCDx_1 delaystart: rcall set1s mov reallybigloopcounter,presetreallybigloopcounter Areallybigloop: mov loopmultiplier,presetloopmultiplier ;****10 ms = $01, 100 ms = $0A, 1 second = $64 Abigloop: mov delaycounter,presetdelaycounter ; set values for delay of 10 ms. delaycounter = $F4, delaycounter1 = $27 mov delaycounter1,presetdelaycounter1 Adealylooproutine: ; 10 millisecond dealy loop dec delaycounter cpi delaycounter,$00 brne Adealylooproutine dec delaycounter1 cpi delaycounter1,$00 brne Adealylooproutine dec loopmultiplier brne Abigloop dec reallybigloopcounter brne Areallybigloop ret ;return to calling routine .exit