;********************************* ;Copyright(C)2002,2003,2004. 2005 by Richard Cappels projects@cappels.org ;http://www.projects.cappels.org ;USES 32 bit binary to packed BCD routine from Atmel applination note. ;Uses ATTiny2313 or similar operating at 20 MHz. Woudl work on AT90S2313 if you ;could clock it that fast. ;Input is D5 ;********************************* ;nfmtr050524 20 MHz clock version, runs at 10 MHz. Measured 4 MHz clock at 4,000,082. ;nfmtr040916A Turn on decimal point and zeros to right of it in modes 2 and 3. ;nfmtr040902A Set input of counter 1 to clock on positive edge. Display ID with lcd. ;nfmtr040901I Mode 0 (counting) eliminated. Max freq. is 5 MHz. ;nfmtr040901H Readings limited to 2 times per second. ;nfmtr040901F Problem printing commas and decimal points after zeros corrected. ;nfmtr040901G Any char from terminal advances mode, except R resets in mode 4. ;nfmtr040901F Decimal points in the right places. ;nfmtr040901E Commas in the right places. ;nfmtr040901D Leading zero suppression. ;nfmtr040901C Working with 2 line LCD. All modes tested. Overflow works. ;nfmtr040901B Counting added. ;nfmtr040901A Label timebase. ;nfmtr040831E With working 100 millisecond to 100 second. No user interface. ;nfmtr040831D 32 bit basic frequency meter. No user interface. ;nfmtr040831C 1 second delay almost correct. ;nfmtr040831B Can send 9 1/2 digit number. Delay routine to 5.05 seconds at 10 MHz ;nfmtr040831 Some pieces of code in place. Not nearly working yet. .include "TN2313def.inc" .equ clock = 20000000 ;clock frequency .equ baudrate = 9600 ;choose a baudrate .equ baudconstant = (clock/(16*baudrate))-1 .def delay0 = r2 ;delay0..delay2 are delay counters. .def delay1 = r3 .def delay2 = r4 .def delayreload0 = r6 ;delayreload0..delayreload2 are reload values for delay counters. .def delayreload1 = r7 .def delayreload2 = r8 .def iterations = r9 ;Number of 1 second iterations. .def temp = r16 ;General purpose scratch register. .def byteA0 = r18 ;byteA0..byteA4 for binary to bcd conversion. .def byteA1 = r19 .def byteA2 = r20 .def byteA3 = r21 .def byteA4 = r22 .def flagreg = r23 ;Definition of flagregister bits ;0 lsb of mode select ;1 middle bit of mode select ;2 msb of mode select ;3 ;4 set to indicate that counting is to stop. ;5 ;6 set to indicate no more leading zeros ;7 set if 32 bit overflow occured. .org $00 rjmp reset ;Power-on and reset vector .org $05 rjmp T1OFLW ;16 Bit timer overflow .org $07 rjmp UARTRCV ;UART receive interrupt reset: ldi temp,low(ramend) out spl,temp ;set spl. ldi temp,baudconstant out ubrr,temp ;load baudrate. ldi temp,$00 out DDRB,temp ldi temp,$FF out PORTB,temp ldi temp,$00 out ddrd,temp ldi temp,$01 ;Weak pullup on UART receive pin. out PORTD,temp sbi ucr,txen ;Enable UART transmitter. sbi ucr,rxen ;Enable UART receiver. sbi ucr,rxcie ;Enable UART receive interrupts. ; shoot rcall Delay1Second ;Wait 2 seconds for display to come on. ; shoot rcall Delay1Second rcall crlf ;Start new line rcall typemessage ;Send ID message for two seconds before starting. rcall Delay1Second ;Display for 2 seconds before starting measurements. ldi flagreg,1 ;Set measurement mode to 1 second frequency measurement. sei ;Enable interrupts rjmp Main ;Start main execution loop. TypeSeconds: push temp ldi temp,'s' rcall EmitUart pop temp ret Delay: ;Maximum delay is 50529045 cycles (5.05 seconds at 10 MHz). mov delay2,delayreload2 moretime3: mov delay1,delayreload1 moretime2: mov delay0,delayreload0 moretime1: dec delay0 brne moretime1 dec delay1 brne moretime2 dec delay2 brne moretime3 ret Delay1Second: ldi temp,100 ;50 is 1 second mov delayreload0,temp ldi temp,0 mov delayreload1,temp ldi temp,255 mov delayreload2,temp rcall Delay ldi temp,143 ;225 mov delayreload0,temp ldi temp,250 mov delayreload1,temp ldi temp,2 mov delayreload2,temp rcall Delay ret measurefreq: cbr flagreg,0b10000000 ;Clear 32 bit overflow flag. ldi temp,$00 ;Set TCCR1A (control of 16 bit counter) to all zeros. out tccr1a,temp ldi temp,$00 ;Clear 16 bit counter. out tcnt1h,temp out tcnt1l,temp clr ZL ;Clear Z register, which is the overflow counter. clr ZH ldi temp,0b10000000 ;Enable overflow interrupts from 16 bit timer. out TIMSK,temp ldi temp,0b00000111 ;Enable input to 16 bit counter (Timer/Counter 1). . out tccr1b,temp AnotherSecond: rcall Delay1Second ;Delay 1 second. dec iterations ;Measure more than 1 second if necessary/ brne AnotherSecond ldi temp,$00 ;Stop 16 bit counter. out tccr1b,temp out TIMSK,temp ;Disable overflow interrupts. ret Meas1Sec: ;Label measurement as with 1 second timebase. ldi temp,'1' rcall EmitUart rcall TypeSeconds rcall crlf ldi temp,1 ;Take 1 second measurement. mov iterations,temp rcall measurefreq rcall displaycounter rjmp main Meas10Sec: ;Label measurement as with 1 second timebase. ldi temp,'1' rcall EmitUart ldi temp,'0' rcall EmitUart rcall TypeSeconds rcall crlf ldi temp,10 ;Take 10 second measurement. mov iterations,temp rcall measurefreq rcall displaycounter rjmp main Meas100Sec: ;Label measurement as with 1 second timebase. ldi temp,'1' rcall EmitUart ldi temp,'0' rcall EmitUart ldi temp,'0' rcall EmitUart rcall TypeSeconds rcall crlf ldi temp,100 ;Take 100 second measurement. mov iterations,temp rcall measurefreq rcall displaycounter rjmp main Main: mov temp,flagreg andi temp,0b00000111 cpi temp,1 breq Meas1Sec cpi temp,2 breq Meas10Sec cpi temp,3 breq Meas100Sec cpi temp,4 breq counting rjmp main Delay100ms: ldi temp,130 mov delayreload0,temp ldi temp,254 mov delayreload1,temp ldi temp,10 mov delayreload2,temp rcall Delay ldi temp,1 mov delayreload0,temp ldi temp,1 mov delayreload1,temp ldi temp,190 mov delayreload2,temp rcall Delay ret Counting: ;Count and display results until a flag goes true. andi flagreg,0b01101111 ;Make sure counting stop and overflow flags are not set. ldi temp,$00 ;Set TCCR1A (control of 16 bit counter) to all zeros. out tccr1a,temp ldi temp,$00 ;Clear 16 bit counter. out tcnt1h,temp out tcnt1l,temp clr ZL ;Clear Z register, which is the overflow counter. clr ZH ldi temp,0b10000000 ;Enable overflow interrupts from 16 bit timer. out TIMSK,temp ldi temp,0b00000111 ;Enable input to 16 bit counter (Timer/Counter 1). . out tccr1b,temp KeepCounting: ;Wait for flag to go high, signaling end of counting. sbrc flagreg,4 rjmp CountingDone rcall displaycounter rcall Delay100ms ;Limit sampling to 2 times per second rcall Delay100ms ;to make display smoother looking. rcall Delay100ms rcall Delay100ms rcall Delay100ms rjmp KeepCounting CountingDone: ldi temp,$00 ;Stop 16 bit counter. out tccr1b,temp out TIMSK,temp ;Disable overflow interrupts. rjmp main displaycounter: ;Display contents of counter via UART. clr XL ;Use XL to count the digits for placement of commans and decimal points andi flagreg,0b10111111 ;Clear nonzero flag. in byteA0,tcnt1l ;move counter contents to input for number conversion in byteA1,tcnt1h mov byteA2,ZL ;Move the upper 16 bits of count into the appropriate registers. mov byteA3,ZH rcall Conv32bit2bcd ;Get binary data in byteA0..byte 3 into byteA0..byteA4. mov temp,byteA4 rcall bcdEmitUart mov temp,byteA3 rcall bcdEmitUart mov temp,byteA2 rcall bcdEmitUart mov temp,byteA1 rcall bcdEmitUart mov temp,byteA0 rcall bcdEmitUart sbrc flagreg,7 ;If flagreg bit 7 (32 bit overflow) is set, send warning. rcall warnoflow rcall crlf ret bcdEmitUart: ;Emit two digite BCD in temp through UART. push temp swap temp andi temp,0b00001111 ori temp,$30 rcall EmitNoLeadZero pop temp andi temp,0b00001111 ori temp,$30 rcall EmitNoLeadZero ret PlaceMark: ;Place comma or period as appropriate. ;based on digit count (XL) and mode (flagreg 0..2) push temp ;Preserve temp. mov temp,flagreg ;Make state byte from mode and digit counter andi temp,0b00000111 ;Mask off all but mode value from flagreg. cpi temp,4 brne NotMode4 ;If in mode 4, make it look like mode 1. ldi temp,1 NotMode4: swap temp ;Get mode into upper nybble. or temp,XL ;Get digit count into lower nybble. cpi temp,$02 breq docomma cpi temp,$05 breq docomma cpi temp,$08 breq docomma cpi temp,$11 breq docomma cpi temp,$14 breq docomma cpi temp,$17 breq docomma cpi temp,$23 breq docomma cpi temp,$26 breq docomma cpi temp,$32 breq docomma cpi temp,$35 breq docomma cpi temp,$1A breq dodpoint cpi temp,$29 breq dodpoint cpi temp,$38 breq dodpoint cpi temp,$0A breq doohdot ;shoot pop temp ret docomma: ldi temp,',' rcall EmitUart pop temp ret dodpoint: ldi temp,'.' rcall EmitUart pop temp ret doohdot: ldi temp,'0' rcall EmitUart ldi temp,'.' rcall EmitUart pop temp ret EmitNoLeadZero: ;Emit number if not a leading zero, otherwise a space. inc XL ;Increment digit count ;Make sure decimal point and zeros shown in modes 2,3. mov XH,flagreg ;Make state byte from mode and digit counter andi XH,0b00000111 ;Mask off all but mode value from flagreg. swap XH ;Get mode into upper nybble. or XH,XL ;Get digit count into lower nybble. cpi XH,$29 ;Set flag to show zeros to rt of decimal point brne NO29 ;in mode 2. ori flagreg,0b01000000 ;Set flagreg to allow sending leading zeros NO29: cpi XH,$38 ;Set flag to show zeros to ret of decimal point brne NO38 ;In mode 3. ori flagreg,0b01000000 ;Set flagreg to allow sending leading zeros NO38: cpi temp,'0' breq ItsAZero ori flagreg,0b01000000 ;Set nonzero flag. rcall EmitUart rcall PlaceMark ret ItsAZero: sbrs flagreg,6 rjmp QX21 rcall emitUart rcall PlaceMark ret QX21: cpi XL,10 breq EmitUart ldi temp,$20 rjmp EmitUart EmitUart: ;Send RFChar via UART, preserves content of RFChar sbis usr,udre ;Wait for data to arrive. rjmp EmitUart out udr,temp ;Send byte. ret crlf: ldi temp,$0A rcall EmitUart ldi temp,$0D rcall EmitUart ret TypeMessage: ;Type greeting push ZL push ZH ldi ZH,high(2*Message) ;Load high part of byte address into ZH ldi ZL,low(2*Message) ;Load low part of byte address into ZL rcall SendRomstring ;Send it pop ZH pop ZL ret Message: .db "nfmtr040916A" .db $0A,$0D .db $00,$00 SendRomstring: ;Send string pointed to by ZH,ZL. lpm ; Load byte from program memory into r0 tst r0 ; Check if we've reached the end of the message breq stringdone ; If so, return mov temp,r0 rcall EmitUart adiw ZL,1 ; Increment Z registers rjmp SendRomstring stringdone: ret WarnOflow: ;Type "+" to indicate overflow push temp ldi temp,'+' rcall EmitUart pop temp ret Conv32bit2bcd: ;Input: r18.19,20.21 (binary); out: r18,19,20,21,22 (bcd) ;Listed above as lsB first, msB last. push r16 ;Save registers not needed for push r17 push r23 ;input or output. push r24 rcall Bin4BCD ;Do the conversion mov r18,r20 mov r19,r21 mov r20,r22 mov r21,r23 mov r22,r24 pop r24 ;Restore saved registers. pop r23 pop r17 pop r16 ret ;code below not used. push r24 ;Re-arrange data in registers push r23 push r22 push r21 push r20 pop r18 pop r19 pop r20 pop r21 pop r22 pop r24 ;Restore saved registers. pop r23 pop r17 pop r16 ret ;******** 32 bit binary to packed BCD routines from Atmel application note ************* ; Call bin4bcd r18r19r20r21 >>> r20r21r22r23r24 Bin2BCD20: mov r16,r20 ;for compatibility with Math32 mov r17,r21 ; Bin2BCD16: ldi r22,0xff ;initialize digit 4 binBCD_4: inc r22 ; subi r16,low(10000);subiw fbin,10000 sbci r17,high(10000) brcc binBCD_4 ; ldi r21,0x9f ;initialize digits 3 and 2 binBCD_3: subi r21,0x10 ; subi r16,low(-1000);subiw fbin,1000 sbci r17,high(-1000) brcs binBCD_3 ; binBCD_2: inc r21 ; subi r16,low(100) ;subiw fbin,100 sbci r17,high(100) ; brcc binBCD_2 ; ldi r20,0xa0 ;initialize digits 1 and 0 binBCD_1: subi r20,0x10 ; subi r16,-10 ;subi fbin,10 brcs binBCD_1 ; add r20,r16 ; binBCD_ret: ret ;* r18:r19:r20:r21 >>> r20:r21:r22:r23:r24 <== this one. ;* hex dec ;* r18r19r20r21 >>> r20r21r22r23r24 Bin4BCD: rcall Bin2BCD20 ; clr r23 ;initial highest bytes of result ldi r24,0xfe ; binBCD_loop: subi r20,-0x33 ;add 0x33 to digits 1 and 0 sbrs r20,3 ;if bit 3 clear subi r20,0x03 ; sub 3 sbrs r20,7 ;if bit 7 clear subi r20,0x30 ; sub $30 subi r21,-0x33 ;add 0x33 to digits 3 and 2 sbrs r21,3 ;if bit 3 clear subi r21,0x03 ; sub 3 sbrs r21,7 ;if bit 7 clear subi r21,0x30 ; sub $30 subi r22,-0x33 ;add 0x33 to digits 5 and 4 sbrs r22,3 ;if bit 3 clear subi r22,0x03 ; sub 3 sbrs r22,7 ;if bit 7 clear subi r22,0x30 ; sub $30 lsl r18 ; rol r19 ;shift lower word rol r20 ;through all bytes rol r21 ; rol r22 ; rol r23 ; rol r24 ; brmi binBCD_loop ;7 shifts w/o correction of MSD rol r17 ;since Bin2BCD r17 = 0xff brcc binBCD_ret ;shoot ; so as to do 16_lsl in total subi r23,-0x33 ;add 0x33 to digits 7 and 6 sbrs r23,3 ;if bit 3 clear subi r23,0x03 ; sub 3 sbrs r23,7 ;if bit 7 clear subi r23,0x30 ; sub $30 subi r24,-0x03 ;add 0x03 to digit 8 only sbrs r24,3 ;if bit 3 clear subi r24,0x03 ; sub 3 rjmp binBCD_loop ; T1OFLW: push temp ;Save temp then save status register in temp. in temp,sreg adiw ZL,1 ;Increment 16 bit Z register upon overflow of 16 bit counter. brne NoOverflow sbr flagreg,0b10000000 ;Set 32 bit overflow flag (very reare event) NoOverflow: out sreg,temp ;Restore status regiser then restore temp. pop temp reti ;************End of binary to bcd conversion routine********** UARTRCV: ;UART receive interrupt push temp ;Save temp then save status register. in temp,sreg push temp in temp,usr in temp,udr ;Read the char. andi temp,$DF ;Make upper-case ascii cpi temp,'R' ;If 'R' reset counters if mode 4 (Counting mode). breq resetcounter conint2: mov temp,flagreg ;Increment mode (flagret 0..2) andi temp,0b00000111 ;Maximum count is 4 inc temp cpi temp,$05 breq modemaxed contint: andi flagreg,0b11111000 or flagreg,temp ori flagreg,0b00010000 ;Set flag to leave counting mode. ;Set timer counters to time out early. ldi temp,1 mov iterations,temp mov delayreload0,temp mov delayreload1,temp mov delayreload2,temp intdone: pop temp ;Restore status regiser then restore temp. out sreg,temp pop temp reti modemaxed: ldi temp,1 ;Lowest mode number is 1. rjmp contint resetcounter: ;If in mode 4, counter mode, reset counter. mov temp,flagreg andi temp,0b00000111 cpi temp,4 brne conint2 ;If not mode 4, continue as if any other key. ldi temp,$00 ;Clear 16 bit counter. out tcnt1h,temp out tcnt1l,temp clr ZL ;Clear Z register, which is the overflow counter. clr ZH rjmp intdone .exit