“Give me FIVE!” – 5 band QRP SSB transceiver – The Software


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;
}

Leave a Reply

Your email address will not be published. Required fields are marked *