A compact project: The “Micro42” – Another “shirt pocket” SSB transceiver.

The Micro42 - A really pocket sized SSB QRP transceiver for 7MHz

Having deferred the work on the “micro multibander” for some time I finished another small QRP rig (this one for 7MHz) that is suitable for my summer excursions by bike or hiking the local mountains here in the State of Rhineland-Palatinate or the Black Forest that is not that far away on the other side of the Rhine valley.

Besides, this transceiver to be discussed here is some sort of a “remake” of a 20 meter rig I built 3 years before. And this time, the transceiver really fits into a shirt pocket without having to wear “XXXXL”- clothing. ;-):

The Micro42 - A really shirt pocket sized QRP SSB transceiver
The Micro42 – A really shirt pocket sized QRP SSB transceiver (this is my work shirt, so don’t mind the stains! 😉 )

General circuit description (instead of presenting a block diagram)

The rig uses two mixers NE602 plus one filter as central elements. The signal way is reversed when switching from receive to trasmit mode. This is done by 2 relays and is a well known technique for simple QRP rigs. You will find lots of equivalent ideas on the internet (Example 1, Example 2).

But not to ignore the shortcomings of these designs: They are somehow inferior to my requirements, particularly concercing receiver performance. I prefer to have higher signal gain and an AGC circuit. AGC for me is a must. But these designs can be expanded easily, so I added an AGC controlled interfrequency amplifier with dual gate MOSFET BF998 into the receiver’s signal path enhancing performance significantly.

Frequency layout

The frequency generation of the superhet transceiver scheme is simple: Again I use one interfrequency (i. e. 9MHz). The VFO is DDS based on AD9835 operating below the desired radio frequency, which means that it is set to the range of about 2 MHz. Due to this low frequency you could replace the DDS by a VFO if you don’t like the relatively complex work with the software programming and microcontroller stuff). A 2MHz VFO can also be made very stable, so this is an alternative not to be ignoered.

Due to the fact that the schematic is not very difficult to analyze you are kindly requested to refer to it for further talking:

Schematic - The Micro42 - A really shirt pocket sized QRP SSB transceiver
Schematic – The Micro42 – A really shirt pocket sized QRP SSB transceiver. Click for full size picture

Circuit description

In the center of the schematic you can see the main elements of the circuit: One SSB filter (9MHz), correctly terminated by 2 resistors of 1k each (to ensure proper filter response curve) and two relays with a double set of switches. These relays reverse the way the signal travels through the filter. The advantage of this: You can use the integrated oscillator of the NE612 controlled by a crystal and a tuning capacitor to set the carrier frequency correctly for the lower sideband because the mixer is used as SSB generator and as product detector in common.

A word on chosing the proper relays: An intense examination of the relays’ data sheet is essential. I built a prototype of this transceiver on a breadboard prior to soldering the components to a veroboard. I found that some SMD relays have signifikant coupling capacities between the unused relay contacts (in the range of some Picofarads). So stray coupling was a severe problem. Later I used some second-hand Teledyne RF relays that I had purchased via ebay two years ago (price originally 50€!) for 1€ each. These relays are absolutely superb!

The receiver

Before we go: In the circuit scheme above I missed out the antenna switch relay because I think every homebrewer knows what to do in this case. 😉 So the receiver’s signal path starts with a band filter for 7MHz consisting of to tuned LC circuits.  The coupling is relatively loose. As coils I use the well known coil formers in TOKO style with 5.5mm outside measure.

Coil data for the 7MHz band pass filter (BPF) is 39 turns primary and 9 turns secondary of 0.1 mm enameled wire. The respective capacitor is 33pF. This is a high L to C ratio which gives you excellent LC quality factor. This is mandatory especially when working on the 40 meter band, because of the strong broadcasters starting from 7.200 kHz intermodulation might be a problem when the receiver is connected to a high gain antenna and broadcasters’ signals might overload the first mixer (remember that NE612 has a relatively low IM3!). If you still should have problems coping with too strong out-of-band signals you can reduce the coupler from 4.7pF down to 2.7pF.

In practical terms I could not detect any unwanted signal products even when using an antenna with high rf output voltage. One reasons for this is, that there is no rf preamplifier for the receiver. This avoids overloading the first mixer generally.

The NE612 has two mixer inputs and two outputs. This makes it very suitable for this sort of radio. In receive mode pin 2 of the right NE612 is used as signal input. VFO signal is fed into pin 6. The resulting mixer products are taken out from pin 4. Next the 9MHz filter follows from right to left.

The 9MHz IF signal then is fed into an IF amplifier. This one is equipped with a dual gate MOSFET (BF998), gain is about 15dB when full AGC voltage is applied wich leads to about 6V by the 1:1 volatge divider in the applied to gate 2 of the MOSFET.

The left NE612 is the product detector. I use the internal oscillator with a 9MHz crsytal and a tuning capacitor here. This saves building an extra oscillator and simplifies the rig again.

One AF low pass filter made of 1k resistor, 100uF rf choke and a 0.1 uF capacitor eliminates high frequency remainders generated by the mixing process.

The audio stages are also made simple: One preamplifier (using bipolar transistor in grounded emmitter circuit) and a final stage with LM386 transform the signal to a level that is sufficient to be fed into a small 8 ohm loudspeaker or a set of standrd MP3-player headphones. Because the rig is very small and there was definetely no space for a loudspeaker I use headphones instead.

Keep an eye on the power supply switching of the two audio stages. The problem was to eliminate the switching click and pops to a minimum and to avoid acoustic feedback when unsing a loudspeaker. So the audio preamp is only connected to DC on receive. When switching to transmit the charged capacitors avoid instant cut off supplying some Milliseconds DC to the amp until significantly discharged. The main amplfier on the other hand is connected to permanent DC supply. So it won’t pop when switching from tx to rx an vice versa but can cause feedback. To avoid feedback a transistor is used to cut the speaker/earphone from the power amplifier.

AGC

AGC is audio derived. A two stage amplifier provides a DC voltage analog to the audio input sginal strength. First amplifier stage is a common emitter bipolar transistor supplying sufficient audio voltage. This voltage is rectified by a two diode circuit letting only the positive halfways pass. You can use silicon diodes (1N1418) oder Schottky diodes here. An electrolytic capacitor (100uF/6V) provides the time constant respectively DC decay once the signal has disappeared. Output of the DC stage is split. The collector is connected to 12V via a 4.7k resistors causing a voltage drop when the transitor’s conductivity increases. The emitter is fed to the ADC of the microcontroller (pin ADC1) causing a proportional voltage to the voltage of the applied audio signal so that on the OLED an S-meter can be displayed.

The transmitter

An electret microphone picks the operator’s voice. The signal output level of these microphones is high enough to drive the left NE612 (which serves as balanced modulator in this case) directly. Signal input for the mixer should be 200mV RMS according to data sheet. An electret produces about 0.5 to 1 V pp if spoken with a decent voice in the distance of some centimeters. So you have more than enough audio signal power for the modulator.

BTW: Carrier suppression of the modulator is excellent. I achieved 56dB without doing anything else!

The resulting DSB signal then is fed into the SSB filter, the SSB signal subsequently is directly sent into the right NE612. A band pass filter for 7 MHz eliminates the unwanted mixer products. You should have 400 to 500 mV pp of rf signal here when the transmitter input is fully driven. I recommend a two-tone test generator to check out the linearity of this and the remaining amplifier stages!

Next parts of the transmitter are a band pass filter (same coils and capacitors like th rx bandpass filter), a preamplifier and a driver. The later should put out about 150 mW into a 50 ohm load. They are made more linear by emitter degeneration (4.7 and 2.2 ohm resistors for predriver and driver) and negative feedback. This helps to ensure that transmitter performance is fine when IMD3 products are concerned even if the main IMD3 problems usually occur in the final stage.

To transfer the rf power into the final stage proper impedance matching is mandatory. Input impedance of the final stage is fairly low (<10ohms), therefore a broadband (down)transformer is used. Data is: Core T37-43, primary 12 turns, secondary 4 turns of 0.4 mm enamled wire.

Last stage is a single ended linear amplifier in AB mode equipped with a 2SC1969 rf power transistor by eleflow.com.

BIAS circuit: The combination of the 1k resistor, a silicon diode (1N4002 or equ.) and a capacitor sets up the correct bias. Bias is fed into the cold end of the input transformer. Quiescant current should be around 40mA. A good thermal contact between the diode and the transistor is recommended. As the transistor gets warmer the diode will increase its conductivity so reducing bias current. This will prevent thermal runaway effectively!

To avoid bulky output transformers the PI-filter (7MHz LPF) is part of the tank circuit of the final amplifier transistor. For this power level this is an acceptable and practical solution because the output impedance of the stage is nearly equivalent to 50 Ohms. A certain mismatch is not a severe problem. DC to the final transistor is applied via an rf choke, for exact data please refer to the schematic!

T2 helps to suppress unwanted signals that I encountered when taking the transmitter from the dummy load test environment to a real antenna. I observed unwanted parasetic oscillation in the range of about 1MHz. T2 has a low reactance for this frequency range thus eliminating the oscillations in a reilable way by short circuiting them towards ground.

Powered with 12.5V DC the transmitter will put out slightly more than 5 watts PEP.

DDS VFO

AD9835 is a simple but well performing 10-bit DDS chip made by Analog Devices (AD). It is controlled via 3 SPI lines transmitting the frequency data. Maximum output frequency is around 16MHz when the chip is clocked with its maximum clock rate of 50 MHz. Oscillator output voltage is some hundred millivolts peak-to-peak, so you can connect the output directly to pin 6 of the NE612 mixer.

Control signals come from an Arduino Pro Mini board. The microcontroller in this module is, if you are an Arduino user, preinstalled with a bootloader program. I overwrote this small portion of code and use the ATMega168, which is the core of the Arduino, in “native” mode. My software is written in C and transferred via “AVR dude” software using the ISP lines MOSI, MISO, SCK and RESET. These lines are not in the schematic, please refor to ATmega168 data sheet. Alternatively you can use, like shown in the schematic, an ATmega168 controller. So you have to de neccessary wiring on your own.

You will find the source code here. I packed it into an Open Document Text File because of problems I encountered when I tried to store the code into this Blogtext. If you need a compiled HEX-file, please feel free to email me!

Display is a very small OLED with 64 by 32 pixels. The OLED is, to my point of view, a little bit noisy. To suppress any rf traveling on VDD line I use an 82 ohm resistor and a set of bypass capacitors of 100uF and 0.1uF capacity closely connected  to the OLED VDD pin to GND.

A low pass filter by the output of the DDS ensures spectral purity and avoids clock oscillator feed through. Remember that if you need another output frequency other than 2 MHz you should redesign the low pass filter.

Frequency control

Tuning is done by a rotary encoder connected to PD5 and PD6 of the microcontroller. I use the pull up resistors internal to the microcontroller, so you won’t see any other things than the mere encoder.

Tunings steps are selected by pushing the encoder knob or another suitable push button. This button is connected to ADC0 in the ATMega168 via a 3.9k resistor. The resulting ADC voltage might be problem because of a certain variation in the values of the pull up resistors that form the second resistor of the voltage divider.  There is an outcommented section in the code that will show you the exact ADC value that has to be typed into the code so that key recognition works exactly.

The button once pushed will increase the tuning step by a certain amount of Hz. Steps are 10, 50, 100 (standard step), 250, 500, 1000 and 5000 Hz in and endlessly revolving chain.  The step will be reset to 100Hz (standard tuning step) by leaving the tuning knob idle for 2 seconds. That’s all with the controls. Very simple, but sufficient.

Practical aspects

The transceiver is constructed on a double sided veroboard with 6 by 8 centimeters area. Components are through hole and SMD where available. The Arduino is mounted to the front panel (another Veroboard carrying the controls etc.) as well as the OLED is. The veroboard is inserted into an aluminium frame connected to the front panel with 4 lateral M2 screws:

Mounting frame - The Micro42 - A really shirt pocket sized QRP SSB transceiver
Mounting frame – The Micro42 – A really shirt pocket sized QRP SSB transceiver

Design hints:

Wiring can be made by using the colored lines stripped from old parallel printer cables. These cables have a diameter of precisely 1mm an fit through the holes of the veroboard excactly.

If you connect any external components that are not on the same veroboard use standard 2.54 mm (0.1″) male and female board connectors! This will make it much easier to dismantle and reassemble the rig in case troubleshooting is neccessary.

Use M2 srews instaed of M3 when building very small rigs like this one!

The reverse side of the main arrangement:

Reverse side of mounting frame - The Micro42 - A really shirt pocket sized QRP SSB transceiverord-and-front-assembled-in-frame-reverse
Reverse side of mounting frame – The Micro42 – A really shirt pocket sized QRP SSB transceiver

Two brass made bends (from the local hardware store and each cut to a length of 8 centimeters) hold the PCB inside the mounting frame. A winding has been cut into the brass to fix the bends with screws in M2.

Final assembly

Together with 2 halves of a bent aluminium cabinet covered with “DC-fix” (a German manufacturer of self-adhesive PVC coating) the final rig looks like that:

The Micro42 - A really pocket sized SSB QRP transceiver for 7MHz
The Micro42 – A really pocket sized SSB QRP transceiver for 7MHz

So, that’s the end of the story so far. Now it’s time for going outdoor and test the rig in field use. 😉

73 and thanks for watching!

Peter (DK7IH)

Advertisements

A Micro Multibander – Step by step (Part III): The Receiver (Overview)

Work is in progress. The recent weeks I finished all the 6 modules that are going to be the receiver:

  • Band pass filter section
  • Relay switches for switching the BPFs
  • RF preamp, RX mixer and IF preamp
  • IF main amp
  • Product detector and AF amp section
  • AGC unit

Mounted together to an aluminium carrier board it looks like this:

Receiver board for Micro Multiband QRP SSB TRX (C) DK7IH 2018
Receiver board for Micro Multiband QRP SSB TRX (C) DK7IH 2018

On the picture the board is not equipped with the neccessary wiring yet to give the reader more sight on the single circuits. Next I will draw a schematic of each board to point out the used circuitry for those who want to build this or a similar receiver.

First test are promising so far, the receiver is sensitive, has a very low noise figure (due to dual gate MOSFETs in the preamp and the two main IF amp stages) and has shown no problems to cope with high out-of-band broadcaster signals on the 40 meter band which is due to the SBL-3 mixer I have used that has a good IM3 performance..

Thanks for watching an 73 de Peter (DK7IH)

A Micro Multibander – Step by step (Part II): VFO and Front Panel

In the last entry about my new project, a micro multibander for QRP SSB HF use, I referred on the circuits of the Si5351 VFO, the microcontroller, OLED module an the other digital circuits controlling the transceiver.

This is the practical side, now: All the digital circuits are placed behind the front panel. This is for practical (to save space in the main cabinet) and electronic reasons. By keeping the digital leads as short as possible you make it is easier avoiding hum, noise and other unwanted radio signals penetrating into your analog circuits, mainly the reciever.

This is how the front section looks from the user side:

Front panel of a SSB QRP micro multiband transceiver for SSB (C) 2018 DK7IH)
Front panel of a SSB QRP micro multiband transceiver for SSB (C) 2018 DK7IH)

The 3 potentiometers on the left (still awaiting suitable knobs) are for audio volume, receiver gain and mic gain. A switch will allow to switch the AGC from fast to slow. The S-meter has been taken from an old CB mini radio. All does not fit that much, some mechanical work still has to be done. 😉

Front panel of a SSB QRP micro multiband transceiver for SSB (C) 2018 DK7IH)
Front panel of a SSB QRP micro multiband transceiver for SSB (C) 2018 DK7IH)

This is the module taken from the side. All electronic stuff is mounted onto a 8cm x 6cm double sided veroboard. I use M2 spacers of various lengths to keep the “subboards” in place, like the Si5351 breakout, that you can see in the middle of the picture. These spacers are available from Chinese vendors on ebay and help a lot to build very compact electronic stuff. All joints and bolts are kept in M2, too.

The module is finished with a 1.5mm aluminium board where the plugs for the connectors are fed through. These connectors will be equipped with home-made plugs (1″ technology) and then connected to the respective parts of the analog circuits like receiver or transmitter.

qrp-ssb-multiband-micro-dk7ih-frontpanel-side2
Front panel of a SSB QRP micro multiband transceiver for SSB (C) 2018 DK7IH)

Here is another view of the lateral arrangement: The old-style S-meter stripped from an old HANDIC-brand CB radio was purchased on ebay for a few Euros. There ist still a lot of old CB stuff there, giving enthusiast homebrewers a large stock in interesting electronic and radio-related material.

(To be continued)

A Micro Mulibander – Step by step (Part I)

This project tries a new personal approach in designing a very small (i. e. a micro) QRP radio. And also new is the way I want to report about it. The blog entries will be published more or less simultanously to the building progress of the respective modules.

1 A brief project description

The main objective is to set up a SSB QRP transceiver for 6 HF bands (similar to my 5-bander introduced in 2015) now starting with 160m, then 80m, 40m, 20m, 15m and 10m at last.

Another idea I have in mind is to build the rig from separate modules for each single stage so that each main circuit (mainly receiver and transmitter section) is constructed with the needed stages on verobaords that are mechanically identical.

The idea behind that is that a board which does not show top performance in function (or even completely fails) can be changed quickly and an improved version can be installed easily without the need to throw the whole receiver (for example) into the junk box labelled with “failed projects”.

Band switching will be done by small relays again (I purchased 60 SMD relays for 40€ some months ago). The band filter section will be shared by tx and rx section this time. This saves space and reduces effort.

The transmitter will be a 4 stage unit again (more or less the same like in my 5 bander). Output power projected is 5 to 10 watts on all the bands.

The receiver is designed once again as a single conversion superhet because experiments with double conversion were not successful due to a large number of spurs audible in the receiver.

The first mixer is set to be an SBL-3 diode ring mixer. This will give the receiver a very good handling of strong signals, I hope. IF amplifier will be a two staged one with dual gate mosfets controlled by an audio derived AGV voltage. The rest? The usual suspects, I would say. Wait and see!

1.1 The VFO module

I have become quite familiar with SiLab’s Si5351 oscillator module the recent months. I first used it in my “Micro 20-3” trx which was a success. The module is very small, completely ready for use (I’m still using a breakout board made by Adafruit) and able to handle 5V. It provides 3 oscillators that can be programmed independently to put out something lieke a square wave ranging from 8kHz to 160MHz. I have developed a software that avoids any tuning noise, so, this oscillator (which is a clock oscillator by intention) can be used as a VFO for an amateur project.

To keep the effort simple, I reused the 1306 oled module that you can see in lots of my previous projects. Both boards (Si5351 and 1306 oled) are controlled by I²C-bus which allowes me to use a relatively simple micro controller. In this case again I have the Arduino Pro Mini containing an ATMega168 controller (16 MHz) on board. If it should turn out that I might need more memory, the same board here is on stock carrying an ATmega328 controller. Let’s see how this will work out.

This is the circuit of the complete VFO module:

Si5351 VFO for Micro Multiband QRP SSB TRX (C) DK7IH 2018
Si5351 VFO for Micro Multiband QRP SSB TRX (C) DK7IH 2018

The module will be placed behind the front panel.

Tuning will be done by a Bourns optical encoder that turns very smoothely. I purchased some for under 5 Euros each from pollin.de. An unbeatable price! Unfortunatley they have been quickly sold out.

The core of this module is the Arduino Pro Mini microcontroller centered on the diagram. It is connected to the Si5351 breakout board and the 1306 oled display by I²C bus.

Si5351: Output 0 is used as VFO terminal and output 1 carries the LO signal with 9Mhz. To avoid digital noise spreading on the +5V line a 100µF capacitor should be switched close to the VDD terminal. Proper and short grounding also is recommended to avoid spurs.

OLED1306: Also a 100µF electrolytic capacitor has been added including a 10µH rf choke forming a low pass filter together. I found that these oleds a very prone to distribute digital noise via VVD line, so this measure contributes much to keep your receiver clean from any unwanted signal spektrum generated by the oled.

Keep in mind to tie SCK and SDA lines to +5V via two resistors of 4.7kOhms each!

Band switching: It is software controlled. To save output ports I did not connect the 6 relay drivers for the 6 bands directly to the ports of the microcontroller. I’m using an open collector BCD to DEC driver (74LS145) instead. Ports PB0, PB1 and PB2 are forming a 3-bit pattern that is switched to 6 output lines (output 0 to output 5) of the BCD2DEC driver IC. 74LS145 is capable of handling switch voltages up to 15V thus working with 12V coil relays is easy.

User control interface: This rig has 4 different switches that will be explained later from the functional point of view. The operator can set nearly all functions of the transceiver by using these push buttons and the main tuning wheel. The buttons  switch to GND by 4 different resistors and are read by PC0 port of the micro. PC0 equivalents to  channel 0 of the integrated analog-to-digital converter (ADC) inside the ATMega168. This also saves controller ports to a large extent (using 3 instead of 6 ports!). So, all in all, I think I can dare controlling a multibander by a relatively small microcontroller.

(To be continued!)

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

My “Vintage Style QRP Transceiver” on YouTube

This transceiver was built to celebrate my 30 years anniversary in homebrewing QRP transceivers. The 14MHz rig was designed building an SSB transceiver like I did in the 80s. The only exception was, that this one uses SMD technology whereas in 1987 I used thru-hole components. But the rest is original 80s-style:

  • VFO instead of DDS
  • Standard S-Meter for TX and RX instead of OLED
  • Dynamic mic instead of electret mike

Have fun watching!

73 de Peter (DK7IH)

The “Micro20 III” QRP SSB Transceiver for 14 MHz – The Software

/*****************************************************************/
/*             VFO for QRP SSB Nano-Transceiver 20m              */
/*                       "Micro20 III"                           */
/*                 w. ATMega168 and Si5351                       */
/*                    Display OLED SSD1306                       */
/*  ************************************************************ */
/*  MUC:              ATMEL AVR ATmega168, 8 MHz                 */
/*                                                               */
/*  Compiler:         GCC (GNU AVR C-Compiler)                   */
/*  Author:           Peter Rachow (DK7IH)                       */
/*  Last change:      OCT 2017                                   */
/*****************************************************************/

//PORTS
//OUTPUT

//INPUT
//PC0: =ADC0: Pull-up for key switches with various resistors against GND 
//PC1: =ADC1: AGC voltage for S-Meter
//PC2: =ADC2: Voltage measurement
//PC3: =ADC3: TX PWR meter



//PD1: TX/RX indicator
//PD5, PD6: Rotary encoder

//TWI
//PC4=SDA, PC5=SCL: I²C-Bus lines: 

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/eeprom.h>
#include <util/delay.h>
#include <util/twi.h>

#undef F_CPU 
#define F_CPU 80000000

/////////////////////
//Defines for Si5351
/////////////////////
#define SI5351_ADDRESS 0xC0 // 0b11000000 for my module. Others may vary! The 0x60 did NOT work with my module!

//Set of Si5351A register addresses
#define CLK_ENABLE_CONTROL       3
#define PLLX_SRC				15
#define CLK0_CONTROL            16 
#define CLK1_CONTROL            17
#define CLK2_CONTROL            18
#define SYNTH_PLL_A             26
#define SYNTH_PLL_B             34
#define SYNTH_MS_0              42
#define SYNTH_MS_1              50
#define SYNTH_MS_2              58
#define PLL_RESET              177
#define XTAL_LOAD_CAP          183

//SI5351 Declarations & frequency
void si5351_write(int, int);
void si5351_start(void);
void si5351_set_freq(int, unsigned long);
void set_oscillators(int, unsigned long, int);
unsigned long scan_frequency(unsigned long, unsigned long, int, int);     

//////////////////////////////////////
//   L   C   D   
//////////////////////////////////////


// Font 5x8 for OLED
const char fontchar[485] = {
0x00,0x00,0x00,0x00,0x00, // 20 space ASCII table for NOKIA LCD: 96 rows * 5 bytes= 480 bytes
0x00,0x00,0x5f,0x00,0x00, // 21 ! Note that this is the same set of codes for character you
0x00,0x07,0x00,0x07,0x00, // 22 " would find on a HD44780 based character LCD.
0x14,0x7f,0x14,0x7f,0x14, // 23 # Also, given the size of the LCD (84 pixels by 48 pixels),
0x24,0x2a,0x7f,0x2a,0x12, // 24 $ the maximum number of characters per row is only 14.
0x23,0x13,0x08,0x64,0x62, // 25 %
0x36,0x49,0x55,0x22,0x50, // 26 &
0x00,0x05,0x03,0x00,0x00, // 27 '
0x00,0x1c,0x22,0x41,0x00, // 28 (
0x00,0x41,0x22,0x1c,0x00, // 29 )
0x14,0x08,0x3e,0x08,0x14, // 2a *
0x08,0x08,0x3e,0x08,0x08, // 2b +
0x00,0x50,0x30,0x00,0x00, // 2c ,
0x08,0x08,0x08,0x08,0x08, // 2d -
0x00,0x60,0x60,0x00,0x00, // 2e .
0x20,0x10,0x08,0x04,0x02, // 2f /
0x3e,0x51,0x49,0x45,0x3e, // 30 0
0x00,0x42,0x7f,0x40,0x00, // 31 1
0x42,0x61,0x51,0x49,0x46, // 32 2
0x21,0x41,0x45,0x4b,0x31, // 33 3
0x18,0x14,0x12,0x7f,0x10, // 34 4
0x27,0x45,0x45,0x45,0x39, // 35 5
0x3c,0x4a,0x49,0x49,0x30, // 36 6
0x01,0x71,0x09,0x05,0x03, // 37 7
0x36,0x49,0x49,0x49,0x36, // 38 8
0x06,0x49,0x49,0x29,0x1e, // 39 9
0x00,0x36,0x36,0x00,0x00, // 3a :
0x00,0x56,0x36,0x00,0x00, // 3b ;
0x08,0x14,0x22,0x41,0x00, // 3c <
0x14,0x14,0x14,0x14,0x14, // 3d =
0x00,0x41,0x22,0x14,0x08, // 3e >
0x02,0x01,0x51,0x09,0x06, // 3f ?
0x32,0x49,0x79,0x41,0x3e, // 40 @
0x7e,0x11,0x11,0x11,0x7e, // 41 A
0x7f,0x49,0x49,0x49,0x36, // 42 B
0x3e,0x41,0x41,0x41,0x22, // 43 C
0x7f,0x41,0x41,0x22,0x1c, // 44 D
0x7f,0x49,0x49,0x49,0x41, // 45 E
0x7f,0x09,0x09,0x09,0x01, // 46 F
0x3e,0x41,0x49,0x49,0x7a, // 47 G
0x7f,0x08,0x08,0x08,0x7f, // 48 H
0x00,0x41,0x7f,0x41,0x00, // 49 I
0x20,0x40,0x41,0x3f,0x01, // 4a J
0x7f,0x08,0x14,0x22,0x41, // 4b K
0x7f,0x40,0x40,0x40,0x40, // 4c L
0x7f,0x02,0x0c,0x02,0x7f, // 4d M
0x7f,0x04,0x08,0x10,0x7f, // 4e N
0x3e,0x41,0x41,0x41,0x3e, // 4f O
0x7f,0x09,0x09,0x09,0x06, // 50 P
0x3e,0x41,0x51,0x21,0x5e, // 51 Q
0x7f,0x09,0x19,0x29,0x46, // 52 R
0x46,0x49,0x49,0x49,0x31, // 53 S
0x01,0x01,0x7f,0x01,0x01, // 54 T
0x3f,0x40,0x40,0x40,0x3f, // 55 U
0x1f,0x20,0x40,0x20,0x1f, // 56 V
0x3f,0x40,0x38,0x40,0x3f, // 57 W
0x63,0x14,0x08,0x14,0x63, // 58 X
0x07,0x08,0x70,0x08,0x07, // 59 Y
0x61,0x51,0x49,0x45,0x43, // 5a Z
0x00,0x7f,0x41,0x41,0x00, // 5b [
0x02,0x04,0x08,0x10,0x20, // 5c Yen Currency Sign
0x00,0x41,0x41,0x7f,0x00, // 5d ]
0x04,0x02,0x01,0x02,0x04, // 5e ^
0x40,0x40,0x40,0x40,0x40, // 5f _
0x00,0x01,0x02,0x04,0x00, // 60 `
0x20,0x54,0x54,0x54,0x78, // 61 a
0x7f,0x48,0x44,0x44,0x38, // 62 b
0x38,0x44,0x44,0x44,0x20, // 63 c
0x38,0x44,0x44,0x48,0x7f, // 64 d
0x38,0x54,0x54,0x54,0x18, // 65 e
0x08,0x7e,0x09,0x01,0x02, // 66 f
0x0c,0x52,0x52,0x52,0x3e, // 67 g
0x7f,0x08,0x04,0x04,0x78, // 68 h
0x00,0x44,0x7d,0x40,0x00, // 69 i
0x20,0x40,0x44,0x3d,0x00, // 6a j
0x7f,0x10,0x28,0x44,0x00, // 6b k
0x00,0x41,0x7f,0x40,0x00, // 6c l
0x7c,0x04,0x18,0x04,0x78, // 6d m
0x7c,0x08,0x04,0x04,0x78, // 6e n
0x38,0x44,0x44,0x44,0x38, // 6f o
0x7c,0x14,0x14,0x14,0x08, // 70 p
0x08,0x14,0x14,0x18,0x7c, // 71 q
0x7c,0x08,0x04,0x04,0x08, // 72 r
0x48,0x54,0x54,0x54,0x20, // 73 s
0x04,0x3f,0x44,0x40,0x20, // 74 t
0x3c,0x40,0x40,0x20,0x7c, // 75 u
0x1c,0x20,0x40,0x20,0x1c, // 76 v
0x3c,0x40,0x30,0x40,0x3c, // 77 w
0x44,0x28,0x10,0x28,0x44, // 78 x
0x0c,0x50,0x50,0x50,0x3c, // 79 y
0x44,0x64,0x54,0x4c,0x44, // 7a z
0x00,0x08,0x36,0x41,0x00, // 7b <
0x00,0x00,0x7f,0x00,0x00, // 7c |
0x00,0x41,0x36,0x08,0x00, // 7d >
0x10,0x08,0x08,0x10,0x08, // 7e Right Arrow ->
0x78,0x46,0x41,0x46,0x78, // 7f Left Arrow <-
0x00,0x06,0x09,0x09,0x06};  // 80 °

///////////////////////////
//     DECLARATIONS
///////////////////////////
//
//I²C
void TWIInit(void);
void TWIStart(void);
void TWIStop(void);
uint8_t TWIReadACK(void);
uint8_t TWIReadNACK(void);
uint8_t TWIGetStatus(void);

//OLED
void oled_command(int value);
void oled_init(void);
void oled_write_byte(int col, int page, int val);
void oled_cls(void);
void oled_putchar1(int, int, char, int);
void oled_putchar2(int, int, char, int);
void oled_putstring(int, int, char *, char, int);
void oled_putnumber(int, int, long, int, int, int);
void oled_clear_section(int, int, int);
int xp2(int xp);

//String
int int2asc(long num, int dec, char *buf, int buflen);
int strlen(char *s);

//Data display functions
void show_frequency(long);
void show_frequency_cls(void);
void show_tstep(int, int);
void show_sideband(int, int);
void show_voltage(int);
void show_meter(int);
void draw_meter_scale(int meter_type);
void show_store(int, int, unsigned long);
void show_txrx(int);
void show_split(int);
void show_split2(int);
void show_rcl(int);


//ADC
int get_adc(int);
int get_keys(void);

//EEPROM
void store_frequency(unsigned long);
unsigned long load_frequency(void);

//MISC
int main(void);
unsigned int menu(void);
int set_lo_frequencies(void);

/////////////////////////////////////
//   Global constants & variables
/////////////////////////////////////
int laststate = 0; //Last state of rotary encoder
int tuningknob = 0;
int split = 0;
	
//Tuning steps available
#define MAXTSTEPS 6 //Highest index of tsteps = n-1
#define STDTSTEP 2 //Standard tuning step
int n_tstep[] = {10, 50, 100, 250, 500, 1000, 5000};
int cur_tstep = STDTSTEP;

//SIDEBAND
#define MAXMODES 2
int sideband = 0;  //Current sideband in use USB=0, LSB=1
unsigned long f_bfo[] = {10697600, 10692700}; //LO FREQUENCIES 10.7MHz

//METER
int sv_old = 0;

///////////////////////////
//
//         TWI
//
///////////////////////////

void twi_init(void)
{
    //set SCL to 400kHz
    TWSR = 0x00;
    TWBR = 0x0C;
	
    //enable TWI
    TWCR = (1<<TWEN);
}

//Send start signal
void twi_start(void)
{
    TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
}

//send stop signal
void twi_stop(void)
{
    TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

void twi_write(uint8_t u8data)
{
    TWDR = u8data;
    TWCR = (1<<TWINT)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
}

uint8_t TWIGetStatus(void)
{
    uint8_t status;
    //mask status
    status = TWSR & 0xF8;
    return status;
}

////////////////////////////////
//
// Si5351A commands
//
///////////////////////////////
void si5351_write(int reg_addr, int reg_value)
{
   	 
   twi_start();
   twi_write(SI5351_ADDRESS);
   twi_write(reg_addr);
   twi_write(reg_value);
   twi_stop();
} 

// Set PLLs (VCOs) to internal clock rate of 900 MHz
// Equation fVCO = fXTAL * (a+b/c) (=> AN619 p. 3
void si5351_start(void)
{
  unsigned long a, b, c;
  unsigned long p1, p2;//, p3;
  
  
  // Init clock chip
  si5351_write(XTAL_LOAD_CAP, 0xD2);      // Set crystal load capacitor to 10pF (default), 
                                          // for bits 5:0 see also AN619 p. 60
  si5351_write(CLK_ENABLE_CONTROL, 0x00); // Enable all outputs
  si5351_write(CLK0_CONTROL, 0x0F);       // Set PLLA to CLK0, 8 mA output
  si5351_write(CLK1_CONTROL, 0x2F);       // Set PLLB to CLK1, 8 mA output
  si5351_write(CLK2_CONTROL, 0x2F);       // Set PLLB to CLK2, 8 mA output
  si5351_write(PLL_RESET, 0xA0);          // Reset PLLA and PLLB

  // Set VCOs of PLLA and PLLB to 900 MHz
  a = 36;           // Division factor 900/25 MHz
  b = 0;            // Numerator, sets b/c=0
  c = 1048757;      //Max. resolution, but irrelevant in this case (b=0)

  //Formula for splitting up the numbers to register data, see AN619
  p1 = 128 * a + (unsigned long) (128 * b / c) - 512;
  p2 = 128 * b - c * (unsigned long) (128 * b / c);
  //p3  = c;

  
  //Write data to registers PLLA and PLLB so that both VCOs are set to 900MHz intermal freq
  si5351_write(SYNTH_PLL_A, 0xFF);
  si5351_write(SYNTH_PLL_A + 1, 0xFF);
  si5351_write(SYNTH_PLL_A + 2, (p1 & 0x00030000) >> 16);
  si5351_write(SYNTH_PLL_A + 3, (p1 & 0x0000FF00) >> 8);
  si5351_write(SYNTH_PLL_A + 4, (p1 & 0x000000FF));
  si5351_write(SYNTH_PLL_A + 5, 0xF0 | ((p2 & 0x000F0000) >> 16));
  si5351_write(SYNTH_PLL_A + 6, (p2 & 0x0000FF00) >> 8);
  si5351_write(SYNTH_PLL_A + 7, (p2 & 0x000000FF));

  si5351_write(SYNTH_PLL_B, 0xFF);
  si5351_write(SYNTH_PLL_B + 1, 0xFF);
  si5351_write(SYNTH_PLL_B + 2, (p1 & 0x00030000) >> 16);
  si5351_write(SYNTH_PLL_B + 3, (p1 & 0x0000FF00) >> 8);
  si5351_write(SYNTH_PLL_B + 4, (p1 & 0x000000FF));
  si5351_write(SYNTH_PLL_B + 5, 0xF0 | ((p2 & 0x000F0000) >> 16));
  si5351_write(SYNTH_PLL_B + 6, (p2 & 0x0000FF00) >> 8);
  si5351_write(SYNTH_PLL_B + 7, (p2 & 0x000000FF));

}

void si5351_set_freq(int synth, unsigned long freq)
{
  unsigned long  a, b, c = 1048575;
  unsigned long f_xtal = 25000000;
  double fdiv = (double) (f_xtal * 36) / freq; //division factor fvco/freq (will be integer part of a+b/c)
  double rm; //remainder
  unsigned long p1, p2;
  
  a = (unsigned long) fdiv;
  rm = fdiv - a;  //(equiv. to fractional part b/c)
  b = rm * c;
  p1  = 128 * a + (unsigned long) (128 * b / c) - 512;
  p2 = 128 * b - c * (unsigned long) (128 * b / c);
    
  //Write data to multisynth registers of synth n
  si5351_write(synth, 0xFF);      //1048757 MSB
  si5351_write(synth + 1, 0xFF);  //1048757 LSB
  si5351_write(synth + 2, (p1 & 0x00030000) >> 16);
  si5351_write(synth + 3, (p1 & 0x0000FF00) >> 8);
  si5351_write(synth + 4, (p1 & 0x000000FF));
  si5351_write(synth + 5, 0xF0 | ((p2 & 0x000F0000) >> 16));
  si5351_write(synth + 6, (p2 & 0x0000FF00) >> 8);
  si5351_write(synth + 7, (p2 & 0x000000FF));
}

void set_oscillators(int txrx, unsigned long vfo_freq, int bfo)
{
    if(txrx) //TX, cause PIND1 is 1
	{
	    si5351_set_freq(SYNTH_MS_0, vfo_freq + f_bfo[bfo]);		   
		si5351_set_freq(SYNTH_MS_1, f_bfo[bfo]);
	}	
	else //RX
	{
	   si5351_set_freq(SYNTH_MS_0, f_bfo[bfo]);
	   si5351_set_freq(SYNTH_MS_1, vfo_freq + f_bfo[bfo]);   
	}    	
		
}

unsigned long scan_frequency(unsigned long f1, unsigned long f2, int ts, int bfo)     
{
     unsigned long f;
     int key;
     int sval = 0;
     
     if(f1 == f2)
     {
		 return 0;
	 }	 
         
     if(f1 > f2)
     {
		 f = f1;
		 f1 = f2;
		 f2 = f;
	 }	 
          
     while(1)
     {
         for(f = f1; f <= f2; f += ts)
         {
		     set_oscillators(0, f, bfo);
		     show_frequency(f);
		     key = get_keys();
		     if(key == 2)
		     {
				 return f;
		     }	 
		     
		     if(key == 1)
		     {
				 return 0;
		     }	 
		     
		     sval = 390 - get_adc(1); //ADC voltage on ADC3 SVAL
		 	 show_meter(sval >> 2); //S-Meter
		 	 
		 	 //Hold, when S value hi!
		 	 if((sval >> 2) > 60)
		 	 {
				 _delay_ms(200);
			 }	 
		 	 

		 }    
	 }	 
	 return 0;
}

////////////////////////////////
//
// OLED commands
//
///////////////////////////////

//Send comand to OLED
void oled_command(int value)
{
   twi_start();
   twi_write(0x78); //Device address
   twi_write(0x00);
   twi_write(value);
   twi_stop();
} 

//Initialize OLED
void oled_init(void)
{
    oled_command(0xae);
	
    oled_command(0xa8);//Multiplex ratio
    oled_command(0x3F);
	
    oled_command(0xd3);
    oled_command(0x00);
    oled_command(0x40);
    oled_command(0xa0);
    oled_command(0xa1);
	
	oled_command(0x20); //Adressing mode
    oled_command(0x00); //HOR
	
    oled_command(0xc0);
    oled_command(0xc8);
    oled_command(0xda);
    oled_command(0x12);
    oled_command(0x81);
    oled_command(0xfF);
    oled_command(0xa4); //Display ON with RAM content
    oled_command(0xa6); //Normal display (Invert display = A7)
    oled_command(0xd5);
    oled_command(0x80);
    oled_command(0x8d);
    oled_command(0x14);
	//oled_command(0x40); //Set display start line
    oled_command(0xAF); //Display ON
   
} 

//Print character in normal size
//Write 8 vertical bits to given col (0..127) and page (0..7)
void oled_write_byte(int col, int page, int val)
{
    int t1;
	
	oled_command(0x21); //COL
	oled_command(col); 
	oled_command(col); 
	
	oled_command(0x22); //PAGE
	oled_command(page); 
	oled_command(page); 
		
    twi_start();
	twi_write(0x78);
	twi_write(0x40); //Data
    for(t1 = 0; t1 < 7; t1++)
    {
        twi_write(val);
    }
	twi_stop();
}

//Clear screen
void oled_cls(void)
{

    int x, y;
	for(x = 0; x < 128; x++)
	{
	    for(y = 0; y < 8; y++)
		{
		    oled_write_byte(x, y, 0);
		}
    }	

}

//Print one character in normal size to OLED
void oled_putchar1(int col, int row, char ch1, int inv)
{ 
    int p, t1;
    char ch2;
	int c = col;
	    
    p = (5 * ch1) - 160;
    for(t1 = 0; t1 < 5; t1++)
    { 
	    if(!inv)
		{
	        ch2 = fontchar[p + t1];
		}
		else
		{
	        ch2 = ~fontchar[p + t1];
		}
		
        oled_write_byte(c++, row, ch2);
    }
	
	if(!inv)
	{
	    oled_write_byte(c, row, 0x00);
	}
	else
	{
	    oled_write_byte(c, row, 0xFF);
	}
    
}

//2^x
int xp2(int xp)
{
    int t1, r = 1;
    for(t1 = 0; t1 < xp; t1++)
    {
        r <<= 1;
    }
    return r;

}


//Print character in double size
void oled_putchar2(int col, int row, char ch1, int inv)
{ 
    int p, t1, t2, x;
	int b, b1, b2; 
    char colval;
	   
    p = (5 * ch1) - 160;
    	
	for(t2 = 0; t2 < 6; t2++)
    { 
	    //Get vertical byte data of char
		if(!inv)
		{
	        colval = fontchar[p];
			if(t2 == 5)
			{
			    colval = 0;
			}
		}
		else
		{
	        colval = ~fontchar[p];
			if(t2 == 5)
			{
			    colval = 255;
			}
		}
	  		
		b = 0;
		x = 1;
        
		for(t1 = 0; t1 < 7; t1++)
        {
            if(colval & x)
            {
	            b += xp2(t1 * 2);
	            b += xp2(t1 * 2 + 1);
            }
            x <<= 1;
	    }
    
        b1 = b & 0xFF; //Lower byte
        b2 = (b & 0xFF00) >> 8; //Upper byte
		
		//Print data to screen
		oled_write_byte(col + t2 * 2, row, b1);
		oled_write_byte(col + t2 * 2, row + 1, b2);
		oled_write_byte(col + t2 * 2 + 1, row, b1);
		oled_write_byte(col + t2 * 2 + 1, row + 1, b2);
		p++;
	}	
	
}

//Print string in given size
//lsize=0 => normal height, lsize=1 => double height
void oled_putstring(int col, int row, char *s, char lsize, int inv)
{
    int c = col;
	
	while(*s)
	{
	    if(!lsize)
		{
	        oled_putchar1(c, row, *s++, inv);
		}
        else
        {
            oled_putchar2(c, row, *s++, inv);
		}	
		c += (lsize + 1) * 6;
	}
}

//Print an integer/long to OLED
void oled_putnumber(int col, int row, long num, int dec, int lsize, int inv)
{
    char *s = malloc(16);
	if(s != NULL)
	{
	    int2asc(num, dec, s, 16);
	    oled_putstring(col, row, s, lsize, inv);
	    free(s);
	}	
}

void oled_clear_section(int x1, int x2, int row)
{
    int t1;
	for(t1 = x1; t1 < x2; t1++)
	{
	    oled_write_byte(t1, row, 0);	
	}

}

/////////////////////////////////
//
// STRING FUNCTIONS
//
////////////////////////////////
//INT 2 ASC
int int2asc(long num, int dec, char *buf, int buflen)
{
    int i, c, xp = 0, neg = 0;
    long n, dd = 1E09;

    if(!num)
	{
	    *buf++ = '0';
		*buf = 0;
		return 1;
	}	
		
    if(num < 0)
    {
     	neg = 1;
	    n = num * -1;
    }
    else
    {
	    n = num;
    }

    //Fill buffer with \0
    for(i = 0; i < 12; i++)
    {
	    *(buf + i) = 0;
    }

    c = 9; //Max. number of displayable digits
    while(dd)
    {
	    i = n / dd;
	    n = n - i * dd;
	
	    *(buf + 9 - c + xp) = i + 48;
	    dd /= 10;
	    if(c == dec && dec)
	    {
	        *(buf + 9 - c + ++xp) = '.';
	    }
	    c--;
    }

    //Search for 1st char different from '0'
    i = 0;
    while(*(buf + i) == 48)
    {
	    *(buf + i++) = 32;
    }

    //Add minus-sign if neccessary
    if(neg)
    {
	    *(buf + --i) = '-';
    }

    //Eleminate leading spaces
    c = 0;
    while(*(buf + i))
    {
	    *(buf + c++) = *(buf + i++);
    }
    *(buf + c) = 0;
	
	return c;
}

//STRLEN
int strlen(char *s)
{
   int t1 = 0;

   while(*(s + t1++));

   return (t1 - 1);
}

/****************************/
//
//  DATA DISPLAY FUNCTIONS
//
/****************************/

//Current frequency (double letter height)
void show_frequency(long f)
{
    oled_putnumber(15, 3, (long) f / 10, 2, 1, 0);
}

void show_frequency_cls(void)
{
    oled_clear_section(0, 127, 3);
    oled_clear_section(0, 127, 4);
}

//Current tuning step (Page 0)
void show_tstep(int n_step, int invert)
{
	int xpos = 0, xlen = 5;
    char *s_tstep[] = {" 10Hz", " 50Hz", "100Hz", "250Hz", "500Hz", " 1kHz", " 5kHz"};
		
	//Clear section of LCD
	oled_clear_section(xpos * 6, xpos + xlen * 6, 0);
	
	//Write string to position
	oled_putstring(0, 0, s_tstep[n_step], 0, invert);
}

void show_sideband(int sb, int invert)
{
	int xpos = 6, xlen = 3;
	char *sidebandstr[MAXMODES + 1] = {"USB", "LSB"};
		
	//Clear section of LCD
	oled_clear_section(xpos * 6 , xpos + xlen * 6, 0);
	
	//Write string to position
	oled_putstring(xpos * 6, 0, sidebandstr[sb], 0, invert);
}

void show_store(int done, int invert, unsigned long f)
{
	int xpos = 10;	
	if(done)
	{
		oled_putnumber(62, 5, (long) f / 10, 2, 0, 0);
		oled_putstring(xpos * 6, 0, "STO", 0, invert);
		return;
	}	
	oled_putstring(xpos * 6, 0, "STO", 0, invert);
}

void show_voltage(int v1)
{
    char *buf;
	int t1, p;
	
	oled_clear_section(0, 30, 1);
	
	buf = malloc(10);
	//Init buffer string
	for(t1 = 0; t1 < 10; t1++)
	{
	    *(buf + t1) = 0;
	}
    p = int2asc(v1, 1, buf, 6) * 6;
    oled_putstring(0, 1, buf, 0, 0);
	oled_putchar1(p, 1, 'V', 0);
	free(buf);
}

void show_txrx(int status)
{
	int xpos = 19;
	
	//Write string to position
	if(status)
	{
	    oled_putstring(xpos * 6, 1, "TX", 0, 1);
	}
	else    
	{
	    oled_putstring(xpos * 6, 1, "RX", 0, 0);
	}
	
}	
//S-Meter bargraph (Page 6)
void show_meter(int sv0)
{
    int t1, sv;
	
	sv = sv0;
	
    if(sv > 120)
	{
	    sv = 120;
	}
		
	//Clear bar graph partly, when new s-val smaller than previous
    if(sv < sv_old)
    {
	     //Clear s-meter
	     for(t1 = sv; t1 < 128; t1 += 3)//
	     {
	          oled_write_byte(t1, 6, 0);
	     }	
         sv_old = sv;
         return;
    }
   
    //Draw bar graph
	for(t1 = 0; t1 < sv; t1 += 3)//
	{
	    oled_write_byte(t1, 6, 0x1E);
	}	
    
    sv_old = sv;
}

void draw_meter_scale(int meter_type)
{
    if(!meter_type)
    {
        oled_putstring(0, 7, "S1 S3 S5 S7 S9 +  ", 0, 0);
    }
    else
    {
        oled_putstring(0, 7, "0  1W   2W   3W   ", 0, 0);
    }
}

void show_split(int stat)
{
	int xpos = 18, xlen = 5;
			
	//Clear section of LCD
	oled_clear_section(xpos * 6 , xpos + xlen * 6, 0);
	
	//Write string to position
	oled_putstring(xpos * 6, 0, "SPL", 0, stat);
	
}

void show_split2(int stat)
{
	int xpos = 6, xlen = 5;
			
	//Clear section of LCD
	oled_clear_section(xpos * 6 , xpos + xlen * 6, 1);
	
	//Write string to position
	if(stat)
	{
	    oled_putstring(xpos * 6, 1, "SPLIT", 0, 1);
	}
	else
	{
		oled_putstring(xpos * 6, 1, "     ", 0, 0);    
	}	
	
}

void show_rcl(int stat)
{
	int xpos = 14, xlen = 3;
			
	//Clear section of LCD
	oled_clear_section(xpos * 6 , xpos + xlen * 6, 0);
	
	//Write string to position
	oled_putstring(xpos * 6, 0, "RCL", 0, stat);
	
}

void show_scan(int stat)
{

	int xpos = 13, xlen = 3;
			
	//Clear section of LCD
	oled_clear_section(xpos * 6 , xpos + xlen * 6, 1);
	
	//Write string to position
	oled_putstring(xpos * 6, 1, "SCAN", 0, stat);
	
}

////////////////////////////////////////////////////
//               INTERRUPT HANDLERS
////////////////////////////////////////////////////
//Rotary encoder
ISR(PCINT2_vect)
{ 
    
    int gray = (PIND & 0x60) >> 5;           // Read PD5 and PD6
	
    int state = (gray >> 1) ^ gray;         // Convert from Gray code to binary

    if (state != laststate)                //Compare states
    {        
        tuningknob += ((laststate - state) & 3) - 2; // Results in -1 or +1
        laststate = state;
    } 
	PCIFR |=  (1 << PCIF0); // Clear pin change interrupt flag.
}

//////////////////////
//
//   A   D   C   
//
/////////////////////
//Read ADC value
int get_adc(int adc_channel)
{
	
	int adc_val = 0;
	
	ADMUX = (1<<REFS0) + adc_channel;     // Kanal adcmode aktivieren
    _delay_ms(3);
	
    ADCSRA |= (1<<ADSC);
    //while(ADCSRA & (1<<ADSC));
	_delay_ms(3);
	
	adc_val = ADCL;
    adc_val += ADCH * 256;   
	
	return adc_val;
	
}	

//Read keys via ADC0
int get_keys(void)
{

    int key_value[] = {151, 241};  //PCB
    //151 left single push button #1, 241 = right button from rotator switch #2, 
    	
    int t1;
    int adcval = get_adc(0);
        
    //TEST display of ADC value 
    //oled_putstring(0, 5, "----", 0, 0);    
    //oled_putnumber(0, 5, adcval, -1, 0, 0);    
    
    if(adcval < 110 && adcval > 106) //Both buttons pressed simultanously PCB
    {
		return 99;
	}
		
    for(t1 = 0; t1 < 2; t1++)
    {
        if(adcval > key_value[t1] - 10 && adcval < key_value[t1] + 10)
        {
             return t1 + 1;
        }
    }
    return 0;
}

//////////////////////////////
//
//    EEPROM-Functions
//
//////////////////////////////

//Load and store frequency from EEPROM based on VFO
unsigned long load_frequency(void)
{
    unsigned long rf;
    unsigned char hmsb, lmsb, hlsb, llsb;
    int start_adr = 0;
		
    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;
	
}


void store_frequency(unsigned long f)
{
    unsigned long hiword, loword;
    unsigned char hmsb, lmsb, hlsb, llsb;
	
    int start_adr = 0;
    
	cli();
    hiword = f >> 16;
    loword = f - (hiword << 16);
    hmsb = hiword >> 8;
    hlsb = hiword - (hmsb << 8);
    lmsb = loword >> 8;
    llsb = loword - (lmsb << 8);

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

//////////////////////////////
//
//    M   E   N   U
//
//////////////////////////////
unsigned int menu(void)
{
	int key = 0;
    int store = 0;
    int rcl = 0;	
    int split2;	
    int scan2 = 0;
	while(get_keys());
	show_tstep(cur_tstep, 1);
	
	//TUNING STEP
    while(!key)
	{
		if(tuningknob > 2)  
		{    
		    if(cur_tstep < MAXTSTEPS)
		    {
			     cur_tstep++;
			}
			else     
			{
				 cur_tstep = 0;
			}	 
			tuningknob = 0;
			show_tstep(cur_tstep, 1);
		}
		
		if(tuningknob < -2 )
		{
		    if(cur_tstep > 0)
		    {
			     cur_tstep--;
			}
			else     
			{
				 cur_tstep = MAXTSTEPS;
			}	 
			tuningknob = 0;
			show_tstep(cur_tstep, 1);
		}
		key = get_keys();
	}	
	show_tstep(cur_tstep, 0);
	
	if(key == 2)
	{
		return 1;
	}
	while(get_keys());
	//////////////////////////
			
	//SIDEBAND SET	
	key = 0;	
	show_sideband(sideband, 1);
	while(!key)
	{
		if(tuningknob > 2 || tuningknob < -2)  
		{    
		    if(!sideband)
		    {
			     sideband = 1;
			}
			else     
			{
				 sideband = 0;
			}	 
			tuningknob = 0;
			show_sideband(sideband, 1);
			si5351_set_freq(SYNTH_MS_0, f_bfo[sideband]);
		}
		key = get_keys();
	}	
	show_sideband(sideband, 0);
	
	if(key == 2)
	{
		return 2;
	}	
	while(get_keys());
	////////////////////////////
		
	//STORE CURRENT QRG
	key = 0;
	store = 1;	
	show_store(0, store, 0); 
	while(!key)
	{
		if(tuningknob > 2 || tuningknob < -2)  
		{    
		    if(!store)
		    {
			     store = 1;
			}
			else     
			{
				 store = 0;
			}	 
			tuningknob = 0;
			show_store(0, store, 0);
		}
		key = get_keys();
	}	
	
	if(key == 2)
	{
	    return 4;
	}	
	
	show_store(0, 0, 0);	
	while(get_keys());
    ////////////////////////
    
	//Recall stored freuency
	key = 0;
	rcl = 1;
	show_rcl(rcl); 
	while(!key)
	{
		if(tuningknob > 2 || tuningknob < -2)  
		{    
		    if(!rcl)
		    {
			     rcl = 1;
			}
			else     
			{
				 rcl = 0;
			}	 
			tuningknob = 0;
			show_rcl(rcl); 
		}
		key = get_keys();
	}	
	
	show_rcl(0); 
	
	if(key == 1)
	{
		rcl = 0;
	}
			
	if(key == 2 && rcl)
	{
		return 6;
	}	
	while(get_keys());
    //////////////////////
		
	//SPLITMODE on/off
	key = 0;
	split2 = 1;
	show_split(split2); 
	while(!key)
	{
		if(tuningknob > 2 || tuningknob < -2)  
		{    
		    if(!split2)
		    {
			     split2 = 1;
			}
			else     
			{
				 split2 = 0;
			}	 
			tuningknob = 0;
			show_split(split2);
		}
		key = get_keys();
	}	
	
	show_split(0);  
	
	if(key == 2)
	{
	    if(split2)
	    {
			split = 1;
			show_split2(split);  
		    return 5;
	    }	
	    else
	    {
			split = 0;
			show_split2(split);  
	        return 0;
	    }	
    }	
    
    while(get_keys());
	
	
	//SCAN on/off
	key = 0;
	scan2 = 1;
	show_scan(scan2); 
	while(!key)
	{
		if(tuningknob > 2 || tuningknob < -2)  
		{    
		    if(!scan2)
		    {
			     scan2 = 1;
			}
			else     
			{
				 scan2 = 0;
			}	 
			tuningknob = 0;
			show_scan(scan2);
		}
		key = get_keys();
	}	
		
		
	if(key == 2)
	{
	    if(scan2)
	    {
			return 7;
	    }	
	    else
	    {
			return 0;
	    }	
    }	
    
    while(get_keys());
		
	return 0;
		
}	

int set_lo_frequencies(void)
{
	int key = 0;
		
    //LO FREQ USB
	key = 0;	
	show_frequency(f_bfo[0]);
	oled_putstring(1, 5, "fBFO USB", 0, 0);
	
	while(!key)
	{
		if(tuningknob > 2)  
		{    
		    f_bfo[0] += n_tstep[cur_tstep];
		    tuningknob = 0;
			show_frequency(f_bfo[0]);
		}	
		
		if(tuningknob < -2)  
		{    
		    f_bfo[0] -= n_tstep[cur_tstep];
			tuningknob = 0;
			show_frequency(f_bfo[0]);
		}	
		
		if(PIND & 0x02) //TX, cause PIND1 is 1
		{
			set_oscillators(1, 14200000, 0);
		    //si5351_set_freq(SYNTH_MS_0, 14200000 + f_bfo[0]);		   
			//si5351_set_freq(SYNTH_MS_1, f_bfo[0]);
		}	
		else
		{
			set_oscillators(0, 14200000, 0);
		    //si5351_set_freq(SYNTH_MS_0, f_bfo[0]);
		    //si5351_set_freq(SYNTH_MS_1, 14200000 + f_bfo[0]);   
		}    
	    key = get_keys();    
	}	
	
	while(get_keys());
		
	//LO FREQ LSB
	key = 0;
	si5351_set_freq(SYNTH_MS_0, f_bfo[1]);	
	show_frequency(f_bfo[1]);
	oled_putstring(1, 5, "fBFO LSB", 0, 0);
	
	while(!key)
	{
		if(tuningknob > 2)  
		{    
		    f_bfo[1] += n_tstep[cur_tstep];
		    tuningknob = 0;
			show_frequency(f_bfo[1]);
		}	
		
		if(tuningknob < -2)  
		{    
		    f_bfo[1] -= n_tstep[cur_tstep];
			tuningknob = 0;
			show_frequency(f_bfo[1]);
		}	
		
		if(PIND & 0x02) //TX, cause PIND1 is 1
		{
			set_oscillators(1, 14200000, 1);
		    //si5351_set_freq(SYNTH_MS_0, 14200000 + f_bfo[1]);		   
			//si5351_set_freq(SYNTH_MS_1, f_bfo[1]);
		}	
		else
		{
			 set_oscillators(0, 14200000, 1);
		     //si5351_set_freq(SYNTH_MS_0, f_bfo[1]);
		     //si5351_set_freq(SYNTH_MS_1, 14200000 + f_bfo[1]);   
		}    
	    key = get_keys();
	}	
			
	while(get_keys());
    oled_putstring(1, 5, "        ", 0, 0);
    return 0;
}

int main(void)
{
	//Keys
	int key = 0, key_old = 0;
	int loopcnt3 = 0;
	
	//Volts measurement
    int adc_v;
    int adc_v_old = 0;
    int v_cnt = 1000;
    double v1;		
        
    //Meter
    int loopcnt1 = 0;
    int sval = 0;
            
    //OPerating frequencies    
    unsigned long freq1 = 14200000;
    unsigned long freq2 = 14200000;
	unsigned long f_scan = 0;
	
	//TX/RX indicator
	int txrx = 0;
	
	//Menu value
	int men = 0;
		
	//INPUT
    PORTC = 0x31;//PC0: Pull-up for key switches with various resistors against GND 
	             //I²C-Bus lines: PC4=SDA, PC5=SCL
	
	PORTD = 0x60;//INPUT: Pullup resistors for PD0 (TX/RX), PD5 and PD6 rotary encoder
					  
	//Watchdog off
	WDTCSR = 0;
	WDTCSR = 0;
    _delay_ms(200);

	//Interrupt definitions for rotary encoder  
	PCMSK2 |= ((1<<PCINT21) | (1<<PCINT22));  //enable encoder pins as interrupt source
	PCICR |= (1<<PCIE2);                      // enable pin change interupts 
	
	//ADC config and ADC init
    ADCSRA = (1<<ADPS0) | (1<<ADPS1) | (1<<ADEN); //Prescaler 64 and ADC on
	get_adc(0); //One dummy conversion
	
	
	freq1 = load_frequency();
	if(freq1 < 14000000 || freq1 > 14350000)
	{
	    freq1 = 14200000;
	}
    freq2 = freq1;
    
	//TWI
	twi_init();
	
	//OLED
	oled_init();
	oled_cls();	

	//Si5351	
	_delay_ms(100);
	si5351_start();
	
    //Frequencies in NORMAL position
    set_oscillators(0, freq1, 0);
    
	//si5351_set_freq(SYNTH_MS_0, f_bfo[sideband]);
	//si5351_set_freq(SYNTH_MS_1, freq1 + f_bfo[sideband]);
		
	show_frequency(freq1);
	show_tstep(cur_tstep, 0);
	show_sideband(sideband, 0);
	draw_meter_scale(0);
    show_store(1, 0, freq1);
    show_store(0, 0, 0);
    show_txrx(0);
    show_split(0);
    show_rcl(0);
    show_scan(0);
    sei();        
    
    for(;;)
    {
        //TUNING		
		if(tuningknob > 2 && !txrx)  
		{    
		    freq1 += n_tstep[cur_tstep];
		    set_oscillators(txrx, freq1, sideband);
			//si5351_set_freq(SYNTH_MS_1, freq1 + f_bfo[sideband]);
			tuningknob = 0;
			show_frequency(freq1);
		}
		
		if(tuningknob < -2 && !txrx)
		{
		    freq1 -= n_tstep[cur_tstep];
		    set_oscillators(txrx, freq1, sideband);
			//si5351_set_freq(SYNTH_MS_1, freq1 + f_bfo[sideband]);
			tuningknob = 0;
			show_frequency(freq1);
		}
				
		//MENU
		if(key_old != key)
		{
			//oled_putstring(0, 20, "    ", 0, 0);
		    //oled_putnumber(0, 20, key, -1, 0, 0);
		    key_old = key;
		    while(get_keys());
		    switch(key)
		    {
				case 1: men = menu();
				        switch(men)
				        {
				            case 4: store_frequency(freq1); //Store QRG
					                show_store(1, 0, freq1);
					                show_store(0, 0, 0);
	                                show_frequency(freq1);				
                                    break;
                                    
                            case 5: if(load_frequency() >= 14000000 && load_frequency() <= 14350000) //Get split freqw
	                                {
	                                    freq2 = load_frequency();
					                }      
					                else
					                {
	                                    freq2 = freq1;
					                }      
					                break;
					                
					        case 6: if(load_frequency() >= 14000000 && load_frequency() <= 14350000) //RCL
					                {
										freq1 = load_frequency(); //Load stored QRG
										set_oscillators(txrx, freq1, sideband);
							            //si5351_set_freq(SYNTH_MS_1, freq1 + f_bfo[sideband]);
	                                    show_frequency(freq1);
	                                }    
	                                break;
	                                
	                        case 7: if(load_frequency() >= 14000000 && load_frequency() <= 14350000)
	                                {      
	                                    show_scan(1);
	                                    f_scan = scan_frequency(load_frequency(), freq1, n_tstep[cur_tstep], sideband);     
	                                    if(get_keys() == 2 && f_scan >= 14000000 && f_scan <= 14350000)
	                                    {
									        freq1 = f_scan;
									    }	
									    show_scan(0);
									    set_oscillators(txrx, freq1, sideband);	
									}
	                                break;
	                                
	                        case 99: set_lo_frequencies();
	                                 set_oscillators(txrx, freq1, sideband);
	                                 show_frequency_cls();
	                                 show_frequency(freq1);
	                                
	                    }            
	        }             
	        show_frequency(freq1);
		}
		
		//VOLTS
		//Voltage divider factor (7.5+2.56k)/2.56 = 3.941176471
		if(v_cnt++ > 5000)
		{
		    v1 = (double) get_adc(2) * 5 / 1024 * 3.94 * 10;
		    adc_v = (int) v1;
   		    if(adc_v != adc_v_old)
		    {
    	        show_voltage(adc_v);
	     		adc_v_old = adc_v;
		    }	
		    v_cnt = 0;
	    }
        
		//After n loops check S-Val resp. PWR value
		if(loopcnt1++ > 20)
		{
			//sval = 390 - get_adc(1); //ADC voltage on ADC1 SVAL
			//oled_putnumber(0, 5, 390 - get_adc(1), -1, 0, 0);
		 	//mval += get_adc(1); //ADC voltage on ADC1 PWR
		 	if(!txrx)
		 	{
				sval = 390 - get_adc(1); //ADC voltage on ADC3 SVAL
		 	    show_meter(sval >> 2); //S-Meter
		 	}
		 	else
		 	{
				sval = get_adc(3); //ADC voltage on ADC3 SVAL
				show_meter(sval); //S-Meter
				
			}    
 		 	loopcnt1 = 0;
		}
		
        //Check if key pressed
        if(loopcnt3++ > 50)
        {
		    key = get_keys();
		    loopcnt3 = 0;
		}    
		
		//TX/RX switching
		if(PIND & 0x02) //TX, cause PIND1 is 1
		{
			if(!txrx)
			{
			    draw_meter_scale(1);	 
			    show_meter(0);
			    show_txrx(1);
			    txrx = 1;
			    
			    //Frequencies in REVERSE position
			    if(split)
			    {
				    show_frequency(freq2);
				    set_oscillators(txrx, freq2, sideband);
					//si5351_set_freq(SYNTH_MS_0, freq2 + f_bfo[sideband]);
				}	 
				else
				{
					set_oscillators(txrx, freq1, sideband);
				    //si5351_set_freq(SYNTH_MS_0, freq1 + f_bfo[sideband]);	
				}
				
				//si5351_set_freq(SYNTH_MS_1, f_bfo[sideband]);
	            
	
			}     
		}	
		
		if(!(PIND & 0x02)) //RX, cause PIND1 is 0
		{
			if(txrx)
			{
				draw_meter_scale(0);
				show_meter(0);
			    show_txrx(0);
			    txrx = 0;
				//Frequencies in NORMAL position
				set_oscillators(txrx, freq1, sideband);
			    //si5351_set_freq(SYNTH_MS_0, f_bfo[sideband]);
  	            //si5351_set_freq(SYNTH_MS_1, freq1 + f_bfo[sideband]);
  	            if(split)
			    {
				    show_frequency(freq1);
				}    
				
			}     
		}
	}
	
	return 0;
}