;Dick Cappels' Project Pages ;Contents ©2002 Richard Cappels All Rights Reserved. email projects@cappels.org ;HOME ;********************************* ;2313 frequency meter and pulse generator program ;frequency meter (C)2002 by Richard Cappels sap@cappels.org ;original pulse generator (C)2000 by info@avr-asm-tutorial. ; To quote the author of the pulse generator code, ; "©2001 by Gerhard Schmidt, ; Wilhelmstrasse 6, D-64646 Heppenheim/Germany ; You may use the information on these pages and distribute it, ; but keep the copyright information with it. ; ; ;When assembled, 12 warnings will be generated stating that ;registers have already been declared in .DEF statments. This is ok. ;Some registers are used by both the frequency meter program and ;the pulse generator program. When control is handed from one to ;the other, everything starts fresh, with the exception of ;initialization of the I/O port, which is handled in the ;frequency meter program, since it runs first after power-on ;reset. ;When running frequency meter program input is on Port D, bit 5. ;When running pulse generator program output is on Port D, bits 3, 4, and 5 ;The default is to drive all three pins when in pulse generator, the three pins ;are driven in various combinations when the amplitude is adjusted. A Ladder network ;can optionally be connected to pins 3,4, and 5 which functions as a D-to-A converter ;and also provides some resistive isolation between the inputs and the source. ;The default for the frequency meter is to Port D bits 3,4, and 5 inputs. Thus, ;the output of the ladder network can be used as the input for the frequency meter, ;making it possible to use a single pin for input and output. ; ;PD-6 goes low during frequency measurements. Can be used to drive a indicator LED. ;Layout of this doucment: ;1. Frequency meter code ;2. BCD conversion application note code ;3. Pulse generator code ;4. Strings ;********************************* .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 .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 ;***** other register assignments for frequency meter .def inbyteh = r20 ; higher byte for asci-hex conversion ;.def currentadd = r21 ;pointer to write address for first page of memory .def temp = r22 ;general purpose register .def delaycounter = r23 .def delaycounter1 = r24 .def loopmultiplier = r25 .def inchar = r26 ;char destined to go out the uart .def outchar = r27 ;char coming in from the uart .def inbytel = r28 ;lower byte for asci-hex conversion .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 .org $00 rjmp reset rjmp reset rjmp reset rjmp reset rjmp reset rjmp reset rjmp reset rjmp pull_the_plug ; uart receiver interrupt -do watchdog reset if fmeter measurement is interrupted rjmp reset rjmp reset rjmp reset jumprunnngtotal: cbi portd,6 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 displayoverandover: rcall displaythedata sbi ucr,rxen ;set reciver bit. sbis usr,rxc ;repeat until char rjmp displayoverandover rjmp pull_the_plug ;exit when char received handleretun: rjmp measurefreqjump ;if return handle same as if R was pressed reset: ldi temp,low(ramend) out spl,temp ;set spl ldi temp,baudconstant out ubrr,temp ;load baudrate ldi temp,$40 ;no pullups on PORTD inputs, bit 6 set high out portd,temp ldi temp,$40 ;preset DDRD out ddrd,temp ; ldi temp,$38 ;preset values to drive pulse dac with mov dacvalue,temp ldi temp,$00 mov daczero,temp ldi inchar,$00 rcall TypeGreeting rjmp set1s ;set default measurement time to 1 second and jump to loop loop: ;***** command interpretation loop for frequency meter ***** ;***** supports jump to pulse generator program ***** ldi outchar,$3A ;send prompt (colon char) to terminal rcall rs_send ldi outchar,$20 ;send a couple of blank spaces after the return rcall rs_send ldi outchar,$20 rcall rs_send rcall rs_rec ;get char from terminal and interpret char cpi inchar,$3F ;if ? then display menu breq domenu cpi inchar,$0D ;if CR then handle it as R instead of echoing it breq handleretun cpi inchar,$21 ;if ! then use watchdog timer to reset the breq pull_the_plug andi inchar,$DF ;make upper-case ascii ;Echo char after making upper-case mov outchar,inchar ;copy input char to output char buffer to echo rcall rs_send ldi outchar,$20 rcall rs_send rcall rs_send cpi inchar,$52 ;if R or r, measure frequency breq measurefreqjump cpi inchar,$4D ;if M or m, monitor memory location breq monitormemory cpi inchar,'T' ;if T, get running total breq jumprunnngtotal cpi inchar,$41 ;A 10ms breq set10ms cpi inchar,$42 ;B 100ms breq set100ms cpi inchar,$43 ;C 1s breq set1s cpi inchar,$44 ;D 10s breq set10s cpi inchar,$45 ;E 100s breq goto100secondrealy cpi inchar,$50 ;P start up pulse generator (will/can not return to this one) breq gotopulsegen rcall crlf ;if no valid input, send carriage return and line feed rjmp loop ;keep going measurefreqjump: rcall measurefreq rjmp loop gotopulsegen: rjmp pulsegenerator decrementanddisplay: ;decrement current address and display current memory contenst rjmp loop domenu: ;temp menu part of greeting message ldi ZH,high(2*menumessage) ; Load high part of byte address into ZH ldi ZL,low(2*menumessage) ; Load low part of byte address into ZL rcall sendstring rjmp loop pull_the_plug: ;enable watchdog timer and wait for hardware reset wdr ldi temp,$08 out wdtcr,temp wait_for_reset: rjmp wait_for_reset ;inctimebase: ;increase timebase ; rjmp loop monitormemory: ;send contents of memory until char received from terminal rcall measurefreq sbi ucr,rxen ;set reciver bit. sbis usr,rxc ;repeat until char rjmp monitormemory rjmp pull_the_plug ;exit when char received goto100secondrealy: rjmp set100s 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 ldi ZH,high(2*tenmsmessage) ; Load high part of byte address into ZH ldi ZL,low(2*tenmsmessage) ; Load low part of byte address into ZL rcall sendstring rjmp loop 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 ldi ZH,high(2*hundredmsmessage) ; Load high part of byte address into ZH ldi ZL,low(2*hundredmsmessage) ; Load low part of byte address into ZL rcall sendstring rjmp loop 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 ldi ZH,high(2*onesmessage) ; Load high part of byte address into ZH ldi ZL,low(2*onesmessage) ; Load low part of byte address into ZL rcall sendstring rjmp loop set10s: ldi temp,$0A mov presetreallybigloopcounter,temp ldi temp,$64 mov presetloopmultiplier,temp ldi temp,$F4 mov presetdelaycounter,temp ldi temp,$27 mov presetdelaycounter1,temp ldi ZH,high(2*tensmessage) ; Load high part of byte address into ZH ldi ZL,low(2*tensmessage) ; Load low part of byte address into ZL rcall sendstring rjmp loop set100s: ldi temp,$64 mov presetreallybigloopcounter,temp ldi temp,$64 mov presetloopmultiplier,temp ldi temp,$F4 mov presetdelaycounter,temp ldi temp,$27 mov presetdelaycounter1,temp ldi ZH,high(2*hundredsmessage) ; Load high part of byte address into ZH ldi ZL,low(2*hundredsmessage) ; Load low part of byte address into ZL rcall sendstring rjmp loop rs_send: sbi ucr,txen ;set sender bit sbis usr,udre ;wait till register is cleared rjmp rs_send out udr,outchar ;send the byte cbi ucr,txen ;clear sender bit ret ;go back rs_rec: sbi ucr,rxen ;set reciver bit... sbis usr,rxc ;wait for a byte rjmp rs_rec in inchar,udr ;read valuable cbi ucr,rxen ;clear register ret ;go back rs_rec_echo: ;receive and echo char rcall rs_rec mov outchar,inchar rcall rs_send ;send to comX ret 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 outchar,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 TypeGreeting: rcall crlf rcall crlf 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 inbytel to ascii in inbyteh,nbytel mov inbyteh,inbytel 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 inbytel at start andi inbytel,0b00001111 ;convert the lower nybble to ascii byte subi inbytel,$D0 ;add $30 cpi inbytel,$3A brlo PC+2 ;If less than 9 skip next instruction subi inbytel,$F9 ;add 8 to ASCII (if data greater than 9) ; byte in inbyteh represents upper nybble that was in inbytel at start ret sendbyte: ;send byte contained in inbytel to terminal rcall byte_to_asciihex mov outchar,inbyteh rcall rs_send mov outchar,inbytel rcall rs_send ret sendbinarybyte: ldi temp,$08 stillsendingbinary: ;rotate byte through carry; send 0 or 1 depending on carry bit ldi outchar,$30 rol inbytel brcc dontsendone ldi outchar,$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 ;looking for a little extra dealy 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 outchar,tBCD2 ldi temp,$30 add outchar,temp rcall rs_send mov inbytel,tBCD1 rcall sendbyte mov inbytel,tBCD0 ;since leading digit on high byte is always zero, dont' sent it. rcall sendbyte ldi outchar,$20 rcall rs_send 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 ; ************************************************************** ; * Pulse Width Generator, programmable via Serial I/O 9k6 8N1 * ; * Input cycle length in µs first, then active cycle in µs * ; * Default cycle length is 25,000 µs, default active cycle is * ; * 2,000 µs. Output is on Port D, Bit 2 * ; * Written for the STK200 board, AT90S8515 * ; * (C)2000 by info@avr-asm-tutorial, error reports welcome * ; ************************************************************** ; modified to work with 2313 as run from a host program ;.NOLIST ;.INCLUDE "2313def.inc" ;.LIST ; ; 2313.def already called out in host program ; Used registers ; .DEF rlpm=R0; Used for LPM commands .DEF rchar=R1; Character buffer for SIO communications .DEF rilo=R2; Low byte word input/active loop .DEF rihi=R3; High byte word input/active loop .DEF rjlo=R4; Low byte for multiplication/inactive loop .DEF rjhi=R5; High byte for multiplication/inactive loop ; .DEF rmpr=R16; A multipurpose register, byte/word .DEF rcl=R18; Desired cycle time, word .DEF rch=R19 .DEF ral=R20; Desired active time, word .DEF rah=R21 ; X=R26/27: Counter for Active time ; Y=R28/29: Counter for inactive time ; Z=R30/31: Pointer for program memory read operation ; ; Constants ; .EQU OutPort=PortD; Desired output port .EQU DataDir=DDRD; Data direction register of that port .EQU ActivePin=2; Desired output pin .EQU ModeControl=0b00000100; Control word for port .EQU cDefCyc=25000; Default cycle length in µs .EQU cDefAct=2000; Default active high length in µs .EQU fq=4000000; Xtal frequency on board in Hz .EQU baud=9600; Baudrate for SIO communication .EQU bddiv=(fq/(16*baud))-1; Baudrate divider .EQU ccr=0x0D; Carriage return character .EQU clf=0x0A; Line feed character .EQU cnul=0x00; NUL character .EQU cesc=0x1B; ESCAPE character .EQU cbel=0x07; Bell character ; ; Macro Check input value for default and transfer to desired register ; .MACRO Default MOV @0,rilo; Copy result to desired register pair MOV @1,rihi MOV rmpr,rilo; Test if input is zero OR rmpr,rihi BRNE nodef; Not zero, don't set default value LDI @0,LOW(@2); Set to default value LDI @1,HIGH(@2) nodef: .ENDM ; ; Code segment start ; .CSEG ; ; all of these vectors are already taken care of in the host program ; Reset- and interrupt-vectors, interrupts not used here ; ; RJMP Start; Reset vector ; RETI; Ext Int 0 ; RETI; Ext Int 1 ; RETI; Timer 1 Capt ; RETI; Timer 1 CompA ; RETI; Timer 1 CompB ; RETI; Timer 1 OVF ; RETI; Timer 0 OVF ; RETI; Serial Transfer Complete ; RETI; UART Rx Complete ; RETI; UART Data register empty ; RETI; UART Tx Complete ; RETI; Analog Comparator ; ; Subroutine for string transmit ; TxStr: SBIS USR,UDRE; Wait until transmit buffer empty RJMP TxStr LPM; Read next character from program memory AND rlpm,rlpm; NUL = end of string BRNE txsend RET txsend: LPM; Read the same char again OUT UDR,rlpm; Tx character read ADIW ZL,1; point to next char im memory RJMP TxStr ; this jump added to merge with frequency meter program resetchip: rjmp pull_the_plug ;initiate hardware reset via watchdog timer ; ; Subroutine for receiving a number (word, 0..65535) ; RxWord: CLR rilo; Set buffer to zero CLR rihi rxw1: sbi portd,6 ;turn off led on port 6 if it was on (set pin high) SBIS USR,RXC; Test if rx buffer empty RJMP rxw1; receive char not available, repeat IN rmpr,UDR; Get the char from the SIO OUT UDR,rmpr; Echo this character cpi rmpr,'f' ; if "!" then do a hardware reset Modification to allow ;initiation of watchdog reset to return to frequency meter breq resetchip cpi rmpr,'F' breq resetchip cpi rmpr,'A' ;if A go to amplitude settng menu breq setpulseamplitude ;(afterward, restart the pulsie generator) cpi rmpr,'a' ; if a go to amplitude settng menu breq setpulseamplitude ;(afterward, restart the pulse generator) CPI rmpr,ccr; Return char = end of input BREQ rxwx SUBI rmpr,'0'; Subtract 48 BRCS rxwerr; not a decimal number, return wit carry set CPI rmpr,10; number >9? BRCS rxwok; legal decimal number rxwerr: LDI ZL,LOW(2*ErrorStr); Echo error string LDI ZH,HIGH(2*ErrorStr) RCALL TxStr SEC; Set carry flag, not a legal number RET rxwok: MOV rjlo,rilo; Copy word for multiplicaton MOV rjhi,rihi LSL rilo; Multiply with 2 = 2* ROL rihi BRCS rxwerr; Overflow, return with carry set LSL rilo; Multiply again by 2, = 4* ROL rihi BRCS rxwerr; Overflow, return with carry set ADD rilo,rjlo; Add copy, = 5* ADC rihi,rjhi BRCS rxwerr; Overflow, return with carry set LSL rilo; Multiply by 2, = 10* ROL rihi BRCS rxwerr; Overflow, return with carry set CLR rjhi; Add the decimal number ADD rilo,rmpr ADC rihi,rjhi BRCS rxwerr; Overflow, return with carry set RJMP rxw1; Get next character rxwx: SBIS USR,UDRE; Wait until transmit buffer empty RJMP rxwx LDI rmpr,clf; Transmit additional line feed char OUT UDR,rmpr CLC; Clear carry, no errors RET setpulseamplitude: ;adjust amplidude of output pulses from ladder network LDI ZL,LOW(2*Selectamplitudemessage); send menu greeting ;********************** LDI ZH,HIGH(2*Selectamplitudemessage) RCALL TxStr rxwPULSEMENU: SBIS USR,RXC; Test if rx buffer empty RJMP rxwPULSEMENU; receive char not available, repeat IN rmpr,UDR; Get the char from the SIO ldi temp,$20 out UDR,temp andi rmpr,$DF ;make upper-case ascii OUT UDR,rmpr; Echo this character cpi rmpr,'A' breq doamplitudea cpi rmpr,'B' breq doamplitudeb cpi rmpr,'C' breq doamplitudec cpi rmpr,'D' breq doamplituded cpi rmpr,'E' breq doamplitudee cpi rmpr,'F' breq doamplitudef cpi rmpr,'G' breq doamplitudeg doamplitudea: ldi temp,$08 ;preset values to drive dac with mov dacvalue,temp rjmp amplselected doamplitudeb: ldi temp,$10 ;preset values to drive dac with mov dacvalue,temp rjmp amplselected doamplitudec: ldi temp,$18 ;preset values to drive dac with mov dacvalue,temp rjmp amplselected doamplituded: ldi temp,$20 ;preset values to drive dac with mov dacvalue,temp rjmp amplselected doamplitudee: ldi temp,$28 ;preset values to drive dac with mov dacvalue,temp rjmp amplselected doamplitudef: ldi temp,$30 ;preset values to drive dac with mov dacvalue,temp rjmp amplselected doamplitudeg: ldi temp,$38 ;preset values to drive dac with mov dacvalue,temp rjmp amplselected amplselected: ;done selecting amplitude. Now restart pulse gen. LDI ZL,LOW(2*valuesetmessage); send menu greeting LDI ZH,HIGH(2*valuesetmessage) RCALL TxStr rjmp pulsegenerator ; ; Start of program ; pulsegenerator: Start: ;Setup the stack for the use of subroutines ; eliminate stack initialization - it was done in the host program. ; LDI rmpr,HIGH(RAMEND); Stack setting to highest RAM adress ; OUT SPH,rmpr LDI rmpr,LOW(RAMEND) OUT SPL,rmpr ; ; Initiate Port D to output on Bit 2 ; this initialization taken care of earlier ; LDI rmpr,ModeControl; Set output pin ; OUT DataDir,rmpr; to Data Direction register ldi temp,$40 out portd,temp ldi temp,$78 ;set the pulse output pins to outputs (frequency meter cannot now see pulses) out ddrd,temp ; Initiate SIO communication ; LDI rmpr,bddiv; Set baud rate OUT UBRR,rmpr LDI rmpr,0b00011000; Enable TX and RX OUT UCR,rmpr ; ; Transmit the hello sequence ; hello: LDI ZH,HIGH(2*InitStr); Point Z to string LDI ZL,LOW(2*InitStr) RCALL TxStr ; ; Get value for total cycle length ; getcycle: LDI ZH,HIGH(2*CycleStr); Point Z to string LDI ZL,LOW(2*CycleStr) RCALL TxStr RCALL RxWord BRCS getcycle; Repeat if error Default rcl,rch,cDefCyc ; ; Get value for active cycle length ; getactive: LDI ZH,HIGH(2*ActiveStr); Point Z to string LDI ZL,LOW(2*ActiveStr) RCALL TxStr RCALL RxWord BRCS getactive; Repeat if error Default ral,rah,cDefAct ; ; Calculate counter value for active time ; MOV XL,ral; Calculate active time MOV XH,rah SBIW XL,5; at least 4 cycles BRCS getcycle; illegal active time ADIW XL,1; At least one cycle required MOV rilo,XL MOV rihi,XH ; ; Calculate counter value for inactive time ; MOV YL,rcl; Calculate inactive time MOV YH,rch SUB YL,XL; Subtract active time SBC YH,XH BRCS getcycle; Active time longer than cycle time SBIW YL,5; Subtract loop delays BRCS getcycle; Less than 3 loop cycles are illegal ADIW YL,1; minimum 1 loop MOV rjlo,YL MOV rjhi,YH LDI ZH,HIGH(2*WaitStr); Output operating string LDI ZL,LOW(2*WaitStr) RCALL TxStr cbi portd,6 ;turn on led on port 6. Sink current to ground. ; ; Counting loop starts here, check char at SIO available? ; ctloop: ; SBI OutPort,ActivePin; Start active phase ;instead of setting a bit, set pins high according to ampltude. nop out Outport,dacvalue ActLoop: SBIW XL,1; 0.5 µs BRNE ActLoop; 0.5 µs SBIC USR,RXC; Test if rx buffer empty RJMP getcycle; get new cycle time ;CBI Outport,ActivePin; Start Inactive phase nop out Outport,daczero ;instead of clearing bit, set all bits low. InactLoop: SBIW YL,1; 0.5 µs BRNE InactLoop; 0.5 µs MOV XL,rilo; Refresh counters MOV XH,rihi MOV YL,rjlo MOV YH,rjhi NOP NOP RJMP ctloop; start a new cycle hellomessage: .db "Frequency meter/pulse generator 2002.02.09 rev.B" .db $0A,$0D .db "Frequency meter (C)2002 by Richard Cappels,avr@cappels.org. " menumessage: .db $0A,$0D .db "A=10ms,B=100ms,C=1s,D=10s,E=100s. " .db $0A,$0D .db "R=read freq. M=continuous freq. T-running total." .db $0A,$0D .db "P to switch to pulse generator, !=reset " .db $0A,$0D .db "Max count= 65536, Max frequency< 4M Hz. No overflow detection." .db $0A,$0D .db $0A,$0D crlfmessage: .db $0A,$0D .db 00,00 tenmsmessage: .db "Timebase= 10 ms. Frequency= Count X100. " .db $0A,$0D .db 00,00 hundredmsmessage: .db "Timebase= 100 ms. Frequency= Count X10" .db $0A,$0D .db 00,00 onesmessage: .db "Timebase= 1 s. Frequency= Count X1" .db $0A,$0D .db 00,00 tensmessage: .db "Timebase= 10 s. Frequency= Count X1/10" .db $0A,$0D .db 00,00 hundredsmessage: .db "Timebase= 100 s. Frequency= Count X1/100 " .db $0A,$0D .db 00,00 ;//////////BELOW ARE MESSAGES FOR PULSE GENERATOR PROGRAM/////////////// valuesetmessage: .db $20,$20 .db "**Pulse amplitude set." .db $0A,$0D,$00,$00 Selectamplitudemessage: .db $0A,$0D .db "Enter amplitude A..G (default= G,max)." .db $20,$20,$00,$00 ; ; Text strings for transmit, ANSI screen encoded! ; ErrorStr: .DB "Error in input. Repeat input. " .DB ccr,clf,cnul,cnul ActiveStr: .DB "Input active time, A or F (default=2,000):" .DB cnul,cnul CycleStr: .DB "Input cycle time, A or F (default=25,000):" .DB cnul,cnul WaitStr: .DB "Continued operation." .DB "Enter new cycle length to stop and restart generator" .DB ccr,clf,cnul,cnul InitStr: .db $0A,$0D,$0A,$0D .DB "PULSE GENERATOR. (C)2000 by info@avr-asm-tutorial." .db $0A,$0D .db "TO RETURN TO FREQUENCY METER, ENTER F KEY. " .DB ccr,clf .db "For pulse amplitude menu, press A." .db $0A,$0D .DB "All times is in micro-seconds, the accepted range is 5..65535." .DB ccr,clf .DB "New value stops operation until all input is completed. " .db $0A,$0D,$0A,$0A .db $00,$00 ;http://projects.cappels.org/
;HOME