This is the firmware for my QRP 5 band SSB transceiver (Link). It is written in C and to be compiled with the GNU C compiler for AVR microcontrollers. Target machine is an ATMega128 running on 14.7456 MHz. This software may be distributed freely among the amateur community. No off-the-shelf use!
Hint: Display characters are defined using “PROGMEM” feature. This is not available in newer version of the compiler. So it is recommended to delete “PROGMEM” statement and use a standard char variable!
73 de Peter (DK7IH)
/////////////////////////////////////////////////////////////////// // DDS with AD9951 for 5-Band QRP-SSB-Transceiver // /////////////////////////////////////////////////////////////////// // MUC: ATMEL AVR ATmega128, 14.7456 MHz // // Display D072 by display3000.com ATMega128A // // Compiler: GCC (GNU AVR C-Compiler) Release 20071221 // // Author: Peter Rachow (DK7IH) // // Last Change: 2016-03-31 // /////////////////////////////////////////////////////////////////// ////////////////////// // PORT USAGE // ////////////////////// ///////////// // OUTPUTs // ///////////// //COM-Port //D2: RXD //D3: TXD //(not used so far) //DISPLAY //B1, B2, B4, B5, B6: Display control and data //B7: Display light // SPI lines to AD9951 DDS-Chip // FQ_UD: PD0 (green) // DATA: PD1 (white) // CLK: PD2 (blue) // RESET: PD3 (pink) //Other control lines on PORTD //PD4 lightyellow (Sideband relay output) //PD5 grey (unused) //PD6 darkgreen (unused) //32.768 kHz clock crystal //PG3, PG4 //Peripheral power control for D072-display //PG1 //Relay outputs for 5 bands //PE3 orange 80 //PE4 pink 40 //PE5 green 20 //PE6 blue 15 //PE7 lightyellow 10 //////////// // INPUTs // //////////// //Switches for user interface //PC0, PC1, PC2, PC3, PC4, PC5, //PC0: VFO set (green) //PC1: Band set (white) //PC2: Tuning step (pink) //PC3: FUNC/CANCEL (grey) //PC4: -/NO etc. (blue) //PC5: +/YES (orange) //Rotatory encoder //PC6: A (green) //PC7: B (lightyellow) //PA0 Indicates sideband switch status (not switched = normal sideband, switched = reverse sideband) //PA1 TX/RX detect //PA2 Switch on tone generator for tuning //ADC channels //PF0: RIT control voltage //PF1: Voltage Sensor //PF2: Temperature Sensor //PF3: AGC-Voltage for digital S-Meter ///////////// // ISP // ///////////// //PE0: MOSI //PE1: MISO //PB1: SCK //(RESET: PIN20) //Unused (so far) //PA3, PA4, PA5, PA6, PA7 //PD5, PD6 (wires prepared on board) //PF4, PF5, PF6, PF7 (ADC channels) ///////////////////////////////// ///// EEPROM structure //////// //Bytes 0..199 //Frequency data for 5 Bands and 12 VFOs, 4 Bytes per VFO //Order //Band 0 VFO 0..11 //Band 1 VFO 0..11 //.... //Band 4 VFO 0..11 //Other data //Byte 250: Last band used //Byte 251: Last VFO used //Byte 252: Display Light Setting //Byte 253...256: Last frequency on 80 //Byte 257...260: Last frequency on 40 //Byte 261...264: Last frequency on 20 //Byte 265...268: Last frequency on 15 //Byte 269...272: Last frequency on 10 //Byte 273: obsolete ///////////////////////////////////////////////////////////////////// #include #include <avr/io.h> #include <avr/iom128.h> #include <avr/interrupt.h> #include <util/delay.h> #include #include <avr/wdt.h> #include <avr/sleep.h> #include <avr/eeprom.h> #include #include <avr/pgmspace.h> // PINs used at PORTB (SPI-Port for Display) #define SPI_CLOCK 1 #define SPI_DATA 2 #define SPI_RESET 4 #define SPI_SELECT 5 #define SPI_DC 6 // Colors #define WHITE 255 #define DARKBLUE 3 #define BLUE 11 #define LIGHTBLUE 23 #define LIGHTYELLOW 252 #define YELLOW 216 #define DARKYELLOW 180 #define ORANGE 232 #define DARKRED 128 #define RED 160 #define LIGHTRED 224 #define LIGHTGREEN 28 #define GREEN 20 #define DARKGREEN 12 #define GREY 185 #define VIOLET 227 #define BROWN 140 #define BLACK 0 #undef F_CPU #define F_CPU 14.7456E6 // otherweise => in C:\WinAVR-20100110\avr\include\util\delay.h //LCD-Pixel width #define LCD_WIDTH 132 #define LCD_HEIGHT 176 #define RITCENTER 800 //VFOs and frequency data (variables and constants) #define MAXVFO 12 //Number of virtuel VFOS available (multiplied by 5 due to number of bands) #define MAXSHIFT 11 //Number of different frequenc steps available when tuning #define STDTUNESTEP 4 //Number of default tuning step //VFO and frequency Data unsigned long vfo[5][MAXVFO]; //12 VFO-frequencies (indexes 0..11) for 5 bands each = 40 VFOs int skip_vfo[MAXVFO] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //12 skip flags for scanning VFOs unsigned int vfo_band[MAXVFO] = {}; //12 vaules showing which VFO is set to which band int cur_vfo = 0; //Pointer to VFO currently used unsigned long freq1; //Frequency currently used by radio int cur_band; //80m = 0, 40m = 1, 20m = 2, 15m = 3, 10m = 4 int band_part = 2; //Defines frequency generation method related to if int sideband_set[] = {0, 0, 1, 0, 0}; //0=Normal (relay OFF), sideband, 1 = reverse (relay ON) int cur_mode; //USB = 0, LSB = 1, CW = 2; unsigned int tuning_step[] = {1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000}; //Tuning step for each pulse from rotary encoder char *tuning_step_str[] = {"1Hz", "5Hz", "10Hz", "25Hz", "50Hz", "100Hz", "250Hz", "500Hz", "1kHz", "2.5kHz", "5kHz", "10kHz"}; //Tuning step string for each pulse from rotary encoder int cur_tuning_step = STDTUNESTEP; int rit_on = 0; //Upper and lower edges of the 5 ham bands -/+ 10 kHZ, band names unsigned long band_l[5] = {3490000, 6990000, 13990000, 20990000, 27990000}; unsigned long band_h[5] = {3810000, 7310000, 14350000, 21460000, 29900000}; char *band_str[5] = {"80m", "40m", "20m", "15m", "10m"}; unsigned long last_freq[] = {0, 0, 0, 0, 0}; //Stores last frequency used on every of the 5 band int get_band(unsigned long); //Get the ham band by given frequency void set_band(int); void set_frequency(unsigned long); ////////////// // Misc // //////////// void colortest(void); void func(void); //Various functions for scanning, storing QRGs etc int get_voltage(void); int get_temp(void); int get_adc(int); int get_svalue(void); int brightness = 127; //Medium brightness int smax; //Max value for S-Meter //FUNCTIONS dealing with EEPROM int load_cur_band(void); int load_cur_vfo(void); void save_freq_to_vfo(int, int, unsigned long); void save_cur_vfo(int, int); void save_last_used_vfo_frequency(int, unsigned long); unsigned long load_last_used_vfo_frequency(int); unsigned long load_freq(int, int); ////////////////////////////////// // SPI functions for Display // ///////////////////////////////// //SPI DISPLAY void spi_display_set_bit(char); void spi_display_reset_bit(char); void spi_display_send_byte_array(unsigned char [], unsigned int count) ; void spi_display_send_int(unsigned int) ; void spi_display_wait(void); void spi_display_send_word_array(unsigned int [], unsigned int); /////////////////////////////// // Functions for Display // ///////////////////////////// void display_init(void); void lcd_cls(unsigned char); void lcd_set_window(int, int, int, int); void lcd_draw_line(int, int, int, int, unsigned char ); void lcd_draw_rectangle(int, int, int, int, unsigned char, char); void lcd_draw_rectangle_filled(int, int, int, int, unsigned char); void lcd_print_char(int, int, char, int, unsigned char, unsigned char); //x, y, Char, Skalierung, VFarbe, BG void lcd_put_string(int, int, char *, int, unsigned char, unsigned char); //x, y, String, Skalierung, Farbe, BG void lcd_putnumber(int, int, long, int, int, char*, char, int, unsigned char, unsigned char ); //////////////////////////////////////////////////////////////// // Display functions to show certain values in defined places //////////////////////////////////////////////////////////////// void show_frequency(unsigned long, int); void show_vfo(int); void show_band(int); void show_voltage(unsigned int); //Voltage multilied by 10 void show_temp(int); void show_txrx(unsigned int); void show_svalue(unsigned int); void show_tuning_step(int); void show_msg_line(char *, int, int); void show_mode(int); void show_rit(int); void show_panorama(int); ////////////////////////////////// // SPI-Functions for AD9951 // ///////////////////////////////// void reset_ad9951(void); void spi_send_byte(int); ////////////////////////////// //// Timing and //// //////////////////////////// unsigned long runsecs = 0; unsigned long idlesecs = 0; unsigned long runsecsold1 = 0; //////////////////////////////// // versch. Anzeigefunktionen // ////////////////////////////// void display_light(int); //////////////// // AD-Wandler // /////////////// #define ADWAITSTATE 3 int adc_val; char adc_mode = 1; // 1=p.amb, 2=T, 3=Ub int main(void); unsigned char forecolor, backcolor; //Font used with 8x14 pixels #define FONTWIDTH 8 #define FONTHEIGHT 14 char fchar[] PROGMEM = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // space (32) 0, 0, 0, 24, 60, 60, 60, 24, 24, 0, 24, 24, 0, 0, // ! 0, 102, 102, 102, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, // " 0, 0, 0, 108, 108, 254, 108, 108, 108, 254, 108, 108, 0, 0, // # 0, 24, 24, 124, 198, 194, 192, 124, 6, 134, 198, 124, 24, 24, // & 0, 0, 0, 0, 0, 194, 198, 12, 24, 48, 102, 198, 0, 0, // % 0, 0, 0, 56, 108, 108, 56, 118, 220, 204, 204, 118, 0, 0, // & 0, 24, 24, 24, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Slash 0, 0, 0, 12, 24, 48, 48, 48, 48, 48, 24, 12, 0, 0, // ( 0, 0, 0, 48, 24, 12, 12, 12, 12, 12, 24, 48, 0, 0, // ) 0, 0, 0, 0, 0, 102, 60, 255, 60, 102, 0, 0, 0, 0, // * 0, 0, 0, 0, 0, 24, 24, 126, 24, 24, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 48, 0, // ´ 0, 0, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0, 0, // - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 0, 0, // . 0, 0, 0, 2, 6, 12, 24, 48, 96, 192, 128, 0, 0, 0, // / 0, 0, 0, 56, 108, 198, 198, 214, 198, 198, 108, 56, 0, 0, // 0 0, 0, 0, 24, 56, 120, 24, 24, 24, 24, 24, 126, 0, 0, // 1 0, 0, 0, 124, 198, 6, 12, 24, 48, 96, 198, 254, 0, 0, // 2 0, 0, 0, 124, 198, 6, 6, 60, 6, 6, 198, 124, 0, 0, // 3 0, 0, 0, 12, 28, 60, 108, 204, 254, 12, 12, 30, 0, 0, // 4 0, 0, 0, 254, 192, 192, 192, 252, 6, 6, 198, 124, 0, 0, // 5 0, 0, 0, 56, 96, 192, 192, 252, 198, 198, 198, 124, 0, 0, // 6 0, 0, 0, 254, 198, 6, 12, 24, 48, 48, 48, 48, 0, 0, // 7 0, 0, 0, 124, 198, 198, 198, 124, 198, 198, 198, 124, 0, 0, // 8 0, 0, 0, 124, 198, 198, 198, 126, 6, 6, 12, 120, 0, 0, // 9 0, 0, 0, 0, 24, 24, 0, 0, 0, 24, 24, 0, 0, 0, // : 0, 0, 0, 0, 24, 24, 0, 0, 0, 24, 24, 48, 0, 0, // ; 0, 0, 0, 12, 24, 48, 96, 192, 96, 48, 24, 12, 0, 0, // > 0, 0, 0, 0, 0, 0, 126, 0, 0, 126, 0, 0, 0, 0, // = 0, 0, 0, 96, 48, 24, 12, 6, 12, 24, 48, 96, 0, 0, // < 0, 0, 0, 124, 198, 198, 12, 24, 24, 0, 24, 24, 0, 0, // ? 0, 0, 0, 124, 198, 198, 222, 222, 222, 220, 192, 124, 0, 0, // @ 0, 0, 0, 16, 56, 108, 198, 198, 254, 198, 198, 198, 0, 0, // A 0, 0, 0, 252, 102, 102, 102, 124, 102, 102, 102, 252, 0, 0, // B 0, 0, 0, 60, 102, 194, 192, 192, 192, 194, 102, 60, 0, 0, // C 0, 0, 0, 248, 108, 102, 102, 102, 102, 102, 108, 248, 0, 0, // D 0, 0, 0, 254, 102, 98, 104, 120, 104, 98, 102, 254, 0, 0, // E 0, 0, 0, 254, 102, 98, 104, 120, 104, 96, 96, 240, 0, 0, // F 0, 0, 0, 60, 102, 194, 192, 192, 222, 198, 102, 58, 0, 0, // G 0, 0, 0, 198, 198, 198, 198, 254, 198, 198, 198, 198, 0, 0, // H 0, 0, 0, 60, 24, 24, 24, 24, 24, 24, 24, 60, 0, 0, // I 0, 0, 0, 30, 12, 12, 12, 12, 12, 204, 204, 120, 0, 0, // J 0, 0, 0, 230, 102, 108, 108, 120, 108, 108, 102, 230, 0, 0, // K 0, 0, 0, 240, 96, 96, 96, 96, 96, 98, 102, 254, 0, 0, // L 0, 0, 0, 198, 238, 254, 214, 198, 198, 198, 198, 198, 0, 0, // M 0, 0, 0, 198, 230, 246, 254, 222, 206, 198, 198, 198, 0, 0, // N 0, 0, 0, 124, 198, 198, 198, 198, 198, 198, 198, 124, 0, 0, // O 0, 0, 0, 252, 102, 102, 102, 124, 96, 96, 96, 240, 0, 0, // P 0, 0, 0, 124, 198, 198, 198, 198, 198, 214, 222, 124, 14, 0, // Q 0, 0, 0, 252, 102, 102, 102, 124, 108, 102, 102, 230, 0, 0, // R 0, 0, 0, 124, 198, 198, 96, 56, 12, 198, 198, 124, 0, 0, // S 0, 0, 0, 126, 126, 90, 24, 24, 24, 24, 24, 60, 0, 0, // T 0, 0, 0, 198, 198, 198, 198, 198, 198, 198, 198, 124, 0, 0, // U 0, 0, 0, 198, 198, 198, 198, 198, 198, 108, 56, 16, 0, 0, // V 0, 0, 0, 198, 198, 198, 198, 214, 214, 254, 108, 108, 0, 0, // W 0, 0, 0, 198, 198, 198, 124, 56, 124, 198, 198, 198, 0, 0, // X 0, 0, 0, 102, 102, 102, 102, 60, 24, 24, 24, 60, 0, 0, // Y 0, 0, 0, 254, 198, 140, 24, 48, 96, 194, 198, 254, 0, 0, // Z 0, 0, 0, 60, 48, 48, 48, 48, 48, 48, 48, 60, 0, 0, // [ 0, 0, 0, 128, 192, 224, 112, 56, 28, 14, 6, 2, 0, 0, // Backslash 0, 0, 0, 60, 12, 12, 12, 12, 12, 12, 12, 60, 0, 0, // ] 16, 56, 108, 198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ^ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, // _ 0, 48, 24, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ´ 0, 0, 0, 0, 0, 0, 120, 12, 124, 204, 204, 118, 0, 0, // a 0, 0, 0, 224, 96, 96, 120, 108, 102, 102, 102, 124, 0, 0, // b 0, 0, 0, 0, 0, 0, 124, 198, 192, 192, 198, 124, 0, 0, // c 0, 0, 0, 28, 12, 12, 60, 108, 204, 204, 204, 118, 0, 0, // d 0, 0, 0, 0, 0, 0, 124, 198, 254, 192, 198, 124, 0, 0, // e 0, 0, 0, 28, 54, 50, 48, 124, 48, 48, 48, 120, 0, 0, // f 0, 0, 0, 0, 0, 0, 118, 204, 204, 204, 124, 12, 204, 120, // g 0, 0, 0, 224, 96, 96, 108, 118, 102, 102, 102, 230, 0, 0, // h 0, 0, 0, 24, 24, 0, 56, 24, 24, 24, 24, 60, 0, 0, // i 0, 0, 0, 6, 6, 0, 14, 6, 6, 6, 6, 102, 102, 60, // j 0, 0, 0, 224, 96, 96, 102, 108, 120, 108, 102, 230, 0, 0, // k 0, 0, 0, 56, 24, 24, 24, 24, 24, 24, 24, 60, 0, 0, // l 0, 0, 0, 0, 0, 0, 236, 254, 214, 214, 214, 214, 0, 0, // m 0, 0, 0, 0, 0, 0, 220, 102, 102, 102, 102, 102, 0, 0, // n 0, 0, 0, 0, 0, 0, 124, 198, 198, 198, 198, 124, 0, 0, // o 0, 0, 0, 0, 0, 0, 220, 102, 102, 102, 124, 96, 96, 240, // P 0, 0, 0, 0, 0, 0, 118, 204, 204, 204, 124, 12, 12, 30, // q 0, 0, 0, 0, 0, 0, 220, 118, 102, 96, 96, 240, 0, 0, // r 0, 0, 0, 0, 0, 0, 124, 198, 112, 28, 198, 124, 0, 0, // s 0, 0, 0, 16, 48, 48, 252, 48, 48, 48, 54, 28, 0, 0, // t 0, 0, 0, 0, 0, 0, 204, 204, 204, 204, 204, 118, 0, 0, // u 0, 0, 0, 0, 0, 0, 198, 198, 198, 108, 56, 16, 0, 0, // v 0, 0, 0, 0, 0, 0, 198, 198, 214, 214, 254, 108, 0, 0, // w 0, 0, 0, 0, 0, 0, 198, 108, 56, 56, 108, 198, 0, 0, // x 0, 0, 0, 0, 0, 0, 198, 198, 198, 198, 126, 6, 12, 120, // y 0, 0, 0, 0, 0, 0, 254, 204, 24, 48, 102, 254, 0, 0, // z 0, 0, 0, 14, 24, 24, 24, 112, 24, 24, 24, 14, 0, 0, // { 0, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, // | 0, 0, 0, 112, 24, 24, 24, 14, 24, 24, 24, 112, 0, 0, // } 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, // unused 126 0, 0, 0, 24, 36, 36, 24, 0, 0, 0, 0, 0, 0, 0, // ° 127 }; ////////////////////////////////// // SPI functions for Display // ///////////////////////////////// //Set one bit of Port B to HI void spi_display_set_bit(char bit) { PORTB |= _BV(bit); } //Set one bit of Port B to LO void spi_display_reset_bit(char bit) { PORTB &= ~_BV(bit); } // Send byte or array data to display void spi_display_send_byte_array(unsigned char bytearray[], unsigned int bytecount) { int t1; for(t1 = 0; t1 < bytecount; ++t1) { SPCR |= _BV(SPE); SPDR = bytearray[t1]; spi_display_wait(); } } // Send integer number to display void spi_display_send_int(unsigned int value) { SPCR |= _BV(SPE); SPDR = (value >> 8) & 0xff; spi_display_wait(); SPCR |= _BV(SPE); SPDR = value & 0xff; spi_display_wait(); } // Send char to display void spi_display_send_byte(unsigned char value) { SPCR |= _BV(SPE); SPDR = value; spi_display_wait(); } // Send array in word (16 bits) to array // used for color data void spi_display_send_word_array(unsigned int wordarray[], unsigned int bytecount) { unsigned int t1; unsigned char msb; unsigned char lsb; for(t1 = 0; t1 < bytecount; ++t1) { spi_display_set_bit(SPI_DC); spi_display_reset_bit(SPI_SELECT); msb = (wordarray[t1] >> 8) & 0xff; lsb = wordarray[t1] & 0xff; SPCR |= _BV(SPE); SPDR = msb; spi_display_wait(); SPCR |= _BV(SPE); SPDR = lsb; spi_display_wait(); spi_display_reset_bit(SPI_DC); spi_display_set_bit(SPI_SELECT); } } //Wait for transmission being successfully completed void spi_display_wait(void) { while (SPCR & _BV(SPE)) { while (!(SPSR & (_BV(SPIF)))); SPCR &= ~(_BV(SPE)); } } /////////////////////////////// // Functions for Display // ///////////////////////////// //Inittialize display void display_init() { //init sequence //after it terminated wait for 75 ms before proceeding unsigned int init_data0[] = {0xFDFD, 0xFDFD}; unsigned int init_data1[] = {0xEF00, 0xEE04, 0x1B04, 0xFEFE, 0xFEFE, 0xEF90, 0x4A04, 0x7F1F, 0xEE04, 0x4306}; unsigned int init_data2[] = {0xEF90, 0x0983, 0x0800, 0x0BAF, 0x0A00, 0x0500, 0x0600, 0x0700, 0xEF00, 0xEE0C, 0xEF90, 0x0080, 0xEFB0, 0x4902, 0xEF00, 0x7F01, 0xE181, 0xE202, 0xE276, 0xE183, 0x8001, 0xEF90, 0x0000}; SPSR |= _BV(SPI2X); SPCR = _BV (SPE) | _BV(MSTR); _delay_ms(300); spi_display_reset_bit(SPI_RESET); _delay_ms(75); spi_display_set_bit(SPI_SELECT); _delay_ms(75); spi_display_reset_bit(SPI_CLOCK); _delay_ms(75); spi_display_set_bit(SPI_DC); _delay_ms(75); spi_display_set_bit(SPI_RESET); _delay_ms(75); spi_display_send_word_array(&init_data0[0], 2); _delay_ms(75); spi_display_send_word_array(&init_data1[0], 10); _delay_ms(75); spi_display_send_word_array(&init_data2[0], 23); spi_display_reset_bit(SPI_SELECT); } //Set window in landscape mode void lcd_set_window(int x0, int y0, int x1, int y1) { unsigned char window_data[] = {0xEF, 0x08, 0x18, 0x05, 0x12, LCD_WIDTH - 1 - y0, 0x15, LCD_WIDTH - 1 - y1, 0x13, x0, 0x16, x1}; spi_display_set_bit(SPI_DC); spi_display_reset_bit(SPI_SELECT); spi_display_send_byte_array(window_data, 12); spi_display_reset_bit(SPI_DC); } // CLS void lcd_cls(unsigned char bgcolor) { unsigned int t1, height, width; height = LCD_HEIGHT; //Full screen width = LCD_WIDTH; lcd_set_window(0, 0, height, width); for (t1 = 0; t1 < ((width + 1) * height); t1++) { spi_display_send_byte(bgcolor); } spi_display_set_bit(SPI_SELECT); } // Write a character to x/y position and use scale for sizing the output void lcd_print_char(int x, int y, char asciicode, int scale, unsigned char fcolor, unsigned char bcolor) { int t1, t2, t3, t4, t5; int xp; lcd_set_window(x, y, x + scale * FONTWIDTH - 1, y + scale * FONTHEIGHT - 1); //Split char into single bits for(t1 = (asciicode - 32) * FONTHEIGHT; t1 < (asciicode - 31) * FONTHEIGHT; t1++) { for(t5 = 0; t5 < scale; t5++) { //linewise for(t2 = FONTWIDTH - 1; t2 >= 0; t2--) { xp = 1; for(t3 = 0; t3 < t2; t3++) { xp <<= 1; } for(t4 = 0; t4 < scale; t4++) { if(pgm_read_byte(&fchar[t1]) & (int) xp) { spi_display_send_byte(fcolor); } else { spi_display_send_byte(bcolor); } } } } } spi_display_set_bit(SPI_SELECT);//Reset } //Write a string scaled by scale void lcd_put_string(int x, int y, char *s, int scale, unsigned char fcolor, unsigned char bcolor) { int col = 0; while(*(s)) { lcd_print_char(x + col++ * scale * FONTWIDTH, y, *(s++), scale, fcolor, bcolor); } } // Write an n-digit integer to display void lcd_putnumber(int x0, int y0, long num, int digits, int dec, char *unit, char orientation, int scale, unsigned char fcolor, unsigned char bcolor) { int xcur, col; char minusflag = 0; unsigned char cdigit[20] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, digitcnt = 0; long n = num, t1, t2, z, r; if(num < 0) { minusflag = 1; n *= -1; } //Get number of digits z = 1; if(digits == -1) { for(t1 = 1; t1 < 10 && (n / z); t1++) z *= 10; digits = t1 - 1; } if(!digits) { digits = 1; } for(t1 = digits - 1; t1 >= 0; t1--) { z = 1; for(t2 = 0; t2 < t1; t2++) { z *= 10; } r = n / z; cdigit[digitcnt++] = r + 48; if(t1 == dec) { cdigit[digitcnt++] = 46; } n -= r * z; } //if neccessary add a unit t1 = digitcnt; t2 = 0; while(unit[t2]) { cdigit[t1++] = unit[t2++]; } // cdigit[] contains the number as a string format //Send to lcd t1 = 0; col = 0; switch(orientation) { case 'l': while(cdigit[t1]) // left { xcur = x0 + col * scale * FONTWIDTH; lcd_print_char(xcur, y0, cdigit[t1++], scale, fcolor, bcolor); col++; } break; case 'r': // right digits = 0; // find end of string while(cdigit[digits]) { digits++; } t1 = 0; while(digits > 0) { xcur = x0 - t1++ * scale * FONTWIDTH; lcd_print_char(xcur, y0, cdigit[--digits], scale, fcolor, bcolor); } break; } } // Draw a rectangle (non filled) void lcd_draw_rectangle(int x0, int y0, int x1, int y1, unsigned char linecolor, char thickness) { //line hor top lcd_draw_rectangle_filled(x0, y0, x1, y0 + thickness, linecolor); //line hor bottom lcd_draw_rectangle_filled(x0, y1, x1, y1 + thickness, linecolor); //line left lcd_draw_rectangle_filled(x0, y0, x0 + thickness, y1, linecolor); //line right lcd_draw_rectangle_filled(x1, y0, x1 + thickness, y1 + thickness, linecolor); } //Draw a line void lcd_draw_line(int x0, int y0, int x1, int y1, unsigned char color) { double m = (y1 - y0) / (x1 - x0); int t1; m = (y1 - y0) / (x1 - x0); for(t1 = x0; t1 < x1; t1++) { lcd_draw_rectangle_filled(t1, y0 + m * (t1 - x0), t1, y0 + m * (t1 - x0 + 1), color); } } // Draw filled rectangle void lcd_draw_rectangle_filled(int x0, int y0, int x1, int y1, unsigned char color) { int t1, t2; lcd_set_window(x0, y0, x1, y1); for(t1 = x0; t1 <= x1; t1++) { for (t2 = y0; t2 <= y1; t2++) { spi_display_send_byte(color); } } spi_display_set_bit(SPI_SELECT); //Zurücksetzen } //Set display light void display_light(int value) { OCR1C = value; } ////////////////////////////////////////////////////////////////// // Display functions to show certain values in defined places // //////////////////////////////////////////////////////////////// //Display current frequency in top left corner void show_frequency(unsigned long f, int cls_line) { int y0 = 50; //CLS in frequency line if necessary if(cls_line) { lcd_draw_rectangle_filled(10, y0, 176, y0 + 28, backcolor); } lcd_putnumber(153, y0, f, -1, 3, "", 'r', 2, WHITE, backcolor); } //VFO number - Rectangle overlap = 2 pixels each //(5 Characters) //x: 4..50 //y: 40..58 void show_vfo(int vfo_num) { int x0 = 0, y0 = 15; int dx = FONTWIDTH * 5, dy = FONTHEIGHT + 4; lcd_draw_rectangle_filled(x0, y0, x0 + dx, y0 + dy, backcolor); lcd_put_string(x0 + 2, y0 + 2, "VFO", 1, GREEN, backcolor); lcd_print_char(x0 + 2 + FONTWIDTH * 3 + 3, y0 + 2, vfo_num + 65, 1, GREEN, backcolor); } //Current band (width 3 Characters = 24+4=28) //x: 52..82 //y: 40..58 void show_band(int band_num) { int x0 = 47, y0 = 15; int dx = FONTWIDTH * 3 + 7, dy = FONTHEIGHT + 4; lcd_draw_rectangle_filled(x0, y0, x0 + dx, y0 + dy, backcolor); lcd_put_string(x0 + 2, y0 + 2, band_str[band_num], 1, LIGHTBLUE, backcolor); } //Current tuning Step (max. 6 Chars => width = 48+4=52) //x: 84..138 //y: 40..58 void show_tuning_step(int st) { int x0 = 78, y0 = 15; int dx = FONTWIDTH * 6 + 10, dy = FONTHEIGHT + 4; lcd_draw_rectangle_filled(x0, y0, x0 + dx, y0 + dy, backcolor); lcd_put_string(x0 + 2, y0 + 2, tuning_step_str[st], 1, YELLOW, backcolor); } //Current Mode (max. 3 Chars => width = 48+4=52) //x: 140..170 //y: 40..58 void show_mode(int op_mode) { char *mode_str[] = {"USB", "LSB"}; int x0 = 141, y0 = 15; int dx = FONTWIDTH * 3 + 7, dy = FONTHEIGHT + 4; unsigned char fcolor; if(op_mode) { fcolor = LIGHTBLUE; } else { fcolor = WHITE; } lcd_draw_rectangle_filled(x0, y0, x0 + dx, y0 + dy, backcolor); lcd_put_string(x0 + 2, y0 + 2, mode_str[op_mode], 1, fcolor, backcolor); } //Current DC voltage void show_voltage(unsigned int volts10) { int x0 = 0, y0 = 32; int dx = FONTWIDTH * 5 + 7, dy = FONTHEIGHT + 4; lcd_draw_rectangle_filled(x0, y0, x0 + dx, y0 + dy, backcolor); if(volts10 > 110) //Voltage OK (>11V) { lcd_putnumber(x0 + 2, y0, volts10, -1, 1, "V", 'l', 1, LIGHTBLUE, backcolor); } else { lcd_putnumber(x0 + 2, y0, volts10, -1, 1, "V", 'l', 1, ORANGE, backcolor); } } //Temp of final amp void show_temp(int xtemp) { int x0 = 134, y0 = 32; int dx = FONTWIDTH * 5 + 7, dy = FONTHEIGHT + 4; lcd_draw_rectangle_filled(x0, y0, x0 + dx, y0 + dy, backcolor); if(xtemp < 40) //TEMP OK (<70°C) { lcd_putnumber(x0 + 2, y0, xtemp, -1, -1, " C", 'l', 1, LIGHTBLUE, backcolor); lcd_print_char(x0 + 18, y0, 127, 1, LIGHTBLUE, backcolor); return; } if(xtemp < 60) //TEMP OK (<70°C) { //lcd_putnumber(x0 + 2, y0, xtemp, -1, -1, "' C", 'l', 1, LIGHTGREEN, backcolor); lcd_putnumber(x0 + 2, y0, xtemp, -1, -1, " C", 'l', 1,LIGHTGREEN, backcolor); lcd_print_char(x0 + 18, y0, 127, 1, LIGHTGREEN, backcolor); return; } if(xtemp < 80) //TEMP OK (<70°C) { //lcd_putnumber(x0 + 2, y0, xtemp, -1, -1, " C", 'l', 1, ORANGE, backcolor); lcd_putnumber(x0 + 2, y0, xtemp, -1, -1, " C", 'l', 1, ORANGE, backcolor); lcd_print_char(x0 + 18, y0, 127, 1, ORANGE, backcolor); return; } if(xtemp >= 80) //TEMP OK (<70°C) { lcd_draw_rectangle_filled(x0, y0, x0 + dx, y0 + dy, YELLOW); //lcd_putnumber(x0 + 2, y0, xtemp, -1, -1, " C", 'l', 1, RED, backcolor); lcd_putnumber(x0 + 2, y0, xtemp, -1, -1, " C", 'l', 1, RED, backcolor); lcd_print_char(x0 + 18, y0, 127, 1, RED, backcolor); return; } //x0=100; //lcd_putnumber(x0 + 2, y0, get_adc(2), -1, -1, "'C", 'l', 1, YELLOW, backcolor); //ADC 299 = 20°C } void show_svalue(unsigned int sval) { int x0 = 48, y0 = 34; int sval2 = (int) (smax - sval) / 2, sred1 = 40, sred2 = 55; lcd_draw_rectangle_filled(x0, y0, 132, y0 + 14, backcolor); //Not in TX-mode if(PINA & (1<<PINA1)) { if(sval2 + x0 > 132) { sval2 = 132 - x0; } if(sval2 > 3) { if(sval2 < sred1) { lcd_draw_rectangle_filled(x0, y0 + 3, x0 + sval2, y0 + 6, GREEN); } else { if(sval2 < sred2) { lcd_draw_rectangle_filled(x0, y0 + 3, x0 + sred1 , y0 + 6, GREEN); lcd_draw_rectangle_filled(x0 + sred1 + 1, y0 + 3, x0 + sval2, y0 + 6, YELLOW); } else { lcd_draw_rectangle_filled(x0, y0 + 3, x0 + sred1 , y0 + 6, GREEN); lcd_draw_rectangle_filled(x0 + sred1 + 1, y0 + 3, x0 + sred2, y0 + 6, YELLOW); lcd_draw_rectangle_filled(x0 + sred2 + 1, y0 + 3, x0 + sval2, y0 + 6, RED); } } } } //lcd_putnumber(1, 80, sval2, -1, -1, "", 'l', 1, YELLOW, backcolor); } void show_txrx(unsigned int txstatus) { lcd_draw_rectangle_filled(130, 97, 179, 113, backcolor); if(txstatus) { lcd_put_string(131, 98, "TX", 1, YELLOW, RED); lcd_put_string(152, 98, "RX", 1, GREY, backcolor); } else { lcd_put_string(131, 98, "TX", 1, GREY, backcolor); lcd_put_string(152, 98, "RX", 1, YELLOW, DARKGREEN); } } //Show RIT void show_rit(int rit_val) { if(rit_on) { lcd_draw_rectangle_filled(0, 96, 99, 113, backcolor); lcd_put_string(5, 98, "RIT", 1, GREEN, backcolor); lcd_putnumber(38, 98, rit_val - RITCENTER, -1, -1, "Hz", 'l', 1, GREEN, backcolor); if(rit_val < RITCENTER) { lcd_put_string(30, 98, "-", 1, GREEN, backcolor); } } else { lcd_draw_rectangle_filled(0, 96, 99, 113, backcolor); lcd_put_string(5, 98, "RIT OFF", 1, RED, backcolor); } } //Message line from x0=0, y0=115; x1=100, y1=132 void show_msg_line(char *msg_txt, int fg, int bg) { lcd_draw_rectangle_filled(0, 115, 176, 132, bg); lcd_put_string(2, 116, msg_txt, 1, fg, bg); } void show_panorama(int band) { unsigned long freq_l[5] = {3500000, 7000000, 14000000, 21000000, 28000000}; unsigned long freq_h[5] = {3800000, 7200000, 14350000, 21450000, 28800000}; int steps[] = {300, 200, 350, 450, 800}; //Steps for each band unsigned long f_temp = freq1; unsigned char col[] = {BLUE, YELLOW, GREEN, RED, WHITE, LIGHTBLUE}; int colc = 0; int sv[1000]; unsigned long t1; int cnt = 0, x; //Get data for(t1 = 0; t1 < 1000; t1++) { sv[t1] = 0; } for(t1 = freq_l[band]; t1 < freq_h[band]; t1 += 1000) { set_frequency(t1); show_frequency(t1, 0); _delay_ms(30); sv[cnt++] = (int) (smax - get_svalue()) / 20; } //Show data x = 32; cnt = 0; lcd_draw_rectangle_filled(0, 78, 179, 96, backcolor); lcd_put_string(2, 85, "PAN", 1, GREEN, backcolor); for(t1 = 0; t1 < steps[band] && x < 179; t1 += 3) { sv[t1] += sv[t1 + 1]; sv[t1] += sv[t1 + 2]; lcd_draw_rectangle_filled(x, 95 - sv[t1], x, 95, col[colc]); x++; if(cnt++ > 33) { colc++; cnt = 0; } } set_frequency(f_temp); show_frequency(f_temp, 1); } ////////////////////////////////////////////////////////// // Functions for transmitting frequency data to AD9951 // //////////////////////////////////////////////////////// //RESET DDS chip void reset_ad9951(void) { PORTD |= 0x08; //Bit PD3 set _delay_ms(1); //wait for > 20ns i. e. 1ms minimum time with _delay_s() PORTD &= ~(0x08); //Bit PD3 erase } //Set PE3 to PE7 for switching the correct band filter for respective band void set_band(int cband) { //First reset all relays PORTE &= ~(8); PORTE &= ~(16); PORTE &= ~(32); PORTE &= ~(64); PORTE &= ~(128); switch(cband) { case 0: PORTE |= 8; //Bit PE3 set break; case 1: PORTE |= 16; //Bit PE4 set break; case 2: PORTE |= 32; //Bit PE5 set break; case 3: PORTE |= 64; //Bit PE6 set break; case 4: PORTE |= 128; //Bit PE7 set break; } } //For AD9951 DDS void set_frequency(unsigned long frequency) { //PORT usage // FQ_UD: PD0 (green) // DATA: PD1 (white) // CLK: PD2 (blue) // RESET: PD3 (pink) unsigned long interfreq = 10E06; //Interfrequency of radio in Hz unsigned long f; unsigned long fword; int t1, shiftbyte = 24, resultbyte; unsigned long comparebyte = 0xFF000000; //Calculate oscillator frequency depending on the question //if desired freq is higher or lower than 10 MHz if(cur_band <= band_part) { f = interfreq + frequency; //80, 40, 20 meters } else { f = frequency - interfreq; //15 and 10 meters } //Calculate frequency word //Clock rate = 120002500 //0xFFFFFFFF / 120002500 = 35.790.... fword = (unsigned long) f * 35.790648; //Start transfer to DDS PORTD &= ~(1); //FQ_UD lo => Bit PD0 = 0 //Send instruction bit to set fequency by frequency tuning word spi_send_byte(0x04); //Calculate and transfer the 4 bytes of the tuning word to DDS //Start with msb for(t1 = 0; t1 < 4; t1++) { resultbyte = (fword & comparebyte) >> shiftbyte; comparebyte >>= 8; shiftbyte -= 8; spi_send_byte(resultbyte); } //End transfer sequence PORTD |= 1; //FQ_UD hi => Bit PD0 = 1 } } //Send one byte to DDS void spi_send_byte(int sbyte) { // PORT usage // // DDS-Line PORT // FQ_UD: PD0 (green) // DATA: PD1 (white) // CLK: PD2 (blue) // RESET: PD3 (pink) int t1, x = 0x80; for(t1 = 0; t1 < 8; t1++) { //SCLK lo PORTD &= ~(4); //Bit PB2 löschen //Bit setzen oder löschen if(sbyte & x) { PORTD |= 2; //SDATA Bit PB1 setzen } else { PORTD &= ~(2); //SDATA Bit PB1 löschen } //Set clock to RISING edge!!! //SCLK hi PORTD |= 4; //Bit PB2 setzen x >>= 1; } } //////////////////////////////////////////////////////////////////////////// //Save VFO and frequency data to EEPROM //for quick loading on startup //Save number of last VFO used void save_cur_vfo(int c_band, int c_vfo) { //Save current band while(!eeprom_is_ready()); eeprom_write_byte((uint8_t*)250, c_band); while(!eeprom_is_ready()); eeprom_write_byte((uint8_t*)251, c_vfo); } //Save last used frequencies for a specific band //start at byte 253, 4 bytes each void save_last_used_vfo_frequency(int lband, unsigned long f) { unsigned int hiword, loword; unsigned char hmsb, lmsb, hlsb, llsb; cli(); int start_adr = 253 + lband * 4; hiword = f / 65536; loword = f - hiword * 65536; hmsb = hiword / 256; hlsb = hiword - hmsb * 256; lmsb = loword / 256; llsb = loword - lmsb * 256; while(!eeprom_is_ready()); eeprom_write_byte((uint8_t*)start_adr, hmsb); while(!eeprom_is_ready()); eeprom_write_byte((uint8_t*)start_adr + 1, hlsb); while(!eeprom_is_ready()); eeprom_write_byte((uint8_t*)start_adr + 2, lmsb); while(!eeprom_is_ready()); eeprom_write_byte((uint8_t*)start_adr + 3, llsb); sei(); } //Load frequency from EEPROM based on VFO unsigned long load_last_used_vfo_frequency(int lband) { unsigned long rf; unsigned char hmsb, lmsb, hlsb, llsb; int start_adr = 253 + lband * 4; cli(); hmsb = eeprom_read_byte((uint8_t*)start_adr); hlsb = eeprom_read_byte((uint8_t*)start_adr + 1); lmsb = eeprom_read_byte((uint8_t*)start_adr + 2); llsb = eeprom_read_byte((uint8_t*)start_adr + 3); sei(); rf = (unsigned long) 16777216 * hmsb + (unsigned long) 65536 * hlsb + (unsigned int) 256 * lmsb + llsb; return rf; } //Get last used band int load_cur_band(void) { int lband = eeprom_read_byte((uint8_t*)250); if(lband < 0 || lband > 4) { return 0; } else { return lband; } } //Get number of last VFO used int load_cur_vfo(void) { int lvfo = eeprom_read_byte((uint8_t*)251); if(lvfo < 0 || lvfo > MAXVFO - 1) { return 0; } else { return lvfo; } } //Save frequency from given VFO to EEPROM in 4 byte format void save_freq_to_vfo(int c_band, int vfo_num, unsigned long num) { unsigned int hiword, loword; unsigned char hmsb, lmsb, hlsb, llsb; int start_adr = c_band * 48 + vfo_num * 4; cli(); hiword = num / 65536; loword = num - hiword * 65536; hmsb = hiword / 256; hlsb = hiword - hmsb * 256; lmsb = loword / 256; llsb = loword - lmsb * 256; while(!eeprom_is_ready()); eeprom_write_byte((uint8_t*)start_adr, hmsb); while(!eeprom_is_ready()); eeprom_write_byte((uint8_t*)start_adr + 1, hlsb); while(!eeprom_is_ready()); eeprom_write_byte((uint8_t*)start_adr + 2, lmsb); while(!eeprom_is_ready()); eeprom_write_byte((uint8_t*)start_adr + 3, llsb); sei(); } //Load frequency from EEPROM based on VFO unsigned long load_freq(int c_band, int vfo_num) { unsigned long rf; unsigned char hmsb, lmsb, hlsb, llsb; int start_adr = c_band * 48 + vfo_num * 4; cli(); hmsb = eeprom_read_byte((uint8_t*)start_adr); hlsb = eeprom_read_byte((uint8_t*)start_adr + 1); lmsb = eeprom_read_byte((uint8_t*)start_adr + 2); llsb = eeprom_read_byte((uint8_t*)start_adr + 3); sei(); rf = (unsigned long) 16777216 * hmsb + (unsigned long) 65536 * hlsb + (unsigned int) 256 * lmsb + llsb; return rf; } //Get the ham band to a given frequency //Returns pointer to band! int get_band(unsigned long f) { int t1, in_band = -1; for(t1 = 0; t1 < 5; t1++) { if((f >= band_l[t1]) && (f <= band_h[t1])) { in_band = t1; } } return in_band; } //Measure voltage int get_voltage(void) { double volts = 10 * 6 * 5 * (double) get_adc(1) / 1024; return (int)(volts); } //Measure temperature of final amplifier //Sensor = KTY81-210 int get_temp(void) { double temp; double rt, rv = 1499, ut; double r0 = 1525.1; //Resistance of temperature sensor at 0°C double m = 14.27; //slope of temperature sensor in Ohms/K //Calculate voltage from ADC value ut = (double)get_adc(2) * 5 / 1024; //Calculate thermal resistor value from ADC voltage ut rt = ut * rv / (3.83 - ut); //Calculate temperature from rt temp = (rt - r0) / m; return (int)(temp); } //Measure S-Value int get_svalue(void) { //double sval; //temp = (1798 / (3.83 / (5 * (double) get_adc(3) / 1024) - 1) - 815) / 12.5; return get_adc(3); } // SPECIAL FUNCTIONS //FUNC //(C0) (C1) (C2) //(C3) (C4) (C5) //STORE FREQ TO VFO //Scan frequency, //Scan all VFOs //TUNE and many more functions void func(void) { int exit_func = 0; int exit_loop = 0; int band = get_band(freq1); int t1, loopcnt1 = 0; char msg_str[] = "Saved. Band: VFO: "; unsigned long tempsecs; //Store current frequncy to current VFO while(!(PINC & (1<<PINC4))); //STORE FREQ TO VFO show_msg_line("Store QRG? C/N/Y", BLACK, WHITE); //Wait for N, C or Y while((PINC & (1<<PINC3)) && (PINC & (1<<PINC4)) && (PINC & (1<<PINC5))); if(!(PINC & (1<<PINC5))) { while(!(PINC & (1<<PINC5))); //YES msg_str[12] = cur_band + '0'; msg_str[18] = cur_vfo + 'A'; //Save number and band of to be relaoded when TRX is turned on save_cur_vfo(cur_band, cur_vfo); //Save frequency an band data save_freq_to_vfo(cur_band, cur_vfo, freq1); vfo[cur_band][cur_vfo] = freq1; show_msg_line(msg_str, BLACK, WHITE); _delay_ms(500); exit_func = 1; } else { while(!(PINC & (1<<PINC3)) || !(PINC & (1<<PINC4)))//NO or cancel pressed => go on to next step { if(!(PINC & (1<<PINC0)))//VFO BTN pressed for ESCAPE { show_msg_line("FUNC quit by user.", BLACK, WHITE); while(!(PINC & (1<<PINC0))); return; } } } //Switch on tone generator for tuning if(!exit_func) { show_msg_line("TUNE? C/N/Y", BLACK, WHITE); tempsecs = runsecs; //Wait for N, C or Y while((PINC & (1<<PINC3)) && (PINC & (1<<PINC4)) && (PINC & (1<<PINC5))) { if(!(PINC & (1<<PINC0)))//VFO pressed for ESCAPE { show_msg_line("FUNC quit by user.", BLACK, WHITE); while(!(PINC & (1<<PINC0))); return; } } while((PINC & (1<<PINC3)) && (PINC & (1<<PINC4))) { //Temperature check if(get_temp() >= 50) { show_txrx(0); PORTA &= ~(8); //TX OFF! show_msg_line("TEMP TOO HI! EXIT.", DARKRED, YELLOW); return; } //GO! if(!(PINC & (1<<PINC5))) { while(!(PINC & (1<<PINC5))); if(get_temp() < 50) { show_txrx(1); PORTA |= 8; exit_func = 1; show_msg_line("TX ON", BLACK, WHITE); } } if(runsecs > tempsecs) { show_temp(get_temp()); tempsecs = runsecs; } } PORTA &= ~(8); show_txrx(0); while(!(PINC & (1<<PINC3)) || !(PINC & (1<<PINC3)) || !(PINC & (1<<PINC5))); //Wait till key released } //Save all frequencies that have been last used for //each VFO if(!exit_func) { show_msg_line("SAVE CUR QRGs?? C/N/Y", BLACK, WHITE); //Wait for N, C or Y while((PINC & (1<<PINC3)) && (PINC & (1<<PINC4)) && (PINC & (1<<PINC5))) { if(!(PINC & (1<<PINC0)))//VFO pressed for ESCAPE { show_msg_line("FUNC quit by user.", BLACK, WHITE); while(!(PINC & (1<<PINC0))); return; } } if(!(PINC & (1<<PINC5))) { for(t1 = 0; t1 < 5; t1++) { save_last_used_vfo_frequency(t1, last_freq[t1]); } show_msg_line("5 frequencies saved.", BLACK, WHITE); _delay_ms(1000); } } //Scan frequency, trigger with C4=UP or C5=DOWN. C3 cancels //(C0) (C1) (C2) //(C3) (C4) (C5) if(!exit_func) { show_msg_line("Scan band? C/Up/Dn", BLACK, WHITE); //Wait for key //UP, DOWN, FUNC while((PINC & (1<<PINC3)) && (PINC & (1<<PINC4)) && (PINC & (1<<PINC5))) { if(!(PINC & (1<<PINC0)))//VFO pressed for ESCAPE { show_msg_line("FUNC quit by user.", BLACK, WHITE); while(!(PINC & (1<<PINC0))); return; } } //UP if(!(PINC & (1<<PINC4))) { while(!(PINC & (1<<PINC4))); while((PINC & (1<<PINC3))) //Do until CANCEL! { if(freq1 > band_h[band]) { freq1 = band_l[band]; } freq1 += tuning_step[cur_tuning_step]; set_frequency(freq1); show_frequency(freq1, 0); _delay_ms(10); //Leave function after performing exit_func = 1; } } //DOWN if(!(PINC & (1<<PINC5))) { while(!(PINC & (1<<PINC5))); while((PINC & (1<<PINC4))) //Do until CANCEL! { if(freq1 < band_l[band]) { freq1 = band_h[band]; } freq1 -= tuning_step[cur_tuning_step]; set_frequency(freq1); show_frequency(freq1, 0); _delay_ms(10); //Leave function after performing exit_func = 1; } } if(!(PINC & (1<<PINC3))) //Skipped { while(!(PINC & (1<<PINC3))); } } //Scan all VFOs if(!exit_func) { show_msg_line("Scan VFOs? C/N/Y", BLACK, WHITE); //Wait for key press C/Y/N while((PINC & (1<<PINC3)) && (PINC & (1<<PINC4)) && (PINC & (1<<PINC5))) { if(!(PINC & (1<<PINC0)))//VFO pressed for ESCAPE { show_msg_line("FUNC quit by user.", BLACK, WHITE); while(!(PINC & (1<<PINC0))); return; } } //Scan VFOs if(!(PINC & (1<<PINC5))) { while(!(PINC & (1<<PINC5))); //Set all skip flags to 0 for(t1 = 0; t1 < MAXVFO - 1; t1++) { skip_vfo[t1] = 0; } show_msg_line("SCANNING C-Skp-Sel", BLACK, WHITE); exit_loop = 0; t1 = 0; while(!exit_loop) { if(!skip_vfo[t1]) //Scan only if VFO not in skip list { runsecsold1 = runsecs; if(get_band(vfo[cur_band][t1]) == cur_band) { set_frequency(vfo[cur_band][t1]); show_frequency(vfo[cur_band][t1], 1); show_vfo(t1); } else { show_msg_line("Invalid data!", BLACK, WHITE); } //Wait 4 seconds or CANCEL or SELECT Vfo for listening to QRG while((PINC & (1<<PINC3)) && (PINC & (1<<PINC5)) && runsecs < runsecsold1 + 4) { if(!(PINC & (1<<PINC4))) //Skip current VFO { while(!PINC & (1<<PINC3)); skip_vfo[t1] = 1; show_msg_line("SKIPPED!", BLACK, WHITE); runsecsold1 = 0; //Quit loop! } lcd_putnumber(158, 116, runsecsold1 + 4 - runsecs, -1, -1, "s", 'l', 1, BLACK, WHITE); //After 50 loops check S-Val if(loopcnt1++ > 50) { show_svalue(get_svalue()); loopcnt1 = 0; } } show_msg_line("SCANNING C-Skp-Sel", BLACK, WHITE); if(!(PINC & (1<<PINC5))) //Select VFO and STOP scanning { while(!(PINC & (1<<PINC5))); exit_loop = 1; cur_vfo = t1; freq1 = vfo[cur_band][cur_vfo]; set_frequency(freq1); } if(!(PINC & (1<<PINC3))) //Abort { while(!(PINC & (1<<PINC3))); exit_loop = 1; } } if(t1 < MAXVFO) { t1++; } else { t1 = 0; } } exit_func = 1; } while(!(PINC & (1<<PINC3)) || !(PINC & (1<<PINC4))); } if(!exit_func) { //USE RIT? show_msg_line("USE RIT? C/N/Y", BLACK, WHITE); //Wait for N, C or Y while((PINC & (1<<PINC3)) && (PINC & (1<<PINC4)) && (PINC & (1<<PINC5))) { if(!(PINC & (1<<PINC0)))//VFO pressed for ESCAPE { show_msg_line("FUNC quit by user.", BLACK, WHITE); while(!(PINC & (1<<PINC0))); return; } } //ON if(!(PINC & (1<<PINC5))) { while(!(PINC & (1<<PINC5))); //YES rit_on = 1; show_msg_line("RIT ON.", BLACK, WHITE); exit_func = 1; } //OFF if(!(PINC & (1<<PINC4))) { while(!(PINC & (1<<PINC4))); //YES rit_on = 0; show_msg_line("RIT OFF.", BLACK, WHITE); exit_func = 1; } //Cancel if(!(PINC & (1<<PINC3))) { while(!(PINC & (1<<PINC3))); rit_on = 0; show_msg_line("NO CHANGE.", BLACK, WHITE); } show_rit(0); } //LIGHT BRIGHTNESS if(!exit_func) { //SET DISP LIGHT show_msg_line("SET LIGHT. C/-/+", BLACK, WHITE); //Wait for N, C or Y while((PINC & (1<<PINC3)) && (PINC & (1<<PINC4)) && (PINC & (1<<PINC5))) { if(!(PINC & (1<<PINC0)))//VFO pressed for ESCAPE { show_msg_line("FUNC quit by user.", BLACK, WHITE); while(!(PINC & (1<<PINC0))); return; } } //Cancel while((PINC & (1<<PINC3))) { //BRIGHTER if(!(PINC & (1<<PINC5))) { exit_func = 1; if(brightness > 10) { brightness -= 10; display_light(brightness); } while(!(PINC & (1<<PINC5))); } //DARKER if(!(PINC & (1<<PINC4))) { exit_func = 1; if(brightness < 240) { brightness += 10; display_light(brightness); } while(!(PINC & (1<<PINC4))); } } show_msg_line("LIGHT SET.", BLACK, WHITE); eeprom_write_byte((uint8_t*)252, brightness); while(!(PINC & (1<<PINC3))); //Wait till key released } //COLORTEST if(!exit_func) { //COLORTEST show_msg_line("COL TEST? C/N/Y", BLACK, WHITE); //Wait for N, C or Y while((PINC & (1<<PINC3)) && (PINC & (1<<PINC4)) && (PINC & (1<<PINC5))) if(!(PINC & (1<<PINC0)))//VFO pressed for ESCAPE { show_msg_line("FUNC quit by user.", BLACK, WHITE); while(!(PINC & (1<<PINC0))); return; } //GO! if(!(PINC & (1<<PINC5))) { while(!(PINC & (1<<PINC5))); colortest(); exit_func = 1; } show_msg_line("FINISHED.", BLACK, WHITE); while(!(PINC & (1<<PINC3)) || !(PINC & (1<<PINC3)) || !(PINC & (1<<PINC5))); //Wait till key released } //Panorama RX if(!exit_func) { //PANORAMA RX show_msg_line("PANORAMA RX? C/N/Y", BLACK, WHITE); //Wait for N, C or Y while((PINC & (1<<PINC3)) && (PINC & (1<<PINC4)) && (PINC & (1<<PINC5))) { if(!(PINC & (1<<PINC0)))//VFO pressed for ESCAPE { show_msg_line("FUNC quit by user.", BLACK, WHITE); while(!(PINC & (1<<PINC0))); return; } } //GO! if(!(PINC & (1<<PINC5))) { while(!(PINC & (1<<PINC5))); show_panorama(cur_band); exit_func = 1; } show_msg_line("FINISHED.", BLACK, WHITE); while(!(PINC & (1<<PINC3)) || !(PINC & (1<<PINC3)) || !(PINC & (1<<PINC5))); //Wait till key released } show_msg_line("Done.", DARKBLUE, WHITE); } void colortest(void) { int r = 0, g = 0, b = 0; int xbyte1; lcd_cls(BLACK); while(1) { if(!(PINC & (1<<PINC0))) { if(r > 0) { r--; } } if(!(PINC & (1<<PINC1))) { if(g > 0) { g--; } } if(!(PINC & (1<<PINC2))) { if(b > 0) { b--;; } } if(!(PINC & (1<<PINC3))) { if(r < 7) { r++; } } if(!(PINC & (1<<PINC4))) { if(g < 7) { g++; } } if(!(PINC & (1<<PINC5))) { if(b < 3) { b++; } } xbyte1 = ((r << 5) + (g << 2)) + b; lcd_draw_rectangle_filled(0, 100, LCD_HEIGHT, LCD_WIDTH, xbyte1); lcd_put_string(5, 10, "RED:", 1, RED, BLACK); lcd_putnumber(80, 10, r, -1, -1, "", 'l', 1, YELLOW, BLACK); lcd_put_string(5, 30, "GREEN:", 1, GREEN, BLACK); lcd_putnumber(80, 30, g, -1, -1, "", 'l', 1, YELLOW, BLACK); lcd_put_string(5, 50, "BLUE:", 1, BLUE, BLACK); lcd_putnumber(80, 50, b, -1, -1, "", 'l', 1, YELLOW, BLACK); lcd_put_string(5, 70, "ALL:", 1, WHITE, BLACK); lcd_put_string(80, 70, " ", 1, WHITE, BLACK); lcd_putnumber(80, 70, xbyte1, -1, -1, "", 'l', 1, WHITE, BLACK); _delay_ms(50); } } //*************************************************** // ADC //*************************************************** int get_adc(int adc_channel) { int adc_val = 0; ADMUX = (ADMUX &~(0x1F)) | (adc_channel & 0x1F); // Kanal adcmode aktivieren PA0=TUNE _delay_ms(ADWAITSTATE); ADCSRA |= (1<<ADSC); _delay_ms(ADWAITSTATE); adc_val = ADCL; adc_val += ADCH * 256; while(ADCSRA & (1<<ADSC)); return adc_val; } //////////////////////////////////////////////// // // INTERRUPTROUTINEN & TIMER / PWM // /////////////////////////////////////////////// // Timer 0 Ereignisroutine (autom. Aufruf 1/s) ISR(TIMER0_OVF_vect) { runsecs++; TCNT0 = 0; // Timerregister auf 0 } //////////////////////////////////////// int main() { //ADC value int adc_val; //Universal Message String char msg_str[] = "BAND: VFO: "; //Elapse times for measurements unsigned long runsecsold2 = 0; //VOltage display unsigned long runsecsold3 = 0; //Temp measurement unsigned long loopcnt1 = 0; //S-Value measurement int t1, t2; //TEMP for frequency unsigned long freq2 = 0; //Variables for rotary encoder unsigned long ti = 0, ac = 0, bc = 0; //Storage for last mode used before setting sideband switch int last_mode = 0; unsigned int txstatold = 0; //Last TX status int rit = 0, old_rit = 0; //Value for rx frequency offset unsigned long rit_check = 0; //RIT check interval /////////////// //SET PORTS // ///////////// //OUTPUT //SPI for DISPLAY DDRB = 255; //SPI-Port für Display und Displayhelligkeit über PWM (PB0..PB7) => Output //SPI for DDS chip AD9xyz DDRD = 0x1F; //SPI out for AD9951 (PD0..PD3) and PD4 for sideband relay switch DDRE = 0xF8; //PD3...PD7 for switching 5 ham bands with transceiver board DDRG = 2; // PG1 auf "Output". Wird benötigt, um // die Peripherie von der Energieversorung zu trennen um Strom zu sparen // ACHTUNG: Option muss auf Modul "D072" vorhanden sein, Brücke "JP" muss getrennt sein!!!! DDRA = 8; //Activate PA2 for output to switch tone generator for tuning //INPUT PORTC = 0xFF; //All PINS of PORTC as inputs with pull-up resistors activated. PORTA = 1; //PA0 for detecting sideband switch position //Basic band and frequency data //Load fromm EEPROM if available //////////////////////////////////////////////////////// //Load all VFOs for all bands if previously stored for(t2 = 0; t2 < 5; t2++) { for(t1 = 0; t1 < MAXVFO - 1; t1++) { freq2 = load_freq(t2, t1); if(get_band(freq2) > -1) { vfo[get_band(freq2)][t1] = freq2; } } } //Load last VFO used in previous session //and set frequency cur_vfo = load_cur_vfo(); if((cur_vfo < 0) || (cur_vfo > MAXVFO - 1)) { cur_vfo = 0; } cur_band = load_cur_band(); if(cur_band < 0 || cur_band > 4) { cur_band = 0; } freq1 = vfo[cur_band][cur_vfo]; //Use default value if data not available if(freq1 <= 0) { freq1 = 3700123; cur_band = 0; } //Load the 5 frequencies that have been used last for(t1 = 1; t1 < 5; t1++) { last_freq[t1] = load_last_used_vfo_frequency(t1); } //Put a reset to distinct reset line reset_ad9951(); set_band(cur_band); set_frequency(freq1); //////////////////////////////////////////////////////////// // Watchdog off wdt_reset(); // Set WDTOE and WDE HI WDTCR |= (1<<WDCE) | (1<<WDE); // WDT of! WDTCR = 0x00; _delay_ms(20); //LCD init display_init(); //Init PWM for display light TCNT1 = 0x00FF; //Set TimerCounter1 TCCR1A = 13; //Set OC1C to "PWM, Phase Correct, 8-bit" TCCR1B = 11; //Prescaler CLK/64 OCR1C = 0x00; // Duty-cycle to 100% TCCR1C = 32; // PWM Outport=OC1C (PORT B7) //Set default color for text and background forecolor = WHITE; backcolor = BLACK; lcd_cls(backcolor); brightness = eeprom_read_byte((uint8_t*)252); if(brightness < 10 || brightness > 255) { brightness = 127; } display_light(brightness); // Set Timer 0 for counting seconds based on 32.768 kHz clock crystal TIMSK &=~((1<<TOIE0)|(1<<OCIE0)); //TC0 interrupt disable ASSR |= (1<<AS0); //Timer/Counter0 asynchronously with clock crystal TCNT0 = 0x00; TCCR0 = 0x05; //f.xtal (CLK / 128) clock rate //one count per second while(ASSR&0x07); //wait till finished TIMSK |= (1<<TOIE0); //8-bit Timer/Counter0 Overflow Interrupt enabled //ADC init ADMUX = (1<<REFS0); // Reference = AVCC ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADEN); //Prescaler 64 and ADC on ADCSRA |= (1<<ADSC); //Do one conversion while (ADCSRA & (1<<ADSC)); //wait adc_val = ADCL; adc_val += ADCH * 256; //read value adc_val = 0; smax = get_svalue(); cur_tuning_step = STDTUNESTEP; cur_mode = 0; //Display current frequency, band and other data show_frequency(freq1, 1); show_vfo(cur_vfo); show_band(cur_band); show_voltage(get_voltage()); show_tuning_step(cur_tuning_step); show_mode(cur_mode); show_txrx(0); show_rit(rit_on); show_temp(get_temp()); //Show dta of recent band and vfo msg_str[5] = eeprom_read_byte((uint8_t*)250) + '0'; //Band msg_str[11] = eeprom_read_byte((uint8_t*)251) + 'A'; //VFO show_msg_line(msg_str, BLACK, WHITE); sei(); // Interrupts enabled set_frequency(freq1); for(;;) { //Tuning with rotary encoder connected to PC6 and PC7 //A lo if(!(PINC & (1<<PINC6)) && !ac) { ac = ti; //Get timestamp when A went low idlesecs = runsecs; } //B lo if(!(PINC & (1<<PINC7)) && !bc) { bc = ti; //Get timestamp when B went low idlesecs = runsecs; } if(ac && bc) //Compare A and B if greater than ZERO { if(ac > bc) //Knob was turned counter clockwise { freq1 -= tuning_step[cur_tuning_step]; set_frequency(freq1); show_frequency(freq1, 0); } if(bc > ac) //Knob was turned clockwise { freq1 += tuning_step[cur_tuning_step]; set_frequency(freq1); show_frequency(freq1, 0); } ac = 0; bc = 0; ti = 0; } ti++; //Increase counter variable if((PINC & (1<<PINC6)) && (PINC & (1<<PINC7))) //Reset all values when knob is idle { ti = 0; ac = 0; bc = 0; } ///////////////////////////////////////////////////////// //VFO-Select - PORT used: PC0 if(!(PINC & (1<<PINC0))) { //Save old band, old VFO number and old frequency data to RAM and EEPROM vfo[cur_band][cur_vfo] = freq1; save_freq_to_vfo(cur_band, cur_vfo, freq1); save_cur_vfo(cur_band, cur_vfo); if(cur_vfo < MAXVFO - 1) { cur_vfo++; } else { cur_vfo = 0; } //set frequency and get current ham band freq1 = vfo[cur_band][cur_vfo]; if(!freq1) { freq1 = band_l[cur_band] + 10000; } set_frequency(freq1); cur_band = get_band(freq1); //Update display show_frequency(freq1, 0); show_vfo(cur_vfo); show_band(cur_band); //wait for key release while(!(PINC & (1<<PINC0))); } /////////////////////////////////////////////////////// //Change Band UP if(!(PINC & (1<<PINC1))) { //Save last frequency from this band last_freq[cur_band] = freq1; if(cur_band < 4) { cur_band++; } else { cur_band = 0; } //Get current VFO frequency for this band freq1 = last_freq[cur_band]; //In case of not plausibel value use default value for given band if(freq1 < band_l[cur_band] || freq1 > band_h[cur_band]) //No valid data { freq1 = band_l[cur_band] + 150000; } set_band(cur_band); set_frequency(freq1); show_frequency(freq1, 1); while(!(PINC & (1<<PINC1))); show_band(cur_band); idlesecs = runsecs; } //Change Band DOWN if(!(PINC & (1<<PINC4))) { //Save last frequency from this band last_freq[cur_band] = freq1; if(cur_band > 0) { cur_band--; } else { cur_band = 4; } //Get current VFO frequency for this band freq1 = last_freq[cur_band]; //In case of not plausibel value use default value for given band if(freq1 < band_l[cur_band] || freq1 > band_h[cur_band]) //No valid data { freq1 = band_l[cur_band] + 150000; } set_band(cur_band); set_frequency(freq1); show_frequency(freq1, 1); while(!(PINC & (1<<PINC4))); show_band(cur_band); idlesecs = runsecs; } ////////////////////////////////////////////////////// //Set Frequency-Shift for tuning UP if(!(PINC & (1<<PINC2))) { if(cur_tuning_step < MAXSHIFT) { cur_tuning_step++; } else { cur_tuning_step = 0; } while(!(PINC & (1<<PINC2))); show_tuning_step(cur_tuning_step); idlesecs = runsecs; } //Set Frequency-Shift for tuning DOWN if(!(PINC & (1<<PINC5))) { if(cur_tuning_step > 0) { cur_tuning_step--; } else { cur_tuning_step = MAXSHIFT; } while(!(PINC & (1<<PINC5))); show_tuning_step(cur_tuning_step); idlesecs = runsecs; } ////////////////////////////////////////////////////// //Go to FUNC to set more functions if(!(PINC & (1<<PINC3))) { while(!(PINC & (1<<PINC3))); func(); } if((runsecs > idlesecs + 2) && (cur_tuning_step != STDTUNESTEP)) { cur_tuning_step = STDTUNESTEP; show_tuning_step(cur_tuning_step); } /* if(!(PINA & (1<<PINA0))) //Sideband switch in "reverse" position { PORTD &= ~(16); //PORTD4 HI => Relay OFF } else { PORTD |= 16; //PORTD4 LO => Relay ON } */ //Detect position of sideband switch //switch relay if neccessary and show current sideband if(!(PINA & (1<<PINA0))) //Sideband switch in "reverse" position { if(!sideband_set[cur_band]) //Sideband standard required? { PORTD |= 16; //PORTD4 LO => Relay ON if(cur_band == 0) cur_mode = 0; if(cur_band == 1) cur_mode = 0; if(cur_band == 3) cur_mode = 1; if(cur_band == 4) cur_mode = 1; } else { PORTD &= ~(16); //PORTD4 HI => Relay OFF if(cur_band == 2) cur_mode = 1; } } else //Sideband switch in NORMAL position { if(!sideband_set[cur_band]) //Relay must be switched OFF { PORTD &= ~(16); //PORTD4 HI => Relay OFF if(cur_band == 0) cur_mode = 1; if(cur_band == 1) cur_mode = 1; if(cur_band == 3) cur_mode = 0; if(cur_band == 4) cur_mode = 0; } else { PORTD |= 16; //PORTD4 LO => Relay ON if(cur_band == 2) cur_mode = 0; } } //Check TX/RX status if(!(PINA & (1<<PINA1))) { if(!txstatold) //On air! { show_txrx(1); txstatold = 1; set_frequency(freq1); } } else { if(txstatold) { show_txrx(0); txstatold = 0; } if(rit_on) { //Ckeck RIT setting if(rit_check < 20000) { rit_check++; } else { rit_check = 0; rit = get_adc(0) * 2; if(rit != old_rit) { show_rit(rit); set_frequency(freq1 + rit - RITCENTER); } } } } //Mode changed, display new one! if(last_mode != cur_mode) { show_mode(cur_mode); last_mode = cur_mode; } //After 6 seconds check voltage if(runsecs > runsecsold2 + 5) { show_voltage(get_voltage()); runsecsold2 = runsecs; } //After 5 seconds check temp if(runsecs > runsecsold3 + 4) { show_temp(get_temp()); runsecsold3 = runsecs; } //After 5000 loops check S-Val if(loopcnt1++ > 5000) { show_svalue(get_svalue()); loopcnt1 = 0; } } return 0; }