/*******************************************************************************
*
* File Name:   asuro.c
* Project  :   ASURO
*
* Description: This file contains ASURO main features
*
* Ver.     Date         Author           Comments
* -------  ----------   --------------   ------------------------------
* 1.00	   14.08.2003   Jan Grewe		 build
* 2.00     14.10.2003   Jan Grewe        LEFT_VEL, RIGHT_VEL -> MotorSpeed(unsigned char left_speed, unsigned char right_speed);
*										 LeftRwd(),LeftFwd(),RightRwd(),RigthFwd() -> MotorDir(unsigned char left_dir, unsigned char right_dir);
*                                        GREEN_ON,GREEN_OFF,RED_ON,RED_OFF -> StatusLED(unsigned char color);
*                                        LED_RED_ON, LED_RED_OFF -> FrontLED(unsigned char color);
*                                        Blink(unsigned char left, unsigned char right) -> BackLED(unsigned char left, unsigned char right);
*                                        Alles in Funktionen gefasst => leichter verständlich ?!?!
* 2.10     17.10.2003   Jan Grewe        new Timer funktion void Sleep(unsigned char time36kHz)  
* 3.0			 Herbst 2008  Anja Poredda		 Changes for RobiTobi
*
* Copyright (c) 2003 DLR Robotics & Mechatronics
*****************************************************************************/

/***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   any later version.                                                    *
***************************************************************************/

#include "asuro.h"
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>

volatile unsigned char count36kHz;
volatile unsigned long timebase;
volatile int autoencode=FALSE;

uint8_t MotorSpeedLeft;
uint8_t MotorSpeedRight;
uint8_t MotorDirLeft;
uint8_t MotorDirRight;

/* uses timer2 (36kHz for IR communication */
SIGNAL (SIG_OVERFLOW2)
{
	TCNT2 += 0x25;
	count36kHz ++;
	if (!count36kHz) timebase ++;
}

SIGNAL (SIG_INTERRUPT1)
{
	switched=1;
	StopSwitch();
}

/*
	Odometrie
*/
SIGNAL (SIG_ADC)
{
	static unsigned char tmp[2],last[2],toggle=0;
	
	if (autoencode)
	{
		tmp[toggle]= ADCH;
		encode_acdh[toggle] = tmp[toggle];

		//Zaehlen bei Flanke		
		if ( (tmp[toggle] < 100) && last[toggle] > 245 )  //&& (flag[toggle] == TRUE) 
		{
			encoder[toggle] ++;

		}
		last[toggle] = tmp[toggle];
		encoder_last_acdh[toggle] = tmp[toggle];
		
		//umschalten auf anderen Eingang
		if (toggle)
		{ 
			ADMUX = (1 <<ADLAR) | (1 <<REFS0) | ODO_RIGHT; 
		}
		else 
		{
			ADMUX = (1 <<ADLAR) | (1 <<REFS0) | ODO_LEFT; 
		}
		toggle ^= 1; 
	}
}

// neue Zeitfunktion
unsigned long Gettime(void)
{
	return ((timebase*256)+count36kHz)/36;
}

/* Init function Processor will be initalized to work correctly */
void Init (void)
{
	
	//-------- seriell interface programmed in boot routine and already running -------
	//  prepare 36kHz for IR - Communication
	TCCR2 = (1 << WGM20) | (1 << WGM21) | (1 << COM20) | (1 << COM21) | (1 << CS20);
	OCR2  = 0x91; // duty cycle for 36kHz
	TIMSK |= (1 << TOIE2); // 36kHz counter for sleep
	
	// prepare RS232 
	UCSRA = 0x00;
	UCSRB = 0x00;	
	UCSRC = 0x86; // No Parity | 1 Stop Bit | 8 Data Bit
	UBRRL = 25; // 19200bps @ 8.00MHz

	//DDRs
	DDRB&= ~FRONT_LOOP;  //Scheife aus Eingang schalten
	DDRB&= ~POWERSTATION;
	DDRB&= ~CHARGED;
	DDRB|= MOWER | (1<<PB5) | (1<<PB7);  //Mower und Schieberegister auf Ausgang schalten - eigentlich siehe sr_init() aus lcd_sr.c

	DDRC = GREEN_LED | RED_LED | LEFT_DIR | RIGHT_DIR ; //LEDS und Motor auf Ausgang schalten
 
	DDRD|= PWM | IRTX | (1<<PD6); // Motor speed, Infrarot und Schieberegister auf Ausgang schalten
	
	// for PWM (8-Bit PWM) on OC1A & OC1B
	TCCR1A = (1 << WGM10) | (1 << COM1A1) | (1 << COM1B1);
	// tmr1 running on MCU clock/8 
	TCCR1B = (1 << CS11);
	
	//Mower
	TCCR0 = (1 << WGM00) | (1 << COM01) | (1 << CS00);
	OCR0 = 0xFF;
	
	// A/D Conversion
	ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); // clk/64 
	
	//Schieberegister
	PORTB &= ~(1<<PB5);
	PORTB |=  (1<<PB7);
	PORTD |=  (1<<PD6);
	
	lcd_init();
	
	//Motor + Mower
	MotorDir(BREAK,BREAK);
	MotorSpeed(0,0);
	MowerSpeed(0);
	
	//Interrupts zulassen 
	sei();
	
	InitI2C();
}

/*
	Bewegungsrichtung der Raeder setzen
*/
void MotorDir(unsigned char left_dir, unsigned char right_dir)
{
	//int	speedl, speedr;

	MotorDirLeft=left_dir;
	MotorDirRight=right_dir;
	
	//rechts
	if (MotorDirRight==RWD) 
	{
		PORTC&=~(1<<PC7);
		PORTC|=(1<<PC6);
	}
	if(MotorDirRight==FWD) 
	{
		PORTC|=(1<<PC7);
		PORTC&=~(1<<PC6);
	}
	if(MotorDirRight==BREAK) 
		{
		PORTC&=~((1<<PC6)|(1<<PC7));		
	}
	if(MotorDirRight==FREE) 
		{
		PORTC&=~((1<<PC6)|(1<<PC7));		
	}
	
	//links
	if(MotorDirLeft==RWD) {
		PORTC&=~(1<<PC5);		
		PORTC|=(1<<PC4);
	}
	if(MotorDirLeft==FWD) {
		PORTC|=(1<<PC5);
		PORTC&=~(1<<PC4);
	}
	if(MotorDirLeft==BREAK) {
		PORTC&=~((1<<PC4)|(1<<PC5));		
	}
	if(MotorDirLeft==FREE) {
		PORTC&=~((1<<PC4)|(1<<PC5));	
	}

}

/*
	Motorengeschwindigkeit setzen
*/
void MotorSpeed(unsigned char left_speed, unsigned char right_speed)
{
	OCR1A = left_speed;
  OCR1B = right_speed;
}

void MowerSpeed(unsigned char speed)
{
	 OCR0 = speed;
}

/* 
	Status LED (OFF,GREEN,YELLOW,RED)
*/
inline void StatusLED(unsigned char color)
{
	if (color == OFF)    {GREEN_LED_OFF; RED_LED_OFF;}
	if (color == GREEN)  {GREEN_LED_ON; RED_LED_OFF;} 
	if (color == YELLOW) {GREEN_LED_ON; RED_LED_ON;}
	if (color == RED)    {GREEN_LED_OFF; RED_LED_ON;}
}

/*
	Batterieabfrage
*/
int  Batterie(void)
{
	
	int   ec_bak = autoencode;            // Sichert aktuellen Zustand
  int   data;

  /*
     Autoencode-Betrieb vom ADC-Wandler unterbinden.
  */
  autoencode = FALSE;
  
  ADMUX = (1 << REFS0) | (1 << REFS1) | BATTERIE; // interne 2.56V Referenz
                                                  // Ref. mit ext. Kapazitaet
  ADCSRA |= (1 << ADSC);                // Starte AD-Wandlung
  while (!(ADCSRA & (1 << ADIF)))       // Ende der AD-Wandlung abwarten
    ;
  ADCSRA |= (1 << ADIF);                // AD-Interupt-Flag zuruecksetzen
  data = ADCL + (ADCH << 8);            // Ergebnis als 16-Bit-Wert
  /*
     Autoencode-Betrieb vom ADC-Wandler wiederherstellen.
  */
  autoencode = ec_bak;
  return data;

}

/***************************************************************************  
*
*	VPlus_ADC_value=VPlus();
*
*	function to read the Reference Voltage
*
*
*	This function returns the adc-value of the vplus-input ( ADC5 )
*	physical Vplus may be calculated by u=Vbandgap/1024*V_Plus_ADC_value*(R12+R13)/R13
*	Vbandgap=2.56V ( datasheet )
*	R12=12K
*	R13=10K
*	On my ASURO processor board I measured 2.73V on the ARef pin ( strange ) so I calculated
*	2.73V instead of the bandgap voltage mentioned in the datasheet
*
****************************************************************************/
unsigned int VPlus()
{
	ADMUX = (1 << REFS0) | (1 << REFS1) | BATTERIE;	// Bandgap Reference and ADC5
	ADCSRA |= (1 << ADSC);													// Start conversion
	while (!(ADCSRA & (1 << ADIF)));								// wait for conversion complete
	ADCSRA |= (1 << ADIF);													// clear ADCIF
	return(ADCL + (ADCH << 8));
	
}

/* function to read out odometrie phototransistors (left,rigth) */
void OdometrieData(unsigned int *data)
{
	DDRA &=~( (1 << PA0) | (1 << PA1));

	ADMUX = (1 << REFS0) | ODO_LEFT; // AVCC reference with external capacitor
	
	ADCSRA |= (1 << ADSC);			// Start conversion
	while (!(ADCSRA & (1 << ADIF)));	// wait for conversion complete
	ADCSRA |= (1 << ADIF);			// clear ADCIF
	data[0] = ADCL + (ADCH << 8);
	
	//ADMUX = (1 << REFS0) | WHEEL_RIGHT; // AVCC reference with external capacitor
	ADMUX = (1 << REFS0) | ODO_RIGHT; // AVCC reference with external capacitor

	ADCSRA |= (1 << ADSC);			// Start conversion
	while (!(ADCSRA & (1 << ADIF)));	// wait for conversion complete
	ADCSRA |= (1 << ADIF);			// clear ADCIF
	data[1] = ADCL + (ADCH << 8);
}

/* function for serial communication */
void SerWrite(unsigned char *data,unsigned char length)
{
	unsigned char i = 0;
	UCSRB = 0x08; // enable transmitter
	while (length > 0) {
		if (UCSRA & 0x20) { // wait for empty transmit buffer
			UDR = data[i++];
			length --;
		}
	}
	while (!(UCSRA & 0x40)); 
	for (i = 0; i < 0xFE; i++)
		for(length = 0; length < 0xFE; length++); 
}

void SerRead(unsigned char *data, unsigned char length,unsigned int timeout)
{
	unsigned char i = 0;
	unsigned int  time = 0;
	UCSRB = 0x10; // enable receiver
	/* non blocking */
	if (timeout != 0) {
		while (i < length && time++ < timeout) {
			if (UCSRA & 0x80) {
				data[i++] = UDR;
				time = 0;
			}
		}
		if (time > timeout) data[0] = 'T';
	}
	/* blocking */
	else {
		while (i < length) {
			if (UCSRA & 0x80) 
				data[i++] = UDR;
		}
	}	
}


/* uses 36kHz timer => Sleep(x) = x/36kHz [sec] */
void Sleep(unsigned char time36kHz)
{   unsigned char ziel=(time36kHz+count36kHz) & 0x00FF;
	while (count36kHz != ziel);
}


void Encoder_Init(void)
{
	/*
     Alle definierten Interrupts im Asuro sperren.
  */
	cli();

	/*
     AD-Wandler einschalten, Parameter einstellen und Starten. (clk/128)
     Startet den ADC im 'free running'-Mode (ADFR). Das heisst, der Wandler
     nach einer Messung automatisch wieder ne startet.
  */
	ADCSRA = (1<<ADEN)| (1<<ADATE) | (1<<ADIE) | (1<<ADSC) | (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2); // clk/128

	/*
     Linken Odometrie-Sensor auswaehlen. (AVCC ref. with external capacitor)
  */
	ADMUX = (1<<ADLAR) |(1 << REFS0) | ODO_LEFT; // AVCC reference with external capacitor

	/*
     Odometrie im Interruptbetrieb weiter bearbeiten.
  */
	autoencode=TRUE;
	
	/*
     Alle definierten Interrupts im Asuro wieder zulassen.
  */
	sei();

	/*
     Die Odometrie initialisieren.
  */

	Encoder_Set(0,0);
}


void Encoder_Stop(void){autoencode  = FALSE;}
void Encoder_Start(void){autoencode = TRUE;}

void Encoder_Set(int setl,int setr)
{
	encoder[LEFT] = setl;
	encoder[RIGHT]= setr;
}

void PrintInt(int wert)
{  	
	char text[6]="      ";
	itoa(wert,text,10);
	SerWrite(text,5);
}

void bluePutChar(uint8_t zeichen)
{
	UCSRB = 0x08; // enable transmitter
	UCSRA|=0x40; // clear transmitter flag 
	while (!(UCSRA & 0x20)); // wait for empty transmit buffer
	UDR = zeichen;
	while (!(UCSRA & 0x40)); // Wait for transmit complete flac (TXC)
}
void bluePrintText(unsigned char *data)
{
	unsigned char i = 0;
	while(data[i]!=0x00) bluePutChar(data[i++]);
}
void bluePrintInt(int wert)
{  	
	char text[6]="      ";
	itoa(wert,text,10);
	bluePrintText(text);
}
void bluePrintTextInt(unsigned char*data,int wert)
{
	bluePrintText(data);
	bluePrintInt(wert);
	bluePrintText(" ");
}
void blueLineFeed(int wert)
{
	bluePrintText("\n\r");
}

uint8_t blueGetChar()
{
	UCSRB = 0x10; // enable receiver
	while(!(UCSRA & 0x80)); // wait for received uint8_t
	return UDR;
}
uint8_t blueCharWaiting()
{
	UCSRB = 0x10; // enable receiver
	if(UCSRA & 0x80) return TRUE; // true if char waiting
	else return FALSE;
}
// 2400 BAUD with Sleep()
#define ONEBIT 15
#define BIT1p5 22

// Software Uart
#define SET_TXD ( PORTB|=(1<<1) )
#define RESET_TXD ( PORTB&=~(1<<1) )

void irPutChar(uint8_t zeichen)
{
	uint8_t n;
	unsigned int sreg;
	sreg=zeichen;
	
	sreg=sreg<<1;
	sreg|=0xfe00;	// set stopbit
	sreg&=0xfffe;	// reset startbit
	for(n=0;n<11;n++) //10=one stopbit, 11=two stopbit
	{
		if((sreg&0x01)==0) RESET_TXD; // clear bit
		else SET_TXD; // set bit
		sreg=sreg>>1;
		Sleep(ONEBIT);
	}
}
#define RxD_HIGH (PINB&(1<<0))

uint8_t irGetChar()
{	
	//DDRB&=~(1<<0);
	uint8_t n,shiftreg;
	while(RxD_HIGH);
	Sleep(BIT1p5);
	for(n=0;n<8;n++) // receive 8 Bits
	{
		shiftreg=shiftreg>>1;
		if (RxD_HIGH) shiftreg|=0x80; /* Bit setzen */
		Sleep(ONEBIT);
	}
	return shiftreg;
}
uint8_t irCharWaiting()
{
	if(!RxD_HIGH) return TRUE; // true if char waiting
	else return FALSE;
}
void irSerPrint(unsigned char *data)
{
	unsigned char i = 0;
	while(data[i]!=0x00) irPutChar(data[i++]);
}

void Msleep(int dauer)
{
	int z;
	for(z=0;z<dauer;z++) Sleep(36);
}

void lcd_data( unsigned char d )
{
	sr_setBit( LCD_RS );	
	lcd_Byte( d );
}
 
void lcd_nibble( unsigned char d )
{
	sr_unsetBit( LCD_B4 );
	sr_unsetBit( LCD_B5 );
	sr_unsetBit( LCD_B6 );
	sr_unsetBit( LCD_B7 );
	
	if ( d & 1<<4 ) sr_setBit( LCD_B4 );
	if ( d & 1<<5 ) sr_setBit( LCD_B5 );
	if ( d & 1<<6 ) sr_setBit( LCD_B6 );
	if ( d & 1<<7 ) sr_setBit( LCD_B7 );
 
	sr_out();
  lcd_enable();
}
 
void lcd_Byte( unsigned char d )
{
 	lcd_nibble( d );
	lcd_nibble( d<<4 );
  _delay_us( 45 );
}
 
void lcd_command( unsigned char d )
{
	sr_unsetBit( LCD_RS );	
	lcd_Byte( d );
	switch( d )
	{
    case 1:
    case 2:
    case 3: _delay_ms( 2 );
	}
}
 
void lcd_enable(void)
{
	sr_setBit( LCD_EN );
	sr_out();
  _delay_us(20);                  
	sr_unsetBit( LCD_EN );
	sr_out();
}
 
void lcd_init(void)
{ 	sr_unsetall();
	sr_out(); 
 
	// warte, damit sich der Kontroller des LCD initialisieren kann
	_delay_ms( 15 );
 
 	// muss 3mal hintereinander gesendet werden zur Initialisierung
 	lcd_nibble(0x30);
 	_delay_ms(5);
 	lcd_nibble(0x30);
 	_delay_ms(1);
 	lcd_nibble(0x30);
 	_delay_ms(1);

 	// 4 bit mode
	lcd_nibble(0x28);	
	_delay_ms( 1 );			    // wait >100æs

 	// inkrement / kein Scrollen
 	lcd_command( 0x06 );

	// Display ein / Cursor aus / kein Blinken
 	lcd_command( 0x0C ); 

	// Display loeschen
 	lcd_clear();
	lcd_command( CURSOR_HOME );
}
 
void lcd_clear(void)
{
  lcd_command( CLEAR_DISPLAY );
  _delay_ms(5);
}
 
void lcd_home(void)
{
  lcd_command( CURSOR_HOME );
  _delay_ms(5);
}
 
void set_cursor(uint8_t x, uint8_t y)
{
  uint8_t tmp = 0x00;

  switch (y) 
  {
    case 1: tmp=0x80+0x00+x; break;    // 1. Zeile
    case 2: tmp=0x80+0x40+x; break;    // 2. Zeile
    case 3: tmp=0x80+0x10+x; break;    // 3. Zeile
    case 4: tmp=0x80+0x50+x; break;    // 4. Zeile
  }
  lcd_command(tmp);
}
 
void lcd_string(char *data)
{
  while(*data) 	
	{
    lcd_data(*data);
    data++;
  }
}

/***********************************************************************************
* Schieberegister Funktionen
************************************************************************************/

// Array fuer die Daten
unsigned char sregister[ COM74HC595_SIZE ];
 
void sr_setBit( unsigned char BitNumber)
{
	unsigned char Port = BitNumber >> 3;
	unsigned char Bit = BitNumber & 7;
	sregister[ Port ] |= (1 << ( Bit ) );
}
 
void sr_unsetBit( unsigned char BitNumber)
{
	unsigned char Port = BitNumber >> 3;
	unsigned char Bit = BitNumber & 7;
	sregister[ Port ] &= ~(1 << ( Bit ) );
}
 
void sr_setall(void)
{
	int i;
	for ( i = 0; i < COM74HC595_BYTES; i++ )
	{
		sr_setBit( i );
	}
}
 
void sr_unsetall(void)
{
	int i;
	for ( i = 0; i < COM74HC595_BYTES; i++ )
	{
		sr_unsetBit( i );
	}
}
 
void lcd_setPort( unsigned char Port, unsigned char Bits )
{
	sregister[ Port ] = Bits;
}
 
void lcd_unsetPort( unsigned char Port )
{
	sregister[ Port ] = 0x00;
}
 
 
void sr_init()
{
  /* Verwendete Ports auf OUT */
	DDRB |= ( 1 << DDB5);
	DDRB |= ( 1 << DDB7);
	DDRD    |= ( 1 << DDD6);

  /* SER auf definierten Level LOW */
	PORTB &= ~(1<<PB5);
 
  /* SCR und RCK auf definierten Level HIGH */
	PORTB |= (1<<PB7);
	PORTD |= (1<<PD6);
 
}
 
void sr_out()
{
  unsigned char anz = COM74HC595_SIZE;
  unsigned char* serp = sregister + COM74HC595_SIZE;

  do
  {
    unsigned char bits;
    unsigned char data = *--serp;

    /* 8 Bits pro Byte rausschieben */
    for (bits = 8; bits > 0; bits--)
    {
			PORTB &= ~(1<<PB5);
      if (data & 0x80)
      {
				PORTB |= (1<<PB5);
      };

      data <<= 1;
      /* Strobe an SCK schiebt Daten im Gaensemarsch */
      /* um 1 Position weiter durch alle Schieberegister */
	    PORTB &= ~(1<<PB7);
	    PORTB |= (1<<PB7);
    }
  }
  while (--anz > 0);

  /* Strobe an RCK bringt die Daten von den Schieberegistern in die Latches */
  PORTD &= ~(1<<PD6);
  PORTD |= (1<<PD6);
}


/********************************************************************************
/*
/*			I2C
/*
/*
/********************************************************************************/

/****************************************************************************
*  I2C Bus Initialisieren.
*  Schaltet PC2 und PC3 als Ausgang. 
*  Setzt die Pins als High
*****************************************************************************/
void InitI2C (void)
{
  SDA_DDR |= (1 << SDA);  
  SCL_DDR |= (1 << SCL);        
  SDA_HI;             
  SCL_HI;             
}


/****************************************************************************
  Daten ueber I2C schreiben
  param:  byte daten
  return: antwort
*****************************************************************************/
unsigned char WriteI2C (unsigned char byte)
{
  unsigned char i;
  
  //alle Bits durchlaufen 
  for (i=8; i>0; i--)
  {
  	//bit bertragen
    if ( byte & (1<<(i-1)) )
      SDA_HI;
    else
      SDA_LO;       
      
    //pro clock pulse kann immer nur ein b it bertragen werden (SCL auf high und dann wieder auf low setzen)  
    SCL_TOGGLE;         
  }
  
  //Acknowledgement entgegen nehmen; Master bernimmt jetzt die šbertragung; (Acknowledgement wird nach jedem Byte gesendet) -> SDA auf input umschalten
  SDA_HI;             
  SDA_DDR &= ~(1 << SDA);
  HDEL;
  SCL_HI;
  byte = SDA_PIN & (1 << SDA);

	//alles wieder fr Uebertragung durch Slave bereitmachen
  HDEL;
  SCL_LO;
  SDA_DDR |= (1 << SDA);
  HDEL;

	//Rueckgabe, ob Uebertragung erfolgreich war
  return (byte == 0);
}



/****************************************************************************
  Daten aus I2C Bus lesen
	param:   ack NAK oder ACK
	return:  erhaltene Daten
*****************************************************************************/
unsigned char ReadI2C(unsigned char ack)
{
  unsigned char i, byte = 0;
  
  //SDA auf input umschalten
  SDA_HI;
  SDA_DDR &= ~(1 << SDA);
  
  //alle bits eines Bytes entgegennehmen
  for (i=0; i<8; i++)
  {
  	HDEL;
    SCL_HI;
    byte <<= 1;
    byte |= (SDA_PIN & (1 << SDA)) >> SDA;
    HDEL;
    SCL_LO;
  }

	//SDA auf output schalten
  SDA_DDR |= (1 << SDA);

	//acknowledgement senden?
  if (ack)
    SDA_LO;                             // ack
  else
    SDA_HI;                             // nak

  SCL_TOGGLE;
  SDA_HI;

	//empfangenes Byte zuruecksenden
  return byte;
}



/****************************************************************************
  Datenaustausch starten
	param:	device Addresse des I2C Geraetes
	return:	antwort
*****************************************************************************/
unsigned char StartI2C (unsigned char device)
{
	//Uebertragungsstart setzen
  I2C_START;
  //Ziel-Geraete Adresse uebertragen
  return WriteI2C (device);
}



/****************************************************************************
  Datenaustausch Stoppen
*****************************************************************************/
void StopI2C (void)
{
  SDA_LO;
  I2C_STOP;
}

 
/********************************************************************************
/*
/* 	Modul zur Einbindung eines Dallas DS1307 Real Time Clock.
/*  Es wird eine Struktur und eine globale Variable dieser Struktur in diesem Modul erzeugt. 
/*  In dieser Struktur sind das Datum und die Zeit hinterlegt. Alle Ein- und Ausgaben bzgl. der Zeit werden ueber diese Struktur abgewickelt.
/*	Da der DS1307 ueber ein I2C-Bus Interface verfuegt ist zwingend das Modul fuer dieses Protokoll nötig. Es wird als include-Anweisung eingebunden. 
/*
/********************************************************************************/

/*
Ein Byte wird in Uhr schreiben. 
Parameter:	adr  - Adresse (00 - seconds, 01 - minutes, 02 - hours, 03 - day (Wochentag), 04 - date, 05 - month, 06 - year, 07 - control 
 						foo  - zu schreibendes Byte  
*/
void ClockWriteByte (unsigned char adr, unsigned char foo)
{
	//Uebertragung Start
  StartI2C (I2C_ADR_Clock_Write);
  
  //Ansage, welcher Zeitteil gesetzt werden soll
  WriteI2C (adr);
  
  //Uebergabe des Wertes fuer diesen Zeitteil
  WriteI2C (foo);
  
  //Beenden der Uebertragung
  StopI2C ();
}

/*
Ein Byte wird aus Uhr gelesen.
Parameter:	adr  - Adresse (00 - seconds, 01 - minutes, 02 - hours, 03 - day (Wochentag), 04 - date, 05 - month, 06 - year, 07 - control 
*/
unsigned char ClockReadByte (unsigned char adr)
{
  unsigned char   RByte;

  //Uebertragung Start
  StartI2C (I2C_ADR_Clock_Write);
  
  //Ansage, welcher Zeitteil gelesen werden soll
  WriteI2C (adr);
  
  //Ende der Uebertragung
  StopI2C ();
  
  //Start des Lesens
  StartI2C (I2C_ADR_Clock_Read);
  
  //Lesen des Zeitteils
  RByte = ReadI2C (1);
  
  //Ende des Lesens
  StopI2C ();
  
  //Rueckgabe des Wertes
  return RByte;
}

/*
Uhr anhalten
*/
void ClockHalt ()
{
	//Start der Uebertragung
  StartI2C (I2C_ADR_Clock_Write);
  
  //Ansage, dass Sekunden register gesetzt werden soll
  WriteI2C (0x00);
  
  //Setzen des Bit 7 (Clock halt) auf 1
  WriteI2C (0x80);
  
  //Ende der Uebertragung
  StopI2C ();
}

/*
12 oder 24 Stunden Mode setzen. 
Parameter:	Hour12  - 12 (high) / 24 (low) Stunden Mode  
*/
void ClockHourMode (int Hour12)
{
  unsigned char   Hour;

	//Auslesen des Stunden registers
  Hour = ClockReadByte (0x02);
  
  //wenn 12 Stundenmode gesetzt werden soll, Bit 6 auf 1 setzen
  if (Hour12)
     Hour |= 0x40;
  else
  		//Bit 6 auf 0 setzen, alle anderen auf eins
     Hour &= 0xBF;
     
  //Schreiben des Hour modus in das Stunden register
  ClockWriteByte (0x02, Hour);
}

/*
Zeit aus rtc setzen.
*/
void ClockSetTime ()
{
	
  //Uebertragung der Sekunden (Bit 0-3 = Einerpotenz; Bit 4-7 = Zehnerpotenz)
	ClockWriteByte(0x00, ((rtc.sec / 10) << 4) + rtc.sec % 10);

  //Uebertragung der Minuten (Bit 0-3 = Einerpotenz; Bit 4-7 = Zehnerpotenz)
	ClockWriteByte(0x01, ((rtc.min / 10) << 4) + rtc.min % 10);

  //Uebertragung der Stunden (Bit 0-3 = Einerpotenz; Bit 4 = Zehnerpotenz; Bit 5 = AM/PM oder Zehnerpotenz; Bit 6 = Hourmode)
	ClockWriteByte(0x02, ((rtc.hour / 10) << 4) + rtc.hour % 10);

}

/*
Datum aus rtc setzen.
*/
void ClockSetDate ()
{
	
 	//Wochentag setzen
 	ClockWriteByte(0x03, rtc.day & 0x07);
  
  //Tag setzen
  ClockWriteByte(0x04,((rtc.date / 10) << 4) + rtc.date % 10);
  
  //Monat setzen
  ClockWriteByte(0x05,((rtc.month / 10) << 4) + rtc.month % 10);
  
  //Jahr setzen
  ClockWriteByte(0x06,((rtc.year / 10) << 4) + rtc.year % 10);

}

/*
Uhrzeit auslesen und in rtc setzen. 
*/
void ClockGetTime ()
{

  unsigned char   dummy;

  //Sekunden lesen
  dummy = ClockReadByte (0x00);
  rtc.sec = (dummy & 0x0F) + 10 * ((dummy & 0x70) >> 4);
  
  //Minuten lesen
  dummy = ClockReadByte (0x01);
  rtc.min = (dummy & 0x0F) + 10 * ((dummy & 0x70) >> 4);

  //Stunden lesen
  dummy = ClockReadByte (0x02);
  rtc.hour = (dummy & 0x0F) + 10 * ((dummy & 0x30) >> 4);

}


/*
Datum auslesen und in rtc setzen. 
*/
void ClockGetDate ()
{
  unsigned char   dummy;

  //Wochentag lesen
  dummy = ClockReadByte (0x03);
  rtc.day = dummy & 0x07;
  
  //Tag lesen
  dummy = ClockReadByte (0x04);
  rtc.date = (dummy & 0x0F) + 10 * ((dummy & 0x30) >> 4);

  //Monat lesen
  dummy = ClockReadByte (0x05);
  rtc.month = (dummy & 0x0F) + 10 * ((dummy & 0x30) >> 4);

  //Jahr lesen
  dummy = ClockReadByte (0x06);
  rtc.year = (dummy & 0x0F) + 10 * ((dummy & 0xF0) >> 4);

}


