#include <msp430x14x.h>

void wait(unsigned int i); // prototypen
void LCDOutc(char str);
void LCDOuts(char* str);
void LCDInit(void);
void LCDClear(void);
void LCDClock(void);
int main(void);

int chars=0;              // var. zur speicherung der anzahl zeichen pro zeile
int row=0;                // var. zur speicherung der aktuellen zeile
int i=0;                  // counter fuer alphabet
char* alphabet[]={"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};

int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;  // watchdog aus
  P2DIR=0xFF;             // port 1 = output (3 LEDs)
  P1DIR=0x00;             // port 6 = input (4 taster)
  P5DIR=0xFF;             // port 4 = output (8 datenleitungen zum LCD)
  P6DIR=0xFF;             // port 5 = output (RS, R/W und E vom LCD an 44, 45 und 46 (entspricht P 5.0, 5.1, 5.2))
  
  P2SEL=0x00;
  P5SEL=0x00;
  P6SEL=0x00;
  P1SEL=0x00;             // alle ports als GPIO nutzen, und nicht als A/D-Wandler oder so ...
  
  P1IE=0x00;              // interrupt ausmachen
  
  P2OUT=0x00;             // initial alle LEDs aus
  P6OUT=0x04;             // initial nur E (clock) auf high, RS und R/W auf low
  P5OUT=0x00;             // ports mit null initialisieren
  
  wait(30000);            // init-zeit des display ist ca. 15 ms
  LCDInit();              // LCD initialisieren ...
  LCDClear();             // ... und dann noch loeschen und cursor an den anfang zurueck

  for(;;) 
  {                       // infinite loop
    if ((P1IN & 0x08)==0)
    {
      LCDClear();         // display loeschen
    }
    if ((P1IN & 0x04) == 0)
    {
      P2OUT=0x01;         // rote LED an
      LCDOuts(alphabet[i++]); // alle buchstaben des alphabetes durchtoggeln
      P5OUT=0x10;         // cursor ein feld nach links bewegen (zurueck auf den buchstaben)
      P6OUT=0x04;         // RS und R/W low, E high
      LCDClock();         // befehl ausfuehren
      chars++;            // chars wieder kleiner machen, weil wir ja zurueck gehen mit dem cursor
      wait(50000);
    }
    if ((P1IN & 0x02) == 0)
    {
      P2OUT=0x02;         // gelbe LED an
      P5OUT=0x14;         // cursor ein feld nach rechts bewegen ("enter")
      i=0;                // alphabetcounter wieder resetten
      P6OUT=0x04;         // RS und R/W low, E high
      LCDClock();         // befehl ausfuehren
      wait(50000);
    }
    if ((P1IN & 0x01) == 0)
    {
      P2OUT=0x04;         // gruene LED an
      P5OUT=0xC0;         // cursor ein feld nach links bewegen (zurueck auf den buchstaben)
      P6OUT=0x04;         // RS und R/W low, E high
      LCDClock();         // befehl ausfuehren
      chars--;            // chars wieder kleiner machen, weil wir ja zurueck gehen mit dem cursor
      wait(50000);
    }
    if ((P1IN & 0x08) && (P1IN & 0x04) && (P1IN & 0x02)) {P2OUT=0x00;} // alle LEDs aus, wenn kein taster gedrueckt
  }
}

void wait(unsigned int i) // delay function
{
  unsigned int j;
  for(j=0;j<i;j++);
}

void LCDClock(void)
{
  wait(15);
  P6OUT|=0x04;            // clock-bit erst mal sicherheitshalber auf high
  wait(15);
  P6OUT&=~0x04;           // und jetzt auf low
  wait(15);
}

void LCDClear(void)
{
  row=0;                  // zeilen- und zeichencounter resetten
  chars=0;
  P5OUT=0x01;             // clear display
  P6OUT=0x04;             // RS und R/W low, E high
  LCDClock();             // befehl ausfuehren
  wait(500);              // clear display braucht was laenger
}

void LCDOutc(char str)
{
  P5OUT=str;              // str einfach an den port schicken
  P6OUT=0x05;             // RS und E high, R/W low
  LCDClock();             // befehl ausfuehren
  chars++;                // zaehlvar. eins erhoehen
  if (chars==16)          // zeile voll?
  {
    row^=1;               // toggle row
    chars=0;              // reset chars
    if (row==1)
    {
      P5OUT=0x20;         // in die zweite zeile springen
      P6OUT=0x04;         // RS und R/W low, E high
      LCDClock();         // befehl ausfuehren
    }
    else
    {
      LCDClear();         // wieder zurueck in die erste zeile springen
    }
  }
}

void LCDOuts(char* str)
{
  while (*str != 0) {LCDOutc(*str++);}
}

void LCDInit(void)
{
  P5OUT=0x38;             // 8 bit operation, 2-zeilen-display, 5*8 dot font
  P6OUT=0x04;             // RS und R/W low, E high
  LCDClock();             // befehl ausfuehren
  P5OUT=0x0E;             // display anschalten, cursor an, cursor blinkt nicht
  P6OUT=0x04;             // RS und R/W low, E high
  LCDClock();             // befehl ausfuehren
  P5OUT=0x06;             // cursorrichtung: nach rechts; kein display-shift
  P6OUT=0x04;             // RS und R/W low, E high
  LCDClock();             // befehl ausfuehren
}
