;last ver March 9,2004 ; added re-zero fucntion to Freq button ;improved leading zero supresion ;expanded number of displayed component digits ;added extended frequency measurement to 45 MHz. ;ELSIE L/C/F meter by Steven Weber KD1JV ;timing based on 8.192 MHz cpu clock ;pd2 push button, inductance ;pd3 push button, capacitance ;pd4 push button, frequency ;portb => 7 seg display output ;pb3 morse out ;pd0 serial in ;pd1 serial out ;pd5 freq counter in ;power up - waits for L/C osc to stablize, ;wait for timer 1 to overflow 15 times ;make L measurment - output morse "R" ;inductance, output L, then number ;capacitance, output C, then number ;frequency, output F, then number ;leading zero suppressed. .include "2313def.inc" .def dv0 =r0 .def dv1 =r1 .def dv2 =r2 .def dv3 =r3 .def dv4 =r4 .def dv5 =r5 .def dv6 =r6 .def dd0 =r7 .def dd1 =r8 .def dd2 =r9 .def dd3 =r10 .def dd4 =r11 .def dd5 =r12 .def dd6 =r13 .def dr0 =r14 .def dr1 =r15 .def dr2 =r16 .def dr3 =r17 .def dr4 =r18 .def dr5 =r19 .def dr6 =r20 .def mp0 =r0 .def mp1 =r1 .def mp2 =r2 .def mp3 =r3 .def mr0 =r0 .def mr1 =r1 .def mr2 =r2 .def mr3 =r3 .def mr4 =r4 .def mr5 =r5 .def mr6 =r6 .def mr7 =r7 .def mc0 =r8 .def mc1 =r9 .def mc2 =r10 .def mc3 =r11 .def tbcd0 =r13 .def tbcd1 =r14 .def tbcd2 =r15 .def tbcd3 =r16 .def temp =r21 .def stemp =r22 .def tcnt =r23 .def counter =r24 .def dotcnt =r25 .def flags =r26 .def tcnt1 =r27 .equ atbcd3 =16 .equ atbcd2 =15 .equ atbcd0 =13 .equ lv0 =$70 .equ lv1 =$71 .equ lv2 =$72 .equ lv3 =$73 .org $00000 rjmp reset nop nop nop rjmp t1cm rjmp t1ovf timer: brts start ;if t flag set, start freq counter dec tcnt ;decement timer counter brne tmext ;check if time finished out tccr1b,tcnt ;stop timers out tccr0,tcnt sbr flags,$80 ;set done flag tmext: reti start: ldi temp,$06 ;set timer 1 for external count out tccr1b,temp clt ;clear t flag reti t1ovf: inc tcnt1 reti t1cm: inc dotcnt reti ;================================= ;start of program ;================================== reset: ldi temp,ramend ;load start of stack pointer ram location out spl,temp ;store location to stack pointer ldi temp,$02 ;set up port d data direction out ddrd,temp ser temp ;set up port b data direction out ddrb,temp ser temp ;set inital port state high out portb,temp out portd,temp ldi temp,52 ;8.192 Mhz value out ubrr,temp ldi temp,$08 ;turn on uart out ucr,temp clr temp ;set up timer 1 compare match for side tone freq out ocr1ah,temp ldi temp,$6a ;8.192 MHz value out ocr1al,temp sei ;enable interupts ;============================================= ;outputs ELSIE to 7 seg display and morse output ;============================================== ldi temp,$2c out portb,temp ldi temp,$45 rcall ssd1 ldi temp,$02 mov r0,temp rcall mrsout ldi temp,$bc out portb,temp ldi temp,$4c rcall ssd1 ldi temp,$14 mov r0,temp rcall mrsout ldi temp,$2a out portb,temp ldi temp,$53 rcall ssd1 ldi temp,$08 rcall mrsout ldi temp,$db out portb,temp ldi temp,$49 rcall ssd1 ldi temp,$04 mov r0,temp rcall mrsout ldi temp,$2c out portb,temp ldi temp,$45 rcall ssd1 ldi temp,$02 mov r0,temp rcall mrsout ldi temp,$4c out portb,temp ldi temp,$32 rcall ssd1 ldi temp,$27 ; mov r0,temp rcall mrsout ser temp out portb,temp ldi temp,$0a rcall ssd1 ldi temp,$0d rcall ssd1 ldi temp,$80 ;set up timer interup register out timsk,temp clr flags ;clear flag register clr tcnt1 ;initilize counter ldi temp,$06 ;set timer 1 for external clock out tccr1b,temp ;================================================================== ;this waits for timer 1 to overflow number of times set by tcnt reg ;a delay to ensure L/C oscillator has started and stablized ;================================================================== osc_st: cpi tcnt1,$10 brne osc_st ;wait for flag to be set clr temp out tccr1b,temp ;turns off timer 1 ldi temp,$02 ;turn on timer 0 interupt out timsk,temp r_zero: sbr flags,$01 ;set flag for doing inital inductance calculation rjmp ind ;jump to measure L ;======================================= ;switch input wait loop ;======================================= ;wait for switch release ;======================================= sw_lp: sbis pind,2 rjmp sw_lp sbis pind,3 rjmp sw_lp sbis pind,4 rjmp sw_lp ;======================================= ;wait for switch to be pressed ;======================================== sw_lp2: sbis pind,2 rjmp ind sbis pind,3 rjmp cap sbis pind,4 rjmp freq rjmp sw_lp2 ;====================================== ;start frequency counter mode ;====================================== freq: ldi counter,$0f fr_jp2: clr dotcnt fr_jp1: sbic pind,4 rjmp fr_eq cpi dotcnt,$ff brne fr_jp1 dec counter brne fr_jp2 rjmp r_zero fr_eq: clr temp ; out tccr1b,temp ;stop timer1 ldi temp,$02 ;set up timer interupts out timsk,temp clr temp out tcnt1h,temp out tcnt1l,temp ;clear the timer 1 count registers clr tcnt1 ldi tcnt,50 ;initalize timer 0 counter ldi temp,$82 ;set up timer interup register out timsk,temp set ;set T flag ldi temp,$03 ;turn on timer 0 out tccr0,temp f_lp1: sbrs flags,7 ;wait for frequency meausre time to be done rjmp f_lp1 cbr flags,$80 ;clear the done flag ldi temp,$02 ;turn on timer 0 interupt out timsk,temp in dd0,tcnt1l in dd1,tcnt1h mov dd2,tcnt1 ;input the frequency count clr dd3 rcall bcd ;convert to bcd sbr flags,$20 ;set freq mode flag rcall duart ;output data on uart rcall mdecode ;output in morse and 7 seg cbr flags,$20 ;clear freq mode flag rjmp sw_lp ;go back to wait for switch input ;================================================== ;start of L/C component measurement routine ;================================================== cap: sbr flags,$40 ;set C mode flag ind: clr temp ; out tccr1b,temp ;stop timer1 ldi temp,$02 ;set up timer interupts out timsk,temp clr temp out tcnt1h,temp out tcnt1l,temp ;clear timer 1 coutner registers ldi tcnt,50 ;load time delay counter set ;set t flag ldi temp,$03 out tccr0,temp ;start timer 0 c_lp1: sbrs flags,7 rjmp c_lp1 ;wait for time interval done cbr flags,$80 ;clear done flag in mp0,tcnt1l in mp1,tcnt1h ;input frequency count rcall cal_lc ;call the calculation routines sbrs flags,0 ;check for start up mode rjmp mess ;jump if not start up ldi temp,$0a ;load "r" morse encoding mov r0,temp rcall mrsout ;output "r" in morse cbr flags,$01 ;clear start up flag rjmp sw_lp ;go wait for switches mess: rcall duart ;output data to uart rcall mdecode ;output data in morse and 7 seg display cbr flags,$42 ;clear mode flag rjmp sw_lp ;go wait for switches ;=============================================== ;calculate component values ;=============================================== cal_lc: mov mc0,mp0 ;square freq mov mc1,mp1 rcall mpy16 sbrc flags,6 rjmp load_l ;if L mode, load C value (1000p) ldi temp,$fc mov mc0,temp ldi temp,$03 mov mc1,temp clr mc2 clr mc3 rjmp cal_1 ;if C mode, load L values load_l: lds mc0,lv0 lds mc1,lv1 lds mc2,lv2 lds mc3,lv3 cal_1: rcall mpy32 ;multiply F^2 by C or L clr dd0 ; load 2533 x 10^8 ldi temp,$20 mov dd1,temp ldi temp,$29 mov dd2,temp ldi temp,$34 mov dd3,temp ldi temp,$80 mov dd4,temp ldi temp,$fd mov dd5,temp ldi temp,$59 mov dd6,temp rcall div56 ;divide 2533 x 10^8 by F^2*C sbrc flags,0 ;check for start up mode rjmp pu_cal ;jump if start up sbrs flags,6 ;check mode rjmp zr_ind ;load C value if L mode ldi temp,$fc ;load C value (1000p) mov mp0,temp ldi temp,$03 mov mp1,temp clr mp2 clr mp3 rjmp cal_2 ;load L value if C mode zr_ind: lds mp0,lv0 lds mp1,lv1 lds mp2,lv2 lds mp3,lv3 ;================================== ;subtract inital value from new vlaue to find test value ;================================== cal_2: sub dd0,mp0 sbc dd1,mp1 sbc dd2,mp2 sbc dd3,mp3 brcs cal_3 ;test for neg result rcall bcd ;convert result to bcd ret cal_3: add dd0,mp0 ;restore original value adc dd1,mp1 adc dd2,mp2 adc dd3,mp3 sub mp0,dd0 sbc mp1,dd1 sbc mp2,dd2 sbc mp3,dd3 mov dd0,mp0 mov dd1,mp1 mov dd2,mp2 mov dd3,mp3 sbr flags,$02 rcall bcd ret ;========================================= ;store inital L vlaue on start up into sram ;========================================= pu_cal: sts lv0,dd0 sts lv1,dd1 sts lv2,dd2 sts lv3,dd3 ret ;=================================== ;16x16 multiply ;==================================== mpy16: clr mr2 clr mr3 ;clear 2 highest bytes of result ldi counter,16 ;init loop counter lsr mp1 ror mp0 mlp_1: brcc noad8 ;if bit 0 of multiplier set add mr2,mc0 ;add multiplicand Low to byte 2 of res adc mr3,mc1 ;add multiplicand high to byte 3 of res noad8: ror mr3 ;shift right result byte 3 ror mr2 ;rotate right result byte 2 ror mr1 ;rotate result byte 1 and multiplier High ror mr0 ;rotate result byte 0 and multiplier Low dec counter ;decrement loop counter brne mlp_1 ;if not done, loop more ret ;================================== ;32x 32 multiply ;=================================== mpy32: clr mr4 clr mr5 clr mr6 clr mr7 ;clear 2 highest bytes of result ldi counter,32 ;init loop counter lsr mp3 ror mp2 ror mp1 ror mp0 mlp_32: brcc noad32 ;if bit 0 of multiplier set add mr4,mc0 ;add multiplicand Low to byte 2 of res adc mr5,mc1 ;add multiplicand high to byte 3 of res adc mr6,mc2 adc mr7,mc3 noad32: ror mr7 ror mr6 ror mr5 ror mr4 ror mr3 ;shift right result byte 3 ror mr2 ;rotate right result byte 2 ror mr1 ;rotate result byte 1 and multiplier High ror mr0 ;rotate result byte 0 and multiplier Low dec counter ;decrement loop counter brne mlp_32 ;if not done, loop more ret ;============================================================= ;56 bit divide routine ;============================================================= div56: clr dr1 ;clear remander registers clr dr2 clr dr3 clr dr4 clr dr5 clr dr6 ldi counter,57 ;init loop counter, # bits to be divided +1 sub dr0,dr0 ;clears registers and carry bit d56_1: rol dd0 ;shift left dividend rol dd1 rol dd2 rol dd3 rol dd4 rol dd5 rol dd6 dec counter ;decrement counter brne d56_2 ;if done ret ;return d56_2: rol dr0 ;shift dividend into remainder rol dr1 rol dr2 rol dr3 rol dr4 rol dr5 rol dr6 sub dr0,dv0 ;remainder = remainder - divisor sbc dr1,dv1 ; sbc dr2,dv2 sbc dr3,dv3 sbc dr4,dv4 sbc dr5,dv5 sbc dr6,dv6 brcc d56_3 ;if result negative add dr0,dv0 ;restore remainder adc dr1,dv1 adc dr2,dv2 adc dr3,dv3 adc dr4,dv4 adc dr5,dv5 adc dr6,dv6 clc ; clear carry to be shifted into result rjmp d56_1 ;else d56_3: sec ; set carry to be shifted into result rjmp d56_1 ;========================================== ;convert bianry to packed bcd ;========================================== bcd: ldi counter,24 ;initilize counter to number of bits to be converted clr tbcd2 ;clear result registers clr tbcd1 clr tbcd0 clr tbcd3 bbcdx_1:lsl dd0 ;shift carry left binary number to be converted rol dd1 rol dd2 rol tbcd0 ;shift carry into result registers rol tbcd1 rol tbcd2 rol tbcd3 dec counter brne bbcdx_2 ;done? ret ;return ;============================== ;check for "9" ;============================== bbcdx_2:ldi r30,atbcd3+1 ;load indirect point to top of result reg +1 clr zh bbcdx_3:ld temp,-z ;load result reg pointed to by predecemented Z subi temp,-$03 ;add 3 to low nibble (sub -3) sbrc temp,3 ;check for carry into bit 3 st z,temp ;store back if carry ld temp,z ;load result reg again subi temp,-$30 ;add 3 to high nibble sbrc temp,7 ;check for carry into bit 7 st z,temp ;store back if carry cpi zl,atbcd0 ;check for last result reg brne bbcdx_3 ;do next reg if not done rjmp bbcdx_1 ;jump back to shift routine ;========================================================= ;send data out UART, 8 bits, 1 stop, no parity, 9600 baud. ;========================================================= duart: ldi temp,$4c ;determine mode and output L, C, or F sbrc flags,6 ldi temp,$43 sbrc flags,5 ldi temp,$46 rcall ssd1 ldi temp,$20 rcall ssd1 ;=============================== ;unpack BCD digits ;=============================== sbrs flags,1 ;test for negative value flag rjmp du_jp ldi temp,$2d ;output "-" rcall ssd1 du_jp: tst tbcd3 brne du_2 tst tbcd2 brne du_1 tst tbcd1 brne du_0 rjmp du_x du_2: mov temp,tbcd3 swap temp cbr temp,$f0 rcall ssd mov temp,tbcd3 cbr temp,$f0 rcall ssd du_1: mov temp,tbcd2 swap temp cbr temp,$f0 rcall ssd mov temp,tbcd2 cbr temp,$f0 rcall ssd du_0: mov temp,tbcd1 swap temp cbr temp,$f0 rcall ssd mov temp,tbcd1 cbr temp,$f0 rcall ssd du_x: sbrc flags,6 ;determine mode rjmp dujp_1 sbrc flags,5 rjmp dujp_1 ldi temp,$2e ;insert "." if L mode rcall ssd1 dujp_1: mov temp,tbcd0 swap temp cbr temp,$f0 rcall ssd mov temp,tbcd0 cbr temp,$f0 rcall ssd ldi temp,$0a ;send carrage return rcall ssd1 ldi temp,$0d ;send line feed rcall ssd1 ret ;============================= ;output data to uart ;============================= ssd: sbr temp,$30 ;convert number to ascii character by adding 30 ssd1: out udr,temp ;output to uart data register ssd_1: in temp,usr ;input uart status reg sbrs temp,5 ;check for data sent finsh flag rjmp ssd_1 ;wait until flag set ret ;return ;========================================================== ;enunciate mode, unpack BCD digits, convert to morse and enunciate ;========================================================== mdecode:ldi temp,$bc ;load 7seg char, L sbrc flags,6 ;skip if not cap mode ldi temp,$3c ;load 7 seg char, C sbrc flags,5 ;skip if not freq mode ldi temp,$2d ;load 7 seg char F out portb,temp ;output to port b ldi temp,$14 ;load morse char L sbrc flags,6 ;skip if not cap mode ldi temp,$1a ;load morse char C sbrc flags,5 ;skip if not freq mode ldi temp,$12 ;load morse char F mov r0,temp ;move char to r0 rcall mrsout ;enunciate morse character ;============================================================ ;unpack bcd number for output ;============================================================ sbrs flags,1 ;check for negative result rjmp mdj_x ldi temp,$ef ;output "-" to display out portb,temp ldi temp,$73 mov r0,temp ;output "-" in morse rcall mrsout mdj_x: tst tbcd3 brne mdj_1 tst tbcd2 brne mdj_2 tst tbcd1 brne mdj_3 rjmp mdj_4 mdj_1: mov temp,tbcd3 swap temp cbr temp,$f0 rcall sseg rcall gmk mov temp,tbcd3 cbr temp,$f0 rcall sseg rcall gmk mdj_2: mov temp,tbcd2 ;get MSD BCD swap temp ;swap nibble to put high in low cbr temp,$f0 ;clear high nibble rcall sseg ;get 7 seg data and output rcall gmk ;get morse encoding and output mov mov temp,tbcd2 ;get BCD MSD again cbr temp,$f0 ;clear high nibble rcall sseg ;get 7 seg data and output rcall gmk ;get morse encoding and output mdj_3: mov temp,tbcd1 ;get next BCD digit swap temp ;swap to put high nibble in low cbr temp,$f0 ;clear high nibble rcall sseg ;get 7seg data rcall gmk ;get morse encoding mov temp,tbcd1 ;get BCD digit again cbr temp,$f0 ;clear high nibble rcall sseg ;get 7 seg data rcall gmk ;get morse encoding mdj_4: sbrc flags,6 ;check for C mode rjmp mdj_5 ;jump if C mode sbrc flags,5 ;check for F mode rjmp mdj_5 ;jump if F mode ldi temp,$ef ;load 7seg "-" data out portb,temp ;outupt to display ldi temp,$0a ;load "r" morse encoding mov r0,temp ;move to R0 rcall mrsout ;send "R" in morse mdj_5: mov temp,tbcd0 ;get last BCD digit swap temp ;swap nibbles cbr temp,$f0 ;clear high nibble rcall sseg ;get 7 seg data rcall gmk ;get morse encoding mov temp,tbcd0 ;get last BCD digit cbr temp,$f0 ;clear high nibble rcall sseg ;get 7 seg data rcall gmk ;get morse encoding ser temp out portb,temp ;blank 7 seg display ret ;return ;=================================== ;get morse character coding gmk: ldi zh,high(mrtbl*2) ldi zl,low(mrtbl*2) add zl,temp clr r0 adc zh,r0 lpm rjmp mrsout mrtbl: .db $3f,$2f .db $27,$23 .db $21,$20 .db $30,$38 .db $3c,$3e ;================================== ;get 7seg character coding sseg: ldi zh,high(sstbl*2) ;load Z indirect pointer to ldi zl,low(sstbl*2) ;7 seg data table add zl,temp ;add table offset (number to be encoded) clr r0 adc zh,r0 ;add 0 with carry to pointer, just in case lpm ;get data from table out portb,r0 ;output to port b ret sstbl: .db $18,$db .db $4c,$4a .db $8b,$2a .db $a8,$5b .db $08,$0b ;================================= ;output morse character ; morse character located in r0 ;rotate left until start bit (1) found ;dash = 1, dot = 0 mrsout: clr temp out tcnt1h,temp ;clear timer 1 counter out tcnt1l,temp ldi temp,$40 out timsk,temp ;set up timer interupts ldi temp,$0b out tccr1b,temp ;set up timer 1 ldi counter,$08 ;int element counter mrs4: rol r0 ;rotate to find start bit dec counter ;decerment count brcc mrs4 ;carry high? start bit mrs2: clr dotcnt ;clear the dot counter ldi temp,$40 ;start the sidetone out tccr1a,temp rol r0 ;rotate to find dot/dash brcs mdash ;brach if carry high, dash mdot: cpi dotcnt,$50 brne mdot ;wait for dot time rjmp mspace mdash: cpi dotcnt,$f0 brne mdash ;wait for dash time mspace: ldi temp,$00 out tccr1a,temp ;turn off sidetone clr dotcnt msp1: cpi dotcnt,$50 brne msp1 ;wait for space time mrs1: dec counter ;dec element counter brne mrs2 ;not done? get next element mrs3: ldi tcnt,7 ;set up for inter character space mrs3b: clr dotcnt mrs3a: cpi dotcnt,$50 brne mrs3a ;wait for space time dec tcnt brne mrs3b ret ;return