
#include "msp430f5529.h"            // Einbinden der Definitionen

#define  T_OnOff   0x02     // Taster an P1.1
#define  T_SET     0x02     // Taster an P2.1
#define  LED_ON    0x80     // LED (grün) an P4.7
#define  LED_X     0x01     // LED (rot) an P1.0
#define  LED_X_Br  0x10     // LED_X Brücke an P7.4 (wegen TB0)

#define  N_Blinken 3 * 2    // 3x ON 3x OFF ....
#define  N_2Hz     5        // 5x wait_0s1 = 0,5s ==> 2Hz

// __________ Prototypen der verwenndeten Funktionen _________________
 void TimerB0 (void);
 void TimerA0 (void);
 void TimerA1 (void);
 void Ports (void);
 
 void Entprell(void);      // Entprellen der Taster
 
// Funktionen zum Bedienen des MSP
 void Ports (void);
 void System_Start(void);
 void System_Stop(void);
 void System_Err(void);

// __________ Prototypen die in anderen Files liegen _________________
 extern void INIT_UART1(void);
 extern void TX_String(unsigned char *cx);
 extern void TX_BYTE(unsigned char xc);

 
// ___________  Globale Variablen ______________________________________
 unsigned int ZustandProg = 0;  // Zustans-Merker des Programms
                               // 0 : deaktiv
                               // 1 : im Hochlauf
                               // 2 : aktiv
                               // 3 : im Runterlauf

 unsigned int Counter = 0;      // Zähler mit Startwert = 0 (0...65535)
 unsigned int tx = 0;           // Aktions-Merker für Timer
 unsigned int MAX = 38;         // oberes Ende beider Arrays
 unsigned int MIN = 0;          // unteres Ende beider Arrays
 unsigned int Wobbel_Dir = 1;   // Schrittrichtung
                                // 0 : Rückwärts
                                // 1 : Vorwärts
 
 unsigned int i = 18;
 int Freq[39];
 int PBreite [39];

 
 // __________ HAUPT-PROGRAMM __________________________
int main( void )
{
   WDTCTL = WDTPW + WDTHOLD;   // WatchDogTimer abschalten
   Ports();
   INIT_UART1();
   
   ZustandProg = 0; 
   tx = 0;
   
   TX_String("    >>>>>> System neu aktiviert <<<<<<<<\n\n");
   TX_String("\n   Start mit T_OnOff\n\n");
     //Array für mögliche Frequenz zwischen 100 Hz bis 2000 Hz

 Freq [0] = 10480;        // 100 Hz bei SMCLK
 Freq [1] = 6987;         // 150 HZ ebi SMCLK
 Freq [2] = 5240;
 Freq [3] = 4192;
 Freq [4] = 3493;         // 300 Hz
 Freq [5] = 2994;
 Freq [6] = 2620;
 Freq [7] = 2329;         // 450 Hz
 Freq [8] = 2096;
 Freq [9] = 1905;
 Freq [10] = 1747;       // 600
 Freq [11] = 1612;
 Freq [12] = 1497;
 Freq [13] = 1397;       // 750
 Freq [14] = 1310;
 Freq [15] = 1233;       // 850
 Freq [16] = 1164;
 Freq [17] = 1103;
 Freq [18] = 1048;
 Freq [19] = 998;
 Freq [20] = 953;
 Freq [21] = 911;        // 1150
 Freq [22] = 873;
 Freq [23] = 838;
 Freq [24] = 806;        // 1300
 Freq [25] = 776;
 Freq [26] = 749;
 Freq [27] = 723;
 Freq [28] = 699;
 Freq [29] = 676;        // 1550
 Freq [30] = 655;
 Freq [31] = 635;
 Freq [32] = 616;
 Freq [33] = 599;        // 1750
 Freq [34] = 582;
 Freq [35] = 566;
 Freq [36] = 552;
 Freq [37] = 537;
 Freq [38] = 524;        // 2000
   
    PBreite [0] =  Freq [0] >> 1; // Rechtsshift, verschiebt den Inhalt einer 
                               // Variablen bitweise nach rechts. Division durch
                               // 2^n, in diesem Fall um 2^1. Außerdem automatisches
                               // Abschneiden der Nachkommastellen. Deswegen kein Float
 PBreite [1] =  Freq [1] >> 1; 
 PBreite [2] =  Freq [2] >> 1;
 PBreite [3] =  Freq [3] >> 1;
 PBreite [4] =  Freq [4] >> 1;
 PBreite [5] =  Freq [5] >> 1;
 PBreite [6] =  Freq [6] >> 1;
 PBreite [7] =  Freq [7] >> 1;
 PBreite [8] =  Freq [8] >> 1;
 PBreite [9] =  Freq [9] >> 1;
 PBreite [10] =  Freq [10] >> 1;
 PBreite [11] =  Freq [11] >> 1;
 PBreite [12] =  Freq [12] >> 1;
 PBreite [13] =  Freq [13] >> 1;
 PBreite [14] =  Freq [14] >> 1;
 PBreite [15] =  Freq [15] >> 1;
 PBreite [16] =  Freq [16] >> 1;
 PBreite [17] =  Freq [17] >> 1;
 PBreite [18] =  Freq [18] >> 1;
 PBreite [19] =  Freq [19] >> 1;
 PBreite [20] =  Freq [20] >> 1;
 PBreite [21] =  Freq [21] >> 1;
 PBreite [22] =  Freq [22] >> 1;
 PBreite [23] =  Freq [23] >> 1;
 PBreite [24] =  Freq [24] >> 1;
 PBreite [25] =  Freq [25] >> 1;
 PBreite [26] =  Freq [26] >> 1;
 PBreite [27] =  Freq [27] >> 1;
 PBreite [28] =  Freq [28] >> 1;
 PBreite [29] =  Freq [29] >> 1;
 PBreite [30] =  Freq [30] >> 1;
 PBreite [31] =  Freq [31] >> 1;
 PBreite [32] =  Freq [32] >> 1;
 PBreite [33] =  Freq [33] >> 1;
 PBreite [34] =  Freq [34] >> 1;
 PBreite [35] =  Freq [35] >> 1;
 PBreite [36] =  Freq [36] >> 1;
 PBreite [37] =  Freq [37] >> 1;
 PBreite [38] =  Freq [38] >> 1;
   
   _BIS_SR(GIE);  // enable Interrupts
   
   while(1)
   {
      _NOP();  // tue nichts
      if(tx == 1)   // wird durch dem TimerA1 Interrupt gesetzt
      {  
         switch(ZustandProg)
         {
            case 1:  // wenn von AUS --> EIN
                   System_Start();
                   tx = 0;
                   break;  
            case 2:  // in Betrieb  ==> EIN
                   _NOP();
                   _NOP();
                   tx = 0;
                   break;
           case 3:  // wenn von EIN --> AUS
                   System_Stop();
                   tx = 0;
                   break;     
           default:
                   // dieser Zustand dürfte normalerweise nie auftreten, wenn
                   // doch, dann liegt wohl ein Fehler vor. In diesem Fall:
                   System_Err();
                   tx = 0;
                   break;
         }
      }
      _NOP();
      _NOP();
   } 
}


// __________ Funktionen __________________________


// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Funktion: PORTS()
// +     Stand .....: 17.02.2020 / JP
// +
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// Port 1
void Ports (void)
//---------
{
  P1SEL &= ~(LED_X);            // Beide sind BIN-IO       
  P1DIR |= LED_X;               // LED    = BIN-OUT
  P1OUT &= ~(LED_X);            // LED_X = AUS (weil H-aktiv)
  //-------
  P1SEL &= ~(T_OnOff);          // Beide sind BIN-IO
  P1DIR &= ~(T_OnOff);          // Taster = BIN-IN

  P1IES &= ~(T_OnOff);          // Int. bei pos. Flanke (L --> H)
  P1IE  |= T_OnOff;             // Int. für Taster freigeben
  P1IFG &= ~(T_OnOff);          // Altes Ereignis vor dieser Init löschen

  P1REN |= T_OnOff;             // Intern.Widerstand = aktiv
  P1OUT |= T_OnOff;             // Als PullUp eingestellt
  
    // INIT_Port_4
  P4SEL  &= ~(LED_ON);          // Funktion ist BIN-IO
  P4DIR  |= LED_ON;             // LED = BIN-OUT
  P4OUT  &= ~(LED_ON);          // Bei System.Start LED = AUS 
}



// +----------------------------------------------------------------------
// |  SubRoutine zum Entprellen eines Tastes 
// |     17.02.2020 / JP
// +----------------------------------------------------------------------
void Entprell(void)
{
  unsigned int k = 0x0FFF;
  while(k > 0) k--;
}
    
   

// +----------------------------------------------------------------------
// |  SubRoutine beim System aktivieren von Zustand AUS --> EIN
// |     17.02.2020 / JP
// +----------------------------------------------------------------------
void System_Start(void)
{
   if(P4OUT & LED_ON)   // wenn LED_ON = EIN
   {
     P4OUT &= ~(LED_ON);
     TX_BYTE('o');
   }
   else
   {
     P4OUT |= LED_ON;
   }
   Counter++;   // Erhöhe Blink-Zähler um 1
   
   if(Counter  >= N_Blinken)
   {
     
     ZustandProg = 2;     // Zustand: EIN
     
     TA1CTL = 0x00;       // Timer für Start / Stop = AUS
     tx = 1;              // weil über den Timer nicht mehr gesetzt wird
     
    //P2IFG &= ~(T_SET);
    //P2IE |= T_SET;       // Freigebe Taster für Interrupt
     
     P7SEL |= LED_X_Br;   // LED_X_Br = Spez. Out 
     P7DIR |= LED_X_Br;   // LED_X_Br auf Timer TB0

     i = 18;
     Wobbel_Dir =1;
     TimerB0();          // START Timer
     
     P4OUT |= LED_ON;     // LED_ON sicher auf EIN setzen
     TX_String("\n\nSystem aktiviert\n\n");
     
   }  
}

// +----------------------------------------------------------------------
// |  SubRoutine beim System deaktivieren von Zustand EIN --> AUS
// |     17.02.2020 / JP
// +----------------------------------------------------------------------
void System_Stop(void)
{
    P7SEL |= (LED_X_Br);            // LED_X_Br = Spez. Out hier korrektur von löschen auf setzen
    P7DIR |= LED_X_Br;            // LED_X_Br auf Timer TB0  
  
   if(P4OUT & LED_ON)   // wenn LED_ON = EIN
   {
     // LED's EIN, dann --> AUS
     P4OUT &= ~(LED_ON);
     P7OUT &= ~(LED_X_Br);
     TX_BYTE('o');
   }
   else
   {
     // LED's AUS, dann --> EIN
     P4OUT |= LED_ON;
     P7OUT |= LED_X_Br;
   }
   
   Counter++;   // ERhöhe Blink-Zähler um 1
   if( Counter  >= N_Blinken)
   {
      ZustandProg = 0;
      TA1CTL = 0x00;       // // Timer für Start / Stop = AUS
      TX_String("\n\n System = AUS\n");
      TX_String("\nStart mit T_OnOff\n\n");
        
      TB0CTL = 0x00;            // Timer = AUS
      TA0CTL = 0x00;
     // P2IFG &= ~(T_SET);
     // P2IE &= ~(T_SET);    // Freigebe Interrupt sperren Taster T_SET 
      P4OUT &= ~(LED_ON);  // LED_ON sicher auf AUS setzen
      P1OUT &= ~(LED_X);   // LED_X sicher auf AUS setzen
      P7OUT &= ~(LED_X_Br);   // LED_X sicher auf AUS setzen
   }
}
                     
// +----------------------------------------------------------------------
// |  SubRoutine wenn ein falscher Zustand aktiv sein sollte, dann
// |          System auf "sofort AUS"
// |     17.02.2020/ JP
// +----------------------------------------------------------------------                     
void System_Err(void)
{
   // dieser Zustand dürfte normalerweise nie auftreten, wenn
   // doch, dann liegt wohl ein Fehler vor. In diesem Fall:
   TA1CTL = 0x00;     // Timer = AUS
   TB0CTL = 0x00;
   tx = 0;
   ZustandProg = 0;             
   P1IFG &= ~(T_OnOff);
   P4OUT &= ~(LED_ON);  // LED_ON sicher auf AUS setzen
   P1OUT &= ~(LED_X);  // LED_X sicher auf AUS setzen 
   P7OUT &= ~(LED_X_Br);  // LED_X sicher auf AUS setzen              
   Counter = 0;    
}



// +----------------------------------------------------------------------
// |  SubRoutine zum Initialisiern und starten des Timers -> Wechselzeit
// |     15.02.2020/ JP
// +----------------------------------------------------------------------
void TimerA0 (void)
{
 TA0CTL = TACLR;
 TA0CTL = TASSEL_2 + ID_0 + MC_1;
 TA0CCR0 = 524;      // entspricht einer Frequenz von 2000 Hz; ausreichend, da
                     // der Wobbelgernerator nicht schneller wird
 TA0CCTL0 = CCIE;
}



// +----------------------------------------------------------------------
// |  SubRoutine zum Initialisiern und starten des Timers -> Wechselzeit
// |     15.02.2020/ JP
// +----------------------------------------------------------------------
void TimerA1 (void)
{
  TA1CTL = TACLR;   // Timer-Counter RESET auf Null
  TA1CCR0 = 16384;  // für 0,5s bei ACLKK, 1:1 und UP-Mode
  TA1CCTL0 = CCIE;  // Interrupt wenn Timer-Counter == TA1CCR0
  TA1CTL = TASSEL_1 + ID_0 + MC_1;
}



// +----------------------------------------------------------------------
// |  SubRoutine zum Initialisiern und starten des Timers -> Wobbelgenerator
// |     15.02.2020 / JP
// +----------------------------------------------------------------------
void TimerB0 (void)
{
  TB0CTL = TBCLR;
  TB0CTL = TBSSEL_2 + ID_0 + MC_1;
  TB0CCR0 = 1048;  // entspricht 1000 Hz, Freq [18]
  TB0CCR2 = 2096;  // entspricht 2*10^-3 s, also CCR0/2 (Pulsbreite halb so groß wie Freq)
  TB0CCTL2 = OUTMOD_7;
  TB0CCTL0 = CLLD_1;          // Änderung der Frequenz wird erst übernommen, wenn 
                            // CCR0 erreicht ist
  TB0CCTL2 = CLLD_1;
}
  


//__________ Interrupt-Funktionen __________________________
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Funktion: TimerA0_0_ISR()
// +     
// +
// +     Wenn dT erreicht wurde
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TA0_0_ISR()
{
  if ( Wobbel_Dir == 1 && i !=  MAX )
  {
    i++;
  }
  else if ( Wobbel_Dir == 1 && i == MAX )
  {
    i--;
    Wobbel_Dir = 0;
  }
  if ( Wobbel_Dir == 0 && i != MIN )
  {
    i--;
  }
  else if ( Wobbel_Dir == 0 && i == MIN)
  {
    i++;
    Wobbel_Dir = 1;  
  }
 TB0CCR0 = Freq [i];
 TB0CCR2 = PBreite [i]; 
}


//__________ Interrupt-Funktionen __________________________
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Funktion: TimerB0 -> lässt rote LED mit Freq [i] leuchten
// +     
// +
// +     Wenn dT erreicht wurde
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#pragma vector = TIMER0_B0_VECTOR
__interrupt void TimerB0_0_ISR ()
{
 P1OUT ^= (LED_X);
}


//__________ Interrupt-Funktionen __________________________
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Funktion: TimerB0 -> lässt rote LED mit PBreite [i] leuchten
// +     
// +
// +     Wenn dT erreicht wurde
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#pragma vector = TIMER0_B1_VECTOR
 __interrupt void TIMERB0_1_ISR ()
{
  switch (TB0IV)
  {
  case TB0IV_TBCCR2:       // TB0CCR2, da LED nur so lange wie PBreite [i] andauert leuchten soll
    {
      P1OUT ^= (LED_X);
      break;
    } 
  }
}
    
    
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Funktion: TimerA1_0_ISR()
// +     Stand .....: 17.02.2020/ JP
// +
// +     Wenn dT erreicht wurde
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#pragma vector=TIMER1_A0_VECTOR
__interrupt void TA1_0_ISR()
{
  tx = 1;
}



// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Funktion: P1_ISR()
// +     Stand .....: 14.04.2019  / JP
// +
// +     Abfrage von Taster T_OnOff
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#pragma vector=PORT1_VECTOR
__interrupt void P1_ISR()
{
  Entprell();
  
  if(P1IFG & T_OnOff)   // Wenn Int. von T_OnOff, dann 
  {
    // hier weiter
    if((ZustandProg == 1)|| (ZustandProg ==2)) // TEST ob Programm bereists aktiv
    {
      // wenn ja, dann EIN --> AUS
      P7OUT |= LED_X_Br;
      P1OUT |= LED_X;
      P4OUT |= LED_ON;
      
      TB0CTL = 0x00;
      TX_String("\nSystem wird herunter gefahren\n");
      ZustandProg = 3;
      Counter = 0;      
      tx = 0;  // das statische tx auf aus, übernimmt jetzt der Timer
    }
    else
    {
      // wenn nein, dann AUS --> EIN  (war im Zustand 0 oder 3)
      TX_String("System wird hoch gefahren\n");
      ZustandProg = 1;
      Counter = 0;
    }
    TimerA1();             // Initialisiuerung und Start des Timers
    P1IFG &= ~(T_OnOff);    // Flanken Ereignis löschen
  }
}
