/************************************************************** PIC18F DDS chip control DDS: AD9834 (Analog Devices Co.) PIC: PIC18F14K50 16MHz Internal Clock Oscillator 2013.05.02 origin www.henteko.org ***************************************************************/ #include #include #include #include #include "lcd.h" #pragma config FOSC = IRC #pragma config WDTEN = OFF #pragma config FCMEN = OFF #pragma config PWRTEN = ON #pragma config BOREN = ON #pragma config BORV = 30 #pragma config LVP = OFF #pragma config MCLRE = OFF #pragma config HFOFST = ON #pragma config PLLEN = OFF #pragma config CPUDIV = NOCLKDIV #define DDS_FSYNC LATCbits.LATC5 // AD9834 sync #define DDS_SCLK LATAbits.LATA5 // AD9834 clock #define DDS_SDATA LATAbits.LATA4 // AD9834 data #define MAX_FREQ 33000000 // max frequency #define MIN_FREQ -33000000 // min frequency #define DEF_FREQ 10000000 // default frequency #define EEPROM 0x0000 // EEPROM address unsigned char tmp[17]; // lcd output srting unsigned long freq; // VFO frequency long offset; // IF frequency unsigned long step; // frequency up down step unsigned char diff; // frequency diff mode unsigned char renc_now, renc_old; // value of rotary encoder unsigned char mode; // 0:normal 1:IF setup mode unsigned char cflag; // frequency change flag /*************************************************************** ms step delay ***************************************************************/ void delay_ms(unsigned int t) { for(; t > 0; t--) // 16MHz clock Delay1KTCYx(4); // 1ms: 0.001 / ((1 / (16000000 / 4)) * 1000) = 12 } /*************************************************************** us step delay ***************************************************************/ void delay_us(unsigned int t) { for(; t > 0; t--) { // 16MHz clock Delay1TCY(); // 1 / (16000000 / 4) = 0.25us ... 0.25 * 4 = 1us Delay1TCY(); // Delay1TCY() = nop() Delay1TCY(); Delay1TCY(); } } /*************************************************************** EEPROM write routine (long) ***************************************************************/ void eeprom_write_long(unsigned int adr, long data) { unsigned char i; for(i = 0; i < 4; i++) { Write_b_eep(EEPROM + adr * 4 + i, (unsigned char)((data >> (i * 8)) & 0x000000ff)); Busy_eep(); } } /*************************************************************** EEPROM read routine (long) ***************************************************************/ long eeprom_read_long(unsigned int adr) { long d; d = (unsigned long)Read_b_eep(EEPROM + adr * 4); d |= (unsigned long)Read_b_eep(EEPROM + adr * 4 + 1) << 8; d |= (unsigned long)Read_b_eep(EEPROM + adr * 4 + 2) << 16; d |= (unsigned long)Read_b_eep(EEPROM + adr * 4 + 3) << 24; return d; } /*************************************************************** serial data send (MSB first) ***************************************************************/ void dds_dataset(unsigned long data, unsigned int bt) { unsigned int i; DDS_FSYNC = 0; for(i = bt; i > 0 ; i--) { DDS_SDATA = (data >> (i - 1)) & 0x00000001; DDS_SCLK = 0; DDS_SCLK = 1; } DDS_FSYNC = 1; } /*************************************************************** AD9834 DDS control (frequency to serial code) ***************************************************************/ void freq2serial(unsigned long f) { unsigned long msb, lsb; unsigned long data; data = f << 2; msb = (data >> 14) + 0x4000; lsb = (data & 0x00003fff) + 0x4000; dds_dataset(0x2000, 16); dds_dataset(lsb, 16); dds_dataset(msb, 16); } /*************************************************************** interrupt (pin change interrupt) ***************************************************************/ #pragma interrupt isr #pragma code isrcode = 0x8 void isr_direct(void) { _asm goto isr _endasm } #pragma code void isr(void) { if(INTCONbits.RABIF) { if(PORTBbits.RB5 == 1) { if(PORTBbits.RB4 == 0) renc_now = 0; else renc_now = 1; } else { if(PORTBbits.RB4 == 1) renc_now = 2; else renc_now = 3; } if((renc_now + 3 + 1) % 3 == renc_old) { diff = 0; } if((renc_now + 3 - 1) % 3 == renc_old) { diff = 1; } renc_old = renc_now; INTCONbits.RABIF = 0; } cflag = 1; } /*************************************************************** long to comma seperater lcd write ***************************************************************/ void long2comma(long data) { int i; char buf[10]; sprintf(buf, "%9ld", data); for(i = 0; i < 9; i++) { lcd_putch(buf[i]); if(i == 2 || i == 5) { if(buf[i] != 0x20 && buf[i] != '-') lcd_putch('.'); else lcd_putch(' '); } } } /*************************************************************** lcd write routine ***************************************************************/ void lcd_write() { INTCONbits.GIE = 0; lcd_gotopos(0, 0); if(mode) { sprintf(tmp, "IF "); lcd_putstr(tmp); long2comma(offset); } else { sprintf(tmp, "VFO"); lcd_putstr(tmp); long2comma(freq); } sprintf(tmp, "Hz"); lcd_putstr(tmp); if(!mode) { lcd_gotopos(0, 1); if(((freq + offset) > 0) && ((freq + offset) < MAX_FREQ)) sprintf(tmp, "DDS"); else sprintf(tmp, "ERR"); lcd_putstr(tmp); long2comma(freq + offset); sprintf(tmp, "Hz"); lcd_putstr(tmp); } INTCONbits.GIE = 1; } /*************************************************************** main ***************************************************************/ void main(void) { unsigned char sw0_state, sw1_state; unsigned int tim0, tim1; unsigned int pos; // cursor position OSCCON = 0b11111111; // 16MHz internal clock TRISA = 0b00000000; // RA4,5 AD9834 serial control TRISB = 0b11110000; // RB4,5 rotary encoder input RB6,7 sw input TRISC = 0b00000000; // LCD and RC5 AD9834 serial control ADCON0bits.ADON = 0; // ad converter off UCONbits.USBEN = 0; // USB disable ANSELHbits.ANS10 = 0; // RB4 digital input ANSELHbits.ANS11 = 0; // RB5 digital input ANSELbits.ANS3 = 0; // RA4 digital input ANSELbits.ANS6 = 0; // RC2 digital input INTCONbits.RABIE = 1; // PortA,B pin change interrupt enable INTCON2bits.RABPU = 0; // PortA,B pull-up enable INTCON2bits.RABIP = 0; // PortA,B interruput priority low WPUB = 0b11110000; // RB4,5,6,7 pull-up IOCBbits.IOCB4 = 1; // RB4 pin change interrupt enable IOCBbits.IOCB5 = 1; // RB5 pin change interrupt enable lcd_init(); lcd_cls(); sw0_state = sw1_state = 0; freq = eeprom_read_long(0); offset = eeprom_read_long(1); pos = 9; mode = 0; step = 1000; diff = 0; tim0 = tim1 = 0; if(freq <= 0 || freq >= MAX_FREQ) { freq = DEF_FREQ; offset = 0; } if(((freq + offset) > 0) && ((freq + offset) < MAX_FREQ)) { PORTCbits.RC2 = 1; freq2serial(freq + offset); } else { PORTCbits.RC2 = 0; freq2serial(0); } lcd_putcmd(0x0e); lcd_write(); INTCONbits.GIE = 1; // general interrupt enable cflag = 0; while(1){ // step down or press for long time to EEPROM memory write if(PORTBbits.RB6 == 0) { sw0_state = 1; delay_ms(10); tim0++; } if(sw0_state && PORTBbits.RB6 == 1) { sw0_state = 0; tim0 = 0; if(step == 10) { step = 1; pos = 13; } else if(step == 100) { step = 10; pos = 12; } else if(step == 1000) { step = 100; pos = 11; } else if(step == 10000) { step = 1000; pos = 9; } else if (step == 100000) { step = 10000; pos = 8; } } // step up or press for long time to IF setup mode if(PORTBbits.RB7 == 0) { sw1_state = 1; delay_ms(10); tim1++; } if(sw1_state && PORTBbits.RB7 == 1) { sw1_state = 0; tim1 = 0; if(step == 1) { step = 10; pos = 12; } else if(step == 10) { step = 100; pos = 11; } else if(step == 100) { step = 1000; pos = 9; } else if(step == 1000) { step = 10000; pos = 8; } else if(step == 10000) { step = 100000; pos = 7; } } // frequency and offset write to EEPROM if(tim0 > 100) { sw0_state = 0; tim0 = 0; lcd_gotopos(0, 1); if(mode == 1) { freq = DEF_FREQ; offset = 0; sprintf(tmp, "Memory Clear!!!!"); } else sprintf(tmp, "Write to EEPROM!"); lcd_putstr(tmp); eeprom_write_long(0, freq); eeprom_write_long(1, offset); delay_ms(1000); lcd_write(); } // mode change (mode0: VFO mode, mode1: IF setup mode) if(tim1 > 100) { sw1_state = 0; tim1 = 0; if(!mode) { mode = 1; dds_dataset(0x0040, 16); // ad9834 sleep PORTCbits.RC2 = 0; lcd_gotopos(0, 1); sprintf(tmp, "IF Setup Mode "); lcd_putstr(tmp); lcd_write(); } else { mode = 0; lcd_gotopos(0, 1); sprintf(tmp, "VFO Mode "); lcd_putstr(tmp); if(((freq + offset) > 0) && ((freq + offset) < MAX_FREQ)) { PORTCbits.RC2 = 1; freq2serial(freq + offset); } else PORTCbits.RC2 = 0; lcd_write(); } while(PORTAbits.RA5 == 0); } // frequency changed if(cflag) { if(!mode) { if(diff) { if((freq + step) <= MAX_FREQ) freq += step; } else { if((freq - step) >= step) freq -= step; } if(((freq + offset) > 0) && ((freq + offset) < MAX_FREQ)) { freq2serial(freq + offset); PORTCbits.RC2 = 1; } else { PORTCbits.RC2 = 0; } } else { if(diff) { if((offset + (long)step) <= MAX_FREQ) offset += step; } else { if((offset - (long)step) >= MIN_FREQ) offset -= step; } } lcd_write(); cflag = 0; } lcd_gotopos(pos, 0); } }