Subversion Repositories Projects

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

 
/****************************************************************/
/*                                                                                                                              */
/*                               NG-Video 5,8GHz                                                        */
/*                                                                                                                              */
/*                              Copyright (C) 2011 - gebad                                              */
/*                                                                                                                              */
/*  This code is distributed under the GNU Public License               */
/*      which can be found at http://www.gnu.org/licenses/gpl.txt       */
/*                                                                                                                              */
/****************************************************************/

#include <avr/io.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <util/delay.h>

#include "config.h"
#include "dogm.h"
#include "messages.h"
#include "ngvideo.h"
#include "menue.h"
#include "servo.h"
#include "tracking.c"


/************************************************************************************/
/*  initialisiert den EEPROM mit default Werten, bzw. liest EEPROM gespeicherte         */
/*  Werte in gloabale Variablen.                                                                                                        */
/*      Parameter:                                                                                                                                              */
/*  uint8_t ep_reset   :0 = zwangsweises Rückstetzen auf default-Werte                          */
/*                                                                                                                                                                      */
/************************************************************************************/
void Init_EEPROM(uint8_t ep_reset)
{ char ver[sizeof(VERSION)];
  uint8_t eep_init;
 
  eep_init = eeprom_read_byte(&ep_eep_init);
  eeprom_read_block(&ver, &ep_version, sizeof(VERSION));
  _delay_ms(1);

  if ((eep_init != EEP_INITB) || (ep_reset == 0) || strcmp(VERSION, ver))
  {
     // nur bei Erstinitialisierung DOGM auf default 3,3V setzen
        if ((eep_init != EEP_INITB) || strcmp(VERSION, ver)){
          eeprom_write_byte(&ep_eep_init, EEP_INITB);
          eeprom_write_byte(&ep_dogm_vers, DOGM3V);
          eeprom_write_byte(&ep_contrast, CONTRAST3V);
      eeprom_write_block(&VERSION, &ep_version, sizeof(VERSION));
    }
        eeprom_write_byte(&ep_light_time, BACKGR_LIGHT_MAX);
        eeprom_write_byte(&ep_u_offset, U_OFFSET);
        eeprom_write_dword(&ep_u_min, U_MIN);
    eeprom_write_byte(&ep_channel, CHANNEL);
    eeprom_write_byte(&ep_av_source, AV_SOURCE);
        eeprom_write_byte(&ep_language, NO_LANGUAGE);
    eeprom_write_word(&ep_udbm_min, UDBM_MIN);
        eeprom_write_word(&ep_udbm_max, UDBM_MAX);
        eeprom_write_word(&ep_udbm_korr_1, UDBM_KORR_FA);
        eeprom_write_word(&ep_udbm_korr_2, UDBM_KORR_FA);
    eeprom_write_byte(&ep_sIdxSteps, STEPS_255);
        eeprom_write_block(&servo[0],&ep_servo[0],sizeof(servo_t));
        eeprom_write_block(&servo[1],&ep_servo[1],sizeof(servo_t));
        eeprom_write_byte(&ep_tracking, TRACKING_MIN);
        eeprom_write_byte(&ep_track_hyst, TRACKING_HYSTERESE);
        eeprom_write_byte(&ep_track_tx, 0);
        eeprom_write_byte(&ep_baudrate, BAUDRATE);
        sIdxSteps = STEPS_255;
  }
  else
  {
        light_time = eeprom_read_byte(&ep_light_time);
        u_offset = eeprom_read_byte(&ep_u_offset);
        u_min = eeprom_read_dword(&ep_u_min);
    channel = eeprom_read_byte(&ep_channel);
    av_source = eeprom_read_byte(&ep_av_source);
        language = eeprom_read_byte(&ep_language);
        udbm_min = eeprom_read_word(&ep_udbm_min);
        udbm_max = eeprom_read_word(&ep_udbm_max);
        udbm_korr_1 = eeprom_read_word(&ep_udbm_korr_1);
        udbm_korr_2 = eeprom_read_word(&ep_udbm_korr_2);
        sIdxSteps = eeprom_read_byte(&ep_sIdxSteps);
        eeprom_read_block(&servo[0],&ep_servo[0],sizeof(servo_t));
        eeprom_read_block(&servo[1],&ep_servo[1],sizeof(servo_t));
    tracking = eeprom_read_byte(&ep_tracking);
    track_hyst = eeprom_read_byte(&ep_track_hyst);
        track_tx = eeprom_read_byte(&ep_track_tx);
        baudrate = eeprom_read_byte(&ep_baudrate);
 }
  dogm_vers = eeprom_read_byte(&ep_dogm_vers);
  contrast = eeprom_read_byte(&ep_contrast);
  hyst_u_min = u_min;
  wudbm = RSSI_Calc_UdBm(pudbm); // Vergleichstabelle für dBm-Balken berechnen
  sw_avx = av_source;
  for (uint8_t i = 0; i < SERVO_NUM_CHANNELS; i++) {
        servoSet_rev(i, servo[i].rev);
        servoSet_min(i, servo[i].min);
        servoSet_max(i, servo[i].max);
        servoSet_mid(i, servo[i].mid);
  }
  // Vorberechnung von ServoChannels[channel].duty
  servoSetDefaultPos(); // Ausgangsstellung beider Servos
  coldstart = 1;
  USART_Init_Baudrate();
  USART_RX_Mode(tracking);
}

void servoSetDefaultPos(void)
{
  servoSetPosition(SERVO_PAN, ServoSteps()/2);  // Ausgangsstellung SERVO_PAN
  servoSetPosition(SERVO_TILT, 0);                              // Ausgangsstellung SERVO_TILT
}

void USART_Init_Baudrate(void)
{
  if (tracking == TRACKING_MKCOCKPIT)
    USART_Init(baud[baudrate]);
  else
    USART_Init(baud[6]);        //57600
}

/************************************************************************************/
/*  setzt Flag für 3,3V oder 5V DOGM                                                                                            */
/*      Parameter:                                                                                                                                              */
/*  uint8_t dogm        :Version                                                                                                                */
/*                                                                                                                                                                      */
/************************************************************************************/
void Set_DOGM_Version(void)
{
  if(dogm_vers == DOGM5V) {
    dogm_vers = DOGM3V;
        contrast = CONTRAST3V;
  }
  else {
    dogm_vers = DOGM5V;
        contrast = CONTRAST5V;
  }
  eeprom_write_byte(&ep_dogm_vers, dogm_vers);
  eeprom_write_byte(&ep_contrast, contrast);
}

/************************************************************************************/
/*  setzt den RX-Kanal von 1 bis 7                                                                                                      */
/*      Parameter:                                                                                                                                              */
/*  uint8_t channel     :Kanal                                                                                                                  */
/*                                                                                                                                                                      */
/************************************************************************************/
void Set_Channel(uint8_t channel)
{ uint8_t tmp;

  channel--;
  tmp = channel & 0b00000111;   // Kanal 1 bis 7 Werte 0 bis 6 setzen
  PORTA |= tmp;
  PORTB |= tmp;
  tmp = channel | 0b11111000;
  PORTA &= tmp;
  PORTB &= tmp;  
}

/************************************************************************************/
/*  schaltet den MUX auf AV1 oder AV2 ohne Darstellung und en-/disabled Interrupt       */
/*  wird nur in main.c (Initialisierung) und Menü Sourceumschaltung eingesetzt          */
/*  deswegen cli() und sei() nur in Menu_AV_Source(void)                                                        */
/*  Parameter:                                                                                                                                          */
/*  uint8_t src :0-AV1, 1-AV2                                                                                                           */
/*                                                                                                                                                                      */
/************************************************************************************/
void SetMux0(void) {
  SET_MUX_0;
  mux_X = 0;    // für Erkennung RX Zeitzähler
}

void SetMux1(void) {
  SET_MUX_1;
  mux_X = 1;    // für Erkennung RX Zeitzähler
}

uint8_t Set_AV_Source(uint8_t src)
{
  switch(src) {
    case AV1:           CLEAR_INT10;    // Interrupt für Sync ausschalten
                                        SetMux0();
                                        break;
    case AV2:           CLEAR_INT10;    // Interrupt für Sync ausschalten
                                        SetMux1();
                                        break;
    case DIVERSITY: SET_INT10;          // External Interrupt Mask Register ein
                                        SetMux0();
                                        break;
  }
  return(src);
}


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

void lcdSet_BackgrLight_Off(void)
{
  backgr_light = OFF;
  lcdBacklightOff();
}

void lcd_BackgrLight_On(void)
{ // ...&& (light_count < light_time)) ==> sonst wird Beleuchtung laufend wieder eingeschaltet
  if ((backgr_light == OFF) && (light_time > BACKGR_LIGHT_MIN) && (light_count < light_time)) {
    cli();
        light_count = 0;
        sei();
        backgr_light = ON;
        lcdBacklightOn();
  }
}

void lcd_BackgrLight(void)
{
  if (backgr_light == ON) {                                     // nur wenn Beleuchtung an
    if (light_time == BACKGR_LIGHT_MIN)         // Hintergrundbeleuchtung immer aus?
      lcdSet_BackgrLight_Off();
        else
          if (light_time < BACKGR_LIGHT_MAX) {  // Hintergrundbeleuchtung immer an?
            cli();
                light_count++;
                sei();
                if (light_count >= light_time) lcdSet_BackgrLight_Off();
          }
  }
}

/**************************************************************/
/*                                                                                                                        */
/*                           ADC                                                      */
/*                                                                                                                        */
/*      http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial  */
/*                                                                                                                        */
/**************************************************************/

void ADC_Init(void)
{
  uint16_t result;
 
  ADMUX = (0<<REFS1) | (1<<REFS0);              // AVcc als Referenz benutzen, da an AREF 4,8 V
  ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);        // Frequenzvorteiler Prescaler 128
  ADCSRA |= (1<<ADEN);                                  // ADC aktivieren
 
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */

 
  ADCSRA |= (1<<ADSC);                                  // eine ADC-Wandlung
  while (ADCSRA & (1<<ADSC) ) {}                // auf Abschluss der Konvertierung warten
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
     Wandlung nicht übernommen. */

  result = ADCW;
}

/* ADC Einzelmessung */
uint16_t ADC_Read( uint8_t channel )
{
  // Kanal waehlen, ohne andere Bits zu beeinflußen
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
  ADCSRA |= (1<<ADSC);                          // eine Wandlung "single conversion"
  while (ADCSRA & (1<<ADSC) ) {}                // auf Abschluss der Konvertierung warten
  return ADCW;                                  // ADC auslesen und zurückgeben
}

/* ADC Mehrfachmessung mit Mittelwertbbildung */
uint16_t ADC_Read_Avg( uint8_t channel, uint16_t average )
{
  uint32_t result = 0;
 
  for (uint16_t i = 0; i < average; ++i ){
    result += ADC_Read( channel );
        _delay_ms(1);
  }
  return (uint16_t)( result / average );
}


/**************************************************************/
/*                                                                                                                        */
/*                         Beeper                                                         */
/*                                                                                                                        */
/**************************************************************/

void Beep(uint8_t time)
{
  PORTB |= (1<<BEEPER);
//  PINB &= ~(1<<BEEPER);
  _delay_ms(time);
//  PINB |= (1<<BEEPER);
  PORTB &= ~(1<<BEEPER);
}

void Double_Beep(uint8_t time, uint8_t pause)
{
        Beep(time);
        _delay_ms(pause);
        Beep(time);
}

/**************************************************************/
/*                                                                                                                        */
/*                        U-Batterie                                              */
/*                                                                                                                        */
/**************************************************************/

/* Funktion zur Umwandlung einer vorzeichenbehafteten Integer
   32-Bit "Festkomma-Zahl"(gedachtes Komma in Integer) in einen String
   vereinfacht Variablenübergabe funktion change_value(uint32_t x),
   kein printf, double oder float
   siehe http://www.mikrocontroller.net/articles/Festkommaarithmetik
   Vorz ==> 0 kein '-' trotz negativer Zahl, 1 wenn kein '-' bleibt Stelle leer
   len max 11, Vorzeichen wird nicht mitgezählt aber Komma; Vorz 0 oder 1
   Festkomma ==> Position der Kommastelle bei Integerwert
   Nachkomma ==> angezeigte Nachkommastellen bei Festkomma
   
   makefile derzeit somit auch ohne! Minimalistic printf version
   Achtung: keine Fehlerprüfung! */

 
char* my_itoa(int32_t zahl, uint8_t Vorz, uint8_t len, uint8_t Festkomma, uint8_t Nachkomma)
{
  int8_t i;
  uint8_t neg = 0;
  char Komma;                                   // Sprachversion Deutsch ',' andere '.'
  static char str[13];

  Komma = Msg(MSG_KOMMA)[0];    // [0] nur als Char, sonst wäre es ein String
  if( zahl < 0 ) {                              // ist die Zahl negativ?
    zahl = -zahl;
    neg = 1;
  }
  if (Vorz) str[0] = '0'; else len--;
  str[len+1]='\0';                              // String Terminator
  if (Nachkomma > 0) Nachkomma++;

  for(i=len; i>=Vorz; i--) {
    if ((len - Festkomma == i) && (Festkomma > 0))
                str[i]= Komma;                  // bei Bedarf Komma einfügen
        else {                                          // Integer-Dezimalumrechnung
          str[i]=(zahl % 10) +'0';      // Modulo rechnen, dann den ASCII-Code von '0' addieren
      zahl /= 10;
        }
        // festgelegt Festkomma aber verkleinern der Anzeige Mantisse
        if ((Festkomma > 0) && (Festkomma >= Nachkomma) && (len - Festkomma + Nachkomma == i)) str[i]= '\0';
  }
  i=0;
  while  ((str[i+1] != Komma) && (i < len))  {
        // Vorzeichen unmittelbar vor Zahl schreiben
        if((Vorz) && (neg) && ((str[i+1] != '0') || (str[i+2] == Komma))) str[i] = '-';
    // eine 0 vor Komma lassen
        if(str[i] == '0') str[i++] = ' '; else break; // Vornullen entfernen
  }
  return(str);
}

// uint32_t u, da bei Displ_Fnct[fu_index](val) der größte Wert UBat gleich 32 Bit
void Displ_1Nk(uint32_t u)
{
  // 0 kein Vorzeichen, 5 => 2 Ziffern vor Komma + 1 Komma + 2 Mantisse, Festkomma, eine Ziffer Nachkomma darstellen
  lcdPuts(my_itoa(u,0,5,2,1));
}

void Displ_U_2Nk(uint32_t u)
{
  lcdPuts(my_itoa(u,0,5,2,2));
  lcdPutc('V');
}

// uint8_t beep_timer :Akku-leer-Beeper nur mit Task_0_1()-Intervalle bei Menü-Rücksprung
uint32_t U_Messen_cmp(uint8_t beep_timer)
{ uint32_t ubat;
  static struct
  { uint8_t time;
        uint8_t count;
  } beep_low;

/*       ubat = ((ADC_Read(VBAT) * Vref * (R104 + R103)) /(1024 * R103)) + UD10 (UD10 ist Offset)
         Verhältniswert * 100 *8192 ( Verhältniswert = realer Korrekturwert;
         mal 100 da alle Werte 2 Nachkommastellen berücksichtigt, aber ohne gerechnet wird
         mal 8192 => ohne Bruch gerechnet aber dabei mehr Kommastellen berücksichtigt) */

  ubat = (ADC_Read(VBAT) * (uint64_t)43504 + (uint64_t)u_offset * 8192)/ 8192;
  if ( ubat <= hyst_u_min )
  {
    if (bat_low != 0) {         // nicht laufend Display neu schreiben
          hyst_u_min = u_min + 20;      // 200mV Hysterese - beruhigt Anzeige
          lcdClear();
          lcdPuts(Msg(MSG_ACCU_LOW));
          bat_low = 0;
          Beep(BEEPBAT);
          // da derzeit Fkt. aller 500ms aufgerufen, mit 2 Min Abstand beginnen
          beep_low.time = BEEP_LOW_TIME;
          beep_low.count = 0;
        }
        // Akku leer, in immer kürzeren Intervallen Beep
        if ((beep_timer == 1) && (beep_low.count++ >= beep_low.time)){
          Beep(BEEPBAT);
          if (beep_low.time > 2)
            beep_low.time /= 2;
          beep_low.count = 0;
        }
  }
  else {
    if (hyst_u_min > u_min) {   // falls Anzeige von Batterie leer
          bat_low = 1;                          // und zurück geschaltet wird,
          hyst_u_min = u_min;           // dann Main_Disp wieder darstellen
          Displ_Main_Disp();
        }
  }
  return(ubat);
}

void Displ_VBat(void) // da u_offset globale Variable
{ uint32_t ubat;
 
  ubat = U_Messen_cmp(ENABLE_BTIMER);
  if (bat_low != 0) { // würde sonst Anzeige Akku leer überschreiben
    lcdGotoXY(11, 0);
    Displ_1Nk(ubat);
  }
}


/**************************************************************/
/*                                                                                                                        */
/*                          RSSI                                                          */
/*                                                                                                                        */
/**************************************************************/

/* RSSI Werte Korrekturfaktor berechnen */
uint16_t  RSSI_Calc_Korr(uint16_t u0, uint16_t u1)
{ uint16_t u_max;

  // immer nur den kleineren Wert vergrößern
  if (u0 < u1) {
    udbm_korr_1 = (((uint32_t)u1 * UDBM_KORR_FA) / u0)+0.5; // nur mit Integer und 2 Nachkommastellen rechnen
        udbm_korr_2 = UDBM_KORR_FA;
        u_max = u1;
  }
  else {
    udbm_korr_2 = (((uint32_t)u0 * UDBM_KORR_FA) / u1)+0.5; // nur mit Integer und 2 Nachkommastellen rechnen
    udbm_korr_1 = UDBM_KORR_FA;
        u_max = u0;
  }
  eeprom_write_word(&ep_udbm_korr_1, udbm_korr_1);
  eeprom_write_word(&ep_udbm_korr_2, udbm_korr_2);
  return(u_max);
}

void Displ_Calibr_Aktiv(void)
{
  lcdClear();
  Displ_Str_mid(Msg(MSG_CALIBRATION),0);
  Displ_Str_mid(Msg(MSG_RUNNING),1);
}

void Displ_Error_TX(uint8_t message)
{
  lcdClear();
  Displ_Str_mid(Msg(MSG_ERROR),0);
  Displ_Str_mid(Msg(MSG_TX_NOT),1);
  Displ_Str_mid(Msg(message), 2);
  for ( uint8_t i=0; i<=30;i++)
    _delay_ms(100);
}

void RSSI_Min_Calibrate(uint16_t *pudbm)
{ uint16_t u0, u1;

  Displ_Calibr_Aktiv();
  u0 = ADC_Read_Avg(RSSI0, 1000);               //1000 Wiederholungen mit
  u1 = ADC_Read_Avg(RSSI1, 1000);               //Mittelwertbildung
  // Plausibilitätsprüfung ob Sender ausgeschaltet
  if (u0 + u1 > 500) {
    udbm_min = RSSI_Calc_Korr(u0, u1); // ist real die größere Spannung, aber der kleinere dbm Wert
    eeprom_write_word(&ep_udbm_min, udbm_min);
        Double_Beep(DBEEPWR, DBEEPWRP);
        wudbm = RSSI_Calc_UdBm(pudbm);
  }
  else Displ_Error_TX(MSG_TX_OFF);
}

void RSSI_Max_Calibrate(uint16_t *pudbm)
{ uint16_t u0, u1;

  Displ_Calibr_Aktiv();
  u0 = ADC_Read_Avg(RSSI0, 1000);       //1000 Wiederholungen mit
  u1 = ADC_Read_Avg(RSSI1, 1000);       //Mittelwertbildung
  // Plausibilitätsprüfung ob Sender in der Nähe eingeschaltet
  if (u0 + u1 < 400) {
    udbm_max = RSSI_Calc_Korr(u0, u1); // ist real die kleinere Spannung, aber der größere dbm Wert
    eeprom_write_word(&ep_udbm_max, udbm_max);
        Double_Beep(DBEEPWR, DBEEPWRP);
    wudbm = RSSI_Calc_UdBm(pudbm);
  }
  else Displ_Error_TX(MSG_TX_ON);
}

// Vergleichstabelle für RSSI-Bargraph berechnen, vermeidet laufend gleiche Berechnung
uint8_t RSSI_Calc_UdBm(uint16_t *pudbm)
{ uint8_t n;
  // -15 um Ende dBm Skala sicher zu erreichen; ohne verfeinerten Bahrgraph war Wert -3
  n = (udbm_min - udbm_max -15)/11;
  for (uint8_t i = 0; i < 12; i++)
    pudbm[i] = (udbm_min - i * n);
  return(n / 5); // da 5 Pixel Breite pro Display-Zeichen; Anzeigebalken pro Pixel differenzieren
}

void Displ_RSSI_Bargraph(uint16_t *pudbm, uint8_t wudbm, uint16_t uadc)
{ char strBar[12];
  uint8_t i;
  int8_t lz = 11;
  char b = 4;
 
  // Balken zeichnen - udbm
  for (i = 0; i < 12; i++) {
        if ((b != ' ') && (uadc > pudbm[i])) {
          b  = ' ';
          lz = i - 1;
        }
    strBar[i] = b;
  }
  if (lz >= 0) {
        strBar[lz] = (pudbm[lz] - uadc) / wudbm ;// Anzeigebalken pro Pixel-"Breite" differenzieren
        // bei Teilung 4 wäre richtig und keine Korr. erforderlich, so aber gleichmäßigerer Balkenverlauf
    if (strBar[lz] > 4) strBar[lz] = 4;
  }
  for (i = 0; i < 12; i++)// lcdPuts (ist auch for) funktioniert hier nicht, da Char'\0' für Zeichen auch Stringende
    lcdPutc(strBar[i]);
}

uint8_t RSSI_Diversity(uint8_t src, uint16_t *pudbm, uint8_t visible)
{ uint16_t u0, u1;
  static uint8_t div_flag, ret_div_flag;
  char marker;

  u0 = (ADC_Read(RSSI0) * (uint32_t)udbm_korr_1)/UDBM_KORR_FA;
  u1 = (ADC_Read(RSSI1) * (uint32_t)udbm_korr_2)/UDBM_KORR_FA;
 
  // falls beide RX gleich gut/schlecht synchronisieren
  // Achtung! Niedrigere Spannung - größere Feldstärke
  if (src == DIVERSITY) {
    if (u0 < u1) {
          ret_div_flag = AV1;
          if ((vscount0 == 255) && (vscount1 == 255)) SetMux0();
    }
    else {
          ret_div_flag = AV2;
          if ((vscount0 == 255) && (vscount1 == 255)) SetMux1();
    }
  }
  else ret_div_flag = src; // sonst leerer Returnwert
   
  if (visible) {
    if (src == DIVERSITY) {
          // Synchronisation vorrangig zur Feldstärke
      if ((vsync0 != vsync1) && ((vscount0 & vscount1) < 255)) {
            // ist nur zur Anzeige - Sync-MUX wird über Interrupt gesteuert
        if (vsync0 == 0) {
              div_flag = AV1;
            }
            else {
              div_flag = AV2;
            }
            marker = MARKER_SYNC;
      }
          else {
            div_flag = ret_div_flag;
                marker = MARKER_RSSI;
          }
    }
    else marker = MARKER_AV;
        // wäre unschön - keine RSSI-Anzeige, aber Marker springt
        if ((u0 > pudbm[0]) && (u1 > pudbm[0])) marker = ' ';
        lcdGotoXY(2, 1);
    Displ_RSSI_Bargraph(pudbm, wudbm, u0);
    lcdGotoXY(2, 2);
        Displ_RSSI_Bargraph(pudbm, wudbm, u1);
        if (src == DIVERSITY) Displ_AV_Mark(div_flag, marker);
  }
  return(ret_div_flag);
}

/**************************************************************/
/*                                                                                                                        */
/*      Diversity v-Synchronisation Interruptroutinen             */
/*                                                                                                                        */
/**************************************************************/

/* Impulszähler für V-Synchronisation 0 und 1
   wird durch Interrupt des jewiligen vSync einzeln zurückgesetzt */

ISR(TIMER2_OVF_vect)
{
  TCNT2 = (int8_t)(int16_t)-(F_CPU / 64 * 500e-6);  // preload
  if (vscount0 < 255) ++vscount0; // Überlauf von vscount vermeiden
  if (vscount1 < 255) ++vscount1; // Überlauf von vscount vermeiden
  if (rx_timeout < RX_TIME_OLD) ++rx_timeout; // veranlasst bei GPS-Tracking MK Datensatz senden
  if ((tracking == TRACKING_GPS) && (MK_Motor_run)) { // MK-Motoren müssen laufen
    if (mux_X)
          rxcount1++;   // kein Test auf Überlauf ==> Counter groß genug - bis Stunden
        else
          rxcount0++;
  }
}

/* Messung von Impulsabstand v-Synchronisation 0
   Zur Vermeidung von Bildstörunen erfolgt MUX-Umschaltung in Bildaustastung */

ISR(INT0_vect)
{
  if ((vscount0 >= 79) && (vscount0 <= 81))
    vsync0 = 0;
  else {
    vsync0 = 1;
        if (vsync1 == 0)
          SetMux1();
  }
  if (vsync0 == vsync1) { //nur wenn vSynchronisation gleich gut/schlecht ist greift RSSI
    if (sw_avx == AV1) {
          SetMux0();
        }
        else
          SetMux1();
  }
  vscount0 = 0;
}

/* Messung von Impulsabstand v-Synchronisation 1
   Zur Vermeidung von Bildstörunen erfolgt MUX-Umschaltung in Bildaustastung */

ISR(INT1_vect)
{
 if ((vscount1 >= 79) && (vscount1 <= 81))
    vsync1 = 0;
  else {
    vsync1 = 1;
    if (vsync0 == 0)
          SetMux0();
  }
  if (vsync0 == vsync1) { //nur wenn vSynchronisation gleich gut/schlecht ist greift RSSI
    if (sw_avx == AV1) {
          SetMux0();
        }
        else
          SetMux1();
  }
  vscount1 = 0;
}

/**************************************************************/
/*                                                                                                                        */
/*                          Tasks                                                         */
/*        ermöglicht unterschiedliche Zeiten f. UBat, Sync...     */
/*                                                                                                                        */
/**************************************************************/

void Task_0_1(void)
{
  if (task_timer0_1) {
    cli();
        task_timer0_1 = 0;
        sei();
    Displ_VBat();
   }
 }

void Task_0_2(void)
{
  if (task_timer0_2) {
    cli();
        task_timer0_2 = 0;
        sei();
        sw_avx = RSSI_Diversity(av_source, pudbm, bat_low);
  }
}

void Task_0_3(void)
{
  if (task_timer0_3) {
    cli();
        task_timer0_3 = 0;
        sei();
    sw_avx = RSSI_Diversity(av_source, pudbm, 0);
        if (tracking == TRACKING_MKCOCKPIT) Tracking_MKCockpit();
  }
}

void Task_0_4(void)
{
  if (task_timer0_4) {
    cli();
        task_timer0_4 = 0;
        sei();
    if (tracking == TRACKING_GPS) Tracking_GPS();
        if (gps_display == GPS_RX_COUNT) Displ_RX_Time(); // aktualisieren der Empfängerzeiten
  }
}

void Task_0_5(void)                     // Nur für Tasten-Beschleunigung/-Wiederholrate! Hintergrund: Rücksetzung.
{                                                       // Hintergrund: Rücksetzung. Beginnt nach jeden Tastendruck neu zu zählen.
  lcd_BackgrLight_On();         // muss bei beliebiger Taste sofort eingeschaltet werden
  if (task_timer0_5) {
    cli();
        task_timer0_5 = 0;
        sei();
        lcd_BackgrLight();
  }
}

void Tasks_unvisible(void)
{
  Task_0_3();
  Task_0_4();
  Task_0_5();
  if (tracking == TRACKING_RSSI) Tracking_RSSI();
}