MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 1 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00001 ; **************************************************************************** 00002 ; * Signal Generator (VFO) with Direct Digital Synthesis * 00003 ; * Version 3a * 00004 ; * September 18, 2003 * 00005 ; * * 00006 ; **************************************************************************** 00007 ; Description: 00008 ; This is the control program for a DDS VFO built with an AD9850 DDS chip, a 00009 ; shaft encoder, a push button switch and an Liquid crystal display. 00010 ; 00011 ; Features: 00012 ; VARIABLE RATE TUNING based on the speed at which the encoder is turned. The 00013 ; encoder also has a built in switch which will change the step size from 1Hz 00014 ; to 1kHz if the encoder shaft is pressed down while turning. 00015 ; 00016 ; BAND MEMORIES an external push button switch allows the frequency to be 00017 ; cycled around the HF ham bands. 00018 ; 00019 ; CALIBRATE MODE is entered if the external push button is pressed during 00020 ; power on. The display is set to 10,000.000 CAL and remains fixed, even as 00021 ; adjustments are being made. If the push button is held pressed, then turning 00022 ; the shaft encoder will increase or decrease the value "osc" used to 00023 ; calculate the DDS control word. The basic calibrate adjustment rate is very 00024 ; low (on the order of a few cycles per turn of the encoder). A somewhat 00025 ; faster adjustment speed is available by pressing the encoder shaft down 00026 ; while turning. An external frequency counter on the DDS output is required 00027 ; to observe this adjustment. To exit calibrate mode, release the external 00028 ; push button and turn the shaft encoder one more time. The calibrated value 00029 ; of "osc" will then be stored in EEPROM memory. 00030 ; 00031 ;****************************************************************************** 00032 ; Author - Curtis W. Preuss - WB2V 00033 ; 00034 ; Modification History 00035 ; 8/19/98 - Version 1 - Initial Version by Curtis W. Preuss - WB2V 00036 ; 12/xx/98 - Version 2 - Converted to MPASM by Bruce Stough, AA0ED 00037 ; 4/21/99 - Version 3 - Fixed and modified by 00038 ; Bruce Stough, AA0ED (sbs1@visi.com) and 00039 ; Craig Johnson, AA0ZZ (aa0zz@arrl.net) 00040 ; 00041 ; FIXES: 00042 ; 1) Fix a bug which caused the frequency to jump to 00043 ; the maximum when going towards zero. 00044 ; 2) Fix several SMASM to MPASM translation bugs. 00045 ; - Code worked, but several cases of "hard coded" 00046 ; constants remained that should have been 00047 ; changed to labels to allow data tables to 00048 ; be moved and/or modified. This bug could 00049 ; cause a reference to a wrong variable. 00050 ; - PortB vs TRISB causing confusion. 00051 ; MODIFICATIONS/ADDITIONS: 00052 ; 1) The lower frequency is changed from 1Khz to zero. 00053 ; 2) Added band table entries of 0 Hz and 30 MHz. MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 2 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00054 ; 3) Changed wait routine names for clarity. 00055 ; 4) Added comments throughout. 00056 ; 5) Subroutine headers added. 00057 ; - Inputs and Outputs specified 00058 ; 6) Changed some data labels for clarity. 00059 ; 7) Changed some routines for efficiency. 00060 ; - Improve path length and save memory 00061 ; NOTE: OUR GOAL was to make this code clear and 00062 ; easy to understand so that it can be used as 00063 ; a springboard for additional changes. 00064 ; By documenting subroutines as clearly as 00065 ; possible, we hope readers will be able to 00066 ; easily use the subroutines in other projects. 00067 ; 9/17/03 Corrected error in PIC16F84 diagram. Pin 4 should be 00068 ; connected to +5v instead of ground. 00069 ; 00070 ;***************************************************************************** 00071 ; 00072 ; Target Controller - PIC16F84 00073 ; __________ 00074 ; ENCODER SWITCH--RA2 |1 18| RA1---------ENCODER A 00075 ; PB SWITCH-------RA3 |2 17| RA0---------ENCODER B 00076 ; +5V-------------RA4 |3 16| OSC1--------XTAL 00077 ; +5V-----------!MCLR |4 15| OSC2--------XTAL 00078 ; Ground----------Vss |5 14| VDD---------+5 V 00079 ; DDS LOAD--------RB0 |6 13| RB7---------DDS DATA/LCD 14 00080 ; LCD_rs----------RB1 |7 12| RB6---------LCD 13 00081 ; LCD_rw----------RB2 |8 11| RB5---------DDS CLOCK/LCD 12 00082 ; LCD_e-----------RB3 |9 10| RB4---------LCD 11 00083 ; ---------- 00084 ; 00085 ;***************************************************************************** 00086 ; 00087 ; ********** HARDWARE CHANGES NEEDED TO FAR CIRCUITS BOARD ********** 00088 ; 00089 ; The circuit board available from FAR Circuits is based on the original 00090 ; QEX article (7/97) by Curt, WB2V, and works with the original dds_vfo 00091 ; code. Subsequently, Curt modified the code to add the calibrate 00092 ; and band select functions. 00093 ; 00094 ; This enhanced PIC code requires a hardware change to allow for the push 00095 ; button which is used to select the calibrate mode and to do band 00096 ; selection. The change removes the +5 volt connection to pin 2 of 00097 ; the PIC chip, and connects a 10K ohm pull-up resistor to pin 2. The 00098 ; push button is connected between pin 2 and ground, so that the pin is 00099 ; grounded when the button is pressed and held high when the button is 00100 ; released. In addition, instead of using the output of Pin 2 to power 00101 ; the LCD and control the LCD contrast, the LCD is connected directly to 00102 ; +5 volts. 00103 ; 00104 ; The change can be done as follows: 00105 ; 00106 ; 1. Locate the PC trace which connects pin 2 of the PIC chip to the MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 3 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00107 ; LCD contrast control pot. This was originally used to power the 00108 ; LCD by setting bit 3 of Port A (pin 2) high. Drill a small hole 00109 ; (#60 - .040") through this trace as near as possible (1/16") to 00110 ; pin 2 of the PIC socket. 00111 ; 00112 ; 2. Near pin 2 of the PIC socket, cut the trace about 1/8" beyond the 00113 ; new hole. Using a 1/4" drill, remove the foil around the hole 00114 ; on the ground plane side of the board to avoid shorting pin 2 to 00115 ; ground when the resistor gets inserted in the hole (Step 4). 00116 ; 00117 ; 3. Locate the +5 volt trace that passes between pin 1 and pin 2 of the 00118 ; PIC socket. Drill a new hole through this trace in the place where 00119 ; it is close to pin 1. Remove the ground side foil from around this 00120 ; hole with a 1/4" drill to avoid shorting +5 v to ground when the 00121 ; resistor lead is inserted. 00122 ; 00123 ; 4. Install a 10K resistor in the new PC board holes. Mount it vertically, 00124 ; with the short resistor lead in the +5 v trace hole and the other end 00125 ; bent close to the resistor body and down into the hole near pin 2 of 00126 ; the PIC socket. Make the solder connection to the traces only, not to 00127 ; ground plane foil on the other side of the board. Make sure both sides 00128 ; of the +5 v trace are soldered to the resistor lead. 00129 ; 00130 ; 5. Connect a wire from one side of the push button to the pin 2 side of 00131 ; the new 10K resistor. This can be done by connecting the wire to the 00132 ; top of the vertically mounted resistor. Connect another wire from the 00133 ; other side of the push button to ground. 00134 ; 00135 ; 6. Using a bit of solid wire, connect the pin of the LCD contrast 00136 ; pot that used to be connected to pin 2 of the PIC socket to the 00137 ; +5 volt trace. This now supplies power to the LCD. 00138 ; 00139 ; **************************************************************************** 00140 ; * Device type and options. * 00141 ; **************************************************************************** 00142 ; 00143 processor PIC16F84 00144 radix dec 00145 ; 00146 ; **************************************************************************** 00147 ; * Configuration fuse information: * 00148 ; **************************************************************************** 00149 0000000F 00150 _CP_ON EQU H'000F' 00003FFF 00151 _CP_OFF EQU H'3FFF' 00003FF7 00152 _PWRTE_ON EQU H'3FF7' 00003FFF 00153 _PWRTE_OFF EQU H'3FFF' 00003FFF 00154 _WDT_ON EQU H'3FFF' 00003FFB 00155 _WDT_OFF EQU H'3FFB' 00003FFC 00156 _LP_OSC EQU H'3FFC' 00003FFD 00157 _XT_OSC EQU H'3FFD' 00003FFE 00158 _HS_OSC EQU H'3FFE' 00003FFF 00159 _RC_OSC EQU H'3FFF' MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 4 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00160 ; 2007 3FF5 00161 __config _CP_OFF & _PWRTE_ON & _WDT_ON & _XT_OSC 00162 ; 00163 ; **************************************************************************** 00164 ; * General equates. These may be changed to accommodate the reference clock* 00165 ; * frequency, the desired upper frequency limit, and the default startup * 00166 ; * frequency. * 00167 ; **************************************************************************** 00168 ; 00169 ; ref_osc represents the change in the frequency control word which results 00170 ; in a 1 Hz change in output frequency. It is interpreted as a fixed point 00171 ; integer in the format . 00172 ; 00173 ; The values for common oscillator frequencies are as follows: 00174 ; 00175 ; Frequency ref_osc_3 ref_osc_2 ref_osc_1 ref_osc_0 00176 ; 00177 ; 120.00 MHz 0x23 0xCA 0x98 0xCE 00178 ; 100.00 MHz 0x2A 0xF3 0x1D 0xC4 00179 ; 90.70 MHz 0x2F 0x5A 0x82 0x7A 00180 ; 66.66 MHz 0x40 0x6E 0x52 0xE7 00181 ; 66.00 MHz 0x41 0x13 0x44 0x5F 00182 ; 50.00 MHz 0x55 0xE6 0x3B 0x88 00183 ; 00184 ; To calculate other values: 00185 ; ref_osc_3 = (2^32 / oscillator_freq_in_Hertz). 00186 ; ref_osc_2, ref_osc_1, and ref_osc_0 are the fractional part of 00187 ; (2^32 / oscillator_freq_in_Hertz) times 2^24. 00188 ; Note: 2^32 = 4294967296 and 2^24 = 16777216 00189 ; 00190 ; For example, for a 120 MHz clock: 00191 ; ref_osc_3 is (2^32 / 120 x 10^6) = 35.791394133 truncated to 35 (0x23) 00192 ; ref_osc_2 is the high byte of (.791394133 x 2^24) = 13277390.32 00193 ; 13277390.32 = 0xCA98CE, so high byte is CA. 00194 ; ref_osc_1 is the next byte of 0xCA98CE, or 98 00195 ; ref_osc_0 is the last byte of 0xCA98CE, or CE 00196 ; 00197 ;==== Currently set for 100 MHz Oscillator ======= 0000002A 00198 ref_osc_3 equ 0x2A ; Most significant osc byte 000000F3 00199 ref_osc_2 equ 0xF3 ; Next byte 0000001D 00200 ref_osc_1 equ 0x1D ; Next byte 000000C4 00201 ref_osc_0 equ 0xC4 ; Least significant byte 00202 ; 00203 ; Limit contains the upper limit frequency as a 32 bit integer. 00204 ; This should not be set to more than one third of the reference oscillator 00205 ; frequency. The output filter of the DDS board must be designed to pass 00206 ; frequencies up to the maximum. 00207 ; 00000001 00208 limit_3 equ 0x01 ; Most significant byte for 30 MHz 000000C9 00209 limit_2 equ 0xC9 ; Next byte 000000C3 00210 limit_1 equ 0xC3 ; Next byte 00000080 00211 limit_0 equ 0x80 ; Least significant byte 00212 ; MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 5 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00213 ; Default contains the default startup frequency as a 32 bit integer. 00214 ; 00000000 00215 default_3 equ 0x00 ; Most significant byte for 14.025 MHz 000000D6 00216 default_2 equ 0xD6 ; Next byte 00000001 00217 default_1 equ 0x01 ; Next byte 00000028 00218 default_0 equ 0x28 ; Least significant byte 00219 ; 00000028 00220 band_end equ 0x28 ; The offset to the last band table entry 00221 ; 00222 ; **************************************************************************** 00223 ; * Port and EEPROM Constants * 00224 ; **************************************************************************** 00225 ; 00000005 00226 PortA equ 0x05 00000006 00227 PortB equ 0x06 00000005 00228 TRISA equ 0x05 00000006 00229 TRISB equ 0x06 00000008 00230 EEdata equ 0x08 00000009 00231 EEadr equ 0x09 00000002 00232 WREN equ 0x02 00000001 00233 WR equ 0x01 00000000 00234 RD equ 0x00 00235 ; 00236 ; **************************************************************************** 00237 ; * ID location information: * 00238 ; * (MPASM warns about DW here, don't worry) * 00239 ; **************************************************************************** 00240 ; 2000 00241 ORG 0x2000 Warning[220]: Address exceeds maximum range for this processor. 2000 007F 00242 DATA 0x007F Warning[220]: Address exceeds maximum range for this processor. 2001 007F 00243 DATA 0x007F Warning[220]: Address exceeds maximum range for this processor. 2002 007F 00244 DATA 0x007F Warning[220]: Address exceeds maximum range for this processor. 2003 007F 00245 DATA 0x007F 00246 ; 00247 ; 00248 ; **************************************************************************** 00249 ; * Setup the initial constant, based on the frequency of the reference * 00250 ; * oscillator. This can be tweaked with the calibrate function. * 00251 ; **************************************************************************** 00252 ; 2100 00253 ORG 0x2100 2100 00C4 00254 DATA ref_osc_0 2101 001D 00255 DATA ref_osc_1 2102 00F3 00256 DATA ref_osc_2 2103 002A 00257 DATA ref_osc_3 00258 ; 00259 ; Clear unused EEPROM bytes. 00260 ; 2104 0000 0000 0000 00261 DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 6 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 2122 0000 0000 0000 00262 DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 00263 ; 00264 ; **************************************************************************** 00265 ; * RAM page independent file registers: * 00266 ; **************************************************************************** 00267 ; 00000000 00268 INDF EQU 0x00 00000002 00269 PCL EQU 0x02 00000003 00270 STATUS EQU 0x03 00000004 00271 FSR EQU 0x04 0000000A 00272 PCLATH EQU 0x0A 0000000B 00273 INTCON EQU 0x0B 00274 ; 00275 ; ***************************************************************************** 00276 ; * Bit numbers for the STATUS file register: * 00277 ; ***************************************************************************** 00278 ; 00000005 00279 B_RP0 EQU 5 00000004 00280 B_NTO EQU 4 00000003 00281 B_NPD EQU 3 00000002 00282 B_Z EQU 2 00000001 00283 B_DC EQU 1 00000000 00284 B_C EQU 0 00285 ; 00286 ; **************************************************************************** 00287 ; * Assign names to IO pins. * 00288 ; **************************************************************************** 00289 ; 00290 ; B register bits: 00291 ; 00000000 00292 DDS_load equ 0x00 ; Update pin on AD9850 00000001 00293 LCD_rs equ 0x01 ; 0=instruction, 1=data 00000002 00294 LCD_rw equ 0x02 ; 0=write, 1=read 00000003 00295 LCD_e equ 0x03 ; 0=disable, 1=enable 00000005 00296 DDS_clk equ 0x05 ; AD9850 write clock MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 7 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00000007 00297 DDS_dat equ 0x07 ; AD9850 serial data input 00298 ; 00299 ; A register bits: 00300 ; 00000003 00301 pb_switch equ 0x03 ; Calibrate Push Button, (active low) 00302 ; 00303 ; **************************************************************************** 00304 ; * Allocate variables in general purpose register space * 00305 ; **************************************************************************** 00306 ; 00307 CBLOCK 0x0c ; Start Data Block 00308 ; 0000000C 00309 freq_0 ; Display frequency (hex) 0000000D 00310 freq_1 ; (4 bytes) 0000000E 00311 freq_2 0000000F 00312 freq_3 00000010 00313 BCD_0 ; Display frequency (BCD) 00000011 00314 BCD_1 ; (5 bytes) 00000012 00315 BCD_2 00000013 00316 BCD_3 00000014 00317 BCD_4 00000015 00318 AD9850_0 ; AD9850 control word 00000016 00319 AD9850_1 ; (5 bytes) 00000017 00320 AD9850_2 00000018 00321 AD9850_3 00000019 00322 AD9850_4 0000001A 00323 fstep_0 ; Frequency inc/dec 0000001B 00324 fstep_1 ; (4 bytes) 0000001C 00325 fstep_2 0000001D 00326 fstep_3 0000001E 00327 BCD_count ; Used in bin2BCD routine 0000001F 00328 BCD_temp ; " 00000020 00329 mult_count ; Used in calc_dds_word 00000021 00330 bit_count ; " 00000022 00331 byte2send ; 00000023 00332 osc_0 ; Current oscillator 00000024 00333 osc_1 ; (4 bytes) 00000025 00334 osc_2 00000026 00335 osc_3 00000027 00336 osc_temp_0 ; Oscillator frequency 00000028 00337 osc_temp_1 ; (4 bytes) 00000029 00338 osc_temp_2 0000002A 00339 osc_temp_3 0000002B 00340 LCD_char ; Character being sent to the LCD 0000002C 00341 LCD_read ; Character read from the LCD 0000002D 00342 timer1 ; Used in delay routines 0000002E 00343 timer2 ; " 0000002F 00344 ren_timer_0 ; For variable rate tuning 00000030 00345 ren_timer_1 ; (2 bytes) 00000031 00346 ren_new ; New value of encoder pins A and B 00000032 00347 ren_old ; Old value of encoder pins A and B 00000033 00348 ren_read ; Encoder pins A and B and switch pin 00000034 00349 last_dir ; Indicates last direction of encoder MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 8 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00000035 00350 next_dir ; Indicates expected direction 00000036 00351 count ; loop counter (gets reused) 00000037 00352 band ; Used to index a table of frequencies 00000038 00353 rs_value ; The LCD rs line flag value 00354 ; 00355 ENDC ; End of Data Block 00356 ; 00357 ; **************************************************************************** 00358 ; * The 16F84 resets to 0x00. * 00359 ; * The Interrupt vector is at 0x04. (Unused) * 00360 ; **************************************************************************** 00361 ; 0000 00362 ORG 0x0000 0000 00363 reset_entry 0000 282E 00364 goto start ; Jump around the band table to main program 00365 ; 00366 ; **************************************************************************** 00367 ; * This is the band table. Each entry is four instructions long, with each * 00368 ; * group of four literals representing the frequency as a 32 bit integer. * 00369 ; * New entries can be added to the end of the table or between existing * 00370 ; * entries. The constant band_end must be incremented by 4 for each entry * 00371 ; * added. * 00372 ; * * 00373 ; * This table is placed near the top of the program to allow as large a * 00374 ; * a table as possible to be indexed with the eight bit value in W. * 00375 ; * * 00376 ; **************************************************************************** 00377 ; 0001 00378 band_table 0001 0782 00379 addwf PCL,f ; 0002 3400 00380 retlw 0x00 ; 0 Hz 0003 3400 00381 retlw 0x00 ; 0004 3400 00382 retlw 0x00 ; 0005 3400 00383 retlw 0x00 ; 0006 3400 00384 retlw 0x00 ; 160 meters 0007 341B 00385 retlw 0x1B ; 0008 3477 00386 retlw 0x77 ; 0009 3440 00387 retlw 0x40 ; 000A 3400 00388 retlw 0x00 ; 80 meters 000B 3435 00389 retlw 0x35 ; 000C 3467 00390 retlw 0x67 ; 000D 34E0 00391 retlw 0xE0 ; 000E 3400 00392 retlw 0x00 ; 40 meters 000F 346A 00393 retlw 0x6A ; 0010 34CF 00394 retlw 0xCF ; 0011 34C0 00395 retlw 0xC0 ; 0012 3400 00396 retlw 0x00 ; 30 meters 0013 349A 00397 retlw 0x9A ; 0014 341D 00398 retlw 0x1D ; 0015 3420 00399 retlw 0x20 ; 0016 3400 00400 retlw 0x00 ; 20 meters 0017 34D5 00401 retlw 0xD5 ; 0018 349F 00402 retlw 0x9F ; MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 9 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0019 3480 00403 retlw 0x80 ; 001A 3401 00404 retlw 0x01 ; 17 meters 001B 3413 00405 retlw 0x13 ; 001C 34B2 00406 retlw 0xB2 ; 001D 3420 00407 retlw 0x20 ; 001E 3401 00408 retlw 0x01 ; 15 meters 001F 3440 00409 retlw 0x40 ; 0020 346F 00410 retlw 0x6F ; 0021 3440 00411 retlw 0x40 ; 0022 3401 00412 retlw 0x01 ; 12 meters 0023 347B 00413 retlw 0x7B ; 0024 34CA 00414 retlw 0xCA ; 0025 3490 00415 retlw 0x90 ; 0026 3401 00416 retlw 0x01 ; 10 meters 0027 34AB 00417 retlw 0xAB ; 0028 343F 00418 retlw 0x3F ; 0029 3400 00419 retlw 0x00 ; 002A 3401 00420 retlw 0x01 ; 30 MHz 002B 34C9 00421 retlw 0xC9 ; 002C 34C3 00422 retlw 0xC3 ; 002D 3480 00423 retlw 0x80 ; 00424 ; 00425 ; ***************************************************************************** 00426 ; * * 00427 ; * Purpose: This is the start of the program. It initializes the LCD and * 00428 ; * detects whether to enter calibrate mode. If so, it calls the * 00429 ; * Calibrate routine. Otherwise, it sets the power-on frequency * 00430 ; * and enters the loop to poll the encoder. * 00431 ; * * 00432 ; * Input: The start up frequency is defined in the default_3 ... * 00433 ; * definitions above, and relies on the reference oscillator * 00434 ; * constant defined in ref_osc_3 ... ref_osc_0. * 00435 ; * * 00436 ; * Output: Normal VFO operation. * 00437 ; * * 00438 ; ***************************************************************************** 00439 ; 002E 00440 start 002E 018B 00441 clrf INTCON ; No interrupts for now 002F 1683 00442 bsf STATUS,B_RP0 ; Switch to bank 1 0030 1781 00443 bsf 0x01,7 ; Disable weak pullups 0031 30FF 00444 movlw 0xFF ; Tristate port A 0032 0085 00445 movwf TRISA ; 0033 0186 00446 clrf TRISB ; Set port B to all outputs 0034 1283 00447 bcf STATUS,B_RP0 ; Switch back to bank 0 0035 20A5 00448 call init_LCD ; Initialize the LCD 00449 ; 00450 ; Enter Calibrate Mode if push button is pressed while turning the 00451 ; power on. 00452 ; 0036 1985 00453 btfsc PortA,pb_switch ; Is the switch pressed? 0037 2839 00454 goto read_EEocs ; No, get clock freq from EEPROM 0038 213F 00455 call calibrate ; Yes, calibrate MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 10 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00456 ; 00457 ; Get the reference oscillator constant from the EEPROM. 00458 ; 0039 00459 read_EEocs 0039 0189 00460 clrf EEadr ; Reset the EEPROM read address 003A 2299 00461 call read_EEPROM ; Read EEPROM 003B 0808 00462 movf EEdata,w ; Get the first osc byte 003C 00A3 00463 movwf osc_0 ; Save osc frequency 003D 2299 00464 call read_EEPROM ; Get next byte 003E 0808 00465 movf EEdata,w ; 003F 00A4 00466 movwf osc_1 ; Save it 0040 2299 00467 call read_EEPROM ; Get the third byte 0041 0808 00468 movf EEdata,w ; 0042 00A5 00469 movwf osc_2 ; Save it 0043 2299 00470 call read_EEPROM ; Get the fourth byte 0044 0808 00471 movf EEdata,w ; 0045 00A6 00472 movwf osc_3 ; Save it 00473 ; 00474 ; Set the power on frequency to the defined value. 00475 ; 0046 3028 00476 movlw default_0 ; Get the least significant byte 0047 008C 00477 movwf freq_0 ; Save it 0048 3001 00478 movlw default_1 ; Get the next byte 0049 008D 00479 movwf freq_1 ; Save it 004A 30D6 00480 movlw default_2 ; And the next 004B 008E 00481 movwf freq_2 ; Save it 004C 3000 00482 movlw default_3 ; Get the most significant byte 004D 008F 00483 movwf freq_3 ; Save it 00484 ; 00485 ; Display the power on frequency. 00486 ; 004E 21F3 00487 call bin2BCD ; Convert it to BCD 004F 2221 00488 call show_freq ; Display it 00489 ; 00490 ; Send power on frequency to the DDS chip. 00491 ; 0050 21A3 00492 call calc_dds_word ; Convert to delta value 0051 21D9 00493 call send_dds_word ; Send the power-on frequency to the 00494 ; AD9850 in serial mode 00495 ; 00496 ; Get the power on encoder value. 00497 ; 0052 0805 00498 movf PortA,w ; Read port A 0053 00B3 00499 movwf ren_read ; Save it in ren_read 0054 3003 00500 movlw 0x03 ; Get encoder mask 0055 0533 00501 andwf ren_read,w ; Get encoder bits 0056 00B2 00502 movwf ren_old ; Save in ren_old 00503 ; 00504 ; Initialize variables. 00505 ; 0057 01B0 00506 clrf ren_timer_1 ; Initialize the encoder speed timer 0058 3040 00507 movlw 0x40 ; to 0059 00AF 00508 movwf ren_timer_0 ; 0x0040 MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 11 LOC OBJECT CODE LINE SOURCE TEXT VALUE 005A 01B4 00509 clrf last_dir ; Clear the knob direction indicator 005B 01B7 00510 clrf band ; Clear the band indicator 00511 ; 00512 ; Fall into the Main Program Loop 00513 ; 00514 ; ***************************************************************************** 00515 ; * * 00516 ; * Purpose: This is the Main Program Loop. The program's main loop * 00517 ; * calls poll_encoder, which continuously polls the rotary shaft * 00518 ; * encoder. When the shaft encoder has changed, the direction * 00519 ; * it moved is determined and stored in last_dir. The subroutine * 00520 ; * then returns to main. * 00521 ; * * 00522 ; * If the push button switch was not pressed, then the variable * 00523 ; * fstep is calculated based on the delay between shaft encoder * 00524 ; * changes. ren_timer contains the delay value determined by * 00525 ; * the poll_encoder subroutine. The variable fstep is added or * 00526 ; * subtracted from the current VFO frequency stored in freq. * 00527 ; * The contents of freq are then converted to a BCD number in * 00528 ; * subroutine bin2BCD. The subroutine show_freq is then called * 00529 ; * to display the result on the Liquid Crystal Display. Next, the * 00530 ; * subroutine calc_dds_word is used to calculate the DDS * 00531 ; * frequency control word from the values in freq and osc. * 00532 ; * The result is stored in AD9850. This data is transferred to * 00533 ; * the AD9850 DDS chip by calling the subroutine send_dds_word. * 00534 ; * * 00535 ; * If the push button is pressed while turning the encoder then * 00536 ; * freq is loaded with a constant stored in band_table. The * 00537 ; * variable band is used as an index into the table. Band * 00538 ; * is incremented or decremented based on the encoder direction. * 00539 ; * * 00540 ; * Input: None. * 00541 ; * * 00542 ; * Output: None. * 00543 ; * * 00544 ; ***************************************************************************** 00545 ; 005C 00546 main 005C 2115 00547 call poll_encoder ; Check for knob movement 005D 1DB3 00548 btfss ren_read,3 ; Change band? 005E 287B 00549 goto change_band ; Yes, change band 00550 ; 00551 ; Determine step size to use (1 Hz or 1 kHz). 00552 ; 005F 019D 00553 clrf fstep_3 ; Guess that we want 1 Hz steps by 0060 019C 00554 clrf fstep_2 ; setting fstep to one. 0061 019B 00555 clrf fstep_1 ; 0062 3001 00556 movlw 0x01 ; 0063 009A 00557 movwf fstep_0 ; 0064 1933 00558 btfsc ren_read,2 ; Is the encoder switch pressed? 0065 2870 00559 goto go_step ; No, use the 1 Hz step 0066 30E8 00560 movlw 0xE8 ; Yes, set the step value to 1 kHz 0067 009A 00561 movwf fstep_0 ; by setting fstep_0 to 0xE8 and MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 12 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0068 3003 00562 movlw 0x03 ; fstep_1 to 0x03 0069 009B 00563 movwf fstep_1 ; 006A 2870 00564 goto go_step ; Use the 1 kHz step 00565 ; 00566 ; Adjust the tuning step based on ren_timer. ren_timer is incremented 00567 ; by 8 from its initial value of 0x0040 each time the poll_encoder finds 00568 ; no change in the encoder input, until the high bit of ren_timer_1 00569 ; becomes a one. The default fstep of 1 Hz is multiplied by two for 00570 ; each leading zero in ren_timer, up to a maximum of 9 times. (This is 00571 ; because ren_timer starts at 0x0040, only the first nine bits can be 00572 ; zero in a row). The faster the knob is turned, the lower the number 00573 ; in ren_timer will be, and the larger the step value will be. 00574 ; 00575 ; 006B 00576 bump_step 006B 1003 00577 bcf STATUS,B_C ; Clear the carry flag 006C 0D9A 00578 rlf fstep_0,f ; Multiply the step by 2 by rotating left 006D 0D9B 00579 rlf fstep_1,f ; 006E 0D9C 00580 rlf fstep_2,f ; 006F 0D9D 00581 rlf fstep_3,f ; 0070 00582 go_step 0070 0DAF 00583 rlf ren_timer_0,f ; Multiply the encoder timer by 2 0071 0DB0 00584 rlf ren_timer_1,f ; 0072 1C03 00585 btfss STATUS,B_C ; Has a one floated to the carry yet? 0073 286B 00586 goto bump_step ; No, then double the step size 00587 ; 00588 ; Based on the knob direction, either add or subtract the increment, 00589 ; then update the LCD and DDS. 00590 ; 0074 18B4 00591 btfsc last_dir,1 ; Is the knob going up? 0075 2878 00592 goto up ; Yes, then add the increment 0076 00593 down 0076 2102 00594 call sub_step ; Subtract fstep from freq 0077 288E 00595 goto write ; Update LCD and DDS 0078 00596 up 0078 20C5 00597 call add_step ; Add fstep to freq 0079 20DD 00598 call check_add ; Make sure we did not exceed the maximum 007A 288E 00599 goto write ; Update LCD and DDS 00600 ; 00601 ; ***************************************************************************** 00602 ; * * 00603 ; * Purpose: This routine increments through the band table each time the * 00604 ; * knob moves a notch, updating the LCD and DDS, until the band * 00605 ; * button is no longer pushed. * 00606 ; * * 00607 ; * Input: The value of the band push button and the encoder bits * 00608 ; * * 00609 ; * Output: Updated freq value, and new frequency on the LCD and DDS. * 00610 ; * * 00611 ; ***************************************************************************** 00612 ; 007B 00613 change_band 007B 18B4 00614 btfsc last_dir,1 ; Are we going up in the band list? MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 13 LOC OBJECT CODE LINE SOURCE TEXT VALUE 007C 2887 00615 goto band_up ; Yes, increment band address 007D 3004 00616 movlw 0x04 ; No, get 4 bytes to subtract 007E 02B7 00617 subwf band,f ; Move down in band list 007F 30D7 00618 movlw 0xFF-band_end ; Check to see if we have fallen off the 0080 0737 00619 addwf band,w ; bottom of the table. 0081 1C03 00620 btfss STATUS,B_C ; Off the bottom? 0082 2885 00621 goto valid ; No, continue 0083 3028 00622 movlw band_end ; Yes, go to highest entry 0084 00B7 00623 movwf band ; 0085 00624 valid 0085 2093 00625 call get_band ; Get the new band frequency 0086 288E 00626 goto write ; Set the frequency and continue 0087 00627 band_up 0087 3004 00628 movlw 0x04 ; Table entries are 4 bytes apart 0088 07B7 00629 addwf band,f ; Increment the band pointer 0089 30D7 00630 movlw 0xFF-band_end ; Check to see if we have gone over the 008A 0737 00631 addwf band,w ; top of the table. 008B 1803 00632 btfsc STATUS,B_C ; Did we go over the top of the table? 008C 01B7 00633 clrf band ; Yes, go to the bottom entry 008D 2093 00634 call get_band ; Get the new band frequency 008E 00635 write 008E 21F3 00636 call bin2BCD ; Convert the frequency to BCD 008F 2221 00637 call show_freq ; Display the frequency on the LCD 0090 21A3 00638 call calc_dds_word ; Find the control word for the DDS chip 0091 21D9 00639 call send_dds_word ; Send the control word to the DDS chip 0092 285C 00640 goto main ; Continue polling the encoder (endless loop) 00641 ; 00642 ; ***************************************************************************** 00643 ; * * 00644 ; * Purpose: This routine reads the frequency value of a band table entry * 00645 ; * pointed to by band and returns it in freq_3...freq_0. * 00646 ; * * 00647 ; * Input: band must contain the index of the desired band entry * 4 * 00648 ; * (with the entries numbered from zero). * 00649 ; * * 00650 ; * Output: The band frequency in freq. * 00651 ; * * 00652 ; ***************************************************************************** 00653 ; 0093 00654 get_band 0093 0837 00655 movf band,w ; Get the index of the high byte 0094 2001 00656 call band_table ; Get the value into W 0095 008F 00657 movwf freq_3 ; Save it in freq_3 0096 0AB7 00658 incf band,f ; Increment index to next byte 0097 0837 00659 movf band,w ; Get the index of the next byte 0098 2001 00660 call band_table ; Get the value into W 0099 008E 00661 movwf freq_2 ; Save it in freq_2 009A 0AB7 00662 incf band,f ; Increment index to the next byte 009B 0837 00663 movf band,w ; Get the index to the next byte 009C 2001 00664 call band_table ; Get the value into W 009D 008D 00665 movwf freq_1 ; Save it in freq_1 009E 0AB7 00666 incf band,f ; Increment index to the low byte 009F 0837 00667 movf band,w ; Get the index to the low byte MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 14 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00A0 2001 00668 call band_table ; Get the value into W 00A1 008C 00669 movwf freq_0 ; Save it in freq_0 00A2 3003 00670 movlw 0x03 ; Get a constant three 00A3 02B7 00671 subwf band,f ; Restore original value of band 00A4 0008 00672 return ; Return to the caller 00673 ; 00674 ; ***************************************************************************** 00675 ; * * 00676 ; * Purpose: Power on initialization of Liquid Crystal Display. The LCD * 00677 ; * controller chip must be equivalent to an Hitachi 44780. The * 00678 ; * LCD is assumed to be a 16 X 1 display. * 00679 ; * * 00680 ; * Input: None * 00681 ; * * 00682 ; * Output: None * 00683 ; * * 00684 ; ***************************************************************************** 00685 ; 00A5 00686 init_LCD 00A5 22A1 00687 call wait_64ms ; Wait for LCD to power up 00A6 3030 00688 movlw 0x30 ; LCD init instruction (First) 00A7 0086 00689 movwf PortB ; Send to LCD via RB7..RB0 00A8 1586 00690 bsf PortB,LCD_e ; Set the LCD E line high, 00A9 22A1 00691 call wait_64ms ; wait a "long" time, 00AA 1186 00692 bcf PortB,LCD_e ; and then Clear E 00AB 3030 00693 movlw 0x30 ; LCD init instruction (Second) 00AC 0086 00694 movwf PortB ; Send to LCD via RB7..RB0 00AD 1586 00695 bsf PortB,LCD_e ; Set E high, 00AE 22A4 00696 call wait_32ms ; wait a while, 00AF 1186 00697 bcf PortB,LCD_e ; and then Clear E 00B0 3030 00698 movlw 0x30 ; LCD init instruction (Third) 00B1 0086 00699 movwf PortB ; Send to LCD via RB7..RB0 00B2 1586 00700 bsf PortB,LCD_e ; Set E high, 00B3 22A4 00701 call wait_32ms ; wait a while, 00B4 1186 00702 bcf PortB,LCD_e ; and then Clear E 00B5 3020 00703 movlw 0x20 ; 4-bit mode instruction 00B6 0086 00704 movwf PortB ; Send to LCD via RB7..RB0 00B7 1586 00705 bsf PortB,LCD_e ; Set E high, 00B8 22A7 00706 call wait_16ms ; wait a while, 00B9 1186 00707 bcf PortB,LCD_e ; and then Clear E 00BA 3028 00708 movlw 0x28 ; 1/16 duty cycle, 5x8 matrix 00BB 226A 00709 call cmnd2LCD ; Send command in w to LCD 00BC 3008 00710 movlw 0x08 ; Display off, cursor and blink off 00BD 226A 00711 call cmnd2LCD ; Send command to LCD 00BE 3001 00712 movlw 0x01 ; Clear and reset cursor 00BF 226A 00713 call cmnd2LCD ; Send command in w to LCD 00C0 3006 00714 movlw 0x06 ; Set cursor to move right, no shift 00C1 226A 00715 call cmnd2LCD ; Send command in w to LCD 00C2 300C 00716 movlw 0x0C ; Display on, cursor and blink off 00C3 226A 00717 call cmnd2LCD ; Send command in w to LCD 00C4 0008 00718 return ; 00719 ; 00720 ; ***************************************************************************** MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 15 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00721 ; * * 00722 ; * Purpose: This routine adds the 32 bit value of fstep to the 32 bit * 00723 ; * value in freq. When incrementing, the fstep value is a * 00724 ; * positive integer. When decrementing, fstep is the complement * 00725 ; * of the value being subtracted. * 00726 ; * * 00727 ; * Input: The 32 bit values in fstep and freq * 00728 ; * * 00729 ; * Output: The sum of fstep and freq is stored in freq. When incrementing * 00730 ; * this value may exceed the maximum. When decrementing, it may * 00731 ; * go negative. * 00732 ; * * 00733 ; ***************************************************************************** 00C5 00734 add_step 00C5 081A 00735 movf fstep_0,w ; Get low byte of the increment 00C6 078C 00736 addwf freq_0,f ; Add it to the low byte of freq 00C7 1C03 00737 btfss STATUS,B_C ; Any carry? 00C8 28CE 00738 goto add1 ; No, add next byte 00C9 0F8D 00739 incfsz freq_1,f ; Ripple carry up to the next byte 00CA 28CE 00740 goto add1 ; No new carry, add next byte 00CB 0F8E 00741 incfsz freq_2,f ; Ripple carry up to the next byte 00CC 28CE 00742 goto add1 ; No new carry, add next byte 00CD 0A8F 00743 incf freq_3,f ; Ripple carry up to the highest byte 00CE 00744 add1 00CE 081B 00745 movf fstep_1,w ; Get the next increment byte 00CF 078D 00746 addwf freq_1,f ; Add it to the next higher byte 00D0 1C03 00747 btfss STATUS,B_C ; Any carry? 00D1 28D5 00748 goto add2 ; No, add next byte 00D2 0F8E 00749 incfsz freq_2,f ; Ripple carry up to the next byte 00D3 28D5 00750 goto add2 ; No new carry, add next byte 00D4 0A8F 00751 incf freq_3,f ; Ripple carry up to the highest byte 00D5 00752 add2 00D5 081C 00753 movf fstep_2,w ; Get the next to most significant increment 00D6 078E 00754 addwf freq_2,f ; Add it to the freq byte 00D7 1C03 00755 btfss STATUS,B_C ; Any carry? 00D8 28DA 00756 goto add3 ; No, add last byte 00D9 0A8F 00757 incf freq_3,f ; Ripple carry up to the highest byte 00DA 00758 add3 00DA 081D 00759 movf fstep_3,w ; Get the most significant increment byte 00DB 078F 00760 addwf freq_3,f ; Add it to the most significant freq 00DC 0008 00761 return ; Return to the caller 00762 ; 00763 ; ***************************************************************************** 00764 ; * * 00765 ; * Purpose: Check if freq exceeds the upper limit. * 00766 ; * * 00767 ; * Input: The 32 bit values in freq * 00768 ; * * 00769 ; * Output: If freq is below the limit, it is unchanged. Otherwise, it is * 00770 ; * set to equal the upper limit. * 00771 ; * * 00772 ; ***************************************************************************** 00773 ; MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 16 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00DD 00774 check_add 00775 ; 00776 ; Check the most significant byte. 00777 ; 00DD 30FE 00778 movlw 0xFF-limit_3 ; Get (FF - limit of high byte) 00DE 070F 00779 addwf freq_3,w ; Add it to the current high byte 00DF 1803 00780 btfsc STATUS,B_C ; Was high byte too large? 00E0 28F9 00781 goto set_max ; Yes, apply limit 00E1 3001 00782 movlw limit_3 ; Get high limit value 00E2 020F 00783 subwf freq_3,w ; Subtract the limit value 00E3 1C03 00784 btfss STATUS,B_C ; Are we at the limit for the byte? 00E4 2901 00785 goto exit1 ; No, below. Checks are done. 00786 ; 00787 ; Check the second most significant byte. 00788 ; 00E5 3036 00789 movlw 0xFF-limit_2 ; Get (FF - limit of next byte) 00E6 070E 00790 addwf freq_2,w ; Add it to the current byte 00E7 1803 00791 btfsc STATUS,B_C ; Is the current value too high? 00E8 28F9 00792 goto set_max ; Yes, apply the limit 00E9 30C9 00793 movlw limit_2 ; Second limit byte 00EA 020E 00794 subwf freq_2,w ; Subtract limit value 00EB 1C03 00795 btfss STATUS,B_C ; Are we at the limit for the byte? 00EC 2901 00796 goto exit1 ; No, below. Checks are done. 00797 ; 00798 ; Check the third most significant byte. 00799 ; 00ED 303C 00800 movlw 0xFF-limit_1 ; Get (FF - limit of next byte) 00EE 070D 00801 addwf freq_1,w ; Add it to the current byte 00EF 1803 00802 btfsc STATUS,B_C ; Is the current value too high? 00F0 28F9 00803 goto set_max ; Yes, apply the limit 00F1 30C3 00804 movlw limit_1 ; Third limit byte 00F2 020D 00805 subwf freq_1,w ; Subtract limit value 00F3 1C03 00806 btfss STATUS,B_C ; Are we at the limit for the byte? 00F4 2901 00807 goto exit1 ; No, below. Checks are done. 00808 ; 00809 ; Check the least significant byte. 00810 ; 00F5 3080 00811 movlw limit_0 ; Fourth limit byte 00F6 020C 00812 subwf freq_0,w ; Subtract limit value 00F7 1C03 00813 btfss STATUS,B_C ; Are we at the limit for the byte? 00F8 2901 00814 goto exit1 ; No, below. Checks are done. 00F9 00815 set_max 00F9 3080 00816 movlw limit_0 ; Get least significant limit 00FA 008C 00817 movwf freq_0 ; Set it in freq 00FB 30C3 00818 movlw limit_1 ; Get the next byte limit 00FC 008D 00819 movwf freq_1 ; Set it in freq_1 00FD 30C9 00820 movlw limit_2 ; Get the next byte limit 00FE 008E 00821 movwf freq_2 ; Set it in freq_2 00FF 3001 00822 movlw limit_3 ; Get the most significant limit 0100 008F 00823 movwf freq_3 ; Set it in freq_3 0101 00824 exit1 0101 0008 00825 return ; Return to the caller 00826 ; MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 17 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00827 ; ***************************************************************************** 00828 ; * * 00829 ; * Purpose: Subtract the increment step from freq, checking that it does * 00830 ; * not go below zero. * 00831 ; * * 00832 ; * Input: The values in fstep and freq. * 00833 ; * * 00834 ; * Output: The updated value in freq. * 00835 ; * * 00836 ; ***************************************************************************** 00837 ; 0102 00838 sub_step 0102 099A 00839 comf fstep_0,f ; Subtraction of fstep from 0103 099B 00840 comf fstep_1,f ; freq is done by adding the 0104 099C 00841 comf fstep_2,f ; twos compliment of fstep to 0105 099D 00842 comf fstep_3,f ; freq. 0106 0F9A 00843 incfsz fstep_0,f ; Increment last byte 0107 290D 00844 goto comp_done ; Non-zero, continue 0108 0F9B 00845 incfsz fstep_1,f ; Increment next byte 0109 290D 00846 goto comp_done ; Non-zero, continue 010A 0F9C 00847 incfsz fstep_2,f ; Increment next byte 010B 290D 00848 goto comp_done ; Non-zero, continue 010C 0A9D 00849 incf fstep_3,f ; Increment the high byte 010D 00850 comp_done 010D 20C5 00851 call add_step ; Add the compliment to do the subtraction 00852 ; 00853 ; If the frequency has gone negative, clear it to zero. 00854 ; 010E 1F8F 00855 btfss freq_3,7 ; Is high order frequency byte "negative"? 010F 2914 00856 goto exit2 ; No, keep going 0110 00857 set_min 0110 018C 00858 clrf freq_0 ; Yes, set the frequency to zero 0111 018D 00859 clrf freq_1 ; 0112 018E 00860 clrf freq_2 ; 0113 018F 00861 clrf freq_3 ; 0114 00862 exit2 0114 0008 00863 return ; Return to the caller 00864 ; 00865 ; ***************************************************************************** 00866 ; * * 00867 ; * Purpose: This routine does the following: * 00868 ; * 1. Records how long it took for the knob to move a notch * 00869 ; * in ren_timer. * 00870 ; * 2. Clears the watchdog timer. * 00871 ; * 3. Reads the encoder bits until a change is detected, then * 00872 ; * determines the direction the knob was moved. * 00873 ; * * 00874 ; * Input: Knob input read from port A * 00875 ; * ren_old -> the last encoder bits read * 00876 ; * last_dir -> the last direction moved * 00877 ; * * 00878 ; * Output: ren_timer -> an indication the speed of the knob. * 00879 ; * ren_new -> the current encoder bits * MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 18 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00880 ; * last_dir -> the last direction (0 = down, 2 = up) * 00881 ; * * 00882 ; ***************************************************************************** 00883 ; 0115 00884 poll_encoder 0115 01B0 00885 clrf ren_timer_1 ; Put starting values in ren_timer 0116 3040 00886 movlw 0x40 ; Start with the high bit set in ren_timer 0117 00AF 00887 movwf ren_timer_0 ; 0118 00888 read_encoder 0118 0064 00889 clrwdt ; Reset the watchdog timer 0119 1BB0 00890 btfsc ren_timer_1,7 ; Has the bit floated to bottom of ren_timer? 011A 291F 00891 goto no_inc ; Yes, don't move it any further 011B 3008 00892 movlw 0x08 ; 011C 07AF 00893 addwf ren_timer_0,f ; 011D 1803 00894 btfsc STATUS,B_C ; Did the add force a carry? 011E 0AB0 00895 incf ren_timer_1,f ; Yes, then add one to ren_timer_1 011F 00896 no_inc ; 011F 0805 00897 movf PortA,w ; Get the current encoder value 0120 00B3 00898 movwf ren_read ; Save it 0121 3003 00899 movlw 0x03 ; Get encoder mask 0122 0533 00900 andwf ren_read,w ; Isolate encoder bits 0123 00B1 00901 movwf ren_new ; Save new value 0124 0632 00902 xorwf ren_old,w ; Has it changed? 0125 1903 00903 btfsc STATUS,B_Z ; 0126 2918 00904 goto read_encoder ; No, keep looking until it changes 00905 ; 00906 ; Determine which direction the encoder turned. 00907 ; 0127 1003 00908 bcf STATUS,B_C ; Clear the carry bit 0128 0DB2 00909 rlf ren_old,f ; 0129 0831 00910 movf ren_new,w ; 012A 06B2 00911 xorwf ren_old,f ; 012B 0832 00912 movf ren_old,w ; 012C 3902 00913 andlw 0x02 ; 012D 00B5 00914 movwf next_dir ; 012E 0634 00915 xorwf last_dir,w ; 00916 ; 00917 ; Prevent encoder slip from giving a false change in direction. 00918 ; 012F 1903 00919 btfsc STATUS,B_Z ; Zero? 0130 2936 00920 goto pe_continue ; No slip; keep going 0131 0835 00921 movf next_dir,w ; Yes, update direction 0132 00B4 00922 movwf last_dir ; 0133 0831 00923 movf ren_new,w ; Save the current encoder bits for next time 0134 00B2 00924 movwf ren_old ; 0135 2918 00925 goto read_encoder ; Try again 0136 00926 pe_continue 0136 18B2 00927 btfsc ren_old,1 ; Are we going down? 0137 293A 00928 goto up2 ; No, indicate we are going up 0138 01B4 00929 clrf last_dir ; Yes, clear last_dir 0139 293C 00930 goto exit3 ; Finish and return 013A 00931 up2 013A 3002 00932 movlw 0x02 ; Set UP value in last_dir MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 19 LOC OBJECT CODE LINE SOURCE TEXT VALUE 013B 00B4 00933 movwf last_dir ; 013C 00934 exit3 013C 0831 00935 movf ren_new,w ; Get the current encoder bits 013D 00B2 00936 movwf ren_old ; Save them in ren_old for the next time 013E 0008 00937 return ; Return to the caller 00938 ; 00939 ; ***************************************************************************** 00940 ; * * 00941 ; * Purpose: This routine is entered at start up if the push button is * 00942 ; * pressed. "10,000.00 CAL" is displayed on the LCD, and the * 00943 ; * the DDS chip is programmed to produce 10 MHz, based on the * 00944 ; * osc value stored in the EEPROM. As long as the button is * 00945 ; * pressed, the osc value is slowly altered to allow the output * 00946 ; * to be trimmed to exactly 10 MHz. Once the encoder is turned * 00947 ; * after the button is released, the new osc value is stored in * 00948 ; * the EEPROM and normal operation begins. * 00949 ; * * 00950 ; * Input: The original osc constant in EEPROM * 00951 ; * * 00952 ; * Output: The corrected osc constant in EEPROM * 00953 ; * * 00954 ; ***************************************************************************** 00955 ; 013F 00956 calibrate 013F 3080 00957 movlw 0x80 ; Set frequency to 10MHz by 0140 008C 00958 movwf freq_0 ; setting freq to the binary equivalent 0141 3096 00959 movlw 0x96 ; of 10,000,000. 0142 008D 00960 movwf freq_1 ; . 0143 3098 00961 movlw 0x98 ; . 0144 008E 00962 movwf freq_2 ; . 0145 3000 00963 movlw 0x00 ; . 0146 008F 00964 movwf freq_3 ; . 00965 ; 00966 ; Read the starting reference oscillator value form EEPROM. 00967 ; 0147 0189 00968 clrf EEadr ; Reset the EEPROM read address 0148 2299 00969 call read_EEPROM ; Read EEPROM 0149 0808 00970 movf EEdata,w ; Get the first osc byte 014A 00A3 00971 movwf osc_0 ; Save osc frequency 014B 2299 00972 call read_EEPROM ; Get next byte 014C 0808 00973 movf EEdata,w ; 014D 00A4 00974 movwf osc_1 ; Save it 014E 2299 00975 call read_EEPROM ; Get the third byte 014F 0808 00976 movf EEdata,w ; 0150 00A5 00977 movwf osc_2 ; Save it 0151 2299 00978 call read_EEPROM ; Get the fourth byte 0152 0808 00979 movf EEdata,w ; 0153 00A6 00980 movwf osc_3 ; Save it 0154 21F3 00981 call bin2BCD ; Calculate BCD version of 10,000.00 0155 2221 00982 call show_freq ; Display the frequency on the LCD 0156 30C4 00983 movlw 0xC4 ; Point LCD at digit 14 0157 00AB 00984 movwf LCD_char ; 0158 226A 00985 call cmnd2LCD ; MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 20 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0159 3043 00986 movlw 'C' ; Send a C 015A 00AB 00987 movwf LCD_char ; 015B 226E 00988 call data2LCD ; 015C 3041 00989 movlw 'A' ; Send an A 015D 00AB 00990 movwf LCD_char ; 015E 226E 00991 call data2LCD ; 015F 304C 00992 movlw 'L' ; Send an L 0160 00AB 00993 movwf LCD_char ; 0161 226E 00994 call data2LCD ; 0162 00995 cal_loop 0162 21A3 00996 call calc_dds_word ; Calculate DDS value based on current osc 0163 21D9 00997 call send_dds_word ; Update the DDS chip 0164 2115 00998 call poll_encoder ; Wait until the encoder has moved. 0165 019D 00999 clrf fstep_3 ; Clear the three most significant 0166 019C 01000 clrf fstep_2 ; bytes of fstep 0167 019B 01001 clrf fstep_1 ; 0168 3010 01002 movlw 0x10 ; Assume that we are adjusting slowly 0169 009A 01003 movwf fstep_0 ; Use small increment 016A 1933 01004 btfsc ren_read,2 ; Was the encoder changing slowly? 016B 296E 01005 goto update_osc ; Yes, then continue with small increment 016C 3080 01006 movlw 0x80 ; No, then use the large increment 016D 009A 01007 movwf fstep_0 ; 016E 01008 update_osc 016E 0000 01009 nop ; Wait a cycle 016F 18B4 01010 btfsc last_dir,1 ; Are we moving down? 0170 297C 01011 goto faster ; No, increase the osc value 01012 ; 01013 ; slower 01014 ; 0171 099A 01015 comf fstep_0,f ; Subtraction of fstep is done by 0172 099B 01016 comf fstep_1,f ; adding the twos compliment of fsetp 0173 099C 01017 comf fstep_2,f ; to osc 0174 099D 01018 comf fstep_3,f ; 0175 0F9A 01019 incfsz fstep_0,f ; Increment last byte 0176 297C 01020 goto faster ; Non-zero, continue 0177 0F9B 01021 incfsz fstep_1,f ; Increment next byte 0178 297C 01022 goto faster ; Non-zero, continue 0179 0F9C 01023 incfsz fstep_2,f ; Increment next byte 017A 297C 01024 goto faster ; Non-zero, continue 017B 0A9D 01025 incf fstep_3,f ; Increment the high byte 017C 01026 faster 017C 081A 01027 movf fstep_0,w ; Get the low byte increment 017D 07A3 01028 addwf osc_0,f ; Add it to the low osc byte 017E 1C03 01029 btfss STATUS,B_C ; Was there a carry? 017F 2985 01030 goto add4 ; No, add the next bytes 0180 0FA4 01031 incfsz osc_1,f ; Ripple carry up to the next byte 0181 2985 01032 goto add4 ; No new carry, add the next bytes 0182 0FA5 01033 incfsz osc_2,f ; Ripple carry up to the next byte 0183 2985 01034 goto add4 ; No new carry, add the next bytes 0184 0AA6 01035 incf osc_3,f ; Ripple carry up to the highest byte 0185 01036 add4 0185 081B 01037 movf fstep_1,w ; Get the second byte increment 0186 07A4 01038 addwf osc_1,f ; Add it to the second osc byte MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 21 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0187 1C03 01039 btfss STATUS,B_C ; Was there a carry? 0188 298C 01040 goto add5 ; No, add the third bytes 0189 0FA5 01041 incfsz osc_2,f ; Ripple carry up to the next byte 018A 298C 01042 goto add5 ; No new carry, add the third bytes 018B 0AA6 01043 incf osc_3,f ; Ripple carry up to the highest byte 018C 01044 add5 018C 081C 01045 movf fstep_2,w ; Get the third byte increment 018D 07A5 01046 addwf osc_2,f ; Add it to the third osc byte 018E 1C03 01047 btfss STATUS,B_C ; Was there a carry? 018F 2991 01048 goto add6 ; No, add the fourth bytes 0190 0AA6 01049 incf osc_3,f ; Ripple carry up to the highest byte 0191 01050 add6 0191 081D 01051 movf fstep_3,w ; Get the fourth byte increment 0192 07A6 01052 addwf osc_3,f ; Add it to the fourth byte 0193 1DB3 01053 btfss ren_read,3 ; Is the button still pressed? 0194 2962 01054 goto cal_loop ; Yes, stay in calibrate mode 0195 0189 01055 clrf EEadr ; Write final value to EEPROM 0196 0823 01056 movf osc_0,w ; Record the first 0197 0088 01057 movwf EEdata ; osc 0198 228C 01058 call write_EEPROM ; byte 0199 0824 01059 movf osc_1,w ; Record the second 019A 0088 01060 movwf EEdata ; osc 019B 228C 01061 call write_EEPROM ; byte 019C 0825 01062 movf osc_2,w ; Record the third 019D 0088 01063 movwf EEdata ; osc 019E 228C 01064 call write_EEPROM ; byte 019F 0826 01065 movf osc_3,w ; Record the fourth 01A0 0088 01066 movwf EEdata ; osc 01A1 228C 01067 call write_EEPROM ; byte 01A2 0008 01068 return ; Return to the caller 01069 ; 01070 ; ***************************************************************************** 01071 ; * * 01072 ; * Purpose: Multiply the 32 bit number for oscillator frequency times the * 01073 ; * 32 bit number for the displayed frequency. * 01074 ; * * 01075 ; * * 01076 ; * Input: The reference oscillator value in osc_3 ... osc_0 and the * 01077 ; * current frequency stored in freq_3 ... freq_0. The reference * 01078 ; * oscillator value is treated as a fixed point real, with a 24 * 01079 ; * bit mantissa. * 01080 ; * * 01081 ; * Output: The result is stored in AD9850_3 ... AD9850_0. * 01082 ; * * 01083 ; ***************************************************************************** 01084 ; 01A3 01085 calc_dds_word 01A3 0195 01086 clrf AD9850_0 ; Clear the AD9850 control word bytes 01A4 0196 01087 clrf AD9850_1 ; 01A5 0197 01088 clrf AD9850_2 ; 01A6 0198 01089 clrf AD9850_3 ; 01A7 0199 01090 clrf AD9850_4 ; 01A8 3020 01091 movlw 0x20 ; Set count to 32 (4 osc bytes of 8 bits) MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 22 LOC OBJECT CODE LINE SOURCE TEXT VALUE 01A9 00A0 01092 movwf mult_count ; Keep running count 01AA 0823 01093 movf osc_0,w ; Move the four osc bytes 01AB 00A7 01094 movwf osc_temp_0 ; to temporary storage for this multiply 01AC 0824 01095 movf osc_1,w ; (Don't disturb original osc bytes) 01AD 00A8 01096 movwf osc_temp_1 ; 01AE 0825 01097 movf osc_2,w ; 01AF 00A9 01098 movwf osc_temp_2 ; 01B0 0826 01099 movf osc_3,w ; 01B1 00AA 01100 movwf osc_temp_3 ; 01B2 01101 mult_loop 01B2 1003 01102 bcf STATUS,B_C ; Start with Carry clear 01B3 1C27 01103 btfss osc_temp_0,0 ; Is bit 0 (Least Significant bit) set? 01B4 29CC 01104 goto noAdd ; No, don't need to add freq term to total 01B5 080C 01105 movf freq_0,w ; Yes, get the freq_0 term 01B6 0796 01106 addwf AD9850_1,f ; and add it in to total 01B7 1C03 01107 btfss STATUS,B_C ; Does this addition result in a carry? 01B8 29BE 01108 goto add7 ; No, continue with next freq term 01B9 0F97 01109 incfsz AD9850_2,f ; Yes, add one and check for another carry 01BA 29BE 01110 goto add7 ; No, continue with next freq term 01BB 0F98 01111 incfsz AD9850_3,f ; Yes, add one and check for another carry 01BC 29BE 01112 goto add7 ; No, continue with next freq term 01BD 0A99 01113 incf AD9850_4,f ; Yes, add one and continue 01BE 01114 add7 01BE 080D 01115 movf freq_1,w ; Use the freq_1 term 01BF 0797 01116 addwf AD9850_2,f ; Add freq term to total in correct position 01C0 1C03 01117 btfss STATUS,B_C ; Does this addition result in a carry? 01C1 29C5 01118 goto add8 ; No, continue with next freq term 01C2 0F98 01119 incfsz AD9850_3,f ; Yes, add one and check for another carry 01C3 29C5 01120 goto add8 ; No, continue with next freq term 01C4 0A99 01121 incf AD9850_4,f ; Yes, add one and continue 01C5 01122 add8 01C5 080E 01123 movf freq_2,w ; Use the freq_2 term 01C6 0798 01124 addwf AD9850_3,f ; Add freq term to total in correct position 01C7 1C03 01125 btfss STATUS,B_C ; Does this addition result in a carry? 01C8 29CA 01126 goto add9 ; No, continue with next freq term 01C9 0A99 01127 incf AD9850_4,f ; Yes, add one and continue 01CA 01128 add9 01CA 080F 01129 movf freq_3,w ; Use the freq_3 term 01CB 0799 01130 addwf AD9850_4,f ; Add freq term to total in correct position 01CC 01131 noAdd 01CC 0C99 01132 rrf AD9850_4,f ; Shift next multiplier bit into position 01CD 0C98 01133 rrf AD9850_3,f ; Rotate bits to right from byte to byte 01CE 0C97 01134 rrf AD9850_2,f ; 01CF 0C96 01135 rrf AD9850_1,f ; 01D0 0C95 01136 rrf AD9850_0,f ; 01D1 0CAA 01137 rrf osc_temp_3,f ; Shift next multiplicand bit into position 01D2 0CA9 01138 rrf osc_temp_2,f ; Rotate bits to right from byte to byte 01D3 0CA8 01139 rrf osc_temp_1,f ; 01D4 0CA7 01140 rrf osc_temp_0,f ; 01D5 0BA0 01141 decfsz mult_count,f ; One more bit has been done. Are we done? 01D6 29B2 01142 goto mult_loop ; No, go back to use this bit 01D7 0199 01143 clrf AD9850_4 ; Yes, clear _4. Answer is in bytes _3 .. _0 01D8 0008 01144 return ; Done. MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 23 LOC OBJECT CODE LINE SOURCE TEXT VALUE 01145 ; 01146 ; ***************************************************************************** 01147 ; * * 01148 ; * Purpose: This routine sends the AD9850 control word to the DDS chip * 01149 ; * using a serial data transfer. * 01150 ; * * 01151 ; * Input: AD9850_4 ... AD9850_0 * 01152 ; * * 01153 ; * Output: The DDS chip register is updated. * 01154 ; * * 01155 ; ***************************************************************************** 01156 ; 01D9 01157 send_dds_word 01D9 3015 01158 movlw AD9850_0 ; Point FSR at AD9850 01DA 0084 01159 movwf FSR ; 01DB 01160 next_byte 01DB 0800 01161 movf INDF,w ; 01DC 00A2 01162 movwf byte2send ; 01DD 3008 01163 movlw 0x08 ; Set counter to 8 01DE 00A1 01164 movwf bit_count ; 01DF 01165 next_bit 01DF 0CA2 01166 rrf byte2send,f ; Test if next bit is 1 or 0 01E0 1C03 01167 btfss STATUS,B_C ; Was it zero? 01E1 29E6 01168 goto send0 ; Yes, send zero 01E2 1786 01169 bsf PortB,7 ; No, send one 01E3 1686 01170 bsf PortB,5 ; Toggle write clock 01E4 1286 01171 bcf PortB,5 ; 01E5 29E9 01172 goto break ; 01E6 01173 send0 01E6 1386 01174 bcf PortB,7 ; Send zero 01E7 1686 01175 bsf PortB,5 ; Toggle write clock 01E8 1286 01176 bcf PortB,5 ; 01E9 01177 break 01E9 0BA1 01178 decfsz bit_count,f ; Has the whole byte been sent? 01EA 29DF 01179 goto next_bit ; No, keep going. 01EB 0A84 01180 incf FSR,f ; Start the next byte unless finished 01EC 301A 01181 movlw AD9850_4+1 ; Next byte (past the end) 01ED 0204 01182 subwf FSR,w ; 01EE 1C03 01183 btfss STATUS,B_C ; 01EF 29DB 01184 goto next_byte ; 01F0 1406 01185 bsf PortB,0 ; Send load signal to the AD9850 01F1 1006 01186 bcf PortB,0 ; 01F2 0008 01187 return ; 01188 ; 01189 ; ***************************************************************************** 01190 ; * * 01191 ; * Purpose: This subroutine converts a 32 bit binary number to a 10 digit * 01192 ; * BCD number. The input value taken from freq(0 to 3) is * 01193 ; * preserved. The output is in BCD(0 to 4), each byte holds => * 01194 ; * (hi_digit,lo_digit), most significant digits are in BCD_4. * 01195 ; * This routine is a modified version of one described in * 01196 ; * MicroChip application note AN526. * 01197 ; * * MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 24 LOC OBJECT CODE LINE SOURCE TEXT VALUE 01198 ; * Input: The value in freq_0 ... freq_3 * 01199 ; * * 01200 ; * Output: The BCD number in BCD_0 ... BCD_4 * 01201 ; * * 01202 ; ***************************************************************************** 01203 ; 01F3 01204 bin2BCD 01F3 3020 01205 movlw 0x20 ; Set loop counter 01F4 009E 01206 movwf BCD_count ; to 32 01F5 0190 01207 clrf BCD_0 ; Clear output 01F6 0191 01208 clrf BCD_1 ; " " 01F7 0192 01209 clrf BCD_2 ; " " 01F8 0193 01210 clrf BCD_3 ; " " 01F9 0194 01211 clrf BCD_4 ; " " 01FA 01212 bin_loop 01FA 1003 01213 bcf STATUS,B_C ; Clear carry bit in STATUS 01214 ; 01215 ; Rotate bits in freq bytes. Move from LS byte (freq_0) to next byte (freq_1). 01216 ; Likewise, move from freq_1 to freq_2 and from freq_2 to freq_3. 01217 ; 01FB 0D8C 01218 rlf freq_0,f ; Rotate left, 0 -> LS bit, MS bit -> Carry 01FC 0D8D 01219 rlf freq_1,f ; Rotate left, Carry->LS bit, MS bit->Carry 01FD 0D8E 01220 rlf freq_2,f ; Rotate left, Carry->LS bit, MS bit->Carry 01FE 0D8F 01221 rlf freq_3,f ; Rotate left, Carry->LS bit, MS bit->Carry 01FF 1803 01222 btfsc STATUS,B_C ; Is Carry clear? If so, skip next instruction 0200 140C 01223 bsf freq_0,0 ; Carry is set so wrap and set bit 0 in freq_0 01224 ; 01225 ; Build BCD bytes. Move into LS bit of BCD bytes (LS of BCD_0) from MS bit of 01226 ; freq_3 via the Carry bit. 01227 ; 0201 0D90 01228 rlf BCD_0,f ; Rotate left, Carry->LS bit, MS bit->Carry 0202 0D91 01229 rlf BCD_1,f ; Rotate left, Carry->LS bit, MS bit->Carry 0203 0D92 01230 rlf BCD_2,f ; Rotate left, Carry->LS bit, MS bit->Carry 0204 0D93 01231 rlf BCD_3,f ; Rotate left, Carry->LS bit, MS bit->Carry 0205 0D94 01232 rlf BCD_4,f ; Rotate left, Carry->LS bit, MS bit->Carry 0206 039E 01233 decf BCD_count,f ; Decrement loop count 0207 1D03 01234 btfss STATUS,B_Z ; Is loop count now zero? 0208 2A0A 01235 goto adjust ; No, go to adjust 0209 0008 01236 return ; Yes, EXIT 01237 ; ============================================================================ 020A 01238 adjust ; Internal subroutine, called by bin2BCD main loop only 01239 ; 01240 ; As BCD bytes are being built, make sure the nibbles do not grow larger than 9. 01241 ; If a nibble gets larger than 9, increment to next higher nibble. 01242 ; (If the LS nibble of a byte overflows, increment the MS nibble of that byte.) 01243 ; (If the MS nibble of a byte overflows, increment the LS nibble of next byte.) 01244 ; 020A 3010 01245 movlw BCD_0 ; Get pointer to BCD_0 020B 0084 01246 movwf FSR ; Put pointer in FSR for indirect addressing 020C 2216 01247 call adj_BCD ; 020D 0A84 01248 incf FSR,f ; Move indirect addressing pointer to BCD_1 020E 2216 01249 call adj_BCD ; 020F 0A84 01250 incf FSR,f ; Move indirect addressing pointer to BCD_2 MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 25 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0210 2216 01251 call adj_BCD ; 0211 0A84 01252 incf FSR,f ; Move indirect addressing pointer to BCD_3 0212 2216 01253 call adj_BCD ; 0213 0A84 01254 incf FSR,f ; Move indirect addressing pointer to BCD_4 0214 2216 01255 call adj_BCD ; 0215 29FA 01256 goto bin_loop ; Back to main loop of bin2BCD 01257 ; ============================================================================ 0216 01258 adj_BCD ; Internal subroutine, called by adjust only 0216 3003 01259 movlw 3 ; Add 3 0217 0700 01260 addwf INDF,w ; to LS digit 0218 009F 01261 movwf BCD_temp ; Save in temp 0219 199F 01262 btfsc BCD_temp,3 ; Is LS digit + 3 > 7 (Bit 3 set) 021A 0080 01263 movwf INDF ; Yes, save incremented value as LS digit 021B 3030 01264 movlw 0x30 ; Add 3 021C 0700 01265 addwf INDF,w ; to MS digit 021D 009F 01266 movwf BCD_temp ; Save as temp 021E 1B9F 01267 btfsc BCD_temp,7 ; Is MS digit + 3 > 7 (Bit 7 set) 021F 0080 01268 movwf INDF ; Yes, save incremented value as MS digit 0220 0008 01269 return ; Return to adjust subroutine 01270 ; 01271 ; ***************************************************************************** 01272 ; * * 01273 ; * Purpose: Display the frequency setting on the LCD. * 01274 ; * * 01275 ; * Input: The values in BCD_4 ... BCD_0 * 01276 ; * * 01277 ; * Output: The number displayed on the LCD * 01278 ; * * 01279 ; ***************************************************************************** 01280 ; 0221 01281 show_freq 0221 3081 01282 movlw 0x81 ; Point the LCD to first LCD digit location 0222 226A 01283 call cmnd2LCD ; Send starting digit location to LCD 01284 ; 01285 ; Running 4-bit mode, so need to send Most Significant Nibble first. 01286 ; 01287 ; Extract and send "XXXX" from byte containing "XXXXYYYY" 01288 ; - Swap halves to get YYYYXXXX 01289 ; - Mask with 0x0F to get 0000XXXX 01290 ; - Add ASCII bias (0030XXXX) 01291 ; 0223 0E13 01292 swapf BCD_3,w ; Swap 10MHz BCD digit into lower nibble of W 0224 390F 01293 andlw 0x0F ; Mask for lower nibble only (0000XXXX) 0225 3E30 01294 addlw 0x30 ; Add offset for ASCII char set (0030XXXX) 0226 226E 01295 call data2LCD ; Send byte in W to LCD 01296 ; 01297 ; Extract and send "YYYY" from byte containing "XXXXYYYY" 01298 ; - Mask with 0x0F to get 0000YYYY 01299 ; - Add offset for ASCII character set in LCD (0030YYYY) 01300 ; 0227 0813 01301 movf BCD_3,w ; Put 1MHz BCD digit into lower nibble of W 0228 390F 01302 andlw 0x0F ; Mask for lower nibble only (0000YYYY) 0229 3E30 01303 addlw 0x30 ; Add offset for ASCII char set (0030YYYY) MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 26 LOC OBJECT CODE LINE SOURCE TEXT VALUE 022A 226E 01304 call data2LCD ; Send byte in W to LCD 01305 ; 022B 302C 01306 movlw ',' ; Get a comma 022C 226E 01307 call data2LCD ; Send byte in W to LCD 01308 ; 022D 0E12 01309 swapf BCD_2,w ; Swap 100KHz BCD digit into lower nibble of W 022E 390F 01310 andlw 0x0F ; Mask for lower nibble only (0000XXXX) 022F 3E30 01311 addlw 0x30 ; Add offset for ASCII char set (0030XXXX) 0230 226E 01312 call data2LCD ; Send byte in W to LCD 01313 ; 0231 0812 01314 movf BCD_2,w ; Put 10KHz BCD digit into lower nibble of W 0232 390F 01315 andlw 0x0F ; Mask for lower nibble only (0000YYYY) 0233 3E30 01316 addlw 0x30 ; Add offset for ASCII char set (0030YYYY) 0234 226E 01317 call data2LCD ; Send byte in W to LCD 01318 ; 0235 0E11 01319 swapf BCD_1,w ; Swap 1KHz BCD digit into lower nibble of W 0236 390F 01320 andlw 0x0F ; Mask for lower nibble only (0000XXXX) 0237 3E30 01321 addlw 0x30 ; Add offset for ASCII char set (0030XXXX) 0238 226E 01322 call data2LCD ; Send byte in W to LCD 01323 ; 0239 302E 01324 movlw '.' ; Set up W with ASCII Period 023A 226E 01325 call data2LCD ; Send data byte in W to LCD 01326 ; 023B 30C0 01327 movlw 0xC0 ; Point to LCD digit number nine 023C 226A 01328 call cmnd2LCD ; Send command byte in W to LCD 01329 ; 023D 0811 01330 movf BCD_1,w ; Put 100 Hz BCD digit into lower nibble of W 023E 390F 01331 andlw 0x0F ; Mask for lower nibble only (0000YYYY) 023F 3E30 01332 addlw 0x30 ; Add offset for ASCII char set (0030YYYY) 0240 226E 01333 call data2LCD ; Send data byte in W to LCD 01334 ; 0241 0E10 01335 swapf BCD_0,w ; Swap 10 Hz BCD digit into lower nibble of W 0242 390F 01336 andlw 0x0F ; Mask for lower nibble only (0000XXXX) 0243 3E30 01337 addlw 0x30 ; Add offset for ASCII char set (0030XXXX) 0244 226E 01338 call data2LCD ; Send data byte in W to LCD 01339 ; 0245 0810 01340 movf BCD_0,w ; Put 1 Hz BCD digit into lower nibble of W 0246 390F 01341 andlw 0x0F ; Mask for lower nibble only (0000YYYY) 0247 3E30 01342 addlw 0x30 ; Add offset for ASCII char set (0030YYYY) 0248 226E 01343 call data2LCD ; Send byte in W to LCD 01344 ; 0249 3020 01345 movlw ' ' ; Send a space 024A 226E 01346 call data2LCD ; to LCD 01347 ; 024B 306B 01348 movlw 'k' ; Send a 'k' 024C 226E 01349 call data2LCD ; to LCD 01350 ; 024D 3048 01351 movlw 'H' ; Send an "H" 024E 226E 01352 call data2LCD ; to LCD 01353 ; 024F 307A 01354 movlw 'z' ; Send a 'z' 0250 226E 01355 call data2LCD ; to LCD 01356 ; MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 27 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0251 0008 01357 return ; 01358 ; 01359 ; ***************************************************************************** 01360 ; * * 01361 ; * Purpose: Check if LCD is done with the last operation. * 01362 ; * This subroutine polls the LCD busy flag to determine if * 01363 ; * previous operations are completed. * 01364 ; * * 01365 ; * Input: None * 01366 ; * * 01367 ; * Output: PortB set as: RB7..RB4 inputs * 01368 ; * RB3..RB0 outputs * 01369 ; ***************************************************************************** 01370 ; 0252 01371 busy_check 0252 0186 01372 clrf PortB ; Clear all outputs on PortB 0253 1683 01373 bsf STATUS,B_RP0 ; Switch to bank 1 for Tristate operation 0254 30F0 01374 movlw b'11110000' ; Set RB7..RB4 as inputs, RB3..RB0 outputs 0255 0086 01375 movwf TRISB ; via Tristate 0256 1283 01376 bcf STATUS,B_RP0 ; Switch back to bank 0 0257 1086 01377 bcf PortB,LCD_rs ; Set up LCD for Read Busy Flag (RS = 0) 0258 1506 01378 bsf PortB,LCD_rw ; Set up LCD for Read (RW = 1) 0259 30FF 01379 movlw 0xFF ; Set up constant 255 025A 00AD 01380 movwf timer1 ; for timer loop counter 025B 01381 LCD_is_busy 025B 1586 01382 bsf PortB,LCD_e ; Set E high 025C 0806 01383 movf PortB,w ; Read PortB into W 025D 00AC 01384 movwf LCD_read ; Save W for later testing 025E 1186 01385 bcf PortB,LCD_e ; Drop E again 025F 0000 01386 nop ; Wait a 0260 0000 01387 nop ; while 0261 1586 01388 bsf PortB,LCD_e ; Pulse E high (dummy read of lower nibble), 0262 0000 01389 nop ; wait, 0263 1186 01390 bcf PortB,LCD_e ; and drop E again 0264 03AD 01391 decf timer1,f ; Decrement loop counter 0265 1903 01392 btfsc STATUS,B_Z ; Is loop counter down to zero? 0266 2A69 01393 goto not_busy ; If yes, return regardless 0267 1BAC 01394 btfsc LCD_read,7 ; Is Busy Flag (RB7) in save byte clear? 0268 2A5B 01395 goto LCD_is_busy ; If not, it is busy so jump back 0269 01396 not_busy 0269 0008 01397 return ; 01398 ; 01399 ; ***************************************************************************** 01400 ; * Purpose: Send Command or Data byte to the LCD * 01401 ; * Entry point cmnd2LCD: Send a Command to the LCD * 01402 ; * Entry Point data2LCD: Send a Data byte to the LCD * 01403 ; * * 01404 ; * Input: W has the command or data byte to be sent to the LCD. * 01405 ; * * 01406 ; * Output: None * 01407 ; ***************************************************************************** 01408 ; 026A 01409 cmnd2LCD ; ****** Entry point ****** MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 28 LOC OBJECT CODE LINE SOURCE TEXT VALUE 026A 00AB 01410 movwf LCD_char ; Save byte to write to LCD 026B 01B8 01411 clrf rs_value ; Remember to clear RS (clear rs_value) 026C 1086 01412 bcf PortB,LCD_rs ; Set RS for Command to LCD 026D 2A71 01413 goto write2LCD ; Go to common code 026E 01414 data2LCD ; ****** Entry point ******** 026E 00AB 01415 movwf LCD_char ; Save byte to write to LCD 026F 1438 01416 bsf rs_value,0 ; Remember to set RS (set bit 0 of rs_value) 0270 1486 01417 bsf PortB,LCD_rs ; Set RS for Data to LCD 0271 01418 write2LCD 0271 2252 01419 call busy_check ; Check to see if LCD is ready for new data 0272 0186 01420 clrf PortB ; Clear all of Port B (inputs and outputs) 0273 1683 01421 bsf STATUS,B_RP0 ; Switch to bank 1 for Tristate operation 0274 3000 01422 movlw 0x00 ; Set up to enable PortB data pins 0275 0086 01423 movwf TRISB ; All pins (RB7..RB0) are back to outputs 0276 1283 01424 bcf STATUS,B_RP0 ; Switch to bank 0 0277 1106 01425 bcf PortB,LCD_rw ; Set LCD back to Write mode (RW = 0) 0278 1086 01426 bcf PortB,LCD_rs ; Guess RS should be clear 0279 1838 01427 btfsc rs_value,0 ; Should RS be clear? (is bit 0 == 0?) 027A 1486 01428 bsf PortB,LCD_rs ; No, set RS 01429 ; 01430 ; Transfer Most Significant nibble (XXXX portion of XXXXYYYY) 01431 ; 027B 300F 01432 movlw 0x0F ; Set up mask 027C 0586 01433 andwf PortB,f ; Clear old RB7..RB4 027D 082B 01434 movf LCD_char,w ; Put byte of data into W 027E 39F0 01435 andlw 0xF0 ; Mask to give XXXX0000 in W 027F 0486 01436 iorwf PortB,f ; Send to RB7..RB4 without changing RB3..RB0 0280 1586 01437 bsf PortB,LCD_e ; Pulse the E line high, 0281 0000 01438 nop ; wait, 0282 1186 01439 bcf PortB,LCD_e ; and drop it again 01440 ; 01441 ; Transfer Least Significant nibble (YYYY portion of XXXXYYYY) 01442 ; 0283 300F 01443 movlw 0x0F ; Set up mask 0284 0586 01444 andwf PortB,f ; Clear old RB7..RB4 0285 0E2B 01445 swapf LCD_char,w ; Move LS nibble of data to MS position in W 0286 39F0 01446 andlw 0xF0 ; Mask to give YYYY0000 in W Message[305]: Using default destination of 1 (file). 0287 0486 01447 iorwf PortB ; Send to RB7..RB4 without changing RB3..RB0 0288 1586 01448 bsf PortB,LCD_e ; Pulse the E line high, 0289 0000 01449 nop ; wait, 028A 1186 01450 bcf PortB,LCD_e ; and drop it again 028B 0008 01451 return 01452 ; 01453 ; ***************************************************************************** 01454 ; * * 01455 ; * Purpose: Write the byte of data at EEdata to the EEPROM at address * 01456 ; * EEadr. * 01457 ; * * 01458 ; * Input: The values at EEdata and EEadr. * 01459 ; * * 01460 ; * Output: The EEPROM value is updated. * 01461 ; * * MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 29 LOC OBJECT CODE LINE SOURCE TEXT VALUE 01462 ; ***************************************************************************** 01463 ; 028C 01464 write_EEPROM 028C 1683 01465 bsf STATUS,B_RP0 ; Switch to bank 1 028D 1508 01466 bsf EEdata,WREN ; Set the EEPROM write enable bit 028E 3055 01467 movlw 0x55 ; Write 0x55 and 0xAA to EEPROM 028F 0089 01468 movwf EEadr ; control register, as required 0290 30AA 01469 movlw 0xAA ; for the write 0291 0089 01470 movwf EEadr ; 0292 1488 01471 bsf EEdata,WR ; Set WR to initiate write 0293 01472 bit_check 0293 1888 01473 btfsc EEdata,WR ; Has the write completed? 0294 2A93 01474 goto bit_check ; No, keep checking 0295 1108 01475 bcf EEdata,WREN ; Clear the EEPROM write enable bit 0296 1283 01476 bcf STATUS,B_RP0 ; Switch to bank 0 0297 0A89 01477 incf EEadr,f ; Increment the EE write address 0298 0008 01478 return ; Return to the caller 01479 ; 01480 ; ***************************************************************************** 01481 ; * * 01482 ; * Purpose: Read a byte of EEPROM data at address EEadr into EEdata. * 01483 ; * * 01484 ; * Input: The address EEadr. * 01485 ; * * 01486 ; * Output: The value in EEdata. * 01487 ; * * 01488 ; ***************************************************************************** 01489 ; 0299 01490 read_EEPROM 0299 1683 01491 bsf STATUS,B_RP0 ; Switch to bank 1 029A 1408 01492 bsf EEdata,RD ; Request the read 029B 1283 01493 bcf STATUS,B_RP0 ; Switch to bank 0 029C 0A89 01494 incf EEadr,f ; Increment the read address 029D 0008 01495 return ; Return to the caller 01496 ; 01497 ; ***************************************************************************** 01498 ; * * 01499 ; * Purpose: Wait for a specified number of milliseconds. * 01500 ; * * 01501 ; * Entry point wait_128ms: Wait for 128 msec * 01502 ; * Entry point wait_64ms : Wait for 64 msec * 01503 ; * Entry point wait_32ms : Wait for 32 msec * 01504 ; * Entry point wait_16ms : Wait for 16 msec * 01505 ; * Entry point wait_8ms : Wait for 8 msec * 01506 ; * * 01507 ; * Input: None * 01508 ; * * 01509 ; * Output: None * 01510 ; * * 01511 ; ***************************************************************************** 01512 ; 029E 01513 wait_128ms ; ****** Entry point ****** 029E 30FF 01514 movlw 0xFF ; Set up outer loop MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 30 LOC OBJECT CODE LINE SOURCE TEXT VALUE 029F 00AD 01515 movwf timer1 ; counter to 255 02A0 2AAC 01516 goto outer_loop ; Go to wait loops 02A1 01517 wait_64ms ; ****** Entry point ****** 02A1 3080 01518 movlw 0x80 ; Set up outer loop 02A2 00AD 01519 movwf timer1 ; counter to 128 02A3 2AAC 01520 goto outer_loop ; Go to wait loops 02A4 01521 wait_32ms ; ****** Entry point ****** 02A4 3040 01522 movlw 0x40 ; Set up outer loop 02A5 00AD 01523 movwf timer1 ; counter to 64 02A6 2AAC 01524 goto outer_loop ; Go to wait loops 02A7 01525 wait_16ms ; ****** Entry point ****** 02A7 3020 01526 movlw 0x20 ; Set up outer loop 02A8 00AD 01527 movwf timer1 ; counter to 32 02A9 2AAC 01528 goto outer_loop ; Go to wait loops 02AA 01529 wait_8ms ; ****** Entry point ****** 02AA 3010 01530 movlw 0x10 ; Set up outer loop 02AB 00AD 01531 movwf timer1 ; counter to 16 01532 ; Fall through into wait loops 01533 ; 01534 ; Wait loops used by other wait routines 01535 ; - 1 microsecond per instruction (with a 4 MHz microprocessor crystal) 01536 ; - 510 instructions per inner loop 01537 ; - (Timer1 * 514) instructions (.514 msec) per outer loop 01538 ; - Round off to .5 ms per outer loop 01539 ; 02AC 01540 outer_loop 02AC 30FF 01541 movlw 0xFF ; Set up inner loop counter 02AD 00AE 01542 movwf timer2 ; to 255 02AE 01543 inner_loop 02AE 0BAE 01544 decfsz timer2,f ; Decrement inner loop counter 02AF 2AAE 01545 goto inner_loop ; If inner loop counter not down to zero, 01546 ; then go back to inner loop again 02B0 0BAD 01547 decfsz timer1,f ; Yes, Decrement outer loop counter 02B1 2AAC 01548 goto outer_loop ; If outer loop counter not down to zero, 01549 ; then go back to outer loop again 02B2 0008 01550 return ; Yes, return to caller 01551 ; 01552 ; ***************************************************************************** 01553 ; 01554 END MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 31 SYMBOL TABLE LABEL VALUE AD9850_0 00000015 AD9850_1 00000016 AD9850_2 00000017 AD9850_3 00000018 AD9850_4 00000019 BCD_0 00000010 BCD_1 00000011 BCD_2 00000012 BCD_3 00000013 BCD_4 00000014 BCD_count 0000001E BCD_temp 0000001F B_C 00000000 B_DC 00000001 B_NPD 00000003 B_NTO 00000004 B_RP0 00000005 B_Z 00000002 DDS_clk 00000005 DDS_dat 00000007 DDS_load 00000000 EEadr 00000009 EEdata 00000008 FSR 00000004 INDF 00000000 INTCON 0000000B LCD_char 0000002B LCD_e 00000003 LCD_is_busy 0000025B LCD_read 0000002C LCD_rs 00000001 LCD_rw 00000002 PCL 00000002 PCLATH 0000000A PortA 00000005 PortB 00000006 RD 00000000 STATUS 00000003 TRISA 00000005 TRISB 00000006 WR 00000001 WREN 00000002 _CP_OFF 00003FFF _CP_ON 0000000F _HS_OSC 00003FFE _LP_OSC 00003FFC _PWRTE_OFF 00003FFF _PWRTE_ON 00003FF7 _RC_OSC 00003FFF _WDT_OFF 00003FFB _WDT_ON 00003FFF _XT_OSC 00003FFD __16F84 00000001 MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 32 SYMBOL TABLE LABEL VALUE add1 000000CE add2 000000D5 add3 000000DA add4 00000185 add5 0000018C add6 00000191 add7 000001BE add8 000001C5 add9 000001CA add_step 000000C5 adj_BCD 00000216 adjust 0000020A band 00000037 band_end 00000028 band_table 00000001 band_up 00000087 bin2BCD 000001F3 bin_loop 000001FA bit_check 00000293 bit_count 00000021 break 000001E9 bump_step 0000006B busy_check 00000252 byte2send 00000022 cal_loop 00000162 calc_dds_word 000001A3 calibrate 0000013F change_band 0000007B check_add 000000DD cmnd2LCD 0000026A comp_done 0000010D count 00000036 data2LCD 0000026E default_0 00000028 default_1 00000001 default_2 000000D6 default_3 00000000 down 00000076 exit1 00000101 exit2 00000114 exit3 0000013C faster 0000017C freq_0 0000000C freq_1 0000000D freq_2 0000000E freq_3 0000000F fstep_0 0000001A fstep_1 0000001B fstep_2 0000001C fstep_3 0000001D get_band 00000093 go_step 00000070 init_LCD 000000A5 MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 33 SYMBOL TABLE LABEL VALUE inner_loop 000002AE last_dir 00000034 limit_0 00000080 limit_1 000000C3 limit_2 000000C9 limit_3 00000001 main 0000005C mult_count 00000020 mult_loop 000001B2 next_bit 000001DF next_byte 000001DB next_dir 00000035 noAdd 000001CC no_inc 0000011F not_busy 00000269 osc_0 00000023 osc_1 00000024 osc_2 00000025 osc_3 00000026 osc_temp_0 00000027 osc_temp_1 00000028 osc_temp_2 00000029 osc_temp_3 0000002A outer_loop 000002AC pb_switch 00000003 pe_continue 00000136 poll_encoder 00000115 read_EEPROM 00000299 read_EEocs 00000039 read_encoder 00000118 ref_osc_0 000000C4 ref_osc_1 0000001D ref_osc_2 000000F3 ref_osc_3 0000002A ren_new 00000031 ren_old 00000032 ren_read 00000033 ren_timer_0 0000002F ren_timer_1 00000030 reset_entry 00000000 rs_value 00000038 send0 000001E6 send_dds_word 000001D9 set_max 000000F9 set_min 00000110 show_freq 00000221 start 0000002E sub_step 00000102 timer1 0000002D timer2 0000002E up 00000078 up2 0000013A update_osc 0000016E MPASM 02.50.02 Intermediate SIGGEN3A.ASM 9-18-2003 10:16:39 PAGE 34 SYMBOL TABLE LABEL VALUE valid 00000085 wait_128ms 0000029E wait_16ms 000002A7 wait_32ms 000002A4 wait_64ms 000002A1 wait_8ms 000002AA write 0000008E write2LCD 00000271 write_EEPROM 0000028C MEMORY USAGE MAP ('X' = Used, '-' = Unused) 0000 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 0040 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 0080 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 00C0 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 0100 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 0140 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 0180 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 01C0 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 0200 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 0240 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 0280 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXX------------- 2000 : XXXX---X-------- ---------------- ---------------- ---------------- 2100 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX All other memory blocks unused. Program Memory Words Used: 691 Program Memory Words Free: 333 Errors : 0 Warnings : 4 reported, 0 suppressed Messages : 1 reported, 0 suppressed