Professional Documents
Culture Documents
;
SweepGen - Swept Frequency Signal Generator using the AmQRP PIC-EL
;
board together with the NJQRP DDS daughtercard.
;
;
Version 1.1 October 4, 2005 by Bob Okas, W3CD (w3cd@arrl.net)
;
;
Description:
;
;
This is the control program for a DDS-based Sweep Generator using the
;
AmQRP PIC-EL board and DDS daughter card. It can be used as a fixed;
frequency signal generator or as a sweep frequency generator. The user
;
programs the start, end, step and marker frequencies.
;
;
SweepGen is based on PICELGen 2.01 by the same author. The following
;
comments are included to provide details of this program's forebears.
;
I indeed stand on the shoulders of giants.
;
;
Version 1.1 is a port of the previous version to the PIC16F628A.
;
Version 1.0 incorporates all of the improvements and changes from
;
the previous versions of PICELGen and modifies the original code base
;
to reduce program memory usage. Comments in the code are provided to
;
note these changes.
;
;
;******************************************************************************
; Original Author - Curtis W. Preuss - WB2V
;
; Modification History
;
8/19/98 - Version 1 - Initial Version by Curtis W. Preuss - WB2V
; 12/xx/98 - Version 2 - Converted to MPASM by Bruce Stough, AA0ED
;
4/21/99 - Version 3 - Fixed and modified by
;
Bruce Stough, AA0ED (sbs1@visi.com) and
;
Craig Johnson, AA0ZZ (cbjohns@cbjohns.com)
;
; 10/31/03 PICELgen1.0 Modify for PIC Elmer project by Craig Johnson, AA0ZZ
;
1) Change to use 1x8 LCD instead of 1x16
;
- Freq displayed as Hz (e.g. 14025000)
;
- CAL freq displayed as Hz (e.g. 10000000)
;
2) Set up to support the NJQRP DDS Daughterboard
;
- 50 MHz oscillator
;
3) Change PORTB pin allocations to support PIC-EL
;
- Change RB4-RB7 to RB0-RB3
;
- Change RB0 (DDS LOAD) to RB7
;
- Change RB1 (LCD_rs) to RB6
;
- Change RB2 (LCD_rw) to RB5
;
- Change RB3 (LCD_e) to RB4
;
- Change Busy_check routine to check correct bit
;
- Change cmnd2LCD/data2LCD routine - swap nibbles
;
4) Change RA2 to always be an LOW output
;
5) Support pushbutton on RA3 instead of encoder
;
shaft switch for bandswitch and calibrate
;
6) Support pushbutton on RA4 for fast tuning
;
;
1/3/04
PICELgen1.1 Add Title and Version on start-up
;
1/7/04
PICELgen1.2 Restructure main loop and change_band
;
2/2/04
PICELgen1.2a Fix confusing comment in the header re shaft sw.
;
Fix comment in header regarding PB_2 for calib.
;
2/8/04
PICELgen1.3 Fix for reliable startup of DDS
;
Add code for 1 MHz steps (up or down)
;
Add code to save new start-up frequency
;
3/12/04 PICELgen1.4 Remove use of watchdog timer (temp sensitivity)
;
Add code to support either 1x8 or 1x16 LCDs
;
- Use #DEFINE to select the LCD type
;
Fix calibrate routine so it stays in cal_loop
;
;
;
4/19/04 PICELgen2.0 Mods by Bob Okas, W3CD as follow:
;
;
1. Added the features listed at the top.
;
2. Fixed PORTA initialization bug that kept RA2
;
as an input, which caused the speaker to
;
continuously draw current.
;
3. Added LCD command definitions.
;
4. Put LCD messages in a table to reduce program
;
memory usage. Added message display function.
;
5. Modified sub_step to re-complement fstep_3..0
;
6. Rewrote pushbutton handler.
;
7. Added feature to display a message when
;
EEPROM contents are changed.
;
8. Changed default startup frequency to 7040 KHz.
;
9. Removed commented-out legacy code.
;
10. Changed hard-coded constants in program code
;
to named constants which appear at the top
;
of the program.
;
11. Added support for linearly addressed 16x1 LCDs
;
12. Removed the "#" characters preceeding IF, ELSE
;
and ENDIF directives to support other assemblers
;
besides MPASM.
;
13. Significant re-writes to optimize program memory
;
usage which are too numerous to mention here.
;
;
4/19/04 PICELgen2.01:
;
;
1. Fixed AmQRP 16x1 display and cursor addressing
;
bugs. Rearranged some initialization code. W3CD
;
; 10/4/05
SweepGen 1.1:
;
Ported ver 1.0 code to the 16F628A. W3CD
;
; 26/2/2012 SweepGen 1.1 Terry Mowles VK5TM
;
;
1. Updated to use AD8950 or AD9851. Currently set for AD9851
;
see code at end of calc_dds_word for change.
;
2. Ref Osc changed to 125MHz for AD9850 or 180MHz fo
r AD9851
;
3. Max frequency changed to 40MHz for AD9850, 60MHz
for AD9851
;
!!! COMMENT and UNCOMMENT code for respective chip !
!!
;
; 1/04/2013 SweepGen 1.1a
;
Added initialise DDS to zero freq at start up to prevent has
h
;
generation as per datasheet - Terry Mowles VK5TM
;
;*****************************************************************************
;
; Target Controller PIC16F628A in PIC-EL board
;
__________
;
PB_3-Speaker----RA2 |1
18| RA1---------ENCODER A
;
PB_2-Bandswitch-RA3 |2
17| RA0---------ENCODER B
;
PB_1-Tuning etc-RA4 |3
16| OSC1--------XTAL
;
+5V-----------!MCLR |4
15| OSC2--------XTAL
;
Ground----------Vss |5
14| VDD---------+5 V
;
LCD11-----------RB0 |6
13| RB7---------DDS_LOAD
;
LCD12-----------RB1 |7
12| RB6---------LCD_rs (LCD Pin 4)
;
LCD13/DDS_CLK---RB2 |8
11| RB5---------LCD_rw (LCD Pin 5)
;
LCD14/DDS_DATA--RB3 |9
10| RB4---------LCD_e (LCD Pin 6)
;
---------;
; ****************************************************************************
; *
Device type and options.
*
; ****************************************************************************
;
processor
PIC16F628A
radix dec
#include P16F628A.inc
LCD Selections. The first batch of AmQRP PIC-EL boards were shipped with
8 character x 1 line LCDs. Later shipments used 16x1 LCDs which are
addressed as two 8x1 blocks. To get to the 9th character, the cursor
must be explicitly moved. There are other LCDs which employ linear display
addressing and no special actions are required to move from the 8th to the
9th character. These displays have been dubbed "linear" for the purposes of
this program. Select the appropriate #define to handle the appropriate LCD
;
;
;
Select only one of the following 3 #defines for your LCD type
;#define LCD_8
;#define LCD_16
#define LCD_16L
;
;
;
IFDEF LCD_8
#define LCDCHAR 8
ENDIF
IFDEF LCD_16
; AmQRP 16x1 LCDs -- Shipped with later kits
#define LCDCHAR 16
; Enable 16-character LCD program features
#define LCD16_LINEAR 0 ; Use for AmQRP 16x1 displays
ENDIF
IFDEF LCD_16L
; Alternative, linearly addressed 16x1 displays
#define LCDCHAR 16
; Enable 16-character LCD program features
#define LCD16_LINEAR 1 ; Use linear addressing
ENDIF
;
; Defining DETENT_ENCODER enables software to debounce the PIC-EL mechanical
; encoder and modifies the incrementing so that only one count changes at
; each detent. Comment out the line below for optical or detent-less encoders
#define DETENT_ENCODER
;
; The Software Version number is kept here
;
#define CODE_VERSION "1.1 "
;
; *****************************************************************************
; * DDS Frequency control equates. These may be changed to accommodate the *
; * reference clock frequency and the desired upper frequency limit frequency.*
*
; *****************************************************************************
;
; ref_osc represents the change in the frequency control word which results
; in a 1 Hz change in output frequency. It is interpreted as a fixed point
; integer in the format <ref_osc_3>.<ref_osc_2><ref_osc_1><ref_osc_0>
;
; The values for common oscillator frequencies are as follows:
;
; Frequency
ref_osc_3
ref_osc_2
ref_osc_1
ref_osc_0
;
; 180.00 MHz
0x17
0xDC
0x65
0xDF
; 125.00 MHz
0x22
0x5C
0x17
0xCA
; 120.00 MHz
0x23
0xCA
0x98
0xCE
; 100.00 MHz
0x2A
0xF3
0x1D
0xC4
; 90.70 MHz
0x2F
0x5A
0x82
0x7A
; 66.66 MHz
0x40
0x6E
0x52
0xE7
; 66.00 MHz
0x41
0x13
0x44
0x5F
; 50.00 MHz
0x55
0xE6
0x3B
0x88
;
; To calculate other values:
;
ref_osc_3 = (2^32 / oscillator_freq_in_Hertz).
;
ref_osc_2, ref_osc_1, and ref_osc_0 are the fractional part of
;
(2^32 / oscillator_freq_in_Hertz) times 2^24.
;
Note: 2^32 = 4294967296 and 2^24 = 16777216
;
equ
equ
equ
equ
0x2A
0xF3
0x1D
0xC4
;
;
;
;
;==== Currently set for 125 MHz Oscillator ======= Modified 22/2/12 TM
;ref_osc_3
;ref_osc_2
;ref_osc_1
;ref_osc_0
equ
equ
equ
equ
0x22
0x5C
0x17
0xD0
;==== Currently set for 180 MHz Oscillator ======= For AD9851 Modified 22/2/12 T
M
ref_osc_3
ref_osc_2
ref_osc_1
ref_osc_0
;
;
;
;
equ
equ
equ
equ
0x17
0xDC
0x65
0xDF
limit3..0 specify the upper limit frequency (in Hz) expressed as a 32 bit
integer. This should not be set to more than one third of the reference
oscillator frequency. The output filter of the DDS board must be designed
to pass frequencies up to the maximum.
;limit_3
;limit_2
;limit_1
;limit_0
equ
equ
equ
equ
0x01
0xC9
0xC3
0x80
;
;
;
;
; oscillator frequency. The output filter of the DDS board must be designed
; to pass frequencies up to the maximum.
limit_3
equ 0x03
; Most significant byte for 60 MHz
limit_2
equ 0x93
; Next byte
limit_1
equ 0x87
; Next byte
limit_0
equ 0x00
; Least significant byte
;-------------------------------------------------------------------------------------------------------; The following is the definition of the 10.00000 MHz
; calibration frequency
cal_freq_0
cal_freq_1
cal_freq_2
cal_freq_3
equ
equ
equ
equ
0x80
0x96
0x98
0x00
; LSB
; MSB
;*******************************************************************************
******
;
;
General definitions
;
;*******************************************************************************
******
EEPROM_BASE
equ 0x2100
RAM_BASE
6F84A
equ 0x20
RAM_ALL
pages
equ 0x70
TABLE_ADJUST
equ 3
MSB
equ 7
UP_BIT
equ 0x02
DIR_BIT
equ 1
FLAG_MASK
ENCODER_BITS
ion
equ 0x03
TEN
equ 10 ;
VFO_SEL
equ 0
FREQ_COUNT
DECADE_MASK
equ 0x07
SMALL_FSTEP
equ 0x04
LARGE_FSTEP
equ 0x80
PORTA_CONTROL
equ 0xfb
DECADE_0
DECADE_1
DECADE_2
DECADE_3
DECADE_4
DECADE_5
DECADE_6
DECADE_7
equ
equ
equ
equ
equ
equ
equ
equ
;
;
;
;
;
;
;
;
1 Hz adjustment value
10 Hz adjustment value
100 HZ
1 KHz
10 KHz
100 KHz
1 MHz
10 MHz
;*******************************************************************************
*******
;
PB_flags bits and related definitions
;
;
These bits define the operation of PB_1 and PB_2 during startup and norm
al
;
operations.
;
;*******************************************************************************
*******
PB_RPT_FLG
PB_CS_FLG
PB_1_PRESS
PB_2_PRESS
F_SET
equ 4
DECADE_DECREMENT
y decade
DECADE_INCREMENT
y decade
equ 0xff
equ 0x01
PB_RPT_WAIT
PB_RPT_DLY
PB_INIT_FREQ_WAIT
;*******************************************************************************
*******
;
;
PIC-EL LED Control bits and related definitions
;
;*******************************************************************************
*******
LED1_ON
LED2_ON
LED3_ON
equ 0x07
equ 0x0b
equ 0x0d
LED1_OFF
LED2_OFF
LED3_OFF
equ 0x08
equ 0x04
equ 0x02
LEDS_OFF
LED_MASK
s
equ 0x0e
equ 0xf1
LED1_2_ON
LED1_3_ON
LED2_3_ON
;*****************************************************************************
;
;
LCD Command Definitions
;
; The following are a series of command definitions and parameters that the
; Hitatchi 44780 LCD controller chip recognizes. Some commands have parameters
; which may be or'ed into the basic data to form a single-byte command. In
; such cases, these parameters have been grouped directly underneath the basic
; command data and bear descriptive names and comments related to their
; functions.
;
;*****************************************************************************
CMD_CLEAR_LCD
equ 0x01
CMD_RESET_LCD
equ 0x03
CMD_SET_IFC_1
IFC1_4_BIT
IFC1_8_BIT
equ 0x02
PICEL_IFC1
CMD_SET_IFC_2
IFC2_4_BIT
IFC2_8_BIT
IFC2_1_LINES
IFC2_2_LINES
IFC2_FONT_5_7
IFC2_FONT_5_10
equ 0x00
equ 0x01
equ 0x00
equ 0x10
equ
equ
equ
equ
0x00
0x08
0x00
0x04
IF LCDCHAR == 16
IF LCD16_LINEAR == 0
PICEL_IFC2
T_5_7
ELSE
PICEL_IFC2
T_5_7
ENDIF
ELSE
PICEL_IFC2
T_5_7
ENDIF
DISP_ON
CUR_OFF
CUR_ON
BLINK_OFF
BLINK_ON
equ 0x04
equ 0x00
equ 0x02
; Enables display
; Disables cursor
; Enables underline cursor
equ 0x00
; Disables blinking block cursor
equ 0x01
; Enables blinking block cursor
PICEL_DISPLAY_OFF
PICEL_DISPLAY_ON
CMD_HOME_CUR_LCD
equ 0x02
CMD_SET_INC
equ 0x04
; Sets Display and cursor movement
INC_DISPLAY_POS equ 0x01
; Shifts the display after data write
INC_CURSOR_POS equ 0x02
; Increments the cursor along with display
PICEL_CURSOR_RT equ CMD_SET_INC + INC_CURSOR_POS
CMD_SET_DSP_CUR equ 0x08
; Controls Display and cursor
ENABLE_BLOCK_BLINK
equ 0x01
; Blinking Block if enabled
ENABLE_CURSOR equ 0x02
; Underline if not blinking block
ENABLE_DISPLAY equ 0x04
; Turns on Display
CMD_SET_SCROLL equ 0x10
SCROLL_ENABLE equ 0x08
SCROLL_RIGHT
equ 0x04
CMD_CURSOR_CGRAM
equ 0x40
; Move cursor position within character
; generator memory. "OR" in the CGRAM
; address to this command. Valid range
; is 0x00 - 0x3f
CMD_MOV_CUR_DISP
equ 0x80
; Move cursor position within Display
; "OR" in the Display position to this command.
; 0x00 is the leftmost position.
equ 0x40
; Offset added to above command to posit
OFFSET_9
ion
LCD_POS_9
equ 8
;
; ****************************************************************************
; * Assign names to IO pins.
*
; ****************************************************************************
;
;
;
B register bits:
DDS_clk
DDS_dat
LCD_busy
LCD_e
LCD_rw
LCD_rs
DDS_load
equ 0x02
equ 0x03
;
;
equ 0x03
equ 0x04
;
equ 0x05
;
equ 0x06
;
equ 0x07
;
;
;
A register bits:
MARKER
PB_3
PB_2
PB_1
;
;
;
;
;
;
equ
equ
equ
equ
;
;
;
;
****************************************************************************
* ID location information:
*
* (MPASM warns about DW here, don't worry)
*
****************************************************************************
ORG
DATA
DATA
DATA
DATA
;
;
;
;
0x02
0x02
0x03
0x04
0x2000
0x57
0x33
0x43
0x44
****************************************************************************
* Setup the initial constant, based on the frequency of the reference
*
* oscillator. This can be tweaked with the calibrate function.
*
****************************************************************************
ORG
EEPROM_BASE
; 2.000 MHz
EE_end_freq_loc
DATA
0x20, 0x0b, 0x20, 0x00
; 2.100 MHz
EE_step_freq_loc
DATA
0x64, 0x00, 0x00, 0x00
; 100 Hz Step
EE_marker_freq_loc
DATA
0xd0, 0x47, 0x1f, 0x00
;
;
;
;
EE_ref_osc
EEcal_freq
EEstart_freq
EEend_freq
EEstep_freq
EEmarker_freq
equ
equ
equ
equ
equ
equ
EE_ref_osc_loc
EE_cal_freq_loc
EE_start_freq_loc
EE_end_freq_loc
EE_step_freq_loc
EE_marker_freq_loc
EEPROM_BASE
EEPROM_BASE
EEPROM_BASE
EEPROM_BASE
EEPROM_BASE
EEPROM_BASE
;
; ****************************************************************************
; *
Allocate variables in general purpose register space
*
; ****************************************************************************
;
CBLOCK RAM_BASE
; Start Data Block
BCD_0
BCD_1
BCD_2
BCD_3
BCD_4
temp_freq_0
temp_freq_1
temp_freq_2
temp_freq_3
osc_0
osc_1
osc_2
osc_3
;
;
;
;
; Current oscillator
; (4 bytes)
AD9850_0
AD9850_1
AD9850_2
AD9850_3
AD9850_4
fstep_0
fstep_1
fstep_2
fstep_3
;
;
;
;
Frequency inc/dec
(4 bytes)
update_decade fills these in
with values from decade_table
start_freq_0
start_freq_1
start_freq_2
start_freq_3
end_freq_0
end_freq_1
end_freq_2
end_freq_3
step_freq_0
step_freq_1
step_freq_2
step_freq_3
marker_freq_0
marker_freq_1
marker_freq_2
marker_freq_3
BCD_count
BCD_temp
bit_count
byte2send
; Used in calc_dds_word
;
LCD_char
LCD_read
timer1
timer2
ren_new
ren_old
ren_read
last_dir
next_dir
count
rs_value
PB_flags
PB_wait_count
; Pushbutton flags
; PB repeat control timer
temp
; Miscellaneous variable
decade
cur_pos
fstruct_ptr
message_pointer
enc_counter
freq_pointer
led_states
ENDC
CBLOCK RAM_ALL
ee_addr
ENDC
;
;
;
;
;
****************************************************************************
* The 16F84 resets to 0x00.
*
* The Interrupt vector is at 0x04. (Unused)
*
****************************************************************************
;
ORG
reset_entry
goto
0x0000
start
;****************************************************************************
;
;
Decade Table
;
; Each entry is four instructions long, with each group of four literals
; representing the frequency as a 32 bit integer. Each four byte entry
; represents the decade increment which can get be assigned to
; fstep_3, fstep_2, fstep_1 and fstep_0. Data is stored MSB first.
;
;****************************************************************************
decade_table
addwf
dt
dt
dt
dt
dt
dt
dt
dt
PCL,f
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x03,
0x27,
0x86,
0x42,
0x96,
0x01
0x0a
0x64
0xe8
0x10
0xa0
0x40
0x80
;
;
;
;
;
;
;
;
1Hz increment
10 Hz increment
100 Hz increment
1 KHz increment
10 KHz increment
100 KHz increment
1 MHz increment
10 MHz increment
;****************************************************************************
;
;
Frequency Data Structures
;
; Collecting the data for the sweep parameters is so repetitious that
; it made sense to write just one function to do the actual data collection,
; thus saving program space. The particulars of the data to collect are
; stored in what amounts to an array of structures, a look-up table if you
; will, that contains the collection function parameters. Each structure
; contains 3 elements:
;
1. Which LED(s) to illuminate
;
2. What message to flash on the LCD
;
3. What decade to start the frequency adjustment
;
4. Starting RAM location used to hold the frequency
;
;****************************************************************************
LED_OFFSET
MSG_OFFSET
DEC_OFFSET
RAM_OFFSET
equ
equ
equ
equ
0
1
2
3
;
;
;
;
Offset
Offset
Offset
Offset
to
to
to
to
f_struct_table
addwf PCL,f
f_start_struct_loc
dt
LED1_ON, start_freq_msg, DECADE_3, start_freq_0
f_end_struct_loc
dt
LED2_ON, end_freq_msg, DECADE_3, end_freq_0
f_step_struct_loc
dt
LED1_2_ON, step_freq_msg, DECADE_0, step_freq_0
f_marker_struct_loc
dt
LED3_ON, marker_freq_msg, DECADE_3, marker_freq_0
;
; Prepare the table offsets for use by the program
;
f_start
f_end
f_step
f_marker
equ
equ
equ
equ
f_start_struct_loc
f_end_struct_loc
f_step_struct_loc
f_marker_struct_loc
f_start_struct_loc
f_start_struct_loc
f_start_struct_loc
f_start_struct_loc
;****************************************************************************
;
;
Cursor Positioning Table
;
; 8 and 16 character LCD displays differ, so cursor positioning for
; frequency displays is put into tables to simplify the software.
;
;****************************************************************************
cursor_table
addwf
PCL,f
IF LCDCHAR == 8
dt
7, 6, 5, 4, 3, 2, 1, 0
ELSE
dt
10, 9, 8, 6, 5, 4, 2, 1
ENDIF
;****************************************************************************
;
; Message Table. All of the PIC-EL LCD messages are stored here. The last
; byte of the message string is set to 0 to indicate the end of string. The
; messages are indexed via an offset value, which is calculated at assembly
; time.
;
;****************************************************************************
message_table
addwf
PCL,f
messages
sign_on_msg_loc
; Displayed at power-on
dt
"SweepGen", 0
ver_msg_loc
; Displayed at power-on
IF LCDCHAR == 8
dt
"Ver ", CODE_VERSION, 0
ELSE
dt
" Ver", CODE_VERSION, 0
ENDIF
start_freq_msg_loc
dt
"Start", 0
end_freq_msg_loc
dt
"End", 0
step_freq_msg_loc
dt
"Step", 0
marker_freq_msg_loc
dt
"Marker", 0
sweep_msg_loc
dt
"Sweeping",0
end_err_msg_loc
dt
"Bad End",0
;
;
;
sign_on_msg
ver_msg
start_freq_msg
end_freq_msg
step_freq_msg
marker_freq_msg
sweep_msg
end_err_msg
equ
equ
equ
equ
equ
equ
equ
equ
sign_on_msg_loc
ver_msg_loc
start_freq_msg_loc
end_freq_msg_loc
step_freq_msg_loc
marker_freq_msg_loc
sweep_msg_loc
end_err_msg_loc
messages
messages
messages
messages
messages
messages
messages
messages
IF LCDCHAR == 16
khz_msg_loc
dt
" KHz",0
calibrate_msg_loc
dt
"CAL ", 0
khz_msg
cal_msg
equ khz_msg_loc
- messages
equ calibrate_msg_loc - messages
ENDIF
;*****************************************************************************
;
;
Purpose: This is the start of the program. Program and hardware
;
initialization takes place here before the execution falls
;
into the main program loop.
;
;
Input: PB_1 determines if calibration is to be performed.
;
;
Output: None.
;
;
Revisions:
;
Ver 1.0: Copied from PICELGen 2.0 and modified for use here
;
4-20-04 W3CD.
;
Ver 1.1: Adapted for PIC16F628A. 10-04-05 W3CD
;
;*****************************************************************************
start
clrf
movlw
movwf
clrf
INTCON
0x07
CMCON
RCSTA
;
;
;
;
bsf
clrf
clrf
clrf
STATUS,RP0
TXSTA
PIE1
VRCON
;
;
;
;
Switch to bank 1
Disable USART Transmitter
Clear all interrupt enable bits
Disable voltage reference
AD9850_0
AD9850_1
AD9850_2
AD9850_3
AD9850_4
send_dds_word
send_dds_word
bsf
PORTA,MARKER
call
movlw
movwf
call
init_LCD
LEDS_OFF
led_states
display_version
;
; Read reference oscillator data
;
movlw osc_0
movwf FSR
movlw EE_ref_osc
call
read_EEPROM_freq
;
; Initialize other variables.
;
clrf
clrf
;
; Get the power
;
movf
movwf
movlw
andwf
movwf
last_dir
PB_flags
on encoder value.
PORTA,w
ren_read
ENCODER_BITS
ren_read,w
ren_old
;
;
;
;
;
Read port A
Save it in ren_read
Get encoder mask (RA0 and RA1)
Get encoder bits
Save in ren_old
;
; Enter Calibrate Mode if push button is pressed while applying power
;
btfss
call
call
ren_read,PB_1
calibrate
;
;
;
read_sweep_freqs ;
;
; *****************************************************************************
;
;
Function: main
;
;
Purpose: This is the Main Program Loop. This section collects the
;
starting and ending sweep frequencies, the frequency increment
;
and the marker frequency from the user. This information is
;
then stored in EEPROM for later use. When all of the parameters
;
have been collected, the sweep function is called to perform
;
the frequency sweeps. When the user presses the appropriate
;
button on the PICEL board, the sweep terminates and control
;
returns back to main.
;
;
Input: No explicit inputs.
;
;
Output: No explicit outputs.
;
;
Revisions:
;
Ver 1.0 New function 4-20-04 W3CD
;
;*********************************************************************
main
movlw
call
f_start
get_frequency
movlw
call
call
btfss
goto
f_end
get_frequency
check_end
STATUS,C
get_step
call
movlw
call
call
clear_lcd
end_err_msg
display_message
wait_512ms
;
;
;
;
;
;
;
;
;
;
get_end
Ending frequency structure
Get the ending frequency
Make sure that end > start
If carry is set, then all's well.
Go get the next parameter
Else, there is a problem.
Erase LCD
Flash error message
Display for 1/2 second
goto
get_end
movlw
call
f_step
get_frequency
movlw
call
f_marker
get_frequency
call
call
write_sweep_freqs
sweep
call
call
goto
read_sweep_freqs
get_decade
main
get_step
;******************************************************************************
;
;
Function: get_frequency
;
;
Purpose: Get the user-specified frequency
;
;
Inputs: W points to the data structure which contains the
;
pertinent data
;
User enters the frequency using the shaft encoder.
;
PB3 is pressed to accept the displayed value.
;
;
Outputs: The LCD displays the current frequency.
;
The DDS is updated as the frequency selection changes.
;
X_freq_3..0 contain the current frequency data when
;
PB3 is pressed.
;
;
Revsisions:
;
Ver 1.0: New function 4-21-04 W3CD
;
;*******************************************************************************
get_frequency
movwf
call
movwf
call
call
fstruct_ptr
f_struct_table
led_states
set_leds
clear_lcd
;
;
;
;
;
movf
addlw
call
call
call
fstruct_ptr,w
MSG_OFFSET
f_struct_table
display_message
wait_512ms
movf
addlw
call
movwf
clrw
call
fstruct_ptr,w
DEC_OFFSET
f_struct_table
decade
;
;
;
;
;
;
;
;
;
;
;
;
update_decade
call
movf
addlw
call
movwf
clear_lcd
fstruct_ptr,w
RAM_OFFSET
f_struct_table
freq_pointer
;
;
;
;
;
call
call
call
show_freq
update_dds
send_dds_word
get_freq_1
call
btfsc
goto
poll_encoder
PB_flags,F_SET
get_freq_2
call
goto
step
get_freq_1
get_freq_2
bcf
PB_flags,F_SET
return
;
;
;
;
;
;
Erase contents
Get the struct pointer
Add in frequency data offset
Get the pointer to frequency data storage
Save this for the following operations
;******************************************************************************
;
;
Function: check_end
;
;
Purpose: Compares the start and end frequencies. If end freq is
;
greater than start freq, the Carry flag is clear. Otherwise,
;
it is set, indicating that end_freq <= start_freq.
;
;
Inputs: start_freq and end_freq contain the user-specified data
;
;
Outputs: Carry flag
;
;
Revsisions:
;
Ver 1.0: New function 4-26-04 W3CD
;
;******************************************************************************
check_end
movf
movwf
movf
movwf
movf
movwf
movf
movwf
start_freq_0,w
AD9850_0
start_freq_1,w
AD9850_1
start_freq_2,w
AD9850_2
start_freq_3,w
AD9850_3
movlw end_freq_3
movwf FSR
call
check_freq_status
return
;
;
;
;
;
;
;
;
;
;
;
;
;
;******************************************************************************
;
;
Function: sweep
;
;
Purpose: Produces a swept frequency output from start_freq to end_freq.
;
It also sets high the PIC RA2 output bit when the marker
;
frequency has been met and exceeded. This marker bit is cleared
;
when the sweep returns to start_freq.
;
;
This function precalculates the DDS data for start_freq,
;
end_freq, step_freq and marker_freq to avoid using calc_dds_word
;
in the loop as this function is costly in terms of time.
;
;
Inputs: start_freq_3..0, end_freq_3..0, step_freq_3..0,
;
marker_freq_3..0, PB_flags
;
;
Outputs: DDS produces swept frequency output until the user presses the
;
appropriate pushbutton to stop.
;
;
Revisions:
;
Rev 1.0: New function. 4-21-04 W3CD
;
;*******************************************************************************
sweep
bsf
movlw
movwf
call
movlw
call
step_freq_0
freq_pointer
calc_dds_word
fstep_0
copy_dds_word
;
;
;
;
;
;
movlw
call
end_freq_0
convert_to_dds
movlw
call
marker_freq_0
convert_to_dds
call
movlw
call
clear_lcd
sweep_msg
display_message
g
Get frequency increment address
Store it in freq_pointer
Convert it to DDS data in AD9850_3..0
Copy target address is fstep_3..0
Copy AD9850_3..0 to fstep
sweep_start
bcf
movlw
movwf
call
PORTA,MARKER
start_freq_0
freq_pointer
calc_dds_word
movlw
movwf
AD9850_0
freq_pointer
sweep_loop
call
btfsc
goto
pb_2_check
PB_flags,F_SET
sweep_end
;
;
;
;
;
;
;
;
call
send_dds_word
;
;
;
;
;
movlw
marker_freq_3
movwf
call
btfsc
FSR
check_freq_status
STATUS,C
; into FSR
; Check if it's time to raise the marker
; If carry is clear, then marker freq reache
bsf
PORTA, MARKER
call
add_step
movlw
movwf
call
btfsc
goto
goto
end_freq_3
FSR
check_freq_status
STATUS,C
sweep_start
sweep_loop
;
;
;
;
;
;
;
;
d
ed
sweep_end
clrf
PB_flags
bsf
PORTA,MARKER
return
;******************************************************************************
;
;
Function: convert_to_dds
;
;
Purpose: Converts the 4-byte frequency value pointed to by W
;
into DDS-compatible data and store it back into the
;
supplied frequency address. Support function for sweep.
;
;
Inputs: W points to X_freq_0
;
;
Outputs: X_freq_3..0 contain the DDS-compatible data
;
;
Revisions:
;
Rev 1.0: New function. 4-21-04 W3CD
;
;*******************************************************************************
convert_to_dds
movwf
call
freq_pointer
calc_dds_word
s 0
movf
freq_pointer,w
call
copy_dds_word
return
;
;
;
;
;******************************************************************************
;
;
Function: check_freq_status
;
;
Purpose: Compares the frequency registers pointed to by FSR against
;
the AD98503..0 bytes.
;
;
Inputs: FSR points to X_freq_3 data to be tested
;
AD9850_3..0 contain the current DDS word
;
;
Outputs: Carry flag is set if X_freq_3..0 >= AD9850_3..0,
;
Else, Carry is clear
;
;
Revisions:
;
Rev 1.0: New function. 4-22-04 W3CD
;
;*******************************************************************************
check_freq_status
movf
subwf
btfss
goto
INDF,w
AD9850_3,w
STATUS,C
check_freq_end
btfss
goto
STATUS,Z
check_freq_end
decf
movf
subwf
btfss
goto
FSR,f
INDF,w
AD9850_2,w
STATUS,C
check_freq_end
btfss
goto
STATUS,Z
check_freq_end
decf
movf
subwf
btfss
goto
FSR,f
INDF,w
AD9850_1,w
STATUS,C
check_freq_end
btfss
goto
STATUS,Z
check_freq_end
decf
movf
subwf
FSR,f
INDF,w
AD9850_0,w
check_freq_end
return
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;******************************************************************************
;
;
Function: copy_dds_word
;
;
Purpose: Copies the AD0950_3..0 bytes to the frequency registers
;
pointed to by FSR
;
;
Inputs: FSR points to X_freq_0 destination
;
AD9850_3..0 contain the current DDS word to be copied
;
;
Outputs: X_freq_3..0 contain AD9850_3..0 data
;
;
Revisions:
;
Rev 1.0: New function. 4-22-04 W3CD
;
;*******************************************************************************
copy_dds_word
movwf
movf
movwf
incf
movf
movwf
incf
movf
movwf
incf
movf
movwf
return
FSR
AD9850_0,w
INDF
FSR,f
AD9850_1,w
INDF
FSR,f
AD9850_2,w
INDF
FSR,f
AD9850_3,w
INDF
;
;
;
;
;
;
;******************************************************************************
;
;
Function: step
;
;
Purpose: Adjusts the frequency by examining the last_dir value and either
;
adds or subtracts the value of fstep_3..0 from the current
;
frequency setting.
;
;
Inputs: last_dir
;
;
Outputs: Adjusts the operating frequency up or down, based on last_dir.
;
the operating frequency is specified by freq_pointer, which
;
is implicitly used here.
;
;
Revisions:
;
Rev 1.0: Copied from PICELGen 2.0 and adapted for use here
;
4-21-04 W3CD
;
;*******************************************************************************
step
btfsc
goto
;
;
;
last_dir,DIR_BIT ;
up
;
call
goto
sub_step
update
call
call
add_step
check_add
call
call
show_freq
update_dds
down
up
update
return
; Back to caller.
; *****************************************************************************
;
;
Function: add_step
;
;
Purpose: This routine adds the 32 bit value of fstep to the 32 bit
;
value in freq. When incrementing, the fstep value is a
;
positive integer. When decrementing, fstep is the complement
;
of the value being subtracted.
;
;
Input: The 32 bit values in fstep and the value pointed to by
;
freq_pointer
;
;
Output: The sum of fstep and the value pointed to by freq_pointer
;
is stored in freq. When incrementing this value may exceed
;
the maximum. When decrementing, it may go negative.
;
;
Revisions:
;
Rev 1.0: Copied from PICELGen Rev 2.0. Modified for use with
;
any frequency variable 4-21-04 W3CD.
;
; *****************************************************************************
add_step
clrf
temp
movf
movwf
freq_pointer,w
FSR
movf
addwf
fstep_0,w
INDF,f
movlw
movwf
call
decf
decf
3
count
ripple_carry
FSR,f
FSR,f
movf
addwf
movlw
movwf
call
decf
fstep_1,w
INDF,f
2
count
ripple_carry
FSR,f
movf
addwf
incf
btfss
goto
incf
add_step1
movf
addwf
return
fstep_2,w
INDF,f
FSR,f
STATUS,C
add_step1
INDF,f
fstep_3,w
INDF,f
; *****************************************************************************
;
;
Function: ripple_carry
;
;
Purpose: This function propagates carries that result from addition
;
into the higher order bytes of the frequency registers
;
;
Input: FSR points to the register which was just added,
;
temp is cleared by the caller
;
count is set to the number of higher order bytes to process
;
;
Output: Any carry resulting from an addition is propagated into the
;
number of higher order bytes specified by count
;
;
Revisions:
;
Rev 1.0: Copied from PICELGen 2.0. 4-20-04 W3CD
;
; *****************************************************************************
ripple_carry
rlf
incf
addwf
decfsz
goto
return
temp,w
FSR,f
INDF,f
count,f
ripple_carry
;
;
;
;
;
;
; *****************************************************************************
;
;
Function: check_add
;
;
Purpose: Check if freq exceeds the upper limit.
;
;
Input:
vfo_select, vfo_a and vfo_b registers
;
;
Output: If freq is below the limit, it is unchanged. Otherwise, it
;
is set to equal the upper limit.
;
;
Revisions:
;
Rev 1.0: Copied from PICELGen 2.0 and modified for use with
;
any frequency variable. 4-21-04 W3CD
;
; *****************************************************************************
check_add
movlw
addwf
movwf
;
;
;
TABLE_ADJUST
freq_pointer,w
FSR
;
;
;
;
limit_3
INDF,w
STATUS,C
check_exit
STATUS,Z
set_max
;
;
;
;
;
;
;
;
;
Check the second most significant byte when MSB equals limit_3
decf
movlw
subwf
btfss
goto
btfss
goto
;
;
;
;
;
;
;
;
;
;
;
;
;
FSR,f
limit_2
INDF,w
STATUS,C
check_exit
STATUS,Z
set_max
FSR,f
limit_1
INDF,w
STATUS,C
check_exit
STATUS,Z
set_max
;
;
;
;
;
;
;
FSR,f
limit_0
INDF,w
STATUS,C
check_exit
;
;
;
;
;
;
Point to LSB
Fourth limit byte
Subtract limit value
Are we at the limit for the byte?
No, below. Checks are done.
Else, it's freq is over limit
movf
movwf
freq_pointer,w
FSR
movlw
movwf
limit_0
INDF
;
;
;
;
;
incf
movlw
movwf
FSR,f
limit_1
INDF
; Point to X_freq_1
; Get next limit byte
; Store it in X_freq_1
incf
movlw
movwf
FSR,f
limit_2
INDF
; Point to X_freq_2
; Get the next limit byte
; Store it in X_freq_2
incf
movlw
movwf
FSR,f
limit_3
INDF
; Point to X_freq_3
; Get the high byte of limit
; Store it in X_freq_3
set_max
check_exit
return
; *****************************************************************************
;
;
Function: sub_step
;
;
Purpose: Subtract the increment step from freq, checking that it does
;
not go below zero.
;
;
Input:
The values in fstep and freq.
;
;
Output: The updated value in freq.
;
;
Revisions:
;
Rev 1.0: Copied from PICELGen 2.0 4-20-04 W3CD
;
; *****************************************************************************
sub_step
call
call
invert_fstep
add_step
movlw
addwf
movwf
TABLE_ADJUST
freq_pointer,w
FSR
;
;
;
;
btfss
goto
INDF,MSB
sub_step_exit
clrf
decf
clrf
decf
clrf
decf
clrf
INDF
FSR,f
INDF
FSR,f
INDF
FSR,f
INDF
;
;
;
;
;
;
;
set_min
sub_step_exit
call
invert_fstep
return
Clear X_freq_3
Next byte
Clear X_freq_2
Next byte
Clear X_freq_1
Last byte
Clear X_freq_0
;*****************************************************************************
;
;
Function: invert_fstep
;
;
Purpose: Support function for sub_step and calibrate. This function
;
negates the value of fstep_3..0 to assist in the frequency
;
decrement. This operation is performed twice by sub_step, and
;
is also used by calibrate.
;
;
Input:
fstep_3, fstep_2, fstep_1, fstep_0
;
;
Output:
fstep_3..0 contain the 2's complement of their original value
;
;
Revisions:
;
Rev 1.0 Copied from PICELGen 2.0 4-20-04 W3CD
;
; *****************************************************************************
invert_fstep
comf
comf
comf
comf
incfsz
goto
fstep_0,f
fstep_1,f
fstep_2,f
fstep_3,f
fstep_0,f
invert_done
;
;
;
;
;
;
;
incfsz fstep_1,f
goto
invert_done
incfsz fstep_2,f
goto
invert_done
incf
fstep_3,f
invert_done
return
;
;
;
;
;
;
;
;
; Back to caller
;*****************************************************************************
;
; Function: poll_encoder
;
; Purpose: This routine does the following:
;
1. Reads the encoder bits until a change is detected, then
;
determines the direction the knob was moved.
;
2. Performs PIC-EL mechanical shaft encoder debounce and
;
detent processing is so enabled.
;
3. Reads PB_2 and determines if a band change is
;
requested.
;
;
Input: Knob input read from port A
;
PB_2
;
ren_old -> the last encoder bits read
;
last_dir -> the last direction moved
;
;
Output: ren_read: The contents of PORTA when the encoder was moved
;
ren_new: The current encoder bits
;
last_dir: The last direction (0 = down, 2 = up [AKA UP_BIT])
;
;
Revisions:
;
;
Ver 1.0: Copied from PICELGen 2.0 and modified for use here
;
4-20-04 W3CD
;
;*****************************************************************************
poll_encoder
call
btfsc
goto
movf
movwf
process_pb
PB_flags,F_SET
pe_exit
PORTA,w
ren_read
IFDEF DETENT_ENCODER
call
wait_1ms
movf
PORTA,w
xorwf ren_read,w
btfss STATUS,Z
goto
poll_encoder
ENDIF
movlw
andwf
movwf
ENCODER_BITS
ren_read,w
ren_new
;
;
;
;
;
debounce time
read the port again
Compare with previous value
Are they equal?
Poll again if not
xorwf
btfsc
goto
ren_old,w
STATUS,Z
poll_encoder
;
;
;
;
Has it changed?
Check zero-flag (zero if no change)
No change, keep looking until it changes
Else, Zero-flag is not set, so continue on
;
;
;
;
;
;
;
pe_continue
clrf
btfsc
goto
last_dir
ren_old,DIR_BIT
pe_up
IFDEF DETENT_ENCODER
movf
ren_new,w
movwf ren_old
decf
enc_counter,f
btfsc enc_counter,0
goto
poll_encoder
btfsc enc_counter,1
goto
poll_encoder
;
;
;
;
;
;
;
;
;
;
;
;
ENDIF
goto
pe_movement
movlw
movwf
UP_BIT
last_dir
; Get UP value
; and set in last_dir
pe_up
IFDEF DETENT_ENCODER
movf
ren_new,w
movwf ren_old
incf
enc_counter,f
btfsc enc_counter,0
goto
poll_encoder
btfsc enc_counter,1
goto
poll_encoder
ENDIF
pe_movement
movf
movwf
;
;
;
;
;
ren_new,w
ren_old
pe_exit
return
;****************************************************************************
;
;
Function: process_pb
;
;
Purpose: This function examines the state of PB_1 and PB_2
;
and has mulitple operating characteristics.
;
;
1. Pressing and releasing PB1 alone moves the cursor left
;
one position and increments the decade to be adjusted
;
by the shaft encoder. The cursor and frequency decade
;
wrap around the 10 MHz position to the 1 Hz position.
;
;
2. Pressing and holding PB1 for more than 1 second starts
;
the auto-repeat function and the decade are updated
;
continuously until PB1 is released. The update rate
;
is 4 times/sec.
;
;
3. Pressing PB2 alone sets the F_SET flag. This tells
;
higher order functions that the selected frequency
;
has been accepted, or in the case of active sweeping,
;
causes the sweep to terminate.
;
;
4. Pressing PB2 while PB1 is held down moves the cursor
;
to the right and the frequency decade is decreased
;
accordingly.
;
;
5. Holding PB1 and PB2 down for more than 1 second enables
;
the auto-repeat function and the cursor moves to the
;
right at a rate of 4 times/sec.
;
;
;
Inputs:
PORTA bits PB_1 and PB_2 and PB_flags
;
;
Outputs: If a button is pressed, then various control variables are
;
updated. The function exits if no buttons are pressed.
;
;
Revisions:
;
Ver 1.0: Copied from PICELGen 2.0 and modified extensively for
;
use here. 4-20-04 W3CD
;
;****************************************************************************
process_pb
btfsc
goto
btfsc
goto
btfss
goto
process_pb_1
movlw
movwf
bcf
pb_1_release_wait
call
wait_32ms
btfsc PORTA,PB_1
goto
pb_1_released
btfss
goto
PORTA,PB_2
process_both
decf
btfss
goto
PB_wait_count,f
STATUS,Z
pb_1_release_wait
movlw
call
DECADE_INCREMENT
update_decade
movlw
movwf
PB_RPT_DLY
PB_wait_count
bsf
bcf
goto
;
;
;
PB_flags,PB_RPT_FLG ;
PB_flags,PB_2_PRESS ;
pb_1_release_wait ;
pb_1_released
movlw
btfsc
goto
goto
DECADE_INCREMENT
PB_flags,PB_2_PRESS
process_pb_exit
process_pb_release
;
;
;
;
;
;******************************************************************************
;
;
Arrive here when PB_1 was not pressed. Check for PB_2 activity, which
; indicates that the displayed frequency has been accepted. If PB_1 is pressed
; during the PB_2 release wait, handle cursor right movement.
;
;******************************************************************************
pb_2_check
btfsc
goto
PORTA,PB_2
process_pb_exit
pb_2_release_wait
call
wait_32ms
btfsc PORTA,PB_2
goto
pb_2_released
btfsc
goto
btfss
goto
goto
pb_2_released
bsf
goto
;************************************************************************
;
;
Arrive here when both PB_1 and PB_2 were pressed.
;
;************************************************************************
process_both
movlw
movwf
bcf
bsf
PB_RPT_WAIT
PB_wait_count
PB_flags,PB_RPT_FLG
PB_flags,PB_2_PRESS
both_release_wait
call
btfsc
goto
btfsc
goto
wait_32ms
PORTA,PB_1
pb_both_done
PORTA,PB_2
pb_both_done
decf
btfss
goto
PB_wait_count,f
STATUS,Z
both_release_wait
;
;
;
;
;
;
;
;
;
;
movlw
call
DECADE_DECREMENT
update_decade
movlw
movwf
bsf
goto
PB_RPT_DLY
PB_wait_count
PB_flags,PB_RPT_FLG
both_release_wait
;
;
;
;
DECADE_DECREMENT
pb_both_done
movlw
;************************************************************************
;
;
Common code to handle the release of either PB_1 or PB_2 in the
;
decade adjust mode. Wreg contains the decade adjustment value.
;
;************************************************************************
process_pb_release
btfsc
goto
addwf
andlw
decade,w
DECADE_MASK
movwf
call
movwf
call
call
return
decade
cursor_table
cur_pos
get_decade
show_freq
;
;
;
;
;
;
;
;
;
;****************************************************************************
;
;
Function: get_decade
;
;
Purpose: Support function which sets new increment values for
;
fstep_3 through fstep_0 using values in decade_table
;
;
Inputs:
decade
;
;
Outputs: fstep_3, fstep_2, fstep_1 and fstep_0 are updated
;
;
Revisions:
;
Ver 1.0 Copied from PICELGen 2.0 4-20-04 W3CD
;
;****************************************************************************
get_decade
movlw
movwf
movlw
movwf
movf
movwf
bcf
rlf
rlf
get_decade_loop
movf
call
movwf
decf
incf
decfsz
goto
return
FREQ_COUNT
count
fstep_3
FSR
decade,w
temp
STATUS,C
temp,f
temp,f
;
;
;
;
;
;
;
;
;
temp,w
decade_table
INDF
FSR,f
temp,f
count,f
get_decade_loop
;
;
;
;
;
;
;
;
;
; *****************************************************************************
;
;
Function: calibrate
;
;
Purpose: This routine is entered at start up if the calibrate
;
push button is (PIC-EL PB_1) is pressed at power-on time.
;
;
If a 8-character LCD is used,"10000000" is displayed
;
If a 16-character LCD is used," 10,000.000 CAL " is displayed
;
;
The DDS chip is programmed to produce 10 MHz, based on the
;
osc value stored in the EEPROM. As long as the button is
;
pressed, the osc value is slowly altered to allow the output
;
to be trimmed to exactly 10 MHz. Once the encoder is turned
;
after the button is released, the new osc value is stored in
;
the EEPROM and normal operation begins.
;
;
Input:
The original osc constant in EEPROM
;
;
Output: The corrected osc constant in EEPROM
;
;
Revisions:
;
Rev 1.0: Copied from PICELGen 2.0 and replaced code that added
;
fstep to frequency with a call to add_step. This saves
;
program space. 4-22-04 W3CD.
;
; *****************************************************************************
calibrate
bsf
movlw
movwf
movlw
call
start_freq_0
FSR
EEcal_freq
read_EEPROM_freq
;
;
;
;
movlw
movwf
call
start_freq_0
freq_pointer
show_freq
ave
; already been read from EEPROM. Convert ref
erence
; freq and display it.
IF LCDCHAR == 16
IF LCD16_LINEAR == 0
movlw PICEL_LONG_9 + 4
D
ELSE
movlw
call
movlw
call
cmnd2LCD
cal_msg
display_message
;
;
;
;
call
call
update_dds
poll_encoder
btfsc
goto
PORTA,PB_1
cal_done
clrf
clrf
clrf
fstep_3
fstep_2
fstep_1
movlw
SMALL_FSTEP
;
;
;
;
;
;
;
;
ENDIF
ENDIF
cal_loop
btfss
movlw
ren_read,PB_2
LARGE_FSTEP
movwf
btfsc
goto
fstep_0
last_dir,DIR_BIT
faster
call
invert_fstep
;
;
;
;
;
;
;
;
p
; and continue
faster
movlw
movwf
call
osc_0
freq_pointer
add_step
movlw
movwf
goto
start_freq_0
freq_pointer
cal_loop
cal_done
movlw
movwf
clrw
call
bcf
return
;
;
;
;
write_EEPROM_freq ;
PB_flags,PB_CS_FLG ;
;
osc_0
FSR
;*****************************************************************************
;
;
Function: calc_dds_word
;
;
Purpose: Multiply the 32 bit number for oscillator frequency times the
;
32 bit number for the displayed frequency.
;
;
Input:
The reference oscillator value in osc_3 ... osc_0 and the
;
current frequency stored in freq_3 ... freq_0. The reference
;
oscillator value is treated as a fixed point real, with a 24
;
bit mantissa.
;
;
Output: The result is stored in AD9850_3 ... AD9850_0.
;
;
Revision:
;
Ver 1.0: Copied from PICELGen 2.0 4-20-04 W3CD
;
; *****************************************************************************
calc_dds_word
clrf
clrf
clrf
clrf
clrf
movlw
movwf
movf
movwf
movf
movwf
movf
AD9850_0
AD9850_1
AD9850_2
AD9850_3
AD9850_4
0x20
count
osc_0,w
temp_freq_0
osc_1,w
temp_freq_1
osc_2,w
;
;
;
;
;
;
;
;
;
;
;
;
movwf
movf
movwf
movf
mult_loop
movwf
ddr.
bcf
btfss
goto
movf
addwf
btfss
goto
incfsz
goto
incfsz
goto
incf
add7
incf
movf
addwf
btfss
goto
incfsz
goto
incf
add8
incf
movf
addwf
btfss
goto
incf
add9
incf
movf
addwf
noAdd
rrf
rrf
rrf
rrf
rrf
rrf
rrf
rrf
rrf
temp_freq_2
osc_3,w
temp_freq_3
freq_pointer,w
;
;
;
; Now develop the active vfo frequency pointer
; Get pointer to X_freq_0
FSR
STATUS,C
temp_freq_0,0
noAdd
INDF,w
AD9850_1,f
STATUS,C
add7
AD9850_2,f
add7
AD9850_3,f
add7
AD9850_4,f
;
;
;
;
;
;
;
;
;
;
;
;
FSR,f
INDF,w
AD9850_2,f
STATUS,C
add8
AD9850_3,f
add8
AD9850_4,f
;
;
;
;
;
;
;
;
Point to X_freq_1
Use the X_freq_1 term
Add freq term to total in correct position
Does this addition result in a carry?
No, continue with next freq term
Yes, add one and check for another carry
No, continue with next freq term
Yes, add one and continue
FSR,f
INDF,w
AD9850_3,f
STATUS,C
add9
AD9850_4,f
;
;
;
;
;
;
Point to X_freq_2
Use the freq_2 term
Add freq term to total in correct position
Does this addition result in a carry?
No, continue with next freq term
Yes, add one and continue
FSR,f
INDF,w
AD9850_4,f
; Point to X_freq_3
; Use the X_freq_3 term
; Add freq term to total in correct position
AD9850_4,f
AD9850_3,f
AD9850_2,f
AD9850_1,f
AD9850_0,f
temp_freq_3,f
temp_freq_2,f
temp_freq_1,f
temp_freq_0,f
;
;
;
;
;
;
;
;
;
movf
freq_pointer,w
decfsz count,f
goto
mult_loop
;
clrf
AD9850_4
(un-comment for AD9850)
movlw 0x01
26/2/12 (comment out for AD9850)
movwf AD9850_4
t out for AD9850)
return
; Done.
; *****************************************************************************
;
;
Function: update_dds, send_dds_word
;
;
Purpose: This routine sends the AD9850 control word to the DDS chip
;
using a serial data transfer. The first entry point, update_dds,
;
calls calc_dds_word to determine the AD9850 data. The second
;
call is used when the DDS data is already calculated.
;
;
Input:
update_dds: freq_pointer points to the frequency value to be
;
converted to DDS data before sending to DDS.
;
;
send_dds_word: AD9850_4 ... AD9850_0 contain the data to send.
;
;
Output: The DDS chip register is updated.
;
;
Revsisions:
;
Rev 1.0: Copied from PICELGen 2.0 and added call to calc_dds_word
;
to reduce program space, since this happens quite often.
;
4-21-04 W3CD.
;
; *****************************************************************************
update_dds
call
send_dds_word
movlw
movwf
next_byte
movf
movwf
movlw
movwf
next_bit
rrf
btfss
goto
bsf
bsf
bcf
goto
send0
bcf
bsf
bcf
break
decfsz
goto
incf
movlw
subwf
btfss
goto
bsf
bcf
call
calc_dds_word
AD9850_0
FSR
INDF,w
byte2send
0x08
bit_count
;
;
; Set counter to 8
;
byte2send,f
STATUS,C
send0
PORTB,DDS_dat
PORTB,DDS_clk
PORTB,DDS_clk
break
;
;
;
;
;
;
;
PORTB,DDS_dat
PORTB,DDS_clk
PORTB,DDS_clk
; Send zero
; Toggle write clock
;
bit_count,f
next_bit
FSR,f
AD9850_4+1
FSR,w
STATUS,C
next_byte
PORTB,DDS_load
PORTB,DDS_load
;
;
;
;
;
;
;
;
;
set_leds
return
;
;
;
;
;
;
;
;
;
;
;
;
;
; Back to caller
*****************************************************************************
*
*
* Purpose: 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 8x1 or a 16x1 display.
P
*
*
* Input: None
*
*
*
* Output: None
*
*
*
*****************************************************************************
init_LCD
call
movlw
movwf
bsf
call
bcf
movlw
movwf
bsf
call
bcf
movlw
movwf
bsf
call
bcf
movlw
movwf
bsf
call
bcf
movlw
call
movlw
call
movlw
call
movlw
call
wait_64ms
CMD_RESET_LCD
PORTB
PORTB,LCD_e
wait_64ms
PORTB,LCD_e
CMD_RESET_LCD
PORTB
PORTB,LCD_e
wait_32ms
PORTB,LCD_e
CMD_RESET_LCD
PORTB
PORTB,LCD_e
wait_32ms
PORTB,LCD_e
PICEL_IFC1
PORTB
PORTB,LCD_e
wait_16ms
PORTB,LCD_e
PICEL_IFC2
cmnd2LCD
PICEL_DISPLAY_OFF
cmnd2LCD
CMD_CLEAR_LCD
cmnd2LCD
PICEL_CURSOR_RT
cmnd2LCD
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
; ****************************************************************************
display_version
movlw
call
sign_on_msg
display_message
IF LCDCHAR == 8
call
wait_a_sec
; Let it sit a while
movlw CMD_MOV_CUR_DISP ; Home the cursor
call
cmnd2LCD
ELSE
IF LCD16_LINEAR == 0
movlw PICEL_LONG_9
call
cmnd2LCD
ENDIF
ENDIF
movlw ver_msg
call
display_message
call
wait_a_sec
return
;*******************************************************************************
;
;
Function: display_message
;
;
Purpose: Displays the selected message in message_table on the LCD
;
;
Input:
Wreg contains the offset of the desired message to display
;
;
Output:
Message is displayed on LCD
;
;
Revisions:
;
Rev 1.0: Copied from PICELGen 2.0 4-20-04 W3CD
;
;*******************************************************************************
display_message
movwf message_pointer
display_loop
call
andlw
btfsc
goto
message_table
FLAG_MASK
STATUS, Z
display_exit
;
;
;
;
data2LCD
message_pointer,f
message_pointer,w
display_loop
;
;
;
;
call
incf
movf
goto
display_exit
return
; *****************************************************************************
;
;
Function: bin2BCD
;
;
Purpose: This subroutine converts a 32 bit binary number to a 10 digit
;
BCD number. The input value taken from freq(0 to 3) is
;
preserved. The output is in BCD(0 to 4), each byte holds =>
;
(hi_digit,lo_digit), most significant digits are in BCD_4.
;
This routine is a modified version of one described in
;
MicroChip application note AN526.
;
;
Input:
The value in freq_0 ... freq_3
;
;
Output: The BCD number in BCD_0 ... BCD_4
;
;
Revisions:
;
Rev. 1.0: Copied from PICELGen 2.0 and modified to use any
;
frequency variable 4-21-04 W3CD.
;
; *****************************************************************************
bin2BCD
movlw
movwf
clrf
clrf
clrf
clrf
clrf
0x20
BCD_count
BCD_0
BCD_1
BCD_2
BCD_3
BCD_4
;
; Unable to use indirect addressing here, so copy the active VFO
; data to freq3..0 for use by this function
;
movf freq_pointer,w
movwf FSR
movf
movwf
incf
movf
movwf
incf
movf
movwf
incf
movf
movwf
;
;
;
;
;
;
;
;
;
;
;
;
INDF,w
temp_freq_0
FSR,f
INDF,w
temp_freq_1
FSR,f
INDF,w
temp_freq_2
FSR,f
INDF,w
temp_freq_3
bin_loop
bcf
STATUS,C
;
; Rotate bits in freq bytes. Move from LS
; Likewise, move from freq_1 to freq_2 and
;
rlf
temp_freq_0,f
; Rotate
rlf
temp_freq_1,f
; Rotate
rlf
temp_freq_2,f
; Rotate
rlf
btfsc
bsf
temp_freq_3,f
STATUS,C
temp_freq_0,0
;
; Build BCD bytes. Move into LS bit of BCD bytes (LS of BCD_0) from MS bit of
; freq_3 via the Carry bit.
;
rlf
BCD_0,f
; Rotate left, Carry->LS bit, MS bit->Carry
rlf
BCD_1,f
; Rotate left, Carry->LS bit, MS bit->Carry
rlf
BCD_2,f
; Rotate left, Carry->LS bit, MS bit->Carry
rlf
BCD_3,f
; Rotate left, Carry->LS bit, MS bit->Carry
rlf
BCD_4,f
; Rotate left, Carry->LS bit, MS bit->Carry
decf
BCD_count,f
; Decrement loop count
btfss STATUS,Z
; Is loop count now zero?
goto
adjust
; No, go to adjust
return
; Yes, EXIT
; ============================================================================
; Internal subroutine, called by bin2BCD main loop only
;
; As BCD bytes are being built, make sure the nibbles do not grow larger than 9.
; If a nibble gets larger than 9, increment to next higher nibble.
; (If the LS nibble of a byte overflows, increment the MS nibble of that byte.)
; (If the MS nibble of a byte overflows, increment the LS nibble of next byte.)
;
adjust
movlw BCD_0
; Get pointer to BCD_0
movwf FSR
; Put pointer in FSR for indirect addressing
call
adj_BCD
;
incf
FSR,f
; Move indirect addressing pointer to BCD_1
call
adj_BCD
;
incf
FSR,f
; Move indirect addressing pointer to BCD_2
call
adj_BCD
;
incf
FSR,f
; Move indirect addressing pointer to BCD_3
call
adj_BCD
;
incf
FSR,f
; Move indirect addressing pointer to BCD_4
call
adj_BCD
;
goto
bin_loop
; Back to main loop of bin2BCD
; ============================================================================
adj_BCD ; Internal subroutine, called by adjust only
movlw 3
; Add 3
addwf INDF,w
; to LS digit
movwf BCD_temp
; Save in temp
btfsc BCD_temp,3
; Is LS digit + 3 > 7 (Bit 3 set)
movwf INDF
; Yes, save incremented value as LS digit
movlw 0x30
; Add 3
addwf INDF,w
; to MS digit
movwf BCD_temp
; Save as temp
btfsc BCD_temp,7
; Is MS digit + 3 > 7 (Bit 7 set)
movwf INDF
; Yes, save incremented value as MS digit
return
; Return to adjust subroutine
; *****************************************************************************
;
;
Function: show_freq
;
;
Purpose: Display the frequency setting on the LCD.
;
If a 1x8 LCD display so display freq in Hz - e.g. 14025000
;
If a 1x16 LCD display so display freq kHz - e.g 14,025.000 kHz
;
;
Input:
The values in BCD_4 ... BCD_0
;
;
Output: The number displayed on the LCD
;
;
Revisions:
;
Rev 1.0 Copied from PICELGen 2.0 and modified to reduce program
;
space by substituting repetitive operations with calls
;
to send_digit. 4-21-04 W3CD
;
; *****************************************************************************
show_freq
call
movlw
call
bin2BCD
; Convert the binary freq. to BCD for display
CMD_HOME_CUR_LCD ; Point the LCD to first LCD digit location
cmnd2LCD
; Send starting digit location to LCD
IF LCDCHAR == 16
movlw ' '
call
data2LCD
ENDIF
swapf
call
movf
call
BCD_3,w
send_digit
BCD_3,w
send_digit
IF LCDCHAR == 16
movlw ','
call
data2LCD
ENDIF
swapf
call
movf
call
swapf
call
BCD_2,w
send_digit
BCD_2,w
send_digit
BCD_1,w
send_digit
IF LCDCHAR == 16
movlw '.'
call
data2LCD
IF LCD16_LINEAR == 0
movlw PICEL_LONG_9
call
cmnd2LCD
ENDIF
ENDIF
movf
call
swapf
call
movf
call
BCD_1,w
send_digit
BCD_0,w
send_digit
BCD_0,w
send_digit
IF LCDCHAR == 16
movlw khz_msg
; Send a space
; to position 1 of LCD
;
;
;
;
;
;
; Get a comma
; Send it to LCD
;
;
;
;
;
;
; Get a period
; Send it to LCD
; If using the AmQRP 16x1 LCD,
; point to LCD digit number nine
; Send command byte in W to LCD
;
;
;
;
;
;
call
display_message
; Position 16 is blank
call
set_cursor_pos
ENDIF
call
set_leds
return
; *****************************************************************************
;
;
Function: send_digit
;
;
Purpose: Formats a BCD digit into ASCII and sends it to the LCD.
;
This is a support function for show_freq.
;
;
Input:
The low nybble of W contains the BCD digit to send
;
;
Output: The formatted digit is send to the LCD
;
;
Revisions:
;
;
Rev 1.0 Added function to reduce program size 4-21-04 W3CD.
;
; *****************************************************************************
send_digit
andlw
addlw
goto
LOW_NYBBLE_MASK
ASCII_NUM_BASE
data2LCD
;
;
;
;
; *****************************************************************************
;
;
Function: set_cursor_pos
;
;
Purpose: Position cursor at the frequency digit position being updated.
;
;
Input:
The cur_pos variable holds the digit position.
;
;
Output: None
;
;
Revisions:
;
Ver 1.0 Copied from PICELGen 2.01. 4-20-04 W3CD
;
; *****************************************************************************
set_cursor_pos
IF LCDCHAR == 8
movlw CMD_MOV_CUR_DISP
iorwf cur_pos,w
ELSE
IF LCD16_LINEAR == 1
;
;
;
;
;
movlw
iorwf
CMD_MOV_CUR_DISP
cur_pos,w
movlw
subwf
btfsc
goto
LCD_POS_9
cur_pos,w
STATUS,C
set_cur_1
movlw
addwf
goto
CMD_MOV_CUR_DISP
cur_pos,w
set_cur_2
;
;
;
;
;
;
;
;
ELSE
set_cur_1
addlw
set_cur_2
PICEL_LONG_9
ENDIF
ENDIF
call
cmnd2LCD
call
set_leds
return
; *****************************************************************************
;
;
Function: clear_lcd
;
;
Purpose: Clears the LCD and homes the cursor.
;
;
Input:
None
;
;
Output: None
;
;
Revisions:
;
Ver 1.0: Copied from PICELGen 2.0 4-20-04 W3CD.
;
; *****************************************************************************
clear_lcd
movlw CMD_CLEAR_LCD
call
cmnd2LCD
return
;
;
;
;
;
;
;
;
;
;
;
*****************************************************************************
*
*
* Purpose: Check if LCD is done with the last operation.
*
*
This subroutine polls the LCD busy flag to determine if
*
*
previous operations are completed.
*
*
*
* Input: None
*
*
*
* On exit: PORTB set as: RB3
input
P
*
all others outputs
P
*****************************************************************************
busy_check
clrf
bsf
movlw
PORTB
STATUS,RP0
b'00001000'
movwf
bcf
bcf
bsf
movlw
movwf
LCD_is_busy
bsf
movf
movwf
bcf
nop
nop
bsf
nop
bcf
decf
btfsc
goto
btfsc
goto
not_busy
return
;
;
;
;
;
;
;
;
;
TRISB
STATUS,RP0
PORTB,LCD_rs
PORTB,LCD_rw
0xFF
timer1
;
;
;
;
;
;
PORTB,LCD_e
PORTB,w
LCD_read
PORTB,LCD_e
;
;
;
;
;
;
PORTB,LCD_e
;
;
PORTB,LCD_e
;
timer1,f
;
STATUS,Z
;
not_busy
;
LCD_read,LCD_busy ;
LCD_is_busy
;
via Tristate
Switch back to bank 0
Set up LCD for Read Busy Flag (RS = 0)
Set up LCD for Read (RW = 1)
Set up constant 255
for timer loop counter
Set E high
Read PORTB into W
Save W for later testing
Drop E again
Wait a
while
Pulse E high (dummy read of lower nibble),
wait,
and drop E again
Decrement loop counter
Is loop counter down to zero?
If yes, return regardless
Busy Flag (RB3) in save byte clear?
If not, it is busy so jump back
*****************************************************************************
* Purpose: Send Command or Data byte to the LCD
*
*
Entry point cmnd2LCD: Send a Command to the LCD
*
*
Entry Point data2LCD: Send a Data byte to the LCD
*
*
*
* Input: W has the command or data byte to be sent to the LCD.
*
*
*
* Output: None
*
*****************************************************************************
cmnd2LCD
HI_NYBBLE_MASK
; Set up mask
andwf
PORTB,f
swapf
andlw
iorwf
bsf
nop
bcf
LCD_char,w
LOW_NYBBLE_MASK
PORTB,f
PORTB,LCD_e
;
;
;
;
;
;
PORTB,LCD_e
;
; Transfer Least Significant nibble
;
movlw HI_NYBBLE_MASK
;
andwf PORTB,f
;
movf
LCD_char,w
;
andlw LOW_NYBBLE_MASK ;
iorwf PORTB,f
;
bsf
PORTB,LCD_e
;
nop
;
bcf
PORTB,LCD_e
;
return
; *****************************************************************************
;
;
Function: read_sweep_freqs
;
;
Purpose: Reads the start, end, step and marker frequencies stored
;
in EEPROM
;
;
Input:
None
;
;
Output: start_freq_3..0, end_freq_3..0, step_freq_3..0 and
;
marker_freq_3..0 are initialized with EEPROM data
;
freq_pointer is set to start_freq_0
;
;
Revisions:
;
Ver 1.0: New function 4-22-04 W3CD.
;
; *****************************************************************************
read_sweep_freqs
movlw
movwf
movwf
movlw
call
start_freq_0
freq_pointer
FSR
EEstart_freq
read_EEPROM_freq
;
;
;
;
;
movlw
movwf
movlw
call
end_freq_0
FSR
EEend_freq
read_EEPROM_freq
;
;
;
;
movlw
movwf
movlw
call
step_freq_0
FSR
EEstep_freq
read_EEPROM_freq
;
;
;
;
movlw
marker_freq_0
movwf
movlw
call
FSR
; Save for indiect addressing
EEmarker_freq
; Point to marker freq in EEPROM
read_EEPROM_freq ; Read the freq
return
; *****************************************************************************
;
;
Function: write_sweep_freqs
;
;
Purpose: Stores start_freq_3..0, end_freq_3..0, step_freq_3..0 and
;
marker_freq_3..0 into EEPROM locations EEstart_loc,
;
EEend_loc, EEstep_loc and EEmarker_loc, respectively.
;
;
Input:
None
;
;
Output: EEPROM is updated
;
;
Revisions:
;
Ver 1.0: New function 4-22-04 W3CD.
;
; *****************************************************************************
write_sweep_freqs
movlw
movwf
movlw
call
start_freq_0
FSR
EEstart_freq
write_EEPROM_freq
;
;
;
;
movlw
movwf
movlw
call
end_freq_0
FSR
EEend_freq
write_EEPROM_freq
;
;
;
;
movlw
movwf
movlw
call
step_freq_0
FSR
EEstep_freq
write_EEPROM_freq
;
;
;
;
movlw
movwf
movlw
call
marker_freq_0
FSR
EEmarker_freq
write_EEPROM_freq
;
;
;
;
return
; *****************************************************************************
;
;
Function: read_EEPROM_freq
;
;
Purpose: Reads a 4-byte frequency value from EEPROM
;
;
Input:
FSR points to the LSB into which the frequency is copied
;
w points to LSB of EEPROM frequency data entry
;
;
Output: The 4-byte target is updated with EEPROM frequency
;
;
Revisions:
;
Ver 1.0: Copied from PICELGen 2.0 4-20-04 by W3CD.
;
Ver 1.1: Adapted to PIC16F628A. 10-04-05 W3CD
;
; *****************************************************************************
read_EEPROM_freq
movwf ee_addr
movlw FREQ_COUNT
movwf count
read_EEPROM_loop
call
read_EEPROM
movwf INDF
incf
ee_addr,f
incf
FSR,f
decfsz count,f
goto
read_EEPROM_loop
return
;
;
;
;
;
;
;
Read a byte
Store new frequency byte
Increment EEPROM read address
Point to next target address
Decrement byte count
Loop if more bytes remaining.
Back to caller
; ****************************************************************************
;
;
Function: write_EEPROM_freq
;
;
Purpose: This function saves a 4-byte frequency value in EEPROM.
;
;
Input: FSR points to the LSB of the frequency data to store
;
w points to LSB of EEPROM frequency data entry
;
;
Output: none
;
;
Revisions:
;
Ver 1.0: New function. 4-22-04 W3CD
;
Ver 1.1: Adapted to PIC16F628A. 10-04-05 W3CD
;
; ****************************************************************************
write_EEPROM_freq
movwf ee_addr
movlw FREQ_COUNT
movwf count
write_EE_loop
movf
call
incf
incf
decfsz
goto
return
;
;
;
;
;
INDF,w
write_EEPROM
FSR,f
ee_addr,f
count,f
write_EE_loop
*****************************************************************************
*
*
* Purpose: Write the byte of data at EEDATA to the EEPROM at address
*
*
EEADR.
*
*
*
;
;
;
;
;
;
;
;
write_EEPROM
bsf
movwf
movf
movwf
bsf
movlw
movwf
movlw
movwf
bsf
bit_check
btfsc
goto
bcf
bcf
return
;
;
;
;
;
;
;
;
;
STATUS,RP0
EEDATA
ee_addr,w
EEADR
;
;
;
;
Switch to bank 1
Store the write data
Get the write address
Prepare EE address
EECON1,WREN
0x55
EECON2
0xAA
EECON2
EECON1,WR
EECON1,WR
bit_check
EECON1,WREN
STATUS,RP0
;
;
;
;
;
*****************************************************************************
*
*
* Purpose: Read a byte of EEPROM data at address EEADR into EEDATA.
*
*
*
* Input: The address EEADR.
*
*
*
* Output: The value in EEDATA.
*
*
*
*****************************************************************************
read_EEPROM
bsf
movf
movwf
bsf
movf
bcf
return
STATUS,RP0
ee_addr,w
EEADR
EECON1,RD
EEDATA,w
STATUS,RP0
;
;
;
;
;
;
;
Switch to bank 1
Get read address
Copy to EE register
Request the read
Get the data
Switch to bank 0
Return to the caller
; *****************************************************************************
;
;
Function: set_leds
;
;
Purpose: Restores the static LED states on Port B after display updates
;
and DDS daughter card writes.
;
;
Input:
led_states
;
;
Output: LEDs are restored to their static values
;
;
Revisions:
;
Ver 1.0 Copied from PICELGen 2.0 4-20-04 W3CD
;
; *****************************************************************************
set_leds
movlw
andwf
movf
iorwf
return
LED_MASK
PORTB,F
led_states,w
PORTB,f
;
;
;
;
;
; *****************************************************************************
; *
*
; * Purpose: Wait for a specified number of milliseconds.
*
; *
*
; *
Entry point wait_a_sec: Wait for 1 second
P
; *
Entry point wait_256ms: Wait for 256 msec
P
; *
Entry point wait_128ms: Wait for 128 msec
*
; *
Entry point wait_64ms : Wait for 64 msec
*
; *
Entry point wait_32ms : Wait for 32 msec
*
; *
Entry point wait_16ms : Wait for 16 msec
*
; *
Entry point wait_8ms : Wait for 8 msec
*
; *
Entry point wait_1ms
*
; *
*
; * Input: None
*
; *
*
; * Output: None
*
; *
*
; *****************************************************************************
;
wait_a_sec ; ****** Entry point ******
call
wait_256ms
;
call
wait_256ms
;
wait_512ms ; ****** Entry point ******
call
wait_256ms
;
call
wait_256ms
;
return
wait_256ms ; ****** Entry point ******
call
wait_128ms
;
call
wait_128ms
;
return
wait_128ms ; ****** Entry point ******
movlw 0xFF
; Set up outer loop
movwf timer1
; counter to 255
goto
outer_loop
; Go to wait loops
wait_64ms ; ****** Entry point ******
movlw 0x80
; Set up outer loop
movwf timer1
; counter to 128
goto
outer_loop
; Go to wait loops
wait_32ms ; ****** Entry point ******
movlw 0x40
; Set up outer loop
movwf timer1
; counter to 64
goto
outer_loop
; Go to wait loops
wait_16ms ; ****** Entry point ******
movlw 0x20
; Set up outer loop
movwf timer1
; counter to 32
goto
outer_loop
; Go to wait loops
wait_8ms
wait_1ms
movlw
movwf
0x2
timer1
;
; Wait loops used by other wait routines
; - 1 microsecond per instruction (with a 4 MHz microprocessor crystal)
; - 510 instructions per inner loop
; - (Timer1 * 514) instructions (.514 msec) per outer loop
; - Round off to .5 ms per outer loop
;
outer_loop
movlw 0xFF
; Set up inner loop counter
movwf timer2
; to 255
inner_loop
decfsz timer2,f
; Decrement inner loop counter
goto
inner_loop
; If inner loop counter not down to zero,
; then go back to inner loop again
decfsz timer1,f
; Yes, Decrement outer loop counter
goto
outer_loop
; If outer loop counter not down to zero,
; then go back to outer loop again
return
; Yes, return to caller
;
; *****************************************************************************
;
END