/* * 7MHz QRP CW transciver for si5351a VFO * File: main.c * Author: www.henteko.org * * Created on 2021/07/29, 17:02 */ #include #include #include "pic16f_i2c.h" #include "oled.h" #include "si5351a.h" #pragma config FEXTOSC = OFF // external clock off #pragma config RSTOSC = HFINT32 // internal clock 16mhz X 2 (pll) #pragma config MCLRE = OFF // RA3 enable #pragma config FCMEN = OFF #pragma config PWRTE = OFF #pragma config WDTE = OFF // #pragma config BOREN = ON // #pragma config LVP = OFF // LVP=off MCLRE=off RA3 input enable #define _XTAL_FREQ 32000000 #define MAX_FREQ 17438600 // max frequency #define MIN_FREQ 17237100 // min frequency #define DEF_FREQ 17237100 // default frequency #define IF_FREQ 10237100 // if frequency #define EEPROM 0x0000 // EEPROM address unsigned long freq; // frequency unsigned long step; // frequency up down step unsigned long tfreq, tstep; unsigned char renc_now, renc_old; // value of rotary encoder unsigned char cflag; // frequency change flag unsigned char diff; // frequency up down flag unsigned char buf[19]; // oled output buffer unsigned char mode; void delay_ms(unsigned int t) { for(; t > 0; t--) __delay_ms(1); } void eeprom_write_long(unsigned int adr, long data) { unsigned char i; for(i = 0; i < 4; i++) { eeprom_write(EEPROM + adr * 4 + i, (unsigned char)((data >> (i * 8)) & 0x000000ff)); } } long eeprom_read_long(unsigned int adr) { long d; d = (unsigned long)eeprom_read(EEPROM + adr * 4); d |= (unsigned long)eeprom_read(EEPROM + adr * 4 + 1) << 8; d |= (unsigned long)eeprom_read(EEPROM + adr * 4 + 2) << 16; d |= (unsigned long)eeprom_read(EEPROM + adr * 4 + 3) << 24; return d; } void interrupt isr(void) { if(IOCIF) { if(RA4) { if(RA5 == 0) { renc_now = 1; } else { renc_now = 0; } } else { if(RA5) { 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; IOCAFbits.IOCAF4 = 0; IOCAFbits.IOCAF5 = 0; renc_old = renc_now; cflag = 1; } } unsigned int get_adc(unsigned char ch) { ADCON1bits.ADFM = 1; // padding right ADCON1bits.ADCS = 101; // Fosc/16 ADCON1bits.ADNREF = 0; // Vref is Vss ADCON0bits.CHS = ch; // ADC channel(see detasheet) ADCON0bits.GO_nDONE = 0; // ADC GO/^DONE ADCON0bits.ADON = 1; // ADC Enable __delay_us(25); GO = 1; while(GO); return (ADRESH << 8) + ADRESL; } void step_write(void) { if(mode) { sprintf(buf, " RIT: %3dHz ", freq - tfreq); } else { if(step == 1) { sprintf(buf, " STEP: 1Hz "); } else if(step == 10) { sprintf(buf, " STEP: 10Hz "); } else if(step == 100) { sprintf(buf, " STEP: 100Hz "); } else if(step == 1000) { sprintf(buf, " STEP: 1kHz "); } else if(step == 10000) { sprintf(buf, " STEP: 10kHz "); } else if(step == 100000) { sprintf(buf, " STEP: 100kHz "); } else { sprintf(buf, " STEP: 1MHz "); } } oled_string(1, 1, 3, buf); } void long2comma(long data) { unsigned int mega, kiro, deci; mega = data * 0.000001; kiro = (data - (mega * 1000000)) * 0.001; deci = (data - (mega * 1000000) - (kiro * 1000)) * 0.1; sprintf(buf, "%d.%03d.%02d", mega, kiro, deci); oled_string(2, 10, 0, buf); } void main(void) { unsigned char sw0_state, sw1_state; unsigned int tim0, tim1; unsigned int x; unsigned int signal; unsigned char txflag; TRISCbits.TRISC4 = 1; // i2c sda TRISCbits.TRISC5 = 1; // i2c sck RC4PPS = 0b11000; // RC4 MSSP 1 Data Output(i2c data) RC5PPS = 0b11001; // RC5 MSSP 1 Clock Output(i2c clock) ANSELC = 0x00; // Port C all digital ANSC2 = 1; // RC2 is analog input TRISCbits.TRISC1 = 1; // RC1 sw input for step select WPUCbits.WPUC1 = 1; // RC1 weak pull-up enable TRISCbits.TRISC3 = 1; // RC3 sw input for key down WPUCbits.WPUC3 = 1; // RC3 weak pull-up enable TRISCbits.TRISC0 = 0; // RC0 send rx mute LATCbits.LATC0 = 0; // rxmute off ANSELA = 0x00; // Port A all digital WPUAbits.WPUA3 = 1; // RA3 weak pull-up enable(RA3 RIT sw-input) TRISAbits.TRISA4 = 1; // RA4 input rotary encoder TRISAbits.TRISA5 = 1; // RA5 input rotary encoder WPUAbits.WPUA4 = 1; // RA4 weak pull-up enable WPUAbits.WPUA5 = 1; // RA5 weak pull-up enable IOCANbits.IOCAN4 = 1; // RA4 interrupt-on-change negative edge IOCANbits.IOCAN5 = 1; // RA5 interrupt-on-change negative edge TRISAbits.TRISA2 = 0; // RA2 PWM output for sidetone RA2PPS = 2; // RA2 PPS set T2CON = 0b00000011; // timer2 prescaler 1/64 TMR2 = 0; // timer2 count register PR2 = 150; // timer2 period register PWM5CONbits.PWM5EN = 1; // pwm5 enable PWM5DCH = PR2 / 2; // pwm5 duty high bits InitI2C(); delay_ms(10); oled_init(); si5351_init(); freq = eeprom_read_long(0); if(freq <= MIN_FREQ || freq >= MAX_FREQ) { freq = DEF_FREQ; } step = 100; diff = 0; cflag = 0; sw0_state = sw1_state = 0; tim0 = tim1 = 0; mode = 0; txflag = 0; oled_clear(); oled_string(1, 109, 1, "MHz"); oled_string(0, 0, 5, "S 1 3 5 7 9 20 40"); for(x = 2; x < 128; x++) { // draw h line oled_pattern(x, 6, 8); } oled_pattern(2, 6, 254); // draw vline for signal start oled_pattern(12, 6, 126); // draw vline for signal 1 oled_pattern(27, 6, 126); // draw vline for signal 3 oled_pattern(42, 6, 126); // draw vline for signal 5 oled_pattern(57, 6, 126); // draw vline for signal 7 oled_pattern(72, 6, 126); // draw vline for signal 9 oled_pattern(95, 6, 126); // draw vline for signal 20 oled_pattern(120, 6, 126); // draw vline for signal 40 oled_pattern(127, 6, 254); // draw vline for signal endline long2comma(freq - IF_FREQ); step_write(); si5351_setfreq(0, freq); IOCIE = 1; // intertupt-on-change interrupt enable GIE = 1; // general interrupt enable while(1) { signal = get_adc(18) / 4; // ADC channel RC2(ANC2) (see datasheet) for(x = 2; x < signal; x += 2) { oled_pattern(x, 7, 255); } for(; x < 128; x += 2) { oled_pattern(x, 7, 0); } if(cflag) { if(diff) { if((freq + step) <= MAX_FREQ) freq += step; } else { if((freq - step) >= MIN_FREQ) freq -= step; } si5351_setfreq(0, freq); long2comma(freq - IF_FREQ); if(mode) step_write(); cflag = 0; } if(PORTAbits.RA3 == 0) { sw0_state = 1; delay_ms(20); tim0++; } if(sw0_state && PORTAbits.RA3 == 1) { sw0_state = 0; tim0 = 0; if(mode) { freq = tfreq; step = tstep; mode = 0; } else { tfreq = freq; tstep = step; step = 10; mode = 1; } si5351_setfreq(0, freq); long2comma(freq - IF_FREQ); step_write(); } if(PORTCbits.RC1 == 0) { sw1_state = 1; delay_ms(20); tim1++; } if(sw1_state && PORTCbits.RC1 == 1) { sw1_state = 0; tim1 = 0; if(step == 10) { step = 100; } else if(step == 100) { step = 1000; } else { step = 10; } step_write(); } if(PORTCbits.RC3 == 0) { if(txflag == 0) { if(mode) { si5351_setfreq(1, tfreq - IF_FREQ); } else { si5351_setfreq(1, freq - IF_FREQ); } T2CONbits.TMR2ON = 1; txflag = 1; LATCbits.LATC0 = 1; } } else { if(txflag) { si5351_setfreq(0, freq); T2CONbits.TMR2ON = 0; txflag = 0; LATCbits.LATC0 = 0; } } if(tim1 > 100) { sw1_state = 0; tim1 = 0; oled_string(1, 1, 3, " =Write Memory= "); eeprom_write_long(EEPROM, freq); delay_ms(2000); step_write(); } } }