Hatte vor Jahren etwas damit zu tun.
Hier der relevante Softwareteil.
Code
Device = Xmega32A4U, VCC = 3.3;
{ $BOOTRST $08000}         {Reset Jump to $08000} 
define_fuses
  Override_Fuses;
  NoteBook   = D; 
  ProgMode   = PDI; 
  COMport    = USB; 
  Supply     = 3.3, 100; 
  LockBits0  = []; 
  FuseBits0  = []; 
  FuseBits1  = []; 
  FuseBits2  = []; 
  FuseBits5  = [BodLevel0, BodLevel2];
  ProgFlash  = true;  // or false – program Flash
  ProgEEprom = false; // or false – program EEprom
  
Import SysTick, WatchDog, QDEC_C0, QDEC_C1, QDEC_D0, SerPortD0, SerPortD1, SPIdriver1, LCDPort, BeepPort, SwitchPort_G, ADC_A;     // TickTimer,
From System import Processes, longword, longint, OEMcharSet;
From SysTick Import SystemTime16;
define
  // The XMegas don't provide any Oscillator fuses. 
  // So the application must setup the desired values 
  // possible OSC types: extXTAL, extClock, ext32kHz, int32Khz, int2MHz, int32MHz 
  
  //>> CPU=32MHz, PeripherX4=32MHz, PeripherX2=32MHz 
  OSCtype        = extXTAL = 7372800, PLLmul = 4, prescB = 1, prescC = 1;
  SysTick        = 10;              {msec}
  WatchDog       = msec125;        {presc = 3}
  StackSize      = $0100, iData; 
  FrameSize      = $0100, iData;
  Scheduler      = iData;
//  TickTimer      = Timer_D1;
  QDECphase_C0   = PortC, 0, 1;        // Port, Phase0, Phase90 input pin
  QDECevChan_C0  = 0;                  // main event on channel 0..1
  QDECphase_C1   = PortC, 2, 3;        // Port, Phase0, Phase90 input pin
  QDECevChan_C1  = 2;                  // main event on channel 2..3
  QDECphase_D0   = PortC, 4, 5;        // Port, Phase0, Phase90 input pin
  QDECevChan_D0  = 4;                  // main event on channel 4..5
  LCDPort        = LCDuserPort;        // SPI_Soft
  LCDrows        = 2;                  // rows
  LCDcolumns     = 16;                 // columns per line
  LCDtype        = 66712;
//  LCDBargraph1   = LCDport;
  SPIdriver1     = PortB, 1, 0, 5, 3;  // SCK, MOSI, MISO, SS
  SPIorder1      = MSB;
  SPIcPHA1       = 1;
  SPIcPol1       = 1;
  BeepPort       = PortD, 0;
  ADCrefA        = REFextA;            // extern reference, input pins at PortA
  ADCprescA      = 256, 8;             // prescaler 256, resolution 8bits
  ADCchansA      = [1..4];             // 4 channels in use, using SysTick
  SerPortD0      = 19200, Databit8, parEven, Stop1;
  TxBufferD0     = 100, iData;
  RxBufferD0     = 100, iData;
  SerPortD1      = 19200, Databit8, parEven, Stop1; // Debugin
  TxBufferD1     = 100, iData;
  RxBufferD1     = 100, iData;
  SwitchPort_G   = [Wartezeit_Reset, PinE, 1], %00000010;
  PolarityP_G    = %00000010;          // Polarity SwitchPort_G
  Debounce       = 3;                  // debounce alle 3 SysTicks
//--------------------------------------------------------------; 
//--------------------------------------- pIncrementalGeber -----------------------------------------------------;
 {$IDATA}
var
  CASE_IncGeber                   : byte;
  TimerIncGeber1                  : SysTimer;
  TimerIncGeber2                  : SysTimer;
  iIntensCounter                  : integer;
  iDauerCounter                   : integer;
  iWartezeitCounter               : integer;
  bIntensEncoderAktiv             : Byte;
  bDauerEncoderAktiv              : Byte;
  bWartezeitEncoderAktiv          : Byte;
const
  iIntLimitUnten                  : Integer = 10;
  iIntLimitOben                   : Integer = 80;
  iDauerLimitUnten                : Integer = 1;
  iDauerLimitOben                 : Integer = 30; // Sekunden
  iWarteLimitUnten                : Integer = 1;
  iWarteLimitOben                 : Integer = 60; // Minuten
//--------------------------------------------------------------------------------------------;
procedure pIncrementalGeber;
begin
  case CASE_IncGeber of
    0  : QDECenable_C0(true);         // Incrementalzähler freigeben.
         QDECenable_C1(true);
         QDECenable_D0(true);
//         QDECclearpos_C0;             // Incrementalzähler Reset.
//         QDECclearpos_C1;
//         QDECclearpos_D0;
         SetSysTimer(TimerIncGeber1, ms50);
         CASE_IncGeber:= 1;
       |
    1  : If iIntensCounter <> QDECgetPos_C0 div 2 Then
           bIntensEncoderAktiv:= Ja;
         EndIf;
         iIntensCounter   := QDECgetPos_C0 div 2;
         If iIntensCounter < iIntLimitUnten Then       // Incrementalzähler auf unteres Limit prüfen.
           QDECsetPos_C0(iIntLimitUnten*2);
           iIntensCounter:= iIntLimitUnten;
         EndIf;
         If iIntensCounter > iIntLimitOben  Then      // Incrementalzähler auf oberes Limit prüfen.
           QDECsetPos_C0(iIntLimitOben*2);
           iIntensCounter:= iIntLimitOben ;
         EndIf;
         CASE_IncGeber:= 2;
       |
    2  : If iDauerCounter <> QDECgetPos_C1 div 2 Then
           bDauerEncoderAktiv:= Ja;
         EndIf;
         iDauerCounter    := QDECgetPos_C1 div 2;
         If iDauerCounter < iDauerLimitUnten Then      // Incrementalzähler auf negativen Wert prüfen.
           QDECsetPos_C1(iDauerLimitUnten*2);
           iDauerCounter:= iDauerLimitUnten;
         EndIf;
         If iDauerCounter > iDauerLimitOben Then      // Incrementalzähler auf positives Limit prüfen.
           QDECsetPos_C1(iDauerLimitOben*2);
           iDauerCounter:= iDauerLimitOben;
         EndIf;
         CASE_IncGeber:= 3;
       |
    3  : If iWartezeitCounter <> QDECgetPos_D0 div 2 Then
           bWartezeitEncoderAktiv:= Ja;
         EndIf;
         iWartezeitCounter:= QDECgetPos_D0 div 2;
         If iWartezeitCounter < iWarteLimitUnten Then  // Incrementalzähler auf negativen Wert prüfen.
           QDECsetPos_D0(iWarteLimitUnten*2);
           iWartezeitCounter:= iWarteLimitUnten;
         EndIf;
         If iWartezeitCounter > iWarteLimitOben Then  // Incrementalzähler auf positives Limit prüfen.
           QDECsetPos_D0(iWarteLimitOben*2);
           iWartezeitCounter:= iWarteLimitOben;
         EndIf;
         CASE_IncGeber:= 5;
       |
    5  : IF (IsSysTimerZero(TimerIncGeber2)) Then
           IF eiIntensCounter    <>  iIntensCounter    Then eiIntensCounter   := iIntensCounter;    EndIf;
           IF eiDauerCounter     <>  iDauerCounter     Then eiDauerCounter    := iDauerCounter;     EndIf;
           IF eiWartezeitCounter <>  iWartezeitCounter Then eiWartezeitCounter:= iWartezeitCounter; EndIf;
           SetSysTimer(TimerIncGeber2, sec1);
         EndIf;
         CASE_IncGeber:= 10;
       |
    10 : IF (IsSysTimerZero(TimerIncGeber1)) Then
          CASE_IncGeber:= 1;
         EndIf;
       |
  endcase;
end pIncrementalGeber;
//--------------------------------------------------------------------------------------------;