Zurück (C) Christof Ermer, Regensburg

15.11.2010


zuätzliche Links:
http://de.wikipedia.org/wiki/R2R
http://www.avr-asm-tutorial.net/avr_de/avr_dac.html
aus dem Kurs Assembler http://www.avr-asm-tutorial.net/avr_de/
Seminarunterlagen : PGA103_PrgAmp.pdf
Manual als PDF:
und ein typisches IC  PGA100.pdf    

Unterfamilien beachten z.B. PGA103
pga103.pdf   einfach googln
mit  vollstaendigem C-Code Bespiel
R2R oder R-2R Netzwerk oder R-2R DAC  (Digital Analog Converter) Der R-2R-Konverter ist der am häufigsten benutzte D/A-Wandler.
Prinzip
Man erkennt, das der 2R immer zwischen einer Spannung (VCC) und 0V geschaltet wird,.  Also ideal wie ein TTL Ausgang 5V oder 0V.
Damit kann man mit einem µC Ausgang direkt in ein R2R Netz einkoppeln.  WiderstandsNiveau sollte aber so um 3...5KOhm ligen
Der R-2R-Konverter ist ein D/A-Wandler, der eine Widerstand-Matrix als Spannungsteiler benutzt. Die einzelnen Widerstände der Matrix werden für die Umwandlung mit elektronischen Schaltern zu- und abgeschaltet. Die Ausgangsspannung ist dabei proportional dem binären Digitalsignal

Prinzip einer R2R Widerstandnsnetzwerkes zur Digital Analog Wandlung:  Achtung

 Im Gegensatz zu dem gewichteten Widerstands-Konverter, bei dem die Widerstandwerte das 2-, 4-, 8- und 16-fache des Basiswiderstands entsprechen, gibt es beim R-2R-Konverter nur zwei Widerstandswerte "R" und "2R". Letztere allerdings mehrfach, da daraus die Spannungsteilung für den 4-, 8- und 16-fachen Wert erstellt werden. Dies geschieht indem man mehrere Widerstände gleichzeitig in den Spannungsteiler zu- oder abschaltet.



Mit dem selben Prinzip kann eine PGA ( Programmable Gain Amplifier )Schaltung generiert werden.
Statt der Referenz wird eben die Eingangs-Spannung angelegt
ein typischer Vertreter heißt PGA100.


Einfacher 8-Bit-Digital-zu-Analog-Wandler mit einem R/2R-Netzwerk
Die Umwandlung von digitalen Werten in eine Analogspannung kann durch integrierte Schaltungen bewerkstelligt werden. Eine billigere und weniger anspruchsvolle Lösung ist ein selbstgebautes R/2R-Widerstandsnetzwerk, gefolgt von einem Operationsverstärker. 

Ein R/2R-Netzwerk ist wie im Bild gezeigt aus Widerständen aufgebaut. Die einzelnen Eingangsbits liegen entweder auf Null Volt oder auf der Betriebsspannung und speisen über doppelt so große Widerstände ein wie der vertikale Teil des Netzwerks. Jedes Bit trägt so seinen spezifischen Teil zur resultierenden Ausgangsspannung bei. Das funktioniert wirklich, und ziemlich gut! Kommerzielle Digital-Analog-Wandler haben solche R/2R-Netzwerke im IC integriert.

Der Ausgang eines AVR liefert nicht sehr viel Strom an seinen Portausgängen, wenn die Spannungen in der Nähe der Versorgungsspannungen bleiben sollen. Daher sollten die Widerstände des R/2R-Netzwerks größer als einige 10 Kiloohm sein. Um das Netzwerk möglichst gering zu belasten entkoppelt ein Operationsverstärker das Netzwerk vom weiteren Verbraucher.

Die Widerstandswerte sollten so genau eingehalten werden wie es vom gesamten Netzwerk erwartet wird. Abweichungen von Widerstandswerten sind besonders bei den höherwertigen Bits relevant. Die folgende Tabelle zeigt einige Beispiele für die schrittweise Spannungssteigerung eines R/2R-Netzwerks mit einer 51k/100k-Kombination.




16Bit Passiv R2R Netzwerk . Letzter Widerstand rechts an Masse ist 2R
Die Waagerechte sind bis auf diesen Lezten 1*R, die Senkrechten 2R

und jetzt die Platine mit Eagle. Man sieht die Ähnlichkeit mit der Simulation

Das Layout...


So einfach kanns sein !!


Aufbau mit vom R-2R Erzeugtem Signalformen
S
Simulation  der R2R Netzwerke
Hier die Array Definition für eine Sinusausgabe mit dem R2R Netzwerk,
Amplitiude 0..255 und Stufen ebenfalls 256 stufen. Wer mehr möchte, bitte...
uint8_t gu8SineVal[256];
gu8SineVal[iNN] = round( 127.5 * (sin( 2*M_PI* iNN/256.0) + 1 ) );

oder feste ProgMem Speichertabelle:
const char MCA_SINUS[] PROGMEM = {        // "256 Byte SINUS von 0..255
128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173,176,179,182,\
185,188,190,193,196,198,201,203,206,208,211,213,215,218,220,222,224,226,228,\
230,232,234,235,237,238,240,241,243,244,245,246,248,249,250,250,251,252,253,\
253,254,254,254,255,255,255,255,255,255,255,254,254,254,253,253,252,251,250,\
250,249,248,246,245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,\
220,218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,176,173,\
170,167,165,162,158,155,152,149,146,143,140,137,134,131,128,124,121,118,115,\
112,109,106,103,100,97,93,90,88,85,82,79,76,73,70,67,65,62,59,57,54,52,49,47,\
44,42,40,37,35,33,31,29,27,25,23,21,20,18,17,15,14,12,11,10,9,7,6,5,5,4,3,2,\
2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,17,18,20,21,23,\
25,27,29,31,33,35,37,40,42,44,47,49,52,54,57,59,62,65,67,70,73,76,79,82,85,88,\
90,93,97,100,103,106,109,112,115,118,121,124};


P.S
Vcc: Betriebsspannung (meist 5V) 
Vdd: dasselbe wie Vcc, manchmal auch für eine andere Spannung neben den 5V (z.B. 3,3V) 
Vee: negative Betriebsspannung, wenn nicht benötigt (z.B. bei 405x Analogschalter): Mit Vss verbinden 
Vss: Masse, GND, 0V


Hier der vollständige Code ( fast Fertig) für einen mit R"R Netzwerk realisierten SIgnal-Frequenz-generator.
Mit einem Timerinterrrupt  gesteuerten Aausgabe.
Sinus, Rechteck 
mit Amplitudensteuerung, Sägezahn (steigend, fallend),


zuerst die mögl Kommandos

#define DATUM                     "16.11.2010"

#define FUNKTION   "Frequenzgenerator mit PGA"

#define HARDWARE            "AT-Mega16 AVR Atmel"

#define AUTOR                     "(C) Christof Ermer, Regensurg"

#define ORGANISATION     "(C) Universität Regensburg - Physik"

 

3 Leitungs- Serial, BAUD 9600 8Bit  1 Stop bit, No Handshake,  No XonXoff.

Pin 2  ist Tx, Pin 3 ist Rx, Pin 5 ist GND

 

Sende im Format:     Befehl[,Value1][,Value2]<CR>  (gross/klein Bucstaben = egal)

<CR> = Ascii 13        Value ist ein Wert , im floatformat, also z.B: 4 oder 4.321 oder 4.0

Anwendung: Ping<CR> = Ping<13> à Antwort:    Pong<13> 

MAX Output Voltage =  5V/256 * 255  =  4.98 V   à PGA OutPut = 0..255 = 0..4.98V

Spannung in Volt(Teilen) eingeben. Eichung automatisch auf den nächsten mögl. Wert.

Auch die Frequenz wird automatisch quantisiert auf den nächst mögl. Wert.

Bereich: Rechteck bis 100Khz, Sinus, Dreick,  etc. nur 0..580Hz weil 256 Schritte/Periode

LIMITS

Frequenz Rechteck <= 150 kHz,      Sinus, Dreieck, Sägezahn <= 585 Hz

Spannung: in Teilen von 256/5 = 551,2 mV Range 0.4.98V




main.c
bitte, wer in benutzt, kann über eine kleine Spende nachdenken !

//------------------------------------------------------------------------------
// Programmed by Christof Ermer
//------------------------------------------------------------------------------

//SYSINFO
#define DATUM            "16.11.2010"
#define FUNKTION        "Frequenzgenerator mit PGA"
#define HARDWARE        "AT-Mega16 AVR Atmel"
#define UHRZEIT        "12:00"
#define AUTOR            "(C) Christof Ermer, Regensburg"
#define ORGANISATION    "(C) Universität Regensburg - Physik"

/*
#define UART_BAUD_RATE    9600
#define F_CPU    16000000
gu8SineVal[iNN] = round( 127.5 * (sin( 2*M_PI* iNN/256.0) + 1 ) );
*/


/*
HISTORIE HISTORIE HISTORIE HISTORIE HISTORIE HISTORIE HISTORIE

UMSTELLUNG Timer 2 to Timer 0
Weil innterrupt des Timer eins vorrang hat !! MUSS Erste Priorität haben
#define TIMER2_OVF_vect            _VECTOR(4)
#define TIMER1_COMPA_vect        _VECTOR(6)
#define TIMER0_OVF_vect            _VECTOR(9)
*/


#include <ctype.h>
#include <inttypes.h>
#include <avr\io.h>
#include <avr\pgmspace.h> // <--#include <progmem.h>

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <avr\interrupt.h>  // obsolete #include <avr\signal.h>

//ACHTUNG STELLT OBSOLETE Procedure in header wieder her
#include <compat\deprecated.h>
#include <avr\wdt.h>
//Produziert Fehler...
#include <util\delay.h>    //_delay_loop_1 _delay_loop_2 delay_ms

#include "main.h"        //with Hardware assigns
#include "uart.h"
#include "lcd.h"

void WarteMal(uint16_t u16WaitTicks);
void Set_Frq(float pfVal);
void FRQ_Off(void);
void FRQ_On(void);
void Timer0_PWM(unsigned char ucPwmRange);


#ifdef ADC_USED_ENABLED
uint16_t ADC_10Bit(uint8_t ucChan); // 0..7
uint16_t ADC_StatistiKRead(uint8_t u8Channel, uint16_t u16LastRead);
float PotiSkalierung( uint16_t u16Poti );    //Normiert Poti mit Offset auf 0..1 von 0..1000
#endif


#ifdef TIMER_TICK_USED
void StartTickTimer(void);    //0.1 Seconds  interrupt
uint32_t GetTickDifference(uint32_t u32Time);
#endif

#ifdef USE_TOGGLE_FLAG
void ToggleTEST_BIT(uint8_t ucCnt);
#endif

#ifdef UART_USE_ENABLED
void UART_TXRX_Check(void);
void ResetRxBuff(void);
void PrintCR(void);
void PrintStrCR(const char* pStr);
void Print_PStrCR(PGM_P pmStr);
void CheckOrder(char* pcStr);
void LongToNumStr(int32_t lVal);
void PrintLongCR(int32_t lVal);
void FloatToNumStr(double fVal);
void PrintFloatCR(double fVal);
#endif


//CONSTANT ARRAYs IN .TEXT = ROM ARREA   .DATA IST SRAM !! .BSS SRAM
//const char MCA_DELIMTERSTR[] PROGMEM = { ',',0 };

// GLOBALE VARIABLEN
//MSG
const char MCA_DELIMITER_MSG[] PROGMEM    = ",";
const char MCA_SPACE[] PROGMEM    = " ";
const char MCA_WELCOME1_MSG[] PROGMEM    = "I have no brain";
const char MCA_WELCOME2_MSG[] PROGMEM    = "use your own";
const char MCA_PGA[] PROGMEM    = "PGA";
const char MCA_FREQUENZ[] PROGMEM    = "Frequenz";
const char MCA_GENERATOR[] PROGMEM    = "Generator";


//gu8SineVal[iNN] = round( 127.5 * sin(2*M_PI* iNN/256.0) + 1 );
// f(x)= Amplitude * sin ( 2* M_PI * NN/X_AUFLOESUNG ) + OFFSET
/*
//f(x) = a * sin (2*Pi*x - b) + o
a ist die Amplitude
b ist die Phasenverschiebung
o ist der "Offset"-Wert
für x setzt du halt n/d ein. (n € N)
d ist die Schrittanzahl pro Periode
*/
/*
ODER
iNN)= 0..255
F(x) = 128 + 127* sin( iNN/2562*M_PI* )
*/
const char MCA_SINUS[] PROGMEM = {    //    256 Werte!
128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173,176,179,182,\
185,188,190,193,196,198,201,203,206,208,211,213,215,218,220,222,224,226,228,\
230,232,234,235,237,238,240,241,243,244,245,246,248,249,250,250,251,252,253,\
253,254,254,254,255,255,255,255,255,255,255,254,254,254,253,253,252,251,250,\
250,249,248,246,245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,\
220,218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,176,173,\
170,167,165,162,158,155,152,149,146,143,140,137,134,131,128,124,121,118,115,\
112,109,106,103,100,97,93,90,88,85,82,79,76,73,70,67,65,62,59,57,54,52,49,47,\
44,42,40,37,35,33,31,29,27,25,23,21,20,18,17,15,14,12,11,10,9,7,6,5,5,4,3,2,\
2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,17,18,20,21,23,\
25,27,29,31,33,35,37,40,42,44,47,49,52,54,57,59,62,65,67,70,73,76,79,82,85,88,\
90,93,97,100,103,106,109,112,115,118,121,124}; // "256 Byte SINUS von 0..255

// sinus = U-Halbe  {0..255}*  (sin ( 2 * M_PI * Zaehler{0..255} / VOLLAUFLÖSUNG{256} +1)
//gu8SineVal[iNN] = round( 127.5 * (sin( 2*M_PI* iNN/256.0) + 1 ) );
//gu8SineVal[iNN] = round( ( gu8PGAVolume/ 2.0 + 0.5) * (sin( 2*M_PI* iNN/SINUS_X_RESOLUTON) + 1 ) );

static volatile uint16_t gu16X_Resolution = SINUS_X_RESOLUTON; //256 Voreinstellung X
static volatile uint8_t * gpu8SineVal = NULL;    //pointer auf MEM
//static volatile uint8_t gu8Y_Resolution;


#ifdef UART_USE_ENABLED
volatile static char* gpcRxPars;
static char gcaRxStr[RX_STRMAX + 1]; //+1 for the 0
static char gcaNumStr[NUMMAX + 1]; //+1 for the 0
static char gcaStr[STRMAX + 1]; //+1 for the 0
static COMMAND_TYPE gsCmd;
#endif

//static uint8_t gcaSegmentStr[SEGMENTSTRMAX + 1]; //+1 for the 0
static volatile uint32_t gu32_Ticks;    //T2 timeCounter, only NN_Counter for Keypressings

//POITS
static volatile uint16_t gu16ModePoti;
static volatile uint16_t gu16VolumePoti;
static volatile uint16_t gu16FrequenzPoti;

// START PARAMETER UND GLOBALS
static volatile uint8_t gu8ModeSelect = RECHTECK_ON;    //START Funktion
static volatile uint8_t gu8PGAVolume = START_PGA_VOLUME; //25 Realer PGA Wert
static volatile double gfInterruptFRQ = START_FREQUENZ;    // Trägt die Information der Interrupts
static volatile uint8_t gu8ProgMode_Flag;
//static volatile float gfFRQScaleFakor;    // fSelectedFRQ * XXX für SetFrequenz zb. Recnagle mal 2
//tatsaechliche FRq wird ausgerechnet, je nach Signalform  z:B RectangleFRQ=( FRQ/2 )

//static volatile uint8_t gu8LCD_FLAG;
static volatile uint8_t gu8Timer_CSxxClkSelect;    //z.B.#define TCCR1B_CLOCKSEL_CPU_1024    0x05

//static volatile uint8_t gu8SineVal[256];


#ifdef TIMER_TICK_USED
// ****************************************************************
//volatile  SIGNAL(TIMER2_OVF_vect) //oder SIGNAL--INTERRUPT(SIG_OVERFLOW2) = mit SEI am Anfang
ISR( TIMER0_OVF_vect ) //oder SIGNAL--INTERRUPT(SIG_OVERFLOW2) = mit SEI am Anfang
// *******************************************************************
{
gu32_Ticks++;
};
#endif


// ***** ***********************************************************
ISR( TIMER1_COMPA_vect )// signal handler
//#define SIG_OUTPUT_COMPARE1A    _VECTOR(6)
// *******************************************************************
{//cli(); //I_SREG automtaic clear by Interrupt and Enabled by RETI   
//register regCnt;
static volatile uint16_t u16PositionToggle;
switch( gu8ModeSelect )
    {
    case SINUS_RESOLUTION_ON :  
        {           
        //PORTC = round( 127.5 * (sin( 2*M_PI * (gu8PGASTEPS++)/256.0) + 1) );
        PORTC = *(gpu8SineVal + u16PositionToggle++); //u16PositionToggle als zaehler missbraucht
        u16PositionToggle %= gu16X_Resolution;
        break;
        };
    case SINUS_5V_AMPLIUDE :  
        {           
        //PORTC = round( 127.5 * (sin( 2*M_PI * (gu8PGASTEPS++)/256.0) + 1) );
        PORTC = pgm_read_byte_near( MCA_SINUS + (u16PositionToggle++ % SINUS_5V_X_RESOLUTON));
        break;
        };
    case RECHTECK_ON:
        {   
        if( PORTC )
            {
            PORTC = 0;
            }
        else
            {
            PORTC = gu8PGAVolume;
            };
        break;
        };
    case DREICKECK_ON :
        {
        if( PORTC == gu8PGAVolume)
            {
            u16PositionToggle = 0;
            };
        if( !PORTC )
            {
            u16PositionToggle = 1;
            };           
        if( u16PositionToggle )
            {
            PORTC++;
            }
        else
            {
            PORTC--;
            };           
        break;
        };
    case SAEGEZAHN_UP :
        {
        if( PORTC < gu8PGAVolume )
            {
            PORTC++;
            }
        else
            {
            PORTC = 0;
            };
        break;
        };
    case SAEGEZAHN_DOWN :
        {   
        if( !PORTC )
            {
            PORTC = gu8PGAVolume;
            }
        else
            {
            PORTC--;
            };
        break;
        };
#ifdef PULSE_MODE_IMPLEMENTED
    case  PULSE_ON :
        {
        PORTC = gu8PGAVolume;
        //_delay_us(1);
        PORTC = 0;       
        break;
        };   
#endif
    };//switch
//sei();
};


#ifdef USE_TOGGLE_FLAG
// ****************************************************************
void ToggleTEST_BIT(uint8_t ucCnt)
// ****************************************************************
{ // #include <util\delay.h>  muss da sein
while(ucCnt--)
    {
    SET_TESTBIT();
    _delay_us(1);
    CLR_TESTBIT();
    _delay_us(1);
    };
};
#endif



// *************************************
void Set_Frq(float fVal) //Verbessert mit Zielbereichskalierung des Vorteilers.
// *************************************
{
float fComVal;
float fTimerDivider;

unsigned char sreg;

if( fVal > MAXIMAL_FRQ ) return;
if( fVal < MINIMAL_FRQ ) return;
//Voreinstellung
fTimerDivider = TIMER_DIVIDE_FRQ_0; //if( pfVal < TIMER_HALFCOMP_FRQ_1024)   
gu8Timer_CSxxClkSelect = TCCR1B_CLOCKSEL_CPU_1;
//Clock udn OCR1A so hoch als möglich
if( ( fComVal = F_CPU / fVal )  > 0xFFFF )
    {
    fTimerDivider = TIMER_DIVIDE_FRQ_8; //if( pfVal < TIMER_HALFCOMP_FRQ_1024)   
    gu8Timer_CSxxClkSelect = TCCR1B_CLOCKSEL_CPU_8;
    if( ( fComVal = TIMER_DIVIDE_FRQ_8 / fVal )  > 0xFFFF )
        {
        fTimerDivider = TIMER_DIVIDE_FRQ_64; //if( pfVal < TIMER_HALFCOMP_FRQ_1024)   
        gu8Timer_CSxxClkSelect = TCCR1B_CLOCKSEL_CPU_64;
        if( ( fComVal = TIMER_DIVIDE_FRQ_64 / fVal )  > 0xFFFF )
            {
            fTimerDivider = TIMER_DIVIDE_FRQ_256; //if( pfVal < TIMER_HALFCOMP_FRQ_1024)   
            gu8Timer_CSxxClkSelect = TCCR1B_CLOCKSEL_CPU_256;
            if( ( fComVal = TIMER_DIVIDE_FRQ_256 / fVal )  > 0xFFFF )
                {   
                fTimerDivider = TIMER_DIVIDE_FRQ_1024; //if( pfVal < TIMER_HALFCOMP_FRQ_1024)   
                gu8Timer_CSxxClkSelect = TCCR1B_CLOCKSEL_CPU_1024;
                fComVal = TIMER_DIVIDE_FRQ_1024 / fVal;
                }}}};

cli();
sreg = SREG; //loakaler Speicher
TCNT1 = 0;  //sicherung gegenen unbeabsichtigten Overrrun
OCR1A = (uint16_t)round( fComVal );
gfInterruptFRQ = fTimerDivider / OCR1A;
TCCR1B = TCCR1B_CTC_MODE | gu8Timer_CSxxClkSelect;//Clear Timer on Compare=CTC.  MODE an OCR1A + / CLk/1024
SREG = sreg; //loakaler Speicher
sei();

/*
uart_putc(13);
uart_putc(13);
uart_puts("fComVal=");
PrintFloatCR(fComVal);
uart_puts("SelectedFRQ=");
PrintFloatCR( gfInterruptFRQ);

uart_puts("OCR1A=");
PrintLongCR( OCR1A );

uart_puts("TimerDivider=");
PrintLongCR( fTimerDivider );

uart_puts("gu8Timer_CSxxClkSelect=");
PrintLongCR( gu8Timer_CSxxClkSelect );
*/
};


// *************************************
void FRQ_Off(void)
// *************************************
{
unsigned char sreg;
cli();
sreg = SREG; //loakaler Speicher
TIMSK &= ~_BV( OCIE1A );  //Interrupt OFF
TCCR1B = TCCR1B_CLOCKSEL_STOP;    //Stopen, damit keine geschachtelten Interrrupts passieren...
SREG = sreg; //loakaler Speicher
sei();
};


// *************************************
void FRQ_On(void)
// *************************************
{
unsigned char sreg;
cli();
sreg = SREG; //loakaler Speicher
TCNT1 = 0;  //sicherung gegenen unbeabsichtigten Overrrun
TIMSK |= _BV( OCIE1A );    //Interrupt ein
TCCR1B = TCCR1B_CTC_MODE | gu8Timer_CSxxClkSelect;//Clear Timer on Compare=CTC.  MODE an OCR1A + / CLk/1024
SREG = sreg; //loakaler Speicher
sei();
};



/*
ISR( TIMER0_OVF_vect )
// *******************************************************************
{
PWM_ENABLE();
};
*/

/*   
// *************************************
void Timer0_PWM(unsigned char ucPwmRange)
// *************************************
{  // 8BIT TIMER T0
unsigned char sreg;
sreg = SREG; //loakaler Speicher
cli();

TIMSK &=  (~(_BV(TOIE0))) & (~(_BV(OCIE0)));

//8 Bit Timerx00);    //Timer Inhalt
TCNT0=  0x00;    //Timer MAX = TOP Compare
OCR0 = ucPwmRange;
//TIMER STARTS with Presscale Select =256
//PWM= WGM01=0; WGM00=1
TCCR0 = TCCR0_CLK_1024 | TCCR0_FAST_PWM | TCCR0_OC0_MODE;    // 0000 0111//Timer Counter CTRL
//timer_enable_int(_BV(TOIE2));    !! WAHRNUNG ÜBERSCHREIBT OFFENBAR ANDERE BITS im TIMSK
//TIMSK |= TOIE0;
SREG = sreg;
sei();
};
*/


// *************************************
void StartTickTimer(void)
// *************************************
{//Normal MODE OC2 Disconnect Prescale 1024
unsigned char sreg;
sreg = SREG; //loakaler Speicher
cli();
//16000000 / 256 / 1024 = 61,03515625 Hz
TCCR0 = TCCR0_CLK_1024;    //frq 15625, NORMAL MODE=NO OCR0
TIMSK |= TIMSK_TOIE0_FLAG;
SREG = sreg;
sei();
};



// ****************************************************************
uint32_t GetTickDifference(uint32_t u32Time)
// ****************************************************************
{
return (gu32_Ticks - u32Time);
};


#ifdef ADC_USED_ENABLED
//****************************************************************
uint16_t ADC_10Bit(uint8_t u8Chan) // 0..7
//****************************************************************
{
DDRA &= ~_BV(u8Chan);  //Bit loeshcne von port A,Chanel Bit Input 
PORTA &= ~_BV(u8Chan); //Wegen Pullup abschalten
//Activate ADC with Prescaler 16 --> 16Mhz/128 = 125 khz
//ADCSRA = _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1) |_BV(ADPS0); 
//MIT INTERNER REFERENCE
ADCSRA = ADCSRA_ADEN | ADCSRA_PRESCALER_128;   //ADC EIN UND PreScaler
ADMUX = ADMUX_REFS1 | ADMUX_REFS0 | u8Chan;    // ADMUX_REFS0 Select pin ADCx using MUX 
_delay_us(1);
ADCSRA |= ADCSRA_ADSC;    //ADCSRA |= _BV(ADSC);    //Start conversion
while( ADCSRA & ADCSRA_ADSC )    //wait until _BV(ADSC)=0 =converstion completed
    {
    //wdt_reset();
    };   
return ADC;    //ADCW; //get converted value
};
#endif


#ifdef ADC_USED_ENABLED
// *******************************************
float PotiSkalierung( uint16_t u16Poti )    //Normiert Poti mit Offset auf 0..1 von 0..1000
//liefert Fakot 0..1 zurück wenn nix zu tun, rweturn -1;
// *******************************************
{
if( (u16Poti > POTI_ZERO_OFFSET ) && (u16Poti < POTI_UPPER_LIMIT) )
    {
    return ((u16Poti - POTI_ZERO_OFFSET) / (float)POTI_RANGE_LIMIT);
    };
return -1;   
};
#endif


#ifdef UART_USE_ENABLED
// *******************************************************************
void UART_TXRX_Check(void)
/*   
* Get received character from ringbuffer
* uart_getc() returns in the lower byte the received character and
* in the higher byte (bitmask) the last receive error
* UART_NO_DATA is returned when no data is available.
*/
// *******************************************************************
{
uint16_t uiRxUart = uart_getc();//!FETCH ALLWAYS BYTE FROM RX RINGBUFF INTERRUPT!
if ( !(uiRxUart & UART_NO_DATA) )  //0x0100
    {
//new data available from UART and check for Frame or Overrun error
#ifdef UART_ERRORMSG
   if( uiRxUart & (UART_FRAME_ERROR | UART_OVERRUN_ERROR | UART_BUFFER_OVERFLOW) )
        {
        ResetRxBuff();
        uart_init( UART_BAUD_SELECT(UART_BAUD_RATE, F_CPU) );// !! Init UART interface
// Framing Error detected, i.e no stop bit detected
        Print_PStrCR(  PSTR("UartErr") );
        };
#endif
//NOW SELECT ACTION FROM ORDER
//Check CR
    if(gpcRxPars < (gcaRxStr + RX_STRMAX))    //ENDANSCHLAG ERREICHT ?
        {
        switch( (unsigned  char)uiRxUart  )
            {
            case 13: // order!! from Terminal
                {
                CheckOrder(gcaRxStr);//gcaRxStr = accumulated str
                ResetRxBuff();
                break;
                };                              
            default: //Accumulate
                {
      // Accumulate String only to gcaRxStr with uiAAA Parser
                *gpcRxPars++ = (unsigned  char)(uiRxUart & 0x0FF);//Append rxByte
                *gpcRxPars = 0; //ZERO carry
                };
            };//switch
        }// if (pcRxPars < (gcaRxStr + RXSTRMAX))
    else  // To much data Rx, than clear simple all
        {
     //overflow of RX clears all
        ResetRxBuff();    // Clear Rx Parspointer in Buff an terminate RxStr with 0
        };
    };//ENDE DER RX EMPFANGSAUSWERTUNG
};
#endif




#ifdef UART_USE_ENABLED
// *******************************************************************
void ResetRxBuff(void)
// *******************************************************************
{
gpcRxPars = gcaRxStr; // Set parse pointer back;
*gpcRxPars = 0;    //clear Rx
};
#endif

#ifdef UART_USE_ENABLED   //MAKLEFILE ANPASSEN
// *******************************************************************
void PrintCR(void)
// *******************************************************************
{
uart_putc( ASC_CR );
};

// *******************************************************************
void PrintStrCR(const char* pStr)
// *******************************************************************
{
uart_puts(pStr);
PrintCR();
};

// *******************************************************************
void Print_PStrCR(PGM_P pmStr)
// *******************************************************************
{
uart_puts_p(pmStr);
PrintCR();
};


// **********************************************
void LongToNumStr(int32_t lVal)
// **********************************************
{
//sprintf(gcaNumStr,"%ld", lVal);  //Ulong = %ld
ltoa(lVal, gcaNumStr, 10);
//sprintf(gcaNumStr,"%li", lVal);  //Ulong = %ld
};

// *******************************************************************
void PrintLongCR(int32_t lVal)
// *******************************************************************
{
LongToNumStr(lVal); PrintStrCR(gcaNumStr);
};

// **********************************************
void FloatToNumStr(double fVal)
// *************
{ // Kommastellen 2 DTOSTR_PLUS_SIGN   DTOSTR_ALWAYS_SIGN
//dtostre(fVal,gcaNumStr,2, DTOSTR_UPPERCASE ); EXPO //  [-]d.ddd
dtostrf(fVal, 6, 3, gcaNumStr ); //[-]d.ddd
//sprintf(gcaNumStr,"%.1f", fVal);
};

// *******************************************************************
void PrintFloatCR(double fVal)
// *******************************************************************
{
FloatToNumStr(fVal); PrintStrCR(gcaNumStr);
};
#endif


// *******************************************************************
void CheckOrder(char *pcStrOrder) //von gcaRxStr
// *******************************************************************
{ //INPUT ERWARTET INDER FOR "BEFEHL,WERT" BSP: "SFR,1000"
//uint16_t uiCnt =0;
char * pStrTok; // für strtok_r
char * pucCh = &pcStrOrder[ strlen(pcStrOrder) ]; // Stelle POINTER auf \0 Ende  // kein unsigned char*

strcpy(gcaStr, pcStrOrder);
strcpy_P(gcaNumStr, MCA_DELIMITER_MSG); //HILFSWEISE gcaNumStr für ","

if( (pStrTok = strtok_r( pcStrOrder, gcaNumStr  , &pucCh)) != NULL)//Trenne CMD, von ID, -"$$$1,CMD
    {   
    strcpy(gsCmd.ucaCmd, pStrTok);
    }
else
    {
    *gsCmd.ucaCmd = 0;
    };
gsCmd.ucaCmd[ COMAMNDSIZEMAX ] = 0; //Sicherheitsterminierung COMAMNDSIZEMAX=10


//strcpy(gcaStr, pcStrOrder);

gsCmd.fCmdVal_1 = gsCmd.fCmdVal_2 = 0;
if( (pStrTok = strtok_r( NULL,  gcaNumStr, &pucCh)) != NULL)
    {
    gsCmd.fCmdVal_1 = atof(pStrTok);// Und dann TO Float   
    };
   
if( (pStrTok = strtok_r( NULL,  gcaNumStr, &pucCh)) != NULL)
    {
    gsCmd.fCmdVal_2 = atof(pStrTok);// Und dann TO Float   
    };

//========================================================================================

/*
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("SPC") ) )
    {
    DDRC=0XFF; //OUTPUTs
    PORTC = (uint8_t)gsCmd.fCmdVal_1;
    };

if( !strcasecmp_P( gsCmd.ucaCmd,  PSTR("RPC") ) )
    {
    DDRC=0X00; //INPUTs
    PORTC = 0X00; // PullUp AUS
    PrintLongCR( PINC );
    };   
*/

//------------------------------------------------
// --- DIES GILT DANN FÜR ALLE FOLGENDEN BEFEHLE
//------------------------------------------------
if( gsCmd.fCmdVal_2 > ADC_4_98_MAX_VOLTAGE ) // Überspannungseingabe wird abgefangen
    {
    gsCmd.fCmdVal_2 = ADC_4_98_MAX_VOLTAGE;
    };
//------------------------------------------------
// --- DIES GILT DANN FÜR ALLE FOLGENDEN BEFEHLE
//------------------------------------------------

if( gu8ModeSelect != SINUS_RESOLUTION_ON ) // evtl nicht freien Speuicher freigeben
    if( gpu8SineVal != NULL )
        {
        cli();
        free( (uint8_t*)gpu8SineVal );                   
        gpu8SineVal = NULL;
        sei();
        };
       
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("PING") )  )
    {   
    Print_PStrCR( PSTR("PONG") );   
    };

if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("FOF") )  )
    {   
    FRQ_Off();
    gu8ModeSelect = 0XFF;
   PORTC = 0;
    };

if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("FON") )  )
    {   
   FRQ_On();
    };

if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("RT") )  )   //RT,fFRQ,fVolt  Rectangle
    {
    FRQ_Off();
    gu8ModeSelect = RECHTECK_ON;   
   if( gsCmd.fCmdVal_1 && ( (gsCmd.fCmdVal_1 * 2.0 ) < INTERRUPT_FRQ_LIMIT  ) )
        {
        Set_Frq(    gsCmd.fCmdVal_1 * 2); //RaufRunter
        };       
   if( gsCmd.fCmdVal_2 )
      {
        gu8PGAVolume = round( BIT_PRO_TTLVOLT() * gsCmd.fCmdVal_2 );
      };
    FRQ_On();
    };


if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("TA") )  )   //TRIANGLE
    {
    FRQ_Off();
    gu8ModeSelect = DREICKECK_ON;
   gu16X_Resolution = DREIECK_X_RESOLUTON;
    if( gsCmd.fCmdVal_1 && ((gsCmd.fCmdVal_1 *gu16X_Resolution) <= INTERRUPT_FRQ_LIMIT)  )
        {
        Set_Frq(    gsCmd.fCmdVal_1 * gu16X_Resolution);
        };
   if( gsCmd.fCmdVal_2 )
      {
        gu8PGAVolume = round( BIT_PRO_TTLVOLT() * gsCmd.fCmdVal_2 );
      };
    FRQ_On();
    };


if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("SIR") )  )   //SINE Resolution
    {        //gu8SineVal[iNN] = round( 127.5 * (sin( 2*M_PI* iNN/256.0) + 1 ) );
    uint16_t u16NN;
    FRQ_Off();
    gu8ModeSelect = SINUS_RESOLUTION_ON;
    if( gpu8SineVal != NULL )
        {
        cli();
        free( (uint8_t*)gpu8SineVal );                   
        gpu8SineVal = NULL;
        sei();
        };
    if( gsCmd.fCmdVal_1 && (gsCmd.fCmdVal_1 <= MAX_X_RESOUTION)    )
        {
        gu16X_Resolution = gsCmd.fCmdVal_1;
        }
    else
        {
        gu16X_Resolution = SINUS_X_RESOLUTON;
        };
       
    if( gsCmd.fCmdVal_2 && (gsCmd.fCmdVal_2 <= ADC_4_98_MAX_VOLTAGE ))
      {
        gu8PGAVolume = round( BIT_PRO_TTLVOLT() * gsCmd.fCmdVal_2 );
      }
    else
        {
        gu8PGAVolume = ADC_4_98_MAX_VOLTAGE;
        };
       
    if( gpu8SineVal == NULL )
        {                   
        cli();
        gpu8SineVal = malloc( gu16X_Resolution );
           
        for(u16NN=0; u16NN < gu16X_Resolution; u16NN++) // Compute SineTable
            {
//gu8SineVal[iNN]    = round( (SINUS_X_RESOLUTON / 2.0 + 0.5) * (sin( 2*M_PI* iNN/SINUS_X_RESOLUTON) + 1 ) );                           
            *(gpu8SineVal + u16NN)    = round( (gu8PGAVolume / 2.0) * (sin( 2*M_PI* u16NN/gu16X_Resolution) + 1 ) );
            };   
        sei();           
        };
    FRQ_On();
    };

if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("SIN") )  )   //5V TTL SINE  si,1000,4.0
    {   
    FRQ_Off();
    gu8ModeSelect = SINUS_5V_AMPLIUDE;
   gu16X_Resolution = SINUS_5V_X_RESOLUTON;
    //gu8SineVal[iNN] = round( 127.5 * (sin( 2*M_PI* iNN/256.0) + 1 ) );
    if( gsCmd.fCmdVal_1 && ((gsCmd.fCmdVal_1 *gu16X_Resolution) <= INTERRUPT_FRQ_LIMIT) )
       {
        Set_Frq(    gsCmd.fCmdVal_1 * SINUS_5V_X_RESOLUTON );
        };
    FRQ_On();
    };

if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("STU") )  )   //SawTooth Sägezahn
    {   
    FRQ_Off();
    gu8ModeSelect = SAEGEZAHN_UP;
   gu16X_Resolution = SAWTOOTH_X_RESOLUTON;  
    if( gsCmd.fCmdVal_1 && ((gsCmd.fCmdVal_1 *gu16X_Resolution) <= INTERRUPT_FRQ_LIMIT) )
       {
        Set_Frq(    gsCmd.fCmdVal_1 * (float)SAWTOOTH_X_RESOLUTON );    //256
        }
    FRQ_On();
    };

if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("STD") )  )   //SawTooth Sägezahn
    {   
    FRQ_Off();
    gu8ModeSelect = SAEGEZAHN_DOWN;
   gu16X_Resolution = SAWTOOTH_X_RESOLUTON;  
    if( gsCmd.fCmdVal_1 && ((gsCmd.fCmdVal_1 *gu16X_Resolution) <= INTERRUPT_FRQ_LIMIT) )
        {
        Set_Frq(    gsCmd.fCmdVal_1 * SAWTOOTH_X_RESOLUTON );
        }
    FRQ_On();
    };

if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("VOL") )  )  //Amplitude einstellen
    {      
   gu8PGAVolume = round( BIT_PRO_TTLVOLT() * gsCmd.fCmdVal_1 );
   };


if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("FRQ") )  )  //Freqeunz einstellen
    {   
   if( gsCmd.fCmdVal_1 <= INTERRUPT_FRQ_LIMIT)
      {
      Set_Frq( gsCmd.fCmdVal_1 );
      };
    };

if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("PGA") )  )  //Amplitude einstellen
    {   
   if( gsCmd.fCmdVal_1 < PGA_AUFLOESUNG )
      {
      gu8PGAVolume = (uint8_t)gsCmd.fCmdVal_1;
      };
    };

if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("RES") )  )   //gu16X_Resolution einstellen
    {
    if( gsCmd.fCmdVal_1 < MAX_X_RESOUTION )
        {
        gu16X_Resolution = (uint16_t)gsCmd.fCmdVal_1;
        };
    };

   
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GV") )  )   //Get Val
    {
    PrintLongCR(gu16VolumePoti);
    };
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GF") )  )   //Get Val
    {
    PrintLongCR(gu16FrequenzPoti);
    };
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GM") )  )   //Get Val
    {
    PrintLongCR(gu16ModePoti);
    };
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GIF") )  )   //Get interrupt Frq
    {
   PrintFloatCR( gfInterruptFRQ );
    };
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GPGA") )  )   //Get PGA Val
    {
   PrintLongCR( gu8PGAVolume );
    };
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GVO") )  )   //Get interrupt Frq
    {
   PrintFloatCR( (gu8PGAVolume * TTL_VOLTAGE)/(float)PGA_AUFLOESUNG  );
    };
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GMO") )  )   //Get Mode Selcet
    {
   PrintLongCR( gu8ModeSelect );
    };  
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("GR") )  )   //Get Mode Selcet
    {
   PrintLongCR( gu16X_Resolution );
    };

if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("XX") )  )
    {
    //PrintCR();
    PrintLongCR( gu32_Ticks );
   //PrintFloatCR( ((gu16X_Resolution - POTI_ZERO_OFFSET) / (float)POTI_RANGE_LIMIT));
    //PrintFloatCR( PotiSkalierung( gu16X_Resolution ) );
    };

#ifdef ENDORDER_CMD_ECHO_ENABLED   
Print_PStrCR( PSTR("OK") );   
#endif   
};




#ifdef ADC_USED_ENABLED
// ****************************************************************
uint16_t ADC_StatistiKRead(uint8_t u8Channel, uint16_t u16LastRead)
// ****************************************************************
{ //Poti erst nach stärkerer Bewegung wieder aktivieren, dann jedoch empfindlicher
static uint32_t u32_PotiActiveTimeTicks;    //T2 timeCounter, only NN_Counter for Keypressings
uint8_t u8NN;
int16_t u16Diff;
int32_t i32Sampel = 0;
//erst mal lesen howmuch
u16Diff = fabs( (i32Sampel = ADC_10Bit( u8Channel )) - u16LastRead) ; //1*lesen
if( u16Diff > ADC_AKTIVATE_MOVEMENT_DIV ) // NIX TUN WEN NNIX PASSIERT
    {
    u32_PotiActiveTimeTicks = gu32_Ticks; //Merke dir Zeit für Timeout
    gu8ProgMode_Flag &= ~PROGMODE_POTI_FREEZE_STATUS; // zeigt an, daß Potis jetzt aktiv
    };
   
if( (u16Diff > ADC_MINI_MOVEMENT_DIV)    &&
    !(gu8ProgMode_Flag & PROGMODE_POTI_FREEZE_STATUS)    
    )    //#define ADC_AKTIVATE_MOVEMENT_DIV    15
    {
    //Jetzt genau messen, statistisch geglättet.
    i32Sampel = 0;
    for( u8NN=0; u8NN < ADC_SAMPLE_CNT; u8NN++ )    //#define SAMPLE_CNT    10.0
        {
        i32Sampel += ADC_10Bit( u8Channel );
        };
    i32Sampel = round(i32Sampel / ADC_SAMPLE_CNT);
    gu8ProgMode_Flag |= PROGMODE_POTI_MINIDIV_DETECT | PROGMODE_NEWVAL_DETECT;
    u32_PotiActiveTimeTicks = gu32_Ticks; //Merke dir Zeit für Timeout
    }
else
    {
    gu8ProgMode_Flag &= ~PROGMODE_POTI_MINIDIV_DETECT; // Damit ungültigkeit festgestellt werden kann
    };

if( GetTickDifference( u32_PotiActiveTimeTicks ) > PULS_4SEcOND_1024 )
    {
    gu8ProgMode_Flag &= ~PROGMODE_POTI_MINIDIV_DETECT;   
    gu8ProgMode_Flag |= PROGMODE_POTI_FREEZE_STATUS;
    };

#ifdef SHOW_ADC_READVAL_ON_LCD   
lcd_gotoxy(0,1);
FloatToNumStr( fabs(i32Sampel - u16LastRead) );
lcd_puts( gcaNumStr );
if( !(gu8ProgMode_Flag & PROGMODE_POTI_FREEZE_STATUS) )
    {
    lcd_puts_p( PSTR(" Act") );   
    }
else
    {
    lcd_puts_p( PSTR("        ") );   
    };
if( gu8ProgMode_Flag & PROGMODE_POTI_MINIDIV_DETECT )
    {
    lcd_puts_p( PSTR(" Div") );   
    };
#endif

return i32Sampel;
}
#endif




// *********************************
void WarteMal(uint16_t u16WaitTicks)
// *********************************
{
uint32_t u32TimeCompare = gu32_Ticks;
while( GetTickDifference( u32TimeCompare ) < u16WaitTicks)// 4*/sec
    {
    wdt_reset();    //WATCHDOG!
    UART_TXRX_Check();    //IMMER VORHANDEN !! IN ALLEN LOOPS DIE ZEIT BRAUCHEN
    };
};





// *******************************************************************
int main(void)
// *******************************************************************
{
//static uint8_t u8Cnt;
//static uint8_t u16PositionToggle;
static uint32_t u32LCD_UpdateTimeCompare;
static uint32_t u32UARTTimeCompare;    //Um nihct zu schnell UART ohne interrupt zu lesen.
float fScaleFactor;
uint16_t u16PotiReadVal;
uint16_t u16NN;
//INITS
cli();//The global interrupt flag is maintained in the I bit of the status register (SREG). 
//Wichtige Schritte.. so bald wie möglich

//INIT HARDWARE
//USing of PORTOUTS  1=OUT, 0=IN
DDRA = PORTA_DDRX_OUTMASK;
PORTA = PORTA_PRESET_PULLMASK;
DDRB = PORTB_DDRX_OUTMASK;
PORTB = PORTB_PRESET_PULLMASK;
DDRC = PORTC_DDRX_OUTMASK;
PORTC = PORTC_PRESET_PULLMASK;
DDRD = PORTD_DDRX_OUTMASK;
PORTD = PORTD_PRESET_PULLMASK;

wdt_enable( WDTO_500MS ); //WDTO_250MS WDTO_500MS WDTO_1S WDTO_2S  WatchDog ENABLE
wdt_reset();   //WATCHDOG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

ResetRxBuff();
uart_init( UART_BAUD_SELECT(UART_BAUD_RATE, F_CPU) );

StartTickTimer();    //8 Bit Timer 0//Wegen Interrupt später!
#ifdef USE_TOGGLE_FLAG
INIT_TESTBIT_REG();
CLR_TESTBIT();
#endif

Print_PStrCR( MCA_WELCOME1_MSG );
Print_PStrCR( MCA_WELCOME2_MSG );
uart_puts_p( MCA_PGA );
uart_puts_p( MCA_SPACE );
uart_puts_p( MCA_FREQUENZ );
uart_puts_p( MCA_SPACE );
Print_PStrCR( MCA_GENERATOR );

lcd_init( LCD_DISP_ON );
_delay_ms(1);
lcd_clrscr();
lcd_gotoxy(0,0);
lcd_puts_p( MCA_WELCOME1_MSG );
lcd_gotoxy(0,1);
lcd_puts_p( MCA_WELCOME2_MSG );
WarteMal( PULS_2SEcOND_1024 );


lcd_clrscr();
lcd_gotoxy(0,0);
lcd_puts_p( MCA_PGA );
lcd_puts_p( MCA_SPACE );
lcd_puts_p( MCA_FREQUENZ );
lcd_gotoxy(0,1);
lcd_puts_p( MCA_GENERATOR );
WarteMal( PULS_1SEcOND_1024 );
 
gu32_Ticks = 0;
u32UARTTimeCompare = 0;
u32LCD_UpdateTimeCompare = 0;
u32UARTTimeCompare = 0;
//gfInterruptFRQ = START_FREQUENZ;

//PORTC= gu8PGAVolume;

SET_SWITCH_DDRX();
SET_SWITCH_PULLX();

Set_Frq( START_FREQUENZ );//1000
FRQ_On();
gu8ProgMode_Flag |= PROGMODE_MODESWITCH_CHANGE_DETECT | PROGMODE_POTI_FREEZE_STATUS;

// ************ MAIN LOOP FOR EVER *********************
// MCUCR |= MCUCR_ADC_NOISE_REDUCTION;
for (;;)  /* loop forever */ //Aber schnell > 200.000 mal/Sekunde
    {   
    sei();
     wdt_reset();    //WATCHDOG!

#ifdef USE_TOGGLE_FLAG
ToggleTEST_BIT(1);
#endif

#ifdef MODE_SWITCH_PRESENT
    if( !READ_SWITCH() )
        {
        if( !(gu8ProgMode_Flag & PROGMODE_MANUEL) )
            { // Im Umschaltmoment
            gu8ProgMode_Flag &= ~PROGMODE_POTI_FREEZE_STATUS;
            gu16VolumePoti =        ADC_StatistiKRead( POTI_VOLUME, 0 ); // alles neu einlesen
            gu16FrequenzPoti =    ADC_StatistiKRead( POTI_FREQUENZ,0 ); // alles neu einlesen
            gu16ModePoti =         ADC_StatistiKRead( POTI_MODE, 0 ); // alles neu einlesen

            gu8ProgMode_Flag |=    PROGMODE_MODESWITCH_CHANGE_DETECT    |
                                        PROGMODE_POTI_MINIDIV_DETECT        |
                                        PROGMODE_FREQUENZ_CHANGE_DETECT      |
                                        PROGMODE_VOLUME_CHANGE_DETECT        |
                                        PROGMODE_MODE_SELECT_CHANGE_DETECT    |
                                        PROGMODE_MANUEL;
            };   

// POTIS CHecken  POTI CHecken  POTI CHecken  POTI CHecken  POTI CHecken  POTI CHecken
        u16PotiReadVal = ADC_StatistiKRead( POTI_VOLUME, gu16VolumePoti );  // Lese erst das Poti    
        if( gu8ProgMode_Flag & PROGMODE_POTI_MINIDIV_DETECT )
            {
            gu16VolumePoti = u16PotiReadVal; //um für Ruhe zu sorgen erst hier zuweisen
            gu8ProgMode_Flag |= PROGMODE_VOLUME_CHANGE_DETECT;
            };
           
#ifndef NURMODEPOTITESTEN
        u16PotiReadVal = ADC_StatistiKRead( POTI_FREQUENZ, gu16FrequenzPoti ); // Erforsche ob Änderung des Wertes
        if( gu8ProgMode_Flag & PROGMODE_POTI_MINIDIV_DETECT )
            {
            gu16FrequenzPoti = u16PotiReadVal; //um für Ruhe zu sorgen erst hier zuweisen
            gu8ProgMode_Flag |= PROGMODE_FREQUENZ_CHANGE_DETECT;
            };

        u16PotiReadVal = ADC_StatistiKRead( POTI_MODE, gu16ModePoti ); // Lese erst das Poti    
        if( gu8ProgMode_Flag & PROGMODE_POTI_MINIDIV_DETECT )
            {
            gu16ModePoti = u16PotiReadVal; //um für Ruhe zu sorgen erst hier zuweisen
            gu8ProgMode_Flag |= PROGMODE_MODE_SELECT_CHANGE_DETECT;
            };
#endif


//------------------- NOT FREZZE -------------------------------
// -------------------------------------------------------------------               
        if( !(gu8ProgMode_Flag & PROGMODE_POTI_FREEZE_STATUS) )
            {                       
// VOLUME SELECT * VOLUME SELECT * VOLUME SELECT * VOLUME SELECT * VOLUME SELECT * VOLUME SELECT *    
// VOLUME SELECT * VOLUME SELECT * VOLUME SELECT * VOLUME SELECT * VOLUME SELECT * VOLUME SELECT *    
// VOLUME SELECT * VOLUME SELECT * VOLUME SELECT * VOLUME SELECT * VOLUME SELECT * VOLUME SELECT *    
            if(gu8ProgMode_Flag & PROGMODE_VOLUME_CHANGE_DETECT)
                {
                gu8ProgMode_Flag &= ~PROGMODE_VOLUME_CHANGE_DETECT;               
                if(  (fScaleFactor = PotiSkalierung( gu16VolumePoti )) != -1 )
                    {
                    gu8PGAVolume = round(PGA_255RANGE * fScaleFactor);    //10To8Bit = 1024/4.0 = 256
                    };               
                switch( gu8ModeSelect )
                    {
                    case SINUS_RESOLUTION_ON:
                        {   
                        break;
                        }
                    case DREICKECK_ON :    //Dreieck
                    case SAEGEZAHN_UP:    //SAEGEZAHN_UP
                    case SAEGEZAHN_DOWN:    //SAEGEZAHN_DOWN
                        {
                        FRQ_Off();
                        Set_Frq( gfInterruptFRQ );
                        FRQ_On();
                        break;
                        };
                    };//switch
#ifdef SHOW_POTSVALS_ONCOM_ON
    uart_puts_p(PSTR("Vol=") );
    PrintFloatCR( gu8PGAVolume );   
#endif                   
                };


// FREQUENZ SELECT * FREQUENZ SELECT * FREQUENZ SELECT * FREQUENZ SELECT * FREQUENZ SELECT * FREQUENZ
// FREQUENZ SELECT * FREQUENZ SELECT * FREQUENZ SELECT * FREQUENZ SELECT * FREQUENZ SELECT * FREQUENZ
// FREQUENZ SELECT * FREQUENZ SELECT * FREQUENZ SELECT * FREQUENZ SELECT * FREQUENZ SELECT * FREQUENZ
            if( gu8ProgMode_Flag & PROGMODE_FREQUENZ_CHANGE_DETECT)
                {
                gu8ProgMode_Flag &= ~PROGMODE_FREQUENZ_CHANGE_DETECT;   
               
                if(  (fScaleFactor = PotiSkalierung( gu16FrequenzPoti )) != -1 )
                    {
                    FRQ_Off(); //pow(M_E, oder 1y= ( 10^x-1)/9
                    // gfInterruptFRQ =;    // umm irgendwie zwischen 0.3..bis 150KHz zu kommemn
                    Set_Frq( INTERRUPT_FRQ_LIMIT * ((pow(10,fScaleFactor) -1) / 9) );
                    FRQ_On();
                    };                       
                };                   
// MODE SELECT * MODE SELECT * MODE SELECT * MODE SELECT * MODE SELECT * MODE SELECT * MODE SELECT *
// MODE SELECT * MODE SELECT * MODE SELECT * MODE SELECT * MODE SELECT * MODE SELECT * MODE SELECT *
// MODE SELECT * MODE SELECT * MODE SELECT * MODE SELECT * MODE SELECT * MODE SELECT * MODE SELECT *           
            if(gu8ProgMode_Flag & PROGMODE_MODE_SELECT_CHANGE_DETECT)
                {
                gu8ProgMode_Flag &= ~PROGMODE_MODE_SELECT_CHANGE_DETECT;               
                if(  (fScaleFactor = PotiSkalierung( gu16ModePoti )) != -1 )
                    {
                    gu8ModeSelect = round( POSSIBLE_MODES_CNT * fScaleFactor );               
//PrintLongCR( gu8ModeSelect );
                    };

                if( (gpu8SineVal == NULL) && (gu8ModeSelect == SINUS_RESOLUTION_ON) )
                    {                   
                    cli();
                    gpu8SineVal = malloc( gu16X_Resolution );
                   
                    for(u16NN=0; u16NN < gu16X_Resolution; u16NN++) // Compute SineTable
                        {
//gu8SineVal[iNN]    = round( (SINUS_X_RESOLUTON / 2.0 + 0.5) * (sin( 2*M_PI* iNN/SINUS_X_RESOLUTON) + 1 ) );                           
*(gpu8SineVal + u16NN)    = round( (gu8PGAVolume / 2.0) * (sin( 2*M_PI* u16NN/SINUS_X_RESOLUTON) + 1 ) );
                        };
                    sei();           
                    };                   
                   
                if( (gpu8SineVal != NULL) && (gu8ModeSelect != SINUS_RESOLUTION_ON)    )
                    {
                    cli();
                    free( (uint8_t*)gpu8SineVal );                   
                    gpu8SineVal = NULL;
                    sei();
                    };
                   
#ifdef SHOW_POTSVALS_ONCOM_ON
                uart_puts_p( PSTR("Frq=") );
                PrintFloatCR( gfInterruptFRQ);                                   
#endif
                };    //gu8ProgMode_Flag & PROGMODE_FREQUENZ_CHANGE_DETECT
            }; //!(gu8ProgMode_Flag & PROGMODE_POTI_FREEZE_STATUS)                           
        }
    else    //readswitch MANUEL Modus
        {
        if( gu8ProgMode_Flag & PROGMODE_MANUEL )
            {
            ADCSRA &= ~ADCSRA_ADEN; //ADC Ausschalten
            ADMUX = 0;    //REF OFF
            gu8ProgMode_Flag &= ~PROGMODE_MANUEL; //ALSO PC-STEUERUNG
            gu8ProgMode_Flag |= PROGMODE_MODESWITCH_CHANGE_DETECT | PROGMODE_POTI_FREEZE_STATUS;
            };
        };
    #endif    //readswitch


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
//** LCD ** LCD ** LCD ** LCD ** LCD ** LCD ** LCD ** LCD ** LCD ** LCD
//** LCD ** LCD ** LCD ** LCD ** LCD ** LCD ** LCD ** LCD ** LCD ** LCD
//** LCD ** LCD ** LCD ** LCD ** LCD ** LCD ** LCD ** LCD ** LCD ** LCD

    // Hier die Modusänderung anzeigen, nach Switchänderung.
    if( gu8ProgMode_Flag & PROGMODE_MODESWITCH_CHANGE_DETECT )
        {
        gu8ProgMode_Flag &= ~PROGMODE_MODESWITCH_CHANGE_DETECT;               
        lcd_clrscr();       
        lcd_puts_p( PSTR("MODE=") );
        if( gu8ProgMode_Flag & PROGMODE_MANUEL)
            {
            lcd_puts_p( PSTR("MANUEL") );
            }
        else
            {
            lcd_puts_p( PSTR("REMOTE") );
            };
    //Wartemal 2 Sekunden   
        WarteMal(PULS_2SEcOND_1024);
        };   


#ifdef LCD_NORMALAUSGABE_ENABLED
    if(GetTickDifference( u32LCD_UpdateTimeCompare ) > PULS_1SEcOND_1024 )
        {       
        u32LCD_UpdateTimeCompare = gu32_Ticks;
        lcd_clrscr();       
        lcd_gotoxy(0, 0);           
        lcd_puts_p( PSTR("Vol=") );
        if( gu8ModeSelect == SINUS_5V_AMPLIUDE )
            {
            FloatToNumStr( ADC_4_98_MAX_VOLTAGE );
            }
        else
            {
            FloatToNumStr( TTLVOLT_PRO_BIT() * gu8PGAVolume );
            };
        lcd_puts( gcaNumStr );       
        lcd_puts_p( PSTR("V ") );       

        switch( gu8ModeSelect )
            {
            case SINUS_RESOLUTION_ON :
                {
                lcd_puts_p( PSTR("SiRes") );
                break;
                };
         case SINUS_5V_AMPLIUDE :
                {
                lcd_puts_p( PSTR("Sine") );
                break;
                };
            case RECHTECK_ON :           
                {
                lcd_puts_p( PSTR("Rectang") );
                break;
                };
            case DREICKECK_ON :
                {
                lcd_puts_p( PSTR("Triang") );
                break;
                };
            case SAEGEZAHN_UP :
                {
                lcd_puts_p( PSTR("SawU") );
                break;
                };
            case SAEGEZAHN_DOWN :
                {
                lcd_puts_p( PSTR("SawD") );
                break;
                };
#ifdef PULSE_MODE_IMPLEMENTED
            case PULSE_ON :
                {
                lcd_puts_p( PSTR("Puls") );
                break;
                };
#endif
            };    //switch               

// -----------------------------------------------------------------
        lcd_gotoxy(0, 1);
        lcd_puts_p( PSTR("Frq=") );           
        switch( gu8ModeSelect )
            {
            case SINUS_RESOLUTION_ON:    //SINE
                {
                FloatToNumStr( gfInterruptFRQ / gu16X_Resolution );
                break;
                };
            case SINUS_5V_AMPLIUDE:    //SINE
                {
                FloatToNumStr( gfInterruptFRQ / SINUS_5V_X_RESOLUTON );
                break;
                };
            case RECHTECK_ON: //RECT
                {
                FloatToNumStr( gfInterruptFRQ / 2.0 );
                break;
                };
            case DREICKECK_ON :    //Dreieck
            case SAEGEZAHN_UP:   
            case SAEGEZAHN_DOWN:
                {
                FloatToNumStr( gfInterruptFRQ / gu16X_Resolution );
                break;
                };
            };//switch
        lcd_puts( gcaNumStr );                   
        lcd_puts_p( PSTR("Hz") );
           
        if( !(gu8ProgMode_Flag & PROGMODE_POTI_FREEZE_STATUS) )
            {
            lcd_puts_p( PSTR(" Act") );
            };               
        /*
            lcd_puts_p( PSTR(" ") );
            LongToNumStr( OCR1A );
            lcd_puts( gcaNumStr );             
            lcd_gotoxy(0,1);       
            lcd_puts_p( PSTR("Tick=") );
            LongToNumStr( gu32_Ticks );
            lcd_puts( gcaNumStr );           
        */   
 // ---------------------------------------
      #ifdef SHOW_POTIS_BYMINIDIV_ON_LCD
      if( gu8ProgMode_Flag & PROGMODE_NEWVAL_DETECT ) // Zeig eim Falle des
         {
         gu8ProgMode_Flag &= ~PROGMODE_NEWVAL_DETECT;
         lcd_clrscr();
         lcd_gotoxy(0,0);   
         LongToNumStr( gu16VolumePoti );
         lcd_puts( gcaNumStr );
         if( gu8ProgMode_Flag & PROGMODE_VOLUME_CHANGE_DETECT )
            {
            lcd_puts_p( PSTR("X") );
            }
         else
            {
            lcd_puts_p( PSTR("=") );
            };
           
         lcd_puts_p( PSTR(" ") );
         LongToNumStr( gu16FrequenzPoti );
         lcd_puts( gcaNumStr );
         if( gu8ProgMode_Flag & PROGMODE_FREQUENZ_CHANGE_DETECT )
            {
            lcd_puts_p( PSTR("X") );
            }
         else
            {
            lcd_puts_p( PSTR("=") );
            };
         lcd_puts_p( PSTR(" ") );

         LongToNumStr( gu16ModePoti );
         lcd_puts( gcaNumStr );   
         if( gu8ProgMode_Flag & PROGMODE_MODE_SELECT_CHANGE_DETECT )
            {
            lcd_puts_p( PSTR("X") );
            }
         else
            {
            lcd_puts_p( PSTR("=") );
            };
         }; 
        #endif
      }; //LCD SECUNDEN UPDATE
#endif //#ifdef LCD_NORMALAUSGABE_ENABLED       

    if( (GetTickDifference( u32UARTTimeCompare ) > PULS_250MS_TICK_1024) &&
         !(gu8ProgMode_Flag & PROGMODE_MANUEL)
    )   //PULS_PER_SEcONDTick_1024) //PULS_250MS_TICK_1024)
        {       
        u32UARTTimeCompare = gu32_Ticks;   
        #ifdef UART_USE_ENABLED
        UART_TXRX_Check();    //IMMER VORNAHANDEN !! IN ALLEN LOOPS DIE ZEIT BRAUCHEN
        #endif   
        };       
    }; //main loop Ende
};
// ******************* MAIN END ********************************************
/*
CODE Schnipsl
//uart_puts_p(PSTR("X"));
*/




main.h
#ifndef MAIN_HEADER  //Prevents multiple includes
#define MAIN_HEADERf

//#define USE_TOGGLE_FLAG
#define TIMER_TICK_USED
#define UART_USE_ENABLED
#define ADC_USED_ENABLED
//#define EEPROM_USED

//#define TEXT_SERVICE_USE_ENABLED
//#define ENDORDER_CMD_ECHO_ENABLED
#define UART_ERRORMSG

#ifdef  USE_TOGGLE_FLAG
    #define TESTBIT_DIRREG        DDRD
    #define TESTBIT_PORT            PORTD
    #define TESTBIT_BIT            0x04    //3te leitung
    #define TESTBIT_INVERT_BIT    0xFB
    #define INIT_TESTBIT_REG()    (TESTBIT_DIRREG |= TESTBIT_BIT);
    #define SET_TESTBIT()    (TESTBIT_PORT |= TESTBIT_BIT);
    #define CLR_TESTBIT()    (TESTBIT_PORT &= TESTBIT_INVERT_BIT);
    extern void ToggleTEST_BIT(uint8_t ucCnt);
#endif




#define STRMAX     64
#define NUMMAX     32
#define RX_STRMAX 64
#define COMAMNDSIZEMAX  64

#define DELIMITER        ','
#define DELIMITERSTR    ","


//TYPEN DEKLARATION
typedef struct
    {
    char ucaCmd[COMAMNDSIZEMAX +1];
    uint8_t ucCmdID;
    float fCmdVal_1;
    float fCmdVal_2;
//uint8_t ucCmdID;
    }COMMAND_TYPE;

// Hardwareassignment
//F_CPU  in makefile !!!
#define UART_BAUD_RATE    9600    /* 9600 baud */
//#define UART_BAUD_RATE    19200
//#define UART_BAUD_RATE    57600

/*     FÜR Timer /256
#define PULS_PER_10TEL_SEc    25
#define PULS_PER_SEcONDTick    244
#define PULS_500MS_Tick        122
#define PULS_250MS_TICK        61
#define PULS_100MS_TICK        25
#define PULS_50MS_TICK        13
#define PULS_13MS_TICK        3
#define PULS_8MS_TICK        2
*/
   
//FÜR Timer /1024 
//16000000 / 256 / 1024 = 61,03515625

#define PULS_5SEcOND_1024        305
#define PULS_4SEcOND_1024        244
#define PULS_2SEcOND_1024        122
#define PULS_1SEcOND_1024        61
#define PULS_500MS_Tick_1024    30
#define PULS_250MS_TICK_1024    15
#define PULS_100MS_TICK_1024    6




#define SYSCLK_256    (SYSCLK / 256) // =  62500 //z.B.Timer2 Überlauf / 256  / Teilerfaktor

#define DISABLE_ALL_PULLUP_MAC    (SFIOR |= _BV(PUD));
#define ENABLE_ALLUP_SCL_MAC    (SFIOR &= ~(_BV(PUD)));

//========================================================================

//TIMERS
//TIMER2  = is 61 miliseconds Timer ~approx.
// 16MhZ / 1024 / 256  = 61,03515625 Hz
// T= 1/f = 0.016384 ms / Interrupt

//TIMER
#define TIMSK_TOIE0_FLAG    0x01
#define TIMSK_OCIE0_FLAG    0x02
#define TIMSK_TOIE1_FLAG    0x04
#define TIMSK_OCIE1B_FLAG    0x08
#define TIMSK_OCIE1A_FLAG    0x10
#define TIMSK_TICIE1_FLAG    0x20
#define TIMSK_TOIE2_FLAG    0x40    //#define TOIE2 6     (1 << TOIE2)
#define TIMSK_OCIE2_FLAG    0x80

#define TIMSK_T0_CLR_ALL_MASK 0b11111100
#define TIMSK_T1_CLR_ALL_MASK 0b11000011
#define TIMSK_T2_CLR_ALL_MASK 0b00111111


#define TIFR_TOV0_TIMER_OVERFLOW_FLAG    0x01
#define TIFR_OCF0_OUT_PCOMPARE_FLAG        0x02
#define TIFR_TOV1_TIMER_OVERFLOW_FLAG    0x04
#define TIFR_OCF1A_OUTP_COMPARE_A_FLAG    0x10
#define TIFR_OCF1B_OUTP_COMPARE_B_FLAG    0x08
#define TIFR_TOV2_TIMER_OVERFLOW_FLAG    0x40
#define TIFR_OCF2_OUTP_COMPARE_FLAG        0x80


//DELAY
//#define TCCR2_CLK_64    0x04    //675 = 0,0014814814814814814814814814814815   mS Interrrupt
// 1 TICK = 1.4814814814814814814814814814815 ms
//NUR UNGEFÄHR
//BERECHUNG Xtime(ms) / 1.48....
#define TIMEOUT_1_5MS     1
#define TIMEOUT_2_9MS     2
#define TIMEOUT_4_4MS     3
#define TIMEOUT_10_3MS     7
#define TIMEOUT_100_7MS    68
#define TIMEOUT_500_7MS    338
#define TIMEOUT_1S         675        //!!  uint16_t
#define TIMEOUT_5S         3375    //!!  uint16_t

//REGISTER
#define TCCR0_FAST_PWM    0x48    //Mode 3
#define TCCR0_OC0_MODE    0x20    //Clear ON compare Match
#define TCCR0_OC0_DISCONNECT_MODE    0x00
#define TCCR0_CLK_STOP    0x00   
#define TCCR0_CLK_0        0x01   
#define TCCR0_CLK_8        0x02   
#define TCCR0_CLK_64        0x03   
#define TCCR0_CLK_256    0x04   
#define TCCR0_CLK_1024    0x05   
#define TCCR0_EXT_CLK_FALL_T0    0x06   
#define TCCR0_EXT_CLK_RISE_T0    0x07   


#define TCCR2_WGM_NORMAL        0x00
#define TCCR2_OC0_MODE            0x20    //Clear ON compare Match
#define TCCR2_CTC_MODE            0x08 //0000 1000
#define TCCR2_COM_NORMALPORT    0x00
#define TCCR2_CLK_STOP            0x00
#define TCCR2_FAST_PWM            0x48    //Mode 3
#define TCCR2_CS_BIST            0x0x    //Mode 3
#define TCCR2_CLK_1024    0x07   
#define TCCR2_CLK_256    0x06   
#define TCCR2_CLK_128    0x05
#define TCCR2_CLK_64    0x04    //
#define TCCR2_CLK_32    0x03
#define TCCR2_CLK_8        0x02    //    1/F =
#define TCCR2_CLK_0        0x01   
#define TCCR2_CLK_STOP    0x00   
//TIMER2 WIRD BERECHNET /z.B:OverFLow SYSCLK /  256 / TCCR2_CLK_64 =  OVL/Sec
// 1/OVLS = 1/ =
//----->

//#define TCCR1B_CLOCKSEL_CTC1         0x08    //Clear Timer/Counter  on Compare Match Timer/Counter 1
#define TCCR1B_CLOCKSEL_STOP        0x00    //Clock Select Bits
#define TCCR1B_CTC_MODE                0x08    //Clock Select Bits
#define TCCR1B_CLOCKSEL_CPU_1        0x01    //Clock Select Bits
#define TCCR1B_CLOCKSEL_CPU_8        0x02    //Clock Select Bits
#define TCCR1B_CLOCKSEL_CPU_64    0x03    //Clock Select Bits
#define TCCR1B_CLOCKSEL_CPU_256    0x04    //Clock Select Bits
#define TCCR1B_CLOCKSEL_CPU_1024    0x05    //Clock Select Bits


//BEI 16 MHz Quarz = F_CPU / Teiler
// QUARZ/DIVIDE = FREQUENZ
#define TIMER_DIVIDE_FRQ_0        ((float)F_CPU)    // 16000000UL
#define TIMER_DIVIDE_FRQ_8        ((float)F_CPU / 8) //2000000UL       
#define TIMER_DIVIDE_FRQ_64    ((float)F_CPU / 64) //250000UL
#define TIMER_DIVIDE_FRQ_256    ((float)F_CPU / 256) //62500U
#define TIMER_DIVIDE_FRQ_1024    ((float)F_CPU / 1024) //15625U

#define MAXIMAL_FRQ    ((float)F_CPU / 64)
#define MINIMAL_FRQ    (F_CPU / 1024/ 0xFFFF * 1.0) // 0.2385 //0,23842221713588158999008163576715  0,2384



//INTERUPT CTRL REG //NICHT mit MCUCSR verwechseln !
#define MCUCR_LOWLEVEL_INT0        0x00   
#define MCUCR_ANYCHANGE_INT0        0x01 //=_BV(ISC01)    
#define MCUCR_FALLING_EDGE_INT0    0x02   
#define MCUCR_RISING_EDGE_INT0    0x03

#define MCUCR_LOWLEVEL_INT1        0x00   
#define MCUCR_ANYCHANGE_INT1        0x04 //=_BV(ISC10)    
#define MCUCR_FALLING_EDGE_INT1    0x08   
#define MCUCR_RISING_EDGE_INT1    0x0C
#define MCUCR_ADC_NOISE_REDUCTION    0x10    //    _BV(SM0)  //SLEEP MODE

#define GATE_ANYCHANGE_INT1_MODE_MAC    (MCUCR |= MCUCR_ANYCHANGE_INT1)


//Global Interrrupt CTRL REG
#define GICR_INT0_ON_MAC    (GICR |= _BV(INT0)) //_BV(INT0)
#define GICR_INT0_OFF_MAC    (GICR &= ~(_BV(INT0)))
#define GICR_INT1_ON_MAC    (GICR |= _BV(INT1))
#define GICR_INT1_OFF_MAC    (GICR &= ~(_BV(INT1)))
#define GICR_INT_0u1_OFF_MAC    (GICR &= 0x3F)  //SIEHE DATENBLATT


#define RCO_B_INT_ON_MAC    GICR_INT0_ON_MAC
#define RCO_B_INT_OFF_MAC    GICR_INT0_OFF_MAC
#define GATE_INT1_ON_MAC    GICR_INT1_ON_MAC
#define GATE_INT1_OFF_MAC    GICR_INT1_OFF_MAC


#define OVERFLOW_CNT_ON_INT0_MAC    RCO_B_INT_ON_MAC
#define OVERFLOW_CNT_OFF_INT0_MAC    RCO_B_INT_OFF_MAC

#define GATE_ALL_EVENT_ON_INT1_MAC    GATE_INT1_ON_MAC
#define GATE_ALL_EVENT_OFF_INT1_MAC    GATE_INT1_OFF_MAC

//GIFR  I_FLAG
#define GIFR_INTF0_SET_MAC    (GIFR |= _BV(INTF0)) //_BV(INT0)
#define GIFR_INTF0_CLR_MAC    (GIFR &= ~(_BV(INTF0)))
#define GIFR_INTF1_CLR_MAC    (GIFR |= _BV(INTF1))
#define GIFR_INTF1_SET_MAC    (GIFR &= ~(_BV(INTF1)))
#define GIFR_INTF_0u1_CLR_MAC    (GIFR &= 0x3F) //Siehe Datenblatt = letzten beiden Bits



//PORTB
#define MOSI_I         3//BIT3
#define MISO_0         4//BIT4
#define SCK_I          5//BIT5

//#define TCCR1B_CLOCKSEL_CTC1         0x08    //Clear Timer/Counter  on Compare Match Timer/Counter 1
#define TCCR1B_CLOCKSEL_STOP        0x00    //Clock Select Bits
#define TCCR1B_CLOCKSEL_CPU_1        0x01    //Clock Select Bits
#define TCCR1B_CLOCKSEL_CPU_8        0x02    //Clock Select Bits
#define TCCR1B_CLOCKSEL_CPU_64    0x03    //Clock Select Bits
#define TCCR1B_CLOCKSEL_CPU_256    0x04    //Clock Select Bits
#define TCCR1B_CLOCKSEL_CPU_1024    0x05    //Clock Select Bits

//ADC //AT8
#define ADMUX_MUX0    0
#define ADMUX_MUX1    1
#define ADMUX_MUX2    2
#define ADMUX_MUX3    3
#define ADMUX_MUX4    4
#define ADMUX_MUX5    5
#define ADMUX_MUX_1_23V    0xE0
#define ADMUX_MUX_GND    0xF0
#define ADMUX_ADLAR    0x20
#define ADMUX_REFS0    0x40
#define ADMUX_REFS1    0x80
#define ADC_MUX_MASK    0x01F

#define ADCSRA_ADPS0    0x01
#define ADCSRA_ADPS1    0x02
#define ADCSRA_ADPS2    0x04
#define ADCSRA_ADIE    0x08
#define ADCSRA_ADIF    0x10    //INTERRRUPT FLAG
#define ADCSRA_ADATE    0x20    //AUTO TRIGGER ENABLE
#define ADCSRA_ADSC    0x40    //START  //while (ADCSRA & _BV(ADSC) )
#define ADCSRA_ADEN    0x80    //Enable

//PRESCALER
#define  ADCSRA_PRESCALER_2    0x01
#define  ADCSRA_PRESCALER_4    0x02
#define  ADCSRA_PRESCALER_8    0x03
#define  ADCSRA_PRESCALER_16    0x04
#define  ADCSRA_PRESCALER_32    0x05
#define  ADCSRA_PRESCALER_64    0x06
#define  ADCSRA_PRESCALER_128    0x07
//WERT IN ADCW

//PORT_ASSIGMNEMTS
#define WDTO_2S   7 //WatchDog
//SOFTWARE USED DEFINES

#define ASC_CR    13
#define ASC_LF    10
#define ASC_DELIMITER    ','


//CHECK PUD = PULLUPDISSABLE in SFIOR
//PORTA      //1=OUT 6BIT
//1=OUT
#define PORTA_DDRX_OUTMASK        0X00    //3 und 4 auf INPUT
#define PORTA_PRESET_PULLMASK    0x08    //Ohne Pullup  SCHALTER

//CHECK PUD = PULLUPDISSABLE in SFIOR
//PORT B      //1=OUT 6BIT
//1=OUT
#define PORTB_DDRX_OUTMASK        0X00           
#define PORTB_PRESET_PULLMASK    0X00    //Ohne Pullup   

//PORT C     TWI //1=OUT  0 = IN  6BIT
//STARTWERTE
#define PORTC_DDRX_OUTMASK        0xFF
#define PORTC_PRESET_PULLMASK    0X00    //Ohne Pullup

//PORT D    //1=OUT 8 BIT
//TX/RX & zusatzhardware
#define PORTD_DDRX_OUTMASK        _BV( PD1 )
#define PORTD_PRESET_PULLMASK    0b00000000    //Ohne Pullup
#define RX_BIT        PD0 //0
#define TX_BIT        PD1 //1

// HIER PROJEKTSPEZIFISCHES



//LCD
#define LCD_BASEMSG__FLAG    0x80
//static volatile uint8_t gu8LCD_FLAG;

//Kurvensyntese
//gu8SineVal[iNN] = Round( 127.5 * (sin( 2*M_PI* iNN/256.0) + 1 ) );
#define SINUS_X_RESOLUTON        256
#define SINUS_5V_X_RESOLUTON    256 // Starrer Wert weil Arrayfeld
#define DREIECK_X_RESOLUTON    256
#define SAWTOOTH_X_RESOLUTON    256
#define MAX_X_RESOUTION            401
#define INTERRUPT_FRQ_LIMIT    150001.0 // Somit sind 75000 RT möglich

#define START_FREQUENZ    1000.0
//PGA Volume PRESET
#define START_PGA_VOLUME    51    //PRESET
#define TTL_VOLUME_ON    0x255



//PGA
#define TTL_VOLTAGE        ( 5.0 )
#define ADC_4_98_MAX_VOLTAGE    ( 4.98046875 )    // 5V/256 * 255

#define PGA_AUFLOESUNG        ( 256 )
#define PGA_255RANGE            ( 255 )
#define TTLVOLT_PRO_BIT()    (TTL_VOLTAGE / PGA_AUFLOESUNG) // VOLT/BIT
#define BIT_PRO_TTLVOLT()    (PGA_AUFLOESUNG / TTL_VOLTAGE) // BIT/VOLT
 
#define SINUS_RESOLUTION_ON    0    //2.er
#define SINUS_5V_AMPLIUDE    1    //2.er
#define RECHTECK_ON            2    //1.er //Start Preset
#define DREICKECK_ON            3    //3.er
#define SAEGEZAHN_UP            4    //4.er
#define SAEGEZAHN_DOWN        5    //5.er
#define PULSE_ON                6    //6.er
//gu8ModeSelect
#define POSSIBLE_MODES_CNT 5   


//PROGRAMM MODUS
#define PROGMODE_MANUEL                                0x01
#define PROGMODE_POTI_FREEZE_STATUS                0x02
#define PROGMODE_POTI_MINIDIV_DETECT            0x04   
#define PROGMODE_MODESWITCH_CHANGE_DETECT        0x08
#define PROGMODE_MODE_SELECT_CHANGE_DETECT    0x10
#define PROGMODE_VOLUME_CHANGE_DETECT            0x20
#define PROGMODE_FREQUENZ_CHANGE_DETECT        0x40
#define PROGMODE_NEWVAL_DETECT                    0x80 // allgemeine ereignisanzeige
//#define PROGMODE_POTI_ACTIVE_DIFF_DETECT    0x80
//gu8PRogMode_Flag;


//ADC SECTION, READ MANUAL PAGE 205
// 8 Channel. ADC1, ADC0 ansd ADC3, ADC2 are PGAs 1*, 10*,200*
#define INTERNAL_VOLTAGE_REFERENCE    2.56    //V
#define ADCRESOLUTION    1024U    //0..1023

#define ADC_SAMPLE_CNT                    2//3    //Statistische Reads mit Durchschnittsbildung   
#define ADC_MINI_MOVEMENT_DIV            2    //Erst diese Änderung akzepieren ( kein Poitflattern dadurch
#define ADC_AKTIVATE_MOVEMENT_DIV    15 // Diese Wertaenderung startet Potijustage

#define POTI_RANGE_LIMIT    1000U
#define POTI_ZERO_OFFSET    11 //Ab diesem Wert wird Wert als 0 definiert
#define POTI_UPPER_LIMIT    1012 // ADCRESOLUTION - POTI_ZERO_OFFSET

#define POTI_VOLUME        2
#define POTI_FREQUENZ    1    //Reihenfolge rein zufällig
#define POTI_MODE            0
#define REMOTE_SWITCH    3

#define SWITCH_PORT_IN    PINA
#define SWICHTPORT_OUT    PORTA
#define DDRXSWICHTPORT    DDRA
#define SWITCH_PIN        0x08    //( Als HExausdruck von REMOTE_SWITCH )   
#define SWITCH_PIN_INV    0xF7    //( Als HExausdruck )
#define SET_SWITCH_DDRX()    (DDRXSWICHTPORT &= SWITCH_PIN_INV) //SWITCH AUF INPUT=0
#define SET_SWITCH_PULLX()    (SWICHTPORT_OUT |= SWITCH_PIN) //SWITCH AUF INPUT=0
#define READ_SWITCH()    (SWITCH_PORT_IN & SWITCH_PIN) //READ SWITCH => !=0


// ** Programmcode Steuerung **
#define MODE_SWITCH_PRESENT
#define LCD_NORMALAUSGABE_ENABLED
//#define SHOW_POTIS_BYMINIDIV_ON_LCD // TESTAUSGABE der Potifunktion = oder !=


//Erweiterungen
#define PULSE_MODE_IMPLEMENTED
//TESTAUSGABEN
//#define SHOW_POTSVALS_ONCOM_ON
//#define SHOW_ADC_READVAL_ON_LCD   
//#define NURMODEPOTITESTEN
//1024 / 5 = 204.8

#endif  //MAIN_HEADER