⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dds.c

📁 AD9850 DDS chip driver
💻 C
📖 第 1 页 / 共 2 页
字号:
/*

 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 + -