Full Version : Frequency Meter with 100 MHz RF desktop channel
avr >>TECHNICAL & HARDWARE >>Frequency Meter with 100 MHz RF desktop channel


AVR_Admin- 04-29-2006
Frequency Meter with 100 MHz RF desktop channel

Notice: Before operating a radio transmitter, find out what kind of transmitter operation, if any, is permitted in your locality. Radio transmitter operation is a serious legal matter. In the United States, operation of unlicensed intentional radiators is covered by Part 15 of Title 47 of the Code of Federal Regulations. This design can be readily adapted to different frequencies and different power levels. If you choose to build and operate the transmitter described here, you do so at your own risk. I'm only publishing this as an example of what can be done.

Link to Site: http://cappels.org/dproj/232LINK/Fmeter%20...nnel/rfwrfl.htm

CODE

;*********************************
;2313 frequency meter with RF link
;*********************************
 
.include "2313def.inc"    
 
 
;***** 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
 
.def inbyteh = r20    ; higher byte for asci-hex conversion
.def temp  = r22     ;general purpose register
 
.def delaycounter = r23
.def delaycounter1 = r24
.def loopmultiplier = r25
 
 
.def inbytel = r28    ;lower byte for asci-hex conversion
 
.def tcounter = r24  ; 8 Bit loop timing counter.
 
.def runincount = r19; Used to keep track of consecutive zeros detected in runin code.
.def wirelessdat  = r19; data to be sent via wireless port
 
.def inbyte  = r26; Decoded data byte could be same register as runincoung
 
.def header  = r21
.def outbyte  = r21;Byte value to be sent (input to send routine)
 
 
 
 
.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 (I think)
.def presetdelaycounter1     =r5; $27 st all times (I think)
 
 
.def bitsout  = r06; counter for bits sent (couple also use a delay counter)
.def sendheader = r07;headerr to place on outgoing RF byte
.def receiveaddress = r08; Address mask for RF received data header
 
 
.equ minzeros = 9;Minimum number of consecutive zeros to qualify as run-in code
 
.equ defaultsendheader = $10;Default value of RF sendingheaderr.
.equ defaultreceiveaddress =$18;Default value for RF receiveing address in header
 
 
.equ RFxmitdat = 4 Port bit used to send transmit data to RF transmitter
.equ RFrcvdat = 6 Port bit used to receive data from RF receiver
 
.org     $00
rjmp reset
rjmp reset
rjmp reset
rjmp reset
rjmp reset
rjmp reset
rjmp reset
rjmp reset
rjmp reset
rjmp reset
rjmp reset
rjmp reset
rjmp reset
rjmp reset
rjmp reset
rjmp reset
 
 
 
reset:     rjmp     init         ;start init
 
 
monitormemory:;measure over and over until char received from terminal
rcall measurefreq
rjmp  loop      ;

 
init:    
ldi     temp,low(ramend)
out     spl,temp     ;set spl

 
cbi PORTD,RFrcvdat;no pullup on receiver input
cbi DDRD,RFrcvdat;make receier input pin an input
cbi PORTD,RFxmitdat ;initial state of transmitter output is low
sbi DDRD,RFxmitdat;make transmitter output pin an output

cbi  DDRD,$05;set DDRD bit 5 as input
cbi PORTD,$05

  ;Fetch default transmit address from EEPROM
ldi temp,defaultsendheader;Establish the default RF sendingheaderr
mov sendheader,temp  

   
cbi  DDRD,$05;set DDRD bit 5 as input

rcall TypeGreeting
rjmp set1s ;set default measurement time to 1 second and jump to loop

loop: ;*****command interpretation loop****
ldi wirelessdat,$3A;send prompt (colon char) to terminal
rcall Sendabyte
ldi wirelessdat,$20
rcall Sendabyte
ldi wirelessdat,$20
rcall Sendabyte
rcall rs_rec ;get char from terminal and
  ;interpret char
 
cpi inbyte,$3F;if ? then display menu
breq domenu
 
cpi inbyte,$21;if ! then use watchdog timer to reset the
breq pull_the_plug
 
andi inbyte,$DF;make upper-case ascii

cpi inbyte,$52;if R or r, measure frequency
breq measurefreqjump

cpi inbyte,$0D;if Retrun measure frequency
breq monitormemory
 


cpi inbyte,$41;A 10ms
breq set10ms
cpi inbyte,$42;B 100ms
breq set100ms
cpi inbyte,$43;C 1s
breq  set1s
cpi inbyte,$44;D 10s
breq  set10s
cpi inbyte,$45;E 100s
breq  goto100secondrealy


rjmp loop ;keep going
 
measurefreqjump:
rcall measurefreq
rjmp  loop

 
decrementanddisplay:;decrement current address and display current memory contenst
rjmp  loop        
   
domenu:
rcall TypeGreeting
rjmp  loop
 
pull_the_plug:  ;enable watchdog timer and wait for hardware reset
ldi     ZH,high(2*resetmessage)    ; Load high part of byte address into ZH
ldi     ZL,low(2*resetmessage)    ; Load low part of byte address into ZL
rcall  sendstring
wdr
ldi temp,$08
out wdtcr,temp
wait_for_reset:
rjmp wait_for_reset
 
inctimebase:;increase timebase
rjmp  loop        
   
     

 
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_rec:    
rcall TrytoGetbytemessage
cpi header,defaultreceiveaddress;Is this data addressed to device 1?
breq itsforme;If it is addressed to device 1, its for me.
rjmp rs_rec
itsforme:
ret              ;go back
   
 
rs_rec_echo:              ;receive and echo char
rcall  rs_rec
mov     wirelessdat,inbyte
     rcall   Sendabyte         ;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     wirelessdat,r0
    rcall     Sendabyte
    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     wirelessdat,inbyteh
     rcall  Sendabyte
     mov     wirelessdat,inbytel
     rcall   Sendabyte
ret

sendbinarybyte:
ldi temp,$08
stillsendingbinary:  ;rotate byte through carry; send 0 or 1 depending on carry bit
ldi wirelessdat,$30
rol inbytel
brcc dontsendone
ldi wirelessdat,$31
dontsendone:
     rcall   Sendabyte
     dec  temp
     brne stillsendingbinary    
ret
 
 
;*******************
;*******************
;******************* MEASURE FREQUENCY
;*******************
;*******************
 
 
measurefreq:
 
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
   
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
 
 ;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 wirelessdat,tBCD2
ldi temp,$30
add wirelessdat,temp
rcall  Sendabyte
mov inbytel,tBCD1
rcall sendbyte
mov inbytel,tBCD0;since leading digit on high byte is always zero, dont' sent it.
rcall sendbyte
ldi wirelessdat,$20
rcall Sendabyte
 
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  
 
 
hellomessage:
.db     "2313 frequency meter  2002.06.11 A RF LINK    Dick Cappels"
.db $0A,$0D
.db "A=10ms,B=100ms,C=1s,D=10s,E=100s. Return or R=meausre "
.db $0A,$0D
.db "Max count = 65535, Max frequency < 4 MHz. "
.db $0A,$0D
.db $00,$00
 
resetmessage:
.db "Hardware reset initiated. "
.db $00,$00
 
 
crlfmessage:
.db     $0A,$0D
.db     00,00
 
 
tenmsmessage:
.db "Timebase set to 10 ms Frequency is Count X100."
.db     $0A,$0D
.db     00,00
 
hundredmsmessage:
.db "Timebase set to 100 ms. Frequency is Count X 10 "
.db     $0A,$0D
.db     00,00
onesmessage:
.db "Timebase set to 1 s. Frequency is Count X 1."
.db     $0A,$0D
.db     00,00
tensmessage:
.db "Timebase set to 10 s. Frequency is Count  X 1/10. "
.db     $0A,$0D
.db     00,00
hundredsmessage:
.db "Timebase set to 100 s. Frequency is Count  X 1/100. "
.db     $0A,$0D
.db     00,00
 
 
 
 
;///////////////RADIO RECEIVE BYTE ROUTINES///////////////////
 
;Try and decode a valid header and data byte. In the case or error, return with header = $00
ErrorQuitReceiving:
ldi header,$00
ret
 
TrytoGetbytemessage:
 
 
ldi header,$00
ldi temp,$00
mov runincount,temp
GetAnotherZero:  ;Start of loop to gather minzeros zeros in runin code.
rcall Getbit
brts ErrorQuitReceiving;It Getbit comes back with T set, its an error; start over.
brcs ErrorQuitReceiving;If Getbit comes back with carry set, its a one, not a zero -start over
inc runincount
cpi runincount,minzeros
brmi GetAnotherZero  

 
WaitForStartbit: ;Start of loop waiting for a one, which will be the start bit.
rcall Getbit
brts ErrorQuitReceiving;It Getbit comes back with T set, its an error; start over.
brcc WaitForStartbit;If its a zero, keep looking

;OK, Now we have the start bit, so the next 8 bits will be the header. Shift them in.

ldi temp,$08
mov runincount,temp
Getheader:
rcall  Getbit
brts ErrorQuitReceiving;It Getbit comes back with T set, its an error; Stop receiveing.
rol header ;Shift new bit into header byte
dec runincount
brne Getheader;If all bits aren't in yet, go get another.
 
;At this point, one could tell whether this data is addressed to this machine, but I am going to leave
;address qualification to another part of the code. If time were very precious, one could stop
;execution of this part of the receive routine right here.

rcall Getbit ;Throw this one away. Its the start bit for the next byte
  ;It must be here so two bytes of zeros can't look like
  ;the runing code.
brts ErrorQuitReceiving;It Getbit comes back with T set, its an error; start over.

;Now we have the runinbits, the start bit, and the header. Next is the data. Shift it in.



ldi temp,$08
mov runincount,temp
GetInbyte:
rcall  Getbit
brts ErrorQuitReceiving;It Getbit comes back with T set, its an error; Stop receiveing.
rol inbyte ;Shift new bit into input data byte
dec runincount
brne GetInbyte;If all bits aren't in yet, go get another


 
ret ;RETURN WITH header IN header AND DATA IN INBYTE
 

Getbit: ;Subroutine to get a received bit.
;It returns the value of the received bit in the carry bit
;If this routine does not receive a valid data bit IT WILL NOT RETURN.
;If it is necessary to recover from this situation, the watchdog timer can be used.
;It measures the time between rising edges on the input pin (B3 originally).
;Successfult bit decoding will return with T flag clear. T flag =1 means error.
 
 
 
ldi tcounter,$00 ;Zero the counter.
;Count, waiting for pin to go low.  
 
WaitForLow:  
ldi delaycounter,$16;load with $16, 1 cycle takes 17.5 us
delayloop1:
dec delaycounter
brne delayloop1
inc  tcounter
breq nobit
sbic PIND,RFrcvdat
rjmp WaitForLow

;Continue to count, waiting for pin to go high.

WaitForHigh:
ldi delaycounter,$16
delayloop2:
dec delaycounter
brne delayloop2

inc  tcounter
breq nobit
sbis PIND,RFrcvdat
rjmp WaitForHigh

;Determine if we measured a "legal" bit and if so wheter it as a one of a zero.
;pcode:
;If tcount < $42 start over  
;If tcount <$6E its a one
;If tcount is < $84 start over
;If tcount is >$DC start over
;Else, its a zero
 
cpi tcounter,$42
brmi nobit
cpi tcounter,$6E
brmi ItsAOne
cpi tcounter,$84
brmi nobit
cpi tcounter,$DC
brpl nobit
 ;If it gets here, its a valid zero.;
clt ;Clear T flag (no error), set the carry bit to show that its a zero and return.  
clc
ret
 
 
ItsAOne:clt ;Clear T flag (error) set carry flag (data is a one), and return.
sec  
ret
 
 
nobit:  ;Error receiving a bit, set T flag and leave
set
ret
 
;/////////////////////////RADIO SEND BYTE ROUTINES/////////////////////////
 
Sendabyte:
 ;SEND RUNIN CODE (16 ZEROS)

ldi outbyte,$00 ;get ready to send 16 zeros
ldi temp,$0F ;$0F databits plus a zero "start bit"
mov bitsout,temp
clc   ;no start bit (it goes as another zero)
rcall LateTransmitAByte;jump into byte sending routine

 
;Send the header byte. The first and last bit in the headder is always a "1". Its the law.
mov outbyte,sendheader
rcall TransmitAByte


;(Ok, now the 16 bits of runin, the start bit, and the 8 bits of header have been sent.
;Time to send the data byte.
 
mov outbyte,wirelessdat
rcall TransmitAByte


ldi outbyte,$FF ;get ready to send 1 one, channel idle, to finish the last data bit.
ldi temp,$02 ;$01 databits plus a start bit
mov bitsout,temp
sec   ;no start bit
rcall LateTransmitAByte;jump into byte sending routine
 
ret  ;finished sending the one byte message
 
 
 
TransmitAByte:;send a byte out the wireless port
ldi temp,$09
mov bitsout,temp
sec;start bit is a "one"

LateTransmitAByte:
SendACycle:;a one or a zero, depending on the state of carry bit
sbi PORTD,RFxmitdat
ldi tcounter,$00
ldi delaycounter,$04
brcs notazero1
ldi delaycounter,$08
notazero1:
 
Delay:
dec tcounter
brne Delay
dec delaycounter
brne delay

cbi PORTD,RFxmitdat
 

ldi tcounter,$00
ldi delaycounter,$04
brcs notazero2
ldi delaycounter,$08
notazero2:
 
Delay2:
dec tcounter
brne Delay2
dec delaycounter
brne delay2

 
rol outbyte;sent start bit and all 8 data bits yet?
dec bitsout
brne SendACycle;if not send another bit

ret
 
 
;//////////END OF CODE FOR SEND ROUTINE///////////////
 




Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.