;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