Você está na página 1de 12

DDS V1.

asm ;************************************************************************** ; Source code for Direct Digital Synthesis VFO controller ; ; **** NOW PORTED TO PIC16C84 **** (see revision note for 10/01/98) ; **** NOW USING MICROCHIP MPASM ASSEMBLER (see revision note for 10/14/98) ; **** WORKS WITH PIC16F84A without further change (03/22/05) ; ; This code is available as is. ; ; Description: ; The program main loop, (Check_Encoder) polls a rotary shaft encoder. ; If the input from the shaft encoder has changed, then direction (up/down) ; is determined. The program then computes the corresponding ; frequency digits to be displayed on the Liquid Crystal Display. ; This data is transfered to the LCD using a 4 bit interface. ; A new DDS control word is then computed and transfered ; serially to the AD9850 DDS chip. ; The program then returns to the shaft encoder polling loop. ; ; Target Controller - PIC1654A (originally) ; Program Size - 474 words, 38 words free ; Assembler - Parallax SPASM v4.2 ; Author - Curtis W. Preuss - WB2V ; Initial creation 11/08/96 ; Modification History ; 11/24/96 Finished debugging ; 12/14/96 Edited comments ; 10/01/98 Ported source to PIC16C84 -- G. Heron, N2APB ; 1) Needed to shift the variables down by 5 bytes due to ; changes in memory architecture ; 2) Needed to modify some of the indirect addressing "reads" ; during compares to list ends (16C84 has more FSR bits) ; 3) Changed assembler directive device code ; 4) Added 2 more function sets during LCD init, per the data ; sheets for my wacko (bargain basement) Seiko M1641 displays ; 5) Changed delays during LCD init (added wait60ms rtn), ; (again, due to wacko Seiko M1641 LCDs?) ; 6) Removed assembler directive for reset vector and just ; added "jmp start" at loc 0 and a new "org 5" to bypass ; some of the interrupt vector locs at start of code space ; 7) Added explicit and separate "setb LCD_rw" in Busy_check ; routine to more reliably read Busy bit. (Again, perhaps ; only because of my wacko model Seiko LCD.) ; 8) Slightly modified source formatting to make it easier ; (for me) to read ; 9) Comments & questions welcome! Email to: n2apb@amsat.org ; ; 10/14/98 Ported source to Microchip MPASM -- Craig B. Johnson, AA0ZZ ; 1) Generates identical HEX code as previous PIC16C84 version ; 2) Added a few comments (for me!) ; 3) Comments & questions -- Email to: johns516@tc.umn.edu ; 10/23/98 ; 1) Corrected translation bug in routine SendMax1 ; ; 03/22/05 ; 1) Digit weights recalculated for a 66.00051MHz reference oscillator ;************************************************************************** list p=16f84 radix hex Indirect Status equ equ 0 3 Page 1

DDS V1.asm FSR PortA PortB equ equ equ 4 5 6 ;(PortA)Power to LCD module ;(PortB)Update pin on AD9850 ;(PortB)0=instruction, 1=data ;(PortB)0=write, 1=read ;(PortB)0=disable, 1=enable ;(PortB)AD9850 write clock ;(PortB)AD9850 serial data input

;Assign names to IO pins LCD_VDD equ 3 AD9850_fqu equ 0 LCD_rs equ 1 LCD_rw equ 2 LCD_e equ 3 AD9850_wc equ 5 AD9850_dat equ 7

;Allocate variables in general purpose register space LCD_Dat equ 0x0C ;current Display data AD9850 equ 0x13 ;control word for DDS chip OP1 equ 0x18 ;Work Space for OP2 equ 0x1C ; the multiply routine temp1 equ 0x1D ;Temp storage temp2 equ 0x1E ;Temp storage temp3 equ 0x1F ;Temp storage old equ 0x20 ;old encoder input data new equ 0x21 ;new encoder input data count1 equ 0x22 ;used for timing the shaft encoder count2 equ 0x23 ; ;Status Bits C equ DC equ Z equ org goto 0 1 2 ;Carry ;Digit (Half) Carry ;Zero ;

0 Start

org 5 ;************************************************************************** ;BusyCheck Subroutine ; ;LCD read/write operations are slooooow, this subroutine ;polls the LCD busy flag to determine if previous operations are completed. ;Note side effect that the LCD_rw and LCD_rs are left in write data mode. BusyCheck movlw tris bsf Busy bsf movf movwf bcf nop bsf bcf btfsc goto bcf bsf return 0xF0 PortB PortB,LCD_rw PortB,LCD_e PortB,w temp1 PortB,LCD_e PortB,LCD_e PortB,LCD_e temp1,7 Busy PortB,LCD_rw PortB,LCD_rs ;Tristate the 4 data pins ; ;Raise the r/w bit to read the LCD ; ;Get first nibble of input data ; and save it ; ; ;Get next nibble to keep LCD happy ; ;Check for busy flag ;It is busy ;Leave LCD in Write Data mode ;

;************************************************************************** ;Send Character to LCD Subroutine ; Page 2

DDS V1.asm ;The character to be sent must have been placed in "temp2" prior to calling ;the subroutine. LCD_rw and LCD_rs must be set up prior to entry. SendChar movlw tris movf movwf movlw andwf movlw andwf movf iorwf bsf bcf swapf movlw andwf movlw andwf movf iorwf bsf bcf return 0x00 PortB temp2,w temp1 0x0F PortB,f 0xF0 temp2,f temp2,w PortB,f PortB,LCD_e PortB,LCD_e temp1,f 0x0F PortB,f 0xF0 temp1,f temp1,w PortB,f PortB,LCD_e PortB,LCD_e ; ;Enable port B ;Save temp2 ; in temp1 ; ; ; ; ; ;Load first nibble ;Transfer first nibble ; ; ; ; ; ;Clear data nibble ; ; ;Transfer second nibble ;

;************************************************************************** ;BCD increment ; ;This routine does a binary coded decimal increment to the values in LCD_Dat. ;On entry the FSR register must point to the LCD_Dat digit to be incremented. ;If the result is over 20MHz the value is reset back to 20MHz. BCDInc movf movwf movlw addwf movf movwf movlw addwf btfsc goto movlw andwf movf movwf movlw subwf btfsc goto return BCDIncCarry clrf movf movwf decf goto SetMax movlw movwf Indirect,w temp2 0x01 temp2,f temp2,w temp1 0x06 temp1,f Status, DC BCDIncCarry 0x0F temp2,f temp2,w Indirect 0x02 LCD_Dat+0,w Status, C SetMax temp2 temp2,w Indirect FSR,f BCDInc 0x12 FSR ; ; ; ; ; ; ; ; ;See if Digit Carry is clear ;Digit Carry is set, so jump ; ; ; ; ; ;Test for max frequency ;See if Carry is clear ;Carry is set, so jump ; ; ; ; ; ;Set the display to 20,000.00 ; Page 3

DDS V1.asm SetMax1 movlw 0x00 ; movwf Indirect ; decf FSR,f ; movlw 0xF3 ; addwf FSR,w ; btfsc Status, C ;See if Carry is clear goto SetMax1 ;Carry is set, so jump movlw 0x02 ; movwf Indirect ; return ; ;************************************************************************** ;BCD decrement ; ;This routine does a binary coded decimal decrement to the values in LCD_Dat. ;On entry the FSR register must point to the LCD_Dat digit to be decremented, ;(one of 10's, 100's, 1K, 10K or 100K digit) ;If the result is under 100KHz the value is reset back to 100KHz. BCDDec movf movwf movlw subwf btfss goto movf movwf movlw addwf btfsc goto movlw addwf btfsc goto movlw addwf btfsc goto goto BCDDecExit return BCDDecCarry movlw movwf movf movwf decf goto SetMin movlw movwf SetMin1 movlw movwf decf movlw addwf btfsc goto movlw movwf Indirect,w temp2 0x01 temp2,f Status, DC BCDDecCarry temp2,w Indirect 0xFF LCD_Dat+0,w Status, C BCDDecExit 0xFF LCD_Dat+1,w Status, C BCDDecExit 0xFF LCD_Dat+2,w Status, C BCDDecExit SetMin ; ; ; ; ;See if Digit Carry is ;Digit Carry is clear, ; ; ; ; ;See if Carry is clear ;Carry is set, so jump ; ; ;See if Carry is clear ;Carry is set, so jump ; ; ;See if Carry is clear ;Carry is set, so jump ;

set so jump

to exit

to exit

to exit

0x09 temp2 temp2,w Indirect FSR,f BCDDec 0x12 FSR 0x00 Indirect FSR,f 0xF1 FSR,w Status, C SetMin1 0x01 Indirect

; ; ; ; ; ; ; ; ; ; ; ; ; ;See if Carry is clear ;Carry is set, so jump ; ; Page 4

DDS V1.asm decf movlw movwf decf movlw movwf return FSR,f 0x00 Indirect FSR,f 0x00 Indirect ; ; ; ; ; ; ;

;************************************************************************** ; Delay 24ms subroutine ; Wait24ms movlw movwf Wait24Outer movlw movwf Wait24Inner decfsz goto decfsz goto return 0x28 temp1 0xC8 temp2 temp2,f Wait24Inner temp1,f Wait24Outer ; use 40 for 24ms wait if clock is 4Mhz ; ; use 200 for 24 ms wait ; ; ; ; ;

;************************************************************************** ; Delay 60ms subroutine ; Wait60ms movlw 0x64 ; use 100 for 60ms wait if clock is 4Mhz movwf temp1 ; Wait60Outer movlw 0xC8 ; use 200 for 60ms wait movwf temp2 ; Wait60Inner decfsz temp2,f ; goto Wait60Inner ; decfsz temp1,f ; goto Wait60Outer ; return ; ;************************************************************************** ; 32 bit add ; ;The value in registers OP1 is added to the current 32 bit value in AD9850 Add32 movf addwf btfss goto incfsz goto incfsz goto incf Add1 movf addwf btfss goto incfsz goto OP1+1,w AD9850+1,f Status, C Add2 AD9850+2,f Add2 ; ; ;See if Carry is set ;Carry is clear, so jump ; ; Page 5 OP1+0,w AD9850+0,f Status, C Add1 AD9850+1,f Add1 AD9850+2,f Add1 AD9850+3,f ; ; ;See if Carry is set ;Carry is clear, so jump ; ; ; ; ;

DDS V1.asm incf Add2 movf addwf btfss goto incf Add3 movf addwf return OP1+3,w AD9850+3,f ; ; ; OP1+2,w AD9850+2,f Status, C Add3 AD9850+3,f ; ; ;See if Carry is set ;Carry is clear, so jump ; AD9850+3,f ;

;************************************************************************** ;Write Data ; ;This subroutine does two things: ; (1) it sends the contents LCD_dat to the LCD, ; (LCD_Dat must contain BCD digits) ; (2) the contents of AD9850 (40 bits) are serial shifted ; into the AD9850 module WriteData movlw movwf call bcf call movf movwf movlw iorwf movlw subwf btfsc goto movlw iorwf Wd2 call call movf movwf movlw iorwf call call movlw movwf call call movf movwf movlw iorwf call call movf movwf movlw iorwf call call movlw 0x83 temp2 BusyCheck PortB,LCD_rs SendChar LCD_Dat+0,w temp2 0x20 temp2,f 0x20 temp2,w Status, Z Wd2 0x10 temp2,f BusyCheck SendChar LCD_Dat+1,w temp2 0x30 temp2,f BusyCheck SendChar 0x2C temp2 BusyCheck SendChar LCD_Dat+2,w temp2 0x30 temp2,f BusyCheck SendChar LCD_Dat+3,w temp2 0x30 temp2,f BusyCheck SendChar 0xC0 ; LCD position for first digit ; ; ; Set LCD for instruction write ; ; ; ;Send a space if first digit is zero ; ;Set up for space check ;Subtract to compare ;See if Zero is clear (not a space) ;Zero is set, so go send the space ;Zero is clear, so convert BCD ; to ASCII ; ;Send 10Mhz digit ; ; ; ; ; ;Send 1Mhz digit ; ; ; ;Send a comma ; ; ; ; ;Send a 100KHz digit

;Send 10 KHz digit ;Point LCD at digit#9 (Gap in LCD address) Page 6

DDS V1.asm movwf call bcf call movf movwf movlw iorwf call call movlw movwf call call movf movwf movlw iorwf call call movf movwf movlw iorwf call call WriteAD9850 clrf movlw movwf movlw tris movlw movwf NextByte movf movwf movlw movwf NextBit rrf btfss goto bsf bsf bcf goto Send0 bcf bsf bcf Break decfsz goto incf decfsz goto bsf bcf return temp2 BusyCheck PortB,LCD_rs SendChar LCD_Dat+4,w temp2 0x30 temp2,f BusyCheck SendChar 0x2E temp2 BusyCheck SendChar LCD_Dat+5,w temp2 0x30 temp2,f BusyCheck SendChar LCD_Dat+6,w temp2 0x30 temp2,f BusyCheck SendChar PortB 0x05 temp3 0x00 PortB 0x13 FSR Indirect,w temp1 0x08 temp2 temp1,f Status, C Send0 PortB,AD9850_dat PortB,AD9850_wc PortB,AD9850_wc Break PortB,AD9850_dat PortB,AD9850_wc PortB,AD9850_wc temp2,f NextBit FSR,f temp3,f NextByte PortB,AD9850_fqu PortB,AD9850_fqu ; ;Set LCD for instruction write ; ;

; Send 1Khz digit

; Send a period ;

; Send 100Hz digit ;

; ; Send 10Hz digit ; ; ; ; ; ; ; ; set bit counter to 8 Clear PortB Send 5 bytes to AD9850 Enable PortB Point at AD9850+0

;See if carry is set ;Carry is clear, so jump ; toggle write clock ; (repeated 40 times)

; send load signal to AD9850 ; Clear after last data dbit is written

;*************************************************************************** ;7 Digit BCD by 32 bit binary mulitply Page 7

DDS V1.asm ; ;The 7 BCD digits stored in LCD_dat are each multiplied by a precalculated digit ;weight, (Digit weigths assume a 66.666MHz input clock). The sum of all 7 ;digits times their weigth is stored in the AD9850 registers. Mult clrf clrf clrf clrf clrf clrf Mult10 movlw movwf movlw movwf clrf clrf movf movwf goto Mult100 movlw movwf movlw movwf clrf clrf movf movwf goto Mult1K movlw movwf movlw movwf clrf clrf movf movwf goto Mult10K movlw movwf movlw movwf movlw movwf clrf movf movwf goto Mult100K movlw movwf movlw movwf movlw movwf clrf movf temp1 AD9850+0 AD9850+1 AD9850+2 AD9850+3 AD9850+4 0x84 OP1+0 0x02 OP1+1 OP1+2 OP1+3 LCD_Dat+6,w OP2 Go 0x2A OP1+0 0x19 OP1+1 OP1+2 OP1+3 LCD_Dat+5,w OP2 Go 0xA9 OP1+0 0xFB OP1+1 OP1+2 OP1+3 LCD_Dat+4,w OP2 Go 0x9B OP1+0 0xD4 OP1+1 0x09 OP1+2 OP1+3 LCD_Dat+3,w OP2 Go 0x19 OP1+0 0x4E OP1+1 0x62 OP1+2 OP1+3 LCD_Dat+2,w ;

; ; ; ; ;

; ; ; ; ; ;

; ; ; ; ;

; ; ; ; Page 8

DDS V1.asm movwf goto Mult1M movlw movwf movlw movwf movlw movwf movlw movwf movf movwf goto Mult10M movlw movwf movlw movwf movlw movwf movlw movwf movf movwf goto Go movlw movwf DigitLoop bcf rrf btfss goto call NoCarry bcf rlf rlf rlf rlf decfsz goto incf movlw subwf btfsc goto movlw subwf btfsc goto movlw subwf btfsc goto movlw subwf btfsc goto movlw subwf btfsc OP2 Go 0xC1 OP1+0 0x0C OP1+1 0xD7 OP1+2 0x03 OP1+3 LCD_Dat+1,w OP2 Go 0x90 OP1+0 0x7F OP1+1 0x66 OP1+2 0x26 OP1+3 LCD_Dat+0,w OP2 Go 0x04 temp2 Status, C OP2,f Status, C NoCarry Add32 Status, C OP1+0,f OP1+1,f OP1+2,f OP1+3,f temp2,f DigitLoop temp1,f 0x01 temp1,w Status, Z Mult100 0x02 temp1,w Status, Z Mult1K 0x03 temp1,w Status, Z Mult10K 0x04 temp1,w Status, Z Mult100K 0x05 temp1,w Status, Z ;Clear Carry bit ;Rotate right (through carry) ;See if Carry is set ;Carry is clear, so jump ;Clear Carry bit ;Rotate left through carry ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

;See if Zero is clear ;Zero is set, so jump ;See if Zero is clear ;Zero is set, so jump ;See if Zero is clear ;Zero is set, so jump ;See if Zero is clear ;Zero is set, so jump ;See if Zero is clear Page 9

goto movlw subwf btfsc goto return

Mult1M 0x06 temp1,w Status, Z Mult10M

DDS V1.asm ;Zero is set, so jump ;See if Zero is clear ;Zero is set, so jump

;************************************************************************** ;Initialize PIC controller ; ; Start here after reset or power on ; Set DDS initially to 10,000.00 Start clrf clrf movlw tris movlw tris movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf clrf clrf PortA PortB 0x00 PortB 0xFF PortA 0x01 LCD_Dat+0 0x00 LCD_Dat+1 0x00 LCD_Dat+2 0x00 LCD_Dat+3 0x00 LCD_Dat+4 0x00 LCD_Dat+5 0x00 LCD_Dat+6 count1 count2 ; ; ; ; ; ; Clear data Port A Clear data Port B Enable port B drivers Tristate Port A drivers

;************************************************************************** ;Power on initialization of Liquid Crystal Display. ; The LCD controller chip must be equivalent to an Hitachi 44780. ; The LCD is assumed to be a 16 X 1 display. movlw tris bsf call bsf movlw movwf bcf call bsf movlw movwf bcf call bsf movlw movwf bcf call bsf movlw 0x07 PortA PortA,LCD_VDD Wait60ms PortB,LCD_e 0x38 PortB PortB,LCD_e Wait60ms PortB,3 0x38 PortB PortB,LCD_e Wait60ms PortB,LCD_e 0x38 PortB PortB,LCD_e ; Wait60ms PortB,LCD_e 0x28 ; Enable LCD_VDD pin ; power up LCD ; Wait for LCD to power up ; ; func set + enable to LCD ; ; func set + enable to LCD ; ; ; func set + enable to LCD ; ; 4bit_mode instruction + enable Page 10

DDS V1.asm movwf bcf call movlw movwf call bcf call movlw movwf call bcf call movlw movwf call bcf call PortB PortB,LCD_e Wait60ms 0x01 temp2 BusyCheck PortB,LCD_rs SendChar 0x06 temp2 BusyCheck PortB,LCD_rs SendChar 0x0C temp2 BusyCheck PortB,LCD_rs SendChar

; Clear and reset cursor

;increment no_shift mode

; Display on

;Send initial 10,000.00 display to LCD call call call call call Mult Wait24ms Wait24ms WriteData WriteData ; allow AD9850 clock time to start ; ; side effect reset power down bits of AD9850 ; load the initial display value

;Get the power on encoder value movf movwf movlw andwf movwf PortA,w temp2 0x03 temp2,w old ; get encoder value ; isolate direction bits ; save initial values

;************************************************************************** ;Check encoder ; PortA.0 shaft encoder output A ; PortA.1 shaft encoder output B ; PortA.2 shaft encoder push button switch ; Timing checks assume a 4MHz cpu clock and that the encoder ; has 32 detents ChkEncoder incf movlw subwf btfss goto incf clrf Ce movf movwf movf movwf movlw andwf movwf xorwf btfsc goto count1,f 0x75 count1,w Status, C Ce count2,f count1 PortA,w temp1 temp1,w temp2 0x03 temp2,w new old,w Status, Z ChkEncoder

;Check encoder loop takes 17 us ;See if Carry is set ;Carry is clear, so jump ;0x75 * 17us = 2ms ;Get encoder value ;Double latch the input

;See if Zero is clear ;Zero is set, so jump Page 11

movlw movwf btfss goto movlw movwf movlw subwf btfsc goto movlw movwf movlw subwf btfsc goto movlw movwf CeGo clrf movlw movwf bcf rlf movf xorwf btfsc goto call call goto CeUp call call CeWrite call movf movwf goto ; ; ; ; ; ;

0x0E FSR temp2,2 CeGo 0x12 FSR 0x0F count2,w Status, C CeGo 0x11 FSR 0x05 count2,w Status, C CeGo 0x10 FSR count2 0x46 count1 Status, C old,f new,w old,f old, DC CeUp BCDDec Mult CeWrite BCDInc Mult WriteData new,w old ChkEncoder

DDS V1.asm ;Pointer set to 100KHz digit ;If pb switch is closed (active low) ; ;Pointer set to 10's ;If speed < 1.0 RPM ;See if Carry is clear ;Carry is set, so jump ;Pointer set to 100's ;If (1.0RPM < Speed < 3.0RPM) ;See if Carry is clear ;Carry is set , so jump ;Pointer set to 1K ;Add time to write LCD etc to count1 ; (about 1.2 ms) ;Clear Carry bit ;Rotate left ;Determine direction ;See if Digit Carry is clear ;Digit Carry is set, so jump ;Calculate new LCD display ;Calculate new AD9850 control word ; calculate new LCD display ; calculate new AD9850 control word

; continue polling the encoder

ID ID ID ID Fuses (CP=Off, PWRTE=Enabled, WDTE=Disabled, OSC=XT) 0001 END

Page 12

Você também pode gostar