/*
 * OLED-Testprogramm für Display
 * WEG005016 von Winstar
 * http://www.eHaJo.de
 * (C) Hannes Jochriem, 2013
 * 
 * Pin-Belegung Display:
 * 1:	GND
 * 2:	VCC
 * 3:	N.C.
 * 4:	RS
 * 5:	R/W
 * 6:	ENABLE
 * 7:	Data0
 * 8:	Data1
 * 9:	Data2
 * 10:	Data3
 * 11:	Data4
 * 12:	Data5
 * 13:	Data6
 * 14:	Data7
 * 15:	N.C.
 * 16:	N.C.
 * 
 * µC-Belegung:
 * Data0:	PD0
 * Data1:	PD1
 * Data2:	PD2
 * Data3:	PD3
 * Data4:	PD4
 * Data5:	PD5
 * Data6:	PD6
 * Data7:	PD7
 * RS:		PC3		H: Daten, L: Befehl
 * R/W:		PC4		H: Lesen(MPU->Modul), L: Schreiben(MPU->Modul)
 * E:		PC5		Aktivieren H, H->L
 * 
 */
 
#define F_CPU 8000000UL     /* Interne 8MHz */
 
#include <avr/io.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <stdlib.h>
 
// Prototypen
void long_delay(uint16_t);
void sende_daten(uint8_t);
void sende_befehl(uint8_t);
void toggle_en(void);
void led_an(void);
void led_aus(void);
void schreibe_text(uint8_t, const char *);
 
// Globals
uint8_t _data_pins[4];
 
#define RS	(1<<PC3)
#define RW	(1<<PC4)
#define ENABLE	(1<<PC5)
#define LED	(1<<PC2)
#define DATA0	(1<<PD0)
#define DATA1	(1<<PD1)
#define DATA2	(1<<PD2)
#define DATA3	(1<<PD3)
#define DATA4	(1<<PD4)
#define DATA5	(1<<PD5)
#define DATA6	(1<<PD6)
#define DATA7	(1<<PD7)
 
int main(void)
{
	uint8_t n, z1 = 0, z2 = 0;
	DDRD = 0xff;			// Datenport als Ausgang
	DDRC |= (LED|RS|RW|ENABLE);	// Steuerpins als Ausgang
	PORTD = 0;			// Datenport auf 0
	PORTC &= ~(RS|ENABLE);	// Steuerpins auf 1
	PORTC |= RW;
	led_an();			// "debug"-LED einschalten
	long_delay(500);		// Display benoetigt 500ms beim Power-up
	led_aus();			// "debug"-LED ausschalten
 
	uint8_t array1[60] =
	{
		0b00000000,
		0b00000000,
		0b11000000,
		0b11100000,
		0b10110000,
		0b10110000,
		0b10110000,
		0b10110000,
		0b10110000,
		0b11100000,
		0b11000000,
		0b00000000,
		0b00001100,
		0b11111100,
		0b11111100,
		0b11001100,
		0b11000000,
		0b11001100,
		0b11111100,
		0b11111100,
		0b00001100,
		0b00000000,
		0b00000000,
		0b00100000,
		0b10110000,
		0b10110000,
		0b10110000,
		0b10110000,
		0b11110000,
		0b11100000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00001100,
		0b00001100,
		0b00001100,
		0b11111100,
		0b11111100,
		0b00001100,
		0b00001100,
		0b11000000,
		0b11100000,
		0b01110000,
		0b00110000,
		0b00110000,
		0b00110000,
		0b01110000,
		0b11100000,
		0b11000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000
	};
 
	uint8_t array2[60] = 
	{
		0b00000000,
		0b00000000,
		0b00000111,
		0b00001111,
		0b00011101,
		0b00011001,
		0b00011001,
		0b00011001,
		0b00011001,
		0b00011101,
		0b00001101,
		0b00000000,
		0b00011000,
		0b00011111,
		0b00011111,
		0b00011000,
		0b00000000,
		0b00011000,
		0b00011111,
		0b00011111,
		0b00011000,
		0b00000000,
		0b00001110,
		0b00011111,
		0b00011011,
		0b00011001,
		0b00011001,
		0b00001101,
		0b00011111,
		0b00011111,
		0b00011000,
		0b00000000,
		0b00001111,
		0b00001111,
		0b00011000,
		0b00011000,
		0b00011000,
		0b00011100,
		0b00001111,
		0b00000111,
		0b00000000,
		0b00000000,
		0b00000111,
		0b00001111,
		0b00011100,
		0b00011000,
		0b00011000,
		0b00011000,
		0b00011100,
		0b00001111,
		0b00000111,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000
	};
 
	sende_befehl(0b00111001);	// Function set: 8bit, 2 Zeilen, 5x8 Punkte, Westeurop. Charset
	_delay_us(5000);
	sende_befehl(0b00001100);	// Display on. Display an, Cursor aus, Blinken aus.
	_delay_us(5000);
	sende_befehl(0b00000001);	// Display clear
	_delay_us(5000);
	sende_befehl(0b00000010);	// Display home
	_delay_us(5000);
	sende_befehl(0b00000110);	// Entry mode: Dekrement.
	_delay_us(5000);
	sende_befehl(0b00011111);
	_delay_us(5000);
 
	sende_befehl(0x80);
	while(1)
	{
		sende_befehl(0x40);
		sende_befehl(0x80);
		for(n=0;n<60;n++)
		{
			sende_daten(array1[z1]);
			z1++;
			z1 %= 60;
		}
		sende_befehl(0x41);
		sende_befehl(0x80);
		for(n=0;n<60;n++)
		{
			sende_daten(array2[z2]);
			z2++;
			z2 %= 60;
		}
 
		long_delay(200);
		z1++;
		z2++;
	}
 
	return 0;
}
 
void sende_daten(uint8_t zeichen)
{
	PORTC |= (RS);	// RS ist 1 bei Daten
	DDRD = 0xff;
	PORTD = (zeichen);
	toggle_en();
}
 
void sende_befehl(uint8_t zeichen)
{
	PORTC &= ~(RS);	// RS ist 0 bei Befehlen
	DDRD = 0xff;
	PORTD = zeichen;
	toggle_en();
}
 
void toggle_en()
{	// ENABLE + RW werden getoggelt, es gibt keien Busy-Bit-Abfrage.
	PORTC |= (ENABLE);
	PORTC &= ~(RW);
	_delay_us(5);
	PORTC &= ~(ENABLE);
	PORTC |= RW;
	_delay_us(5);
}
 
void schreibe_text(uint8_t zeile, const char *text)
{
	char zeichen;
 
	if(zeile == 0)
		sende_befehl((0x80)+0);	// Setze Adresse an die erste Position von Zeile 1
	else
		sende_befehl((0x80)+64);	// Setze Adresse an die erste Position von Zeile 2
	while ((zeichen = *text++)) 
	{	// Solange Zeichen vorhanden sind zum Display schicken
		sende_daten(zeichen);
	}
}
 
void led_an()
{
	PORTC |= LED;
}
 
void led_aus()
{	
	PORTC &= ~(LED);
}
 
void long_delay(uint16_t ms) 
{
        for(; ms>0; ms--) 
                _delay_ms(1);
}