/* * si5351a RF two-tone generator * * Created: 2022/01/08 20:18:21 * Author : www.henteko.org * * 2022/02/13 eeprom_write_dword -> eeprom_write_float */ #include #include #include #include #include #include #include "TinyI2CMaster.h" #include "i2c_lcd.h" #include "si5351a.h" #define MAX_FREQ 148999999 // max frequency #define MIN_FREQ 1000000 // min frequency #define DEF_FREQ 7000000 // default frequency #define DIF_FREQ -20000 // default difference frequency #define MAX_DIFF 1000000 // max difference frequency #define MIN_DIFF -1000000 // min difference frequency FILE *fp; unsigned char mode; // operation mode long freq; // frequency long dfreq; // difference frequency long step; // frequency step unsigned char pos; // frequency cursor position volatile unsigned char cflag; // rotary-encoder change flag volatile unsigned char diff; // frequency up/down flag volatile unsigned char renc_now, renc_old; // value of rotary encoder static unsigned long fmem[2] __attribute__((section(".eeprom"))); // eeprom // millisecond order delay void delay_ms(unsigned int t) { while(t--) _delay_ms(1); } // pin change interrupt for rotaly encoder ISR(PCINT0_vect) { if(bit_is_set(PINB, PB3)) { if(bit_is_clear(PINB, PB4)) renc_now = 0; else renc_now = 1; } else { if(bit_is_set(PINB, PB4)) 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; cflag = 1; } // lcd output frequency void lcd_output(long f) { unsigned char buf[16]; unsigned int i; if(mode == 0) { sprintf(buf, "Fr %9ldHz", f); i2c_lcd_goto(0, 0); } else { sprintf(buf, "Df %9ldHz", f); i2c_lcd_goto(1, 0); } for(i = 0; i < 16; i++) { i2c_lcd_putch(buf[i]); if(i == 5) { if(f >= 1000000 || f <= -1000000) i2c_lcd_putch('.'); else i2c_lcd_putch(' '); } if(i == 8) { if(f >= 1000 || f <= -1000) i2c_lcd_putch('.'); else i2c_lcd_putch(' '); } } if(mode == 0) i2c_lcd_goto(0, pos); else i2c_lcd_goto(1, pos); } // write value to eeprom void setvalue_write(void) { eeprom_busy_wait(); eeprom_write_float(&fmem[0], dfreq); delay_ms(100); eeprom_busy_wait(); eeprom_write_float(&fmem[1], freq); delay_ms(100); } // read value from eeprom void setvalue_read(void) { eeprom_busy_wait(); dfreq = eeprom_read_float(&fmem[0]); if(dfreq >= MAX_DIFF || dfreq < MIN_DIFF) dfreq = DIF_FREQ; eeprom_busy_wait(); freq = eeprom_read_float(&fmem[1]); if((freq + dfreq)> MAX_FREQ || (freq + dfreq) < MIN_FREQ) freq = DEF_FREQ; } int main(void) { unsigned char sw0_state; unsigned int tim0; DDRB = _BV(PB0)|_BV(PB2); // PB0,2 output for i2c PORTB = _BV(PB3)|_BV(PB4)|_BV(PB1); // PB1,3,4 pull up(PB1 switch. PB3,4 rotary encoder) GIMSK = _BV(PCIE); // pin change interrupt enable PCMSK = _BV(PCINT3)|_BV(PCINT4); // PB3,4 pin change interrupt setvalue_read(); TinyI2C_Master_init(); si5351_init(); i2c_lcd_init(32); fp = fdevopen(i2c_lcd_putch, NULL); step = 1000000; pos = 5; cflag = diff = sw0_state = tim0 = 0; si5351_setfreq(0, freq); si5351_setfreq(1, freq + dfreq); mode = 0; lcd_output(freq); mode = 1; lcd_output(dfreq); mode = 0; i2c_lcd_goto(0, pos); i2c_lcd_cursor(2); sei(); while(1) { if(cflag) { if(mode == 0) { if(diff) { if((freq + step ) <= MAX_FREQ) freq += step; } else { if((freq - step) >= MIN_FREQ) freq -= step; } si5351_setfreq(0, freq); si5351_setfreq(1, freq + dfreq); lcd_output(freq); } else { if(diff) { if((dfreq + step ) <= MAX_DIFF) dfreq += step; } else { if((dfreq - step) >= MIN_DIFF) dfreq -= step; } lcd_output(dfreq); } cflag = 0; } if(bit_is_clear(PINB, PB1)) { // frequency step change sw0_state = 1; delay_ms(30); tim0++; } if(sw0_state && bit_is_set(PINB, PB1)) { sw0_state = 0; tim0 = 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; } else if (step == 100000) { step = 1000000; pos = 5; } else if(step == 1000000) { step = 1; pos = 13; } if(mode == 0) i2c_lcd_goto(0, pos); else i2c_lcd_goto(1, pos); } if(tim0 > 40) { sw0_state = 0; tim0 = 0; if(mode == 0) { i2c_lcd_goto(0, 0); fprintf(fp, "Difference Setup"); delay_ms(2000); mode = 1; step = 1000; pos = 9; lcd_output(dfreq); } else { mode = 0; cli(); i2c_lcd_goto(0, 0); fprintf(fp, "==Write Memory=="); delay_ms(2000); setvalue_write(); si5351_setfreq(1, freq + dfreq); lcd_output(freq); sei(); } } } }