📄 dds.c
字号:
/*
DDS Synthesizer with Analog Devices AD9850 chip
Juha Niinikoski OH2NLT 28.03.2004
Note if you use 16F877A chip add -NO_STRING_PACK option for correct putst() operation.
! Beware faulty 16F877A (shit) parts. Two weeks work for nothing to find this. ! 22.01.2004
Read Microchip Errata papers.
You can use either 16F877A or 16F877 chips. With 16F877A you get better back light control
EEPROM routines added 03.04.2004
Fixed point frequency calculations, Osc. calibration & some IRQ routine cleaning 05.04.2004
SW3 Menu down added, Display Freq = Freq/4 19.4.2004, v1.00 release
SWR calculations added 14.05.2004, v1.01 release
PC interface added 17.05.2004
More commands to PC interface added 18.05.2004, v1.02 test release
Some errors corrected, upper dds freq limit to 62MHz 20.05.2004
Lag filter added to tx power display & Hohtola additions 22.05.2004
Peak hold for tx power graph, freq step button direction changed big to small 23.05.2004
Display page order changed. Separator commas changed to periods 23.05.2004
*/
//*********************
//include header files
//*********************
#include <pic.h>
#include "dds.h"
// __CONFIG(UNPROTECT|BODEN|FOSC1|BKBUG|WRT|CPD); // CPU config bits v7.xx
__CONFIG(UNPROTECT&WDTDIS&BOREN&HS&DEBUGDIS&PWRTEN&DUNPROT&PWRTEN&LVPDIS); // config bits for v8.01
//*********************
// Global variables
//*********************
//const char banner[] = {" OH2NLT"}; // banner
const char banner[] = {" OH2NLT/OH7SV"}; // banner
const char _version[] = {" DDS 23.05.2004"}; // system version info
const char swid[] = {" sw v1.02 "}; // sw version
#define DEF_MODE 1 // default display mode
#define DEF_INT 7 // default display intensity
char d_mode; // display mode
bit redraw; // something changed redraw display
bit service_mode; // service mode selected
bank1 char dac; // Voltage reference module (DAC) value
bank1 int adc_ch0; // adc raw values
bank1 int adc_ch1;
bit pw_ready; // pulse wheel data available
long f_step; // wheel +/- step
const long f_steps[3] = {1, 1000, 1000000}; // increment / decrement steps
bank1 char step_idx; // step table index
struct dds_regs
{
unsigned long dds_freq;
unsigned char dds_config;
};
union // AD9850 frequency & config data, index 0 = LSB
{
struct dds_regs dds_regs;
unsigned char ad9850[5];
} dds;
#define MIN_DDS 0 // DDS limits
//#define MAX_DDS 1374389535 // 40 MHz upper limit
//#define MAX_DDS 1717986918 // 50 MHz upper limit
#define MAX_DDS 2130303779 // 62MHz upper limit, Nyquist frequency = 62,5MHz
#define DEFAULT_FREQ 508386689 // "factory default" 4 * 3.699 MHz
#define CLKIN 125000000 // oscilator 125 MHz
/* Calibration data */
struct caldata
{
unsigned long osc_freq; // oscilator frequency with +/- correction
unsigned long start_freq; // startup frequency stting
unsigned char start_step; // startup frequency step
unsigned char start_dmode; // startup display mode
unsigned char start_dac; // startup display back ligth setting
unsigned char spare[21];
unsigned char cal_csum; // calibration EEPROM data block checksum
};
union
{
struct caldata caldata; // map calibration data to EEPROM registers
unsigned char eeprom[32]; // eeprom[31] reserved for checksum
}bank1 eedata;
/* SWR meter variables */
#define FWD 0 // FWD power voltage
#define REV 1 // REV power channell
bank2 unsigned int fwd; // forward voltage
bank2 unsigned int rev; // reverse voltage
bank2 unsigned int fwd_max; // forward voltage peak
bank2 unsigned int rev_max; // reverse voltage peak
#define PSCALE 1395 // scaling factor for power display
#define SWR_ALARM 300 // swr alarm lamp limit 300 = 3,00
#define SWR_HIGH 200 // high swr lamp limit
bank2 unsigned int p100; // rev/fwd ratio * 100
bank2 unsigned int fwdpwr; // forward power
bank2 unsigned int revpwr; // reverse power
bank2 unsigned int power; // total power W
bank2 unsigned int oldpwr; // old total power, lag filtered value
bank2 unsigned int swr; // swr * 100
bank2 unsigned int peak_fwdpwr; // peak forward power
bank2 unsigned int peak_revpwr; // peak reverse power
bank2 unsigned int peak_power; // peak total power W
bank2 unsigned int peak_swr; // peak swr * 100
int max_timer; // max display timer
#define MAX_TIME 2000 // max display delay mS
#define MEAN_VAL // mean value voltage measurement if defined
#define PWR_PH_TIME 250 // peak hold time for power meter graph. Max = 255ms
unsigned char pwr_ph_timer; // Power graph peak-hold counter -- @ 1ms to 0
//*********************
// Include files
//*********************
#include "timers.c"
#include "lcd8.c"
#include "term.c"
#include "adc.c"
#include "eeprom.c"
#include "ad9850.c"
//**************************************
// Measure swr voltages & calculate swr
//**************************************
void meas_swr( void )
{
int x;
int f[4]; // mean value calc table
int r[4];
long ptemp, ltemp;
#ifdef MEAN_VAL
f[0] = convert_adc(FWD); // take four samples
r[0] = convert_adc(REV);
f[1] = convert_adc(FWD);
r[1] = convert_adc(REV);
f[2] = convert_adc(FWD);
r[2] = convert_adc(REV);
f[3] = convert_adc(FWD);
r[3] = convert_adc(REV);
fwd = (f[0] + f[1] + f[2] + f[3] + 2) >> 2; // calculate mean value of
rev = (r[0] + r[1] + r[2] + r[3] + 2) >> 2; // fwd & rev voltages
#else
fwd = convert_adc(FWD); // 10.00V = 1000
rev = convert_adc(REV);
#endif
// calculate current values & lag filtered power value
ltemp = fwd; // calculate forward power
ptemp = ltemp * ltemp; // U pwr2
fwdpwr = ptemp / PSCALE; // scale for test swr bridge
ltemp = rev; // calculate forward power
ptemp = ltemp * ltemp; // U pwr2
revpwr = ptemp / PSCALE; // scale for test swr bridge
power = fwdpwr - revpwr; // calculate outgoing power
x = power - oldpwr; // fast attac, slow decay action (Hohtola spec)
if(x > 0) // if positive use new value immediatelly
{
oldpwr = power;
pwr_ph_timer = PWR_PH_TIME;
}
else
{
if(pwr_ph_timer == 0) // start decay after peak hold time (Hohtola spec II)
{
oldpwr = oldpwr + (x >> 4); // lag filter coefficient = 1/16
if(oldpwr < 0) // calculate lag filtered outgoing power
oldpwr = 0;
}
}
p100 = (rev*100) / fwd; // rev/fwd ratio * 100
x = 100 - p100;
if(x < 1)
x = 1; // prevent divide by zero
if(fwd >= 10)
swr = ((100 + p100) * 100) / x;
else
swr = 0; // no swr reading if low power
// calculate peak values
if((fwd > fwd_max) || (rev > rev_max)) // check if new max
{
fwd_max = fwd;
rev_max = rev; // set new max values
max_timer = MAX_TIME; // set display delay
}
ltemp = fwd_max; // calculate forward power
ptemp = ltemp * ltemp; // U pwr2
peak_fwdpwr = ptemp / PSCALE; // scale for test swr bridge
ltemp = rev_max; // calculate forward power
ptemp = ltemp * ltemp; // U pwr2
peak_revpwr = ptemp / PSCALE; // scale for test swr bridge
peak_power = peak_fwdpwr - peak_revpwr; // calculate outgoing power
p100 = (rev_max*100) / fwd_max; // rev/fwd ratio * 100
x = 100 - p100;
if(x < 1)
x = 1; // prevent divide by zero
if(fwd_max >= 10)
peak_swr = ((100 + p100) * 100) / x;
else
peak_swr = 0; // no swr reading if low power
}
//****************************************
// Clumsy but working 32*32 multiply JNi
// elemantary school scheme but with
// base 256 numbers.
//****************************************
// bank2 variables, problems with RAM space
union // 32-bit term 1
{
unsigned long m1l;
unsigned char m1b[4];
}bank2 m1;
union // 32-bit term 2
{
unsigned long m2l;
unsigned char m2b[4];
}bank2 m2;
struct prodlng
{
unsigned long prodlo;
unsigned long prodhi;
};
union // 64-bit product register
{
struct prodlng prodlng;
unsigned char pb[8];
}bank2 prod;
union // digit sum register
{
unsigned int dsi;
unsigned char dsc[2];
}bank2 ds;
union // product sum register
{
unsigned int psi;
unsigned char psc[2];
}bank2 ps;
#if 0
void pdebug(char d1, char d2) // debug printouts
{
char x;
sio_putst("\n\n d1, d2 = ");
sio_putchhex(d1);
sio_putch(' ');
sio_putchhex(d2);
sio_putst("\nm1 ");
for(x=0; x<4; x++)
{
sio_putchhex(m1.m1b[x]);
sio_putch(' ');
}
sio_putst("\nm2 ");
for(x=0; x<4; x++)
{
sio_putchhex(m2.m2b[x]);
sio_putch(' ');
}
sio_putst("\npr ");
for(x=0; x<8; x++)
{
sio_putchhex(prod.pb[x]);
sio_putch(' ');
}
}
#endif
void add_prod(char idx, unsigned char d) // 8-bit to product array idx position
{
ps.psi = prod.pb[idx] + d; // sum digit
prod.pb[idx] = ps.psc[0];
while((ps.psc[1] != 0) || idx < 8) // continue adding if carry
{
idx++;
ps.psi = prod.pb[idx] + ps.psc[1];
prod.pb[idx] = ps.psc[0];
}
}
void clear_prod(void) // clear product array
{
char x;
for(x=0; x<8; x++)
{
prod.pb[x] = 0;
}
}
void vlmul(void) // 32*32 multiply. prod = m1*m2
{
char d1, d2;
clear_prod();
for(d2=0; d2<4; d2++)
{
for(d1=0; d1<4; d1++)
{
ds.dsi = m1.m1b[d1] * m2.m2b[d2]; // multiply digit
add_prod((d1+d2), ds.dsc[0]); // add to product
if(ds.dsc[1] != 0)
add_prod((d2+d1+1), ds.dsc[1]); // add carry number
}
}
}
//***************************
// Helper & I/O functions
//***************************
/* SW2 functions */
void freq_step_adj(void)
{
if(SW2 == 0) // addjust freq step
{
#if 0
step_idx++; // step up
if(step_idx >= 3)
step_idx = 0;
#endif
if(step_idx == 0) // step down test
step_idx = 2;
else
step_idx--;
if(step_idx > 2) // range check
step_idx = 2;
f_step = f_steps[step_idx];
delay(250); // button debounce / repeat
delay(150);
redraw = 1; // force update
}
}
//***************************
// DDS Main
//***************************
void main( void )
{
int temp;
long ltemp;
char dly;
/* Init IO Ports */
// Set up PORTA
TRISA = TRISA_INIT;
PORTA = PORTA_INIT;
ADCON0 = ADCON0_INIT;
ADCON1 = ADCON1_INIT;
// Set up PORTB
TRISB = TRISB_INIT;
PORTB = PORTB_INIT;
// Set up PORTC
TRISC = TRISC_INIT;
PORTC = PORTC_INIT;
// Set up PORTD
TRISD = TRISD_INIT;
PORTD = PORTD_INIT;
// Set up PORTE
TRISE = TRISE_INIT;
PORTE = PORTE_INIT;
// init LCD controller
initlcd(); // init LCD system
set_chgen(); // set bar graph fonts
// init serial port
serial_setup();
// print hello messages
putst(banner); // hello to LCD
set_cur_lcd(LINE2);
putst(_version);
sio_putst("\n"); // hello to serial port
sio_putst(banner);
sio_putch(' ');
sio_putst(_version);
sio_putst("\n Prototype running\n");
for(dly = 0; dly < 16; dly++) // show Hello message for a while
{
delay( 250 );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -