for your code in the post. [/color]
[code]//==================================================================
//===== =====
//===== 2 Meter Receiver Program =====
//===== By: Steve Hageman 29Mar98 =====
//===== www.sonic.net/~shageman =====
//==================================================================
//===== Copyright 1998 by Steven C. Hageman =====
//===== All rights reserved =====
//==================================================================
//===== Version: 0.0 - Initial Writing - 29Mar98 =====
//===== Version: 1.0 - First release - 19Sep98 =====
//==================================================================
//-----< Include Files, setup fuses >-----
#include <16c73a.h>
#include <stdio.h>
#fuses HS, NOWDT, NOPROTECT, PUT, BROWNOUT
//-----< Compiler use statements >-----
// Tell compiler clock speed, baud, and Hardware UART pins
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
//-----< Port location defines >-----
#pragma byte port_a = 0x05
#pragma byte port_b = 0x06
#pragma byte port_c = 0x07
//-----< Pin defines >-----
#pragma bit AUDIO_PIN = port_a.2 // Audio override pin
#pragma bit A_SW = port_b.0 // Encoder A switch input
#pragma bit B_SW = port_b.1 // Encoder B switch input
#pragma bit INC_SW = port_b.2 // Freq increment select switch
#pragma bit SCAN_SW = port_b.3 // Scan select switch
#pragma bit RS232_PIN = port_c.7 // RS232 input pin
//-----< MC145170 PLL Chip Pins >-----
#pragma bit DIN = port_b.5
#pragma bit CLK = port_b.6
#pragma bit EN = port_b.7
//-----< General Program Defines >-----
#define DOOMSDAY 0 // Not here yet!
#define AUDIO_OFF 1 // Set AUDIO OFF
#define AUDIO_ON 0 // Set AUDIO ON
#define PUSHED 0 // For switched closed sense
#define RSSI 0 // Analog input for RSSI
#define SQUELCH 1 // Analog input for squelch pot
#define BAT 3 // Analog input for battery voltage
#define EOT 255 // End of RS232 transmission character
//-----< Global Variables >-----
unsigned long Channel; // PLL channel number 0 - 799 for 5 kHz steps
int Increment; // Frequency increment (in channel units)
int Changed; // Frequency changed flag
int Rssi_val; // RSSI A/D value
int Squelch_val; // Squelch pot setting
int Bat_val; // Battery voltage value
int Keep_scanning; // Flag used during scanning
//-----< LCD Routines >----------------------------------------------
// LCD is connected to port c, definitions below
// LCD Connections -
// C5 C4 C3 C2 C1 C0 - PORT PINS
// E R/S D7 D6 D5 D4 - LCD PINS
void blip_e_delay()
{
// Set enable high for 2 cycles then low
// Minimum E cycle time is 450 nS.
#asm
bsf port_c,5
nop
nop
bcf port_c,5
#endasm
// Wait for longest lcd routine to finish, takes time
// but saves code in not checking for the busy flag.
delay_ms(5);
}
void blip_e()
{
// Set enable high for 2 cycles then low
// Minimum E cycle time is 450 nS.
#asm
bsf port_c,5
nop
nop
bcf port_c,5
#endasm
// Wait for shortest lcd routine to finish, takes time
// but saves code in not checking for the busy flag.
delay_us(50);
}
void first_line()
{
// Set the LCD to the first display line
// Send 0x80 for first line.
port_c = 0x08;
blip_e();
port_c = 0x00;
blip_e();
}
void second_line()
{
// Set the LCD to the second display line
// Send 0xc0 for second line.
port_c = 0x0c;
blip_e();
port_c = 0x00;
blip_e();
}
void init_lcd()
{
// Clear and initilize LCD panel to 4 bit mode
// two line mode, cursor off, display on.
// RS needs to be low for all of these instructions.
// -> Takes 60 mS to complete <-
// Send 0x03 three times
port_c = 0x03;
blip_e_delay();
port_c = 0x03;
blip_e_delay();
port_c = 0x03;
blip_e_delay();
// Send 0x02
port_c = 0x02;
blip_e_delay();
// send 0x28
port_c = 0x02;
blip_e_delay();
port_c = 0x08;
blip_e_delay();
// send 0x01
port_c = 0x00;
blip_e_delay();
port_c = 0x01;
blip_e_delay();
// send 0x06
port_c = 0x00;
blip_e_delay();
port_c = 0x06;
blip_e_delay();
// send 0x0c
port_c = 0x00;
blip_e_delay();
port_c = 0x0c;
blip_e_delay();
// Send 0x0f to set cursor on with blink
// Send 0x0e to set cursor on w/o blink
// Clean up port on exit
port_c = 0x00;
}
void write_lcd(byte ch)
{
// writes the char ch to the lcd. HB then LB.
// The OR sets RS high
port_c = (ch/0x10) | 0x10;
blip_e();
port_c = (ch & 0x0f) | 0x10;
blip_e();
// Clean up port on exit
port_c = 0x00;
}
void display_frequency(void)
{
unsigned long freq;
// Calculate actual frequency
freq = Channel*5 + 4000;
// Write frequency to display
first_line();
write_lcd("14");
write_lcd((int)(freq / 1000) + '0');
write_lcd('.');
write_lcd((int)((freq / 100) % 10) + '0');
write_lcd((int)((freq / 10) % 10) + '0');
write_lcd((int)(freq % 10) + '0');
write_lcd(" MHz");
// Write increment to display
switch(Increment)
{
case 0:
write_lcd(" Lock");
break;
case 1:
write_lcd(" 5k");
break;
case 2:
write_lcd(" 10k");
break;
case 20:
write_lcd(" 100k");
break;
case 200:
write_lcd(" 1M");
break;
}
}
//-----< PLL Routines >----------------------------------------------
void setup_pll(void)
{
// PLL setup routine, only needs to be done once, at startup.
// Note: Until control register is set, the PIC clock will be running at
// 1.25 MHz.
//----- Initilize PLL -----
// EN High, Din Low, 4 clocks
CLK = 0;
DIN = 0;
EN = 1;
CLK = 1;
CLK = 0;
CLK = 1;
CLK = 0;
CLK = 1;
CLK = 0;
CLK = 1;
CLK = 0;
// EN Low, Din Low (except clock 4 = 1), 5 clocks
DIN = 0;
EN = 0;
CLK = 1;
CLK = 0;
CLK = 1;
CLK = 0;
CLK = 1;
CLK = 0;
DIN = 1;
CLK = 1;
CLK = 0;
DIN = 0;
CLK = 1;
CLK = 0;
EN = 1;
// PLL is now reset
//----- Setup C Reg with proper bits -----
EN = 0;
// Bit 7 - PD Polarity
DIN = 0;
CLK = 1;
CLK = 0;
// Bit 6 - PD Output
DIN = 1;
CLK = 1;
CLK = 0;
// Bit 5 - Lock Detect Off
DIN = 0;
CLK = 1;
CLK = 0;
// Bit 4, 3, 2 - Ref divider output (001 = /1)
DIN = 0;
CLK = 1;
CLK = 0;
DIN = 0;
CLK = 1;
CLK = 0;
DIN = 1;
CLK = 1;
CLK = 0;
// Bit 1 - FV off -- NOTE: Set this bit high to get
// the N counter out on pin 10.
DIN = 0;
CLK = 1;
CLK = 0;
// Bit 0 - FR off -- NOTE: Set this bit high to get
// the PD ref frequency on pin 9.
DIN = 0;
CLK = 1;
CLK = 0;
DIN = 0;
// EN back high
EN = 1;
// Note: The PIC clock will now be 10 MHz
//----- Setup Ref Divider -----
// 10 MHz / 2000 = 5 KHz (2000 = 0x07d0)
EN = 0;
// BIT 14-12 = 000
CLK = 1;
CLK = 0;
CLK = 1;
CLK = 0;
CLK = 1;
CLK = 0;
// BIT 11-8 = 0111
CLK = 1;
CLK = 0;
DIN = 1;
CLK = 1;
CLK = 0;
CLK = 1;
CLK = 0;
CLK = 1;
CLK = 0;
// BIT 7-4 = 1101
CLK = 1;
CLK = 0;
CLK = 1;
CLK = 0;
DIN = 0;
CLK = 1;
CLK = 0;
DIN = 1;
CLK = 1;
CLK = 0;
// BIT 4-0 = 0000
DIN = 0;
CLK = 1;
CLK = 0;
CLK = 1;
CLK = 0;
CLK = 1;
CLK = 0;
CLK = 1;
CLK = 0;
// Enable Back High
EN = 1;
}
void tune_pll(void)
{
int ctr;
unsigned long n_reg;
// Convert channel number to N counter value
n_reg = Channel + 30940;
// Set clock, enable low
CLK = 0;
EN = 0;
// Shift in channel frequency to N reg (MSB first)
for( ctr = 0 ; ctr <= 15 ; ctr++)
{
// Decompose the PLL N value into bits, set data pin
DIN = shift_left(&n_reg, 2, 0);
// Cycle the clock
CLK = 1;
CLK = 0;
}
// Clean up and set enable high which
// transfers count to N reg
DIN = 0;
EN = 1;
}
//-----< Set Analog Globals >----------------------------------------
void update_analog(void)
{
// Read all the analog channels and set their global variables
set_adc_channel(RSSI);
delay_us(20);
Rssi_val = read_adc();
// Bound the value, so it does not interfere with RS232 'EOT'.
// As design was orginaly done, this won't ever hapen.
// I put this here just in case something is changed.
if( Rssi_val == 255 )
Rssi_val = 254;
set_adc_channel(SQUELCH); // The /4 scales the squelch range
delay_us(20); // to match the RSSI range
Squelch_val = read_adc()/4;
set_adc_channel(BAT);
delay_us(20);
Bat_val = read_adc();
// Bound the value, so it does not interfere with RS232 'EOT'.
if( Bat_val == 255 )
Bat_val = 254;
}
//-----< RS232 Control loop >-----------------------------------------
void rs232_mode(void)
{
char buf;
int hb, lb;
// We just stay in this routine forever!
// Update LCD display
write_lcd("-- Hagtronics --");
second_line();
write_lcd("-- RS232 Mode --");
while(!DOOMSDAY)
{
// Get command
buf = getc();
// Process command
switch(buf)
{
case 'A': // Set Audio
{
// Say first char was OK
putc(EOT);
// Get mode
buf = getc();
switch(buf)
{
case 'N': // Set audio on
AUDIO_PIN = AUDIO_ON;
putc(EOT);
break;
case 'F': // Set audio off
AUDIO_PIN = AUDIO_OFF;
putc(EOT);
break;
default: // What did they want?
putc('?');
putc(EOT);
break;
}
break;
}
case 'C': // Channel Set
{
// Say first char was OK
putc(EOT);
// Get channel bytes HB, LB
hb = getc();
// Say HB was OK
putc(EOT);
// Get LB
lb = getc();
// Say it was good!
putc(EOT);
// Figure channel number
Channel = hb * 256 + lb;
// Set N Reg with frequency
tune_pll();
break;
}
case 'D': // Write data valid status out
{
//Send back current signal levels
update_analog();
putc(Rssi_val);
putc(Bat_val);
putc(EOT);
break;
}
default: // Say char was not understood
{
putc('?');
putc(EOT);
}
} // End of first char switch
} // End of main while
}
void update_audio(void)
{
// Decide if RSSI level is greater than the squelch level
// This will determine if the audio needs to be turned on or not
// Get current RSSI and squelch value
update_analog();
if(Rssi_val >= Squelch_val)
{
// Set audio on
AUDIO_PIN = AUDIO_ON;
}
else
{
// Set audio off
AUDIO_PIN = AUDIO_OFF;
}
}
//-----< Scanning routine >------------------------------------------
// Note: Scan is also killed by turning the tune knob
void scan(void)
{
int ctr;
// Turn off audio to start with
AUDIO_PIN = AUDIO_OFF;
// Initilize variable
Keep_scanning = TRUE;
// Scan till the cows come home
while(Keep_scanning == TRUE)
{
// Increment channel
Channel += Increment;
// Bound the channel values -- implements roll over
if( Channel > 60000 ) // Catch unsigned underflow
Channel = 800;
if( Channel > 800 ) // Catch overflow
Channel = 0;
// Update PLL & wait a while
tune_pll();
delay_ms(20); // Enough time for a full scale step
// Update display
display_frequency();
// Check if anything is on this channel
update_analog();
while((Rssi_val >= Squelch_val) && (Keep_scanning == TRUE))
{
// Yup got a signal, turn Audio on
AUDIO_PIN = AUDIO_ON;
// Delay a while (2 seconds) on signal, but check scan switch
// This loop runs at about 10 times a second
for(ctr = 0; ctr <= 19 ; ctr++)
{
// Hurry up and wait!
delay_ms(100);
// Is the scan switch depressed?
if(SCAN_SW == PUSHED)
{
// Clean up display for the user, giving feedback
second_line();
write_lcd(" ");
// Wait 'till switch is not pressed
while(SCAN_SW == PUSHED);
// Exit out of here
Keep_scanning = FALSE;
}
// If audio drops during this time turn it off
// but stay in loop (keep resetting loop counter)
update_analog();
if(Rssi_val >= Squelch_val)
{
AUDIO_PIN = AUDIO_ON;
ctr = 0;
}
else
AUDIO_PIN = AUDIO_OFF;
// If something has set keep_scanning false,
// break out of loop
if(keep_scanning == FALSE)
break;
} // End of signal delay loop
} // End of signal capture delay while loop
// Check to see if scan is stopped
if(SCAN_SW == PUSHED)
{
// Clean up display for the user, giving feedback
second_line();
write_lcd(" ");
// wait till switch is not pushed
while(SCAN_SW == PUSHED);
// Now get outa town
Keep_scanning = FALSE;
}
} // End of main loop
// Clean up display for the user, giving feedback
second_line();
write_lcd(" ");
// Turn the audio back off, it will turn on later is there is
// still a signal
AUDIO_PIN = AUDIO_OFF;
}
void change_increment(void)
{
// Change to next tuning increment value (Step size)
switch(Increment)
{
case 0: // 0 Channels = Locked
Increment = 1;
break;
case 1: // 1 Channel = 5 kHz
Increment = 2;
break;
case 2: // 2 Channels = 10 kHz
Increment = 20;
break;
case 20: // 20 Channels = 100 kHz
Increment = 200;
break;
case 200: // 200 Channels = 1 MHz
Increment = 0;
break;
default: // Just in case, set 1 channel
Increment = 1;
}
}
void update_rssi_display(void)
{
static int old_rssi; // Note: old_rssi is not initilized
int scaled_rssi, char_pos;
// Displays the RSSI level of a signal on the LCD
// Note: This one A/D read is used several placed below
update_analog();
scaled_rssi = Rssi_val/2; // Divide by 2 to maximize range
// Scale RSSI a/d value
if(scaled_rssi > 8)
{
scaled_rssi -= 8; // The 8 offsets the display to zero
}
else
{
scaled_rssi = 0; // Floor a/d value
}
if(scaled_rssi > 16) // Bound scaled a/d value
scaled_rssi = 16;
// Only update display if RSSI value changed
if(scaled_rssi != old_rssi)
{
second_line();
for(char_pos=1 ; char_pos <= 16 ; char_pos++)
{
if(char_pos <= scaled_rssi)
{
write_lcd(255);
}
else
{
write_lcd(' ');
}
}
old_rssi = scaled_rssi;
}
}
//-----< Rotary Encoder routine >------------------------------------
#INT_EXT // Change on falling edge of RB
// Note: Must set int reg to get falling edge trigger
void encoder(void)
{
// If here then the A encoder must have had a falling edge...
// Read encoder B switch and check direction
if( B_SW == 1 )
{
// CW Direction
Channel += Increment;
}
else
{
// CCW Direction
Channel -= Increment;
}
// Bound the channel values -- implements roll over
if( Channel > 60000 ) // Catch unsigned underflow
Channel = 800;
if( Channel > 800 ) // Catch overflow
Channel = 0;
// Set the changed flag, cancel scanning (if we were scanning)
Changed = TRUE;
Keep_scanning = FALSE;
}
//-----< Main >------------------------------------------------------
// Note: At powerup the PIC clock will be 1.25 MHz. After PLL setup is
// done the clock will be 10 MHz. No RS232 can take place untill PLL
// is setup.
void main(void)
{
int ctr; // Local variables
//----- Setup Ports / Unused pins are set to output
set_tris_a(0b00001011); //
set_tris_b(0b00001111); //
set_tris_c(0b10000000); //
port_b_pullups(TRUE); // ON for the switches
//----- Housekeeping -----
// Initilize Pins
EN = 1;
AUDIO_PIN = AUDIO_OFF;
// Initilize global/local variables
Channel = 400; // Set for 146.000 MHz
Changed = TRUE; // Update display
Increment = 2; // Set for 10 kHz increment
// Initilize interrupts
disable_interrupts(GLOBAL);
ext_int_edge(H_TO_L);
// Initilize A/D
setup_port_a(RA0_RA1_RA3_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
// Wait for LCD powerup
// Note: Here clock is really 1.25 MHz, so delay is not
// accurate (8 times more than value called out)
delay_ms(100);
// Initilize LCD
init_lcd();
// Display power on banner
write_lcd(" Hagtronics ");
second_line();
write_lcd("2 Meter Receiver");
// Reset PLL, setup C, R regs
setup_pll();
// Setup PLL for initial turn on frequency of 146 MHz
tune_pll();
// Clean up display
delay_ms(1000);
init_lcd();
//----- Determine if RS232 cable is hooked up
// Read from RS232 receive pin, if it is high then
// RS232 is connected.
if(RS232_PIN == 1)
{
// RS232 is connected, operate in the remote mode
rs232_mode();
}
//----- Main loop -----
// This outer loop operates about 4 times a second
while(!DOOMSDAY)
{
disable_interrupts(GLOBAL);
// Check battery level
update_analog();
if( Bat_val <= 141 ) // 141 gives about 1.1 volt per cell
{
// Low battery
second_line();
write_lcd("BAT");
}
// Update display / PLL if channel changed
if( Changed )
{
display_frequency();
// Update PLL
tune_pll();
// Reset the changed flag
Changed = FALSE;
}
// Set the encoder interrupt on again
enable_interrupts(GLOBAL);
// Real time update loop
for( ctr = 0 ; ctr <= 24 ; ctr++ )
{
// Check if scan switch is pushed
if(SCAN_SW == PUSHED)
{
// Give user feedback that switch was pushed
second_line();
write_lcd("----Scanning----");
// Wait till scan is not pushed anymore
while(SCAN_SW == PUSHED);
// OK, Let's scan :)
scan();
}
// Check if Increment switch has been changed
if(INC_SW == PUSHED)
{
// Increment tuning step size
change_increment();
// Give user feedback on button being pushed
display_frequency();
// Wait till increment switch is not pushed anymore
while(INC_SW == PUSHED);
}
// Update signal strength display
update_rssi_display();
// Check squelch level, open audio if needed
update_audio();
delay_ms(10); // Update loop about every 10 mSec
} // End of 'real time' loop
} // End of main while loop
} //----- End of main -----