http://homepages.uni-regensburg.de/~erc24492/
Zurück
  (C) Christof Ermer, Regensburg Gästebuch (public. sonst besser Email)   ChristofErmer@gmail.com



30.06.2016


E-Bike 25 KmH Begrenzung. Selbt gebaut weil  es keine gibt. !!
Das Kalbel der Bremse-OFF Schalter wird gebrückt ab 25 Km/H
ATTiny2313







/*
http://de.fahrrad.wikia.com/wiki/Reifenumfang_(Tabelle)

Reifenumfang in mm = (Reifenhöhe *2 + Reifeninnendurchmesser in mm) * pi
eifeninnendurchmesser = Durchmesser der Felge

Reifenhöhe ~ "Dicke" des Reifens ~ Schlauchdicke

Für \pi gilt: \pi = 3{,}14159...


Neue Version mit ATTiny im DIL gehäuse mit 8 MHZ
ATTiny2313_25KmHLimiter

BODEN=4.3V  FUSE 8MHz WDT BrownOut=> L=0xFF H=0xC9
BODEN=2.7V    FUSE 8MHz WDT BrownOut=> L=0xFF H=0xCB
FUSES MIT 8 MHZ Quarz
watchdog, SPI = BODEN=2,7V ON
ALLE Häckchen WEG, !! Gepüft !  Außer WDTON
1 = KEIN Häckchen
CKDIV8 = 1
SUT1 SUT0 = 11
CKSEL 3/2/1/0 = 1111
WDTON = 0
BODLEVEL 2/1/0 = 111
EESAVE= =1
DWEN = 1
*/

//------------------------------------------------------------------------------
// Programmed by Christof Ermer
//------------------------------------------------------------------------------

///SYSINFO
#define DATUM        "28.06.2016"
#define FUNKTION    "25KmHLimiter"
#define AUTOR        "Christof Ermer"
#define BAUDRATE    "9600"
//FUSE 8MHz BrownOut=> L=0xFF H=0xD9
//http://www.engbedded.com/fusecalc
// ORG NewChip Tiyn2313  FUSE  0x64 0xDF
//

/*
ftoa braucht Speicher wie sau

libusb0.dll

ZADIUG FÜR USBASP  stelle auf
http://rayshobby.net/dead-simple-driver-installation-for-usbasp-and-usbtiny-on-windows/
http://www.heesch.net/


http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=373283
!!!!!!!!!!!!!!
Unter Windows NT,2000,XP,Vista? braucht AVRDUDE einen Treiber
GIVEIO.SYS, um auf die Ports zugreifen zu können.
Du kannst den Treiber durch den Aufruf der Batchdatei
WinAVR\bin\install_giveio.bat installieren.


in io.h
#elif defined (__AVR_ATtiny2313__)
#include <avr/iotn2313.h>
*/

#include <avr/io.h>
//#include <ctype.h>
#include <inttypes.h>
#include <avr\io.h>
#include <avr\pgmspace.h> // <--#include <progmem.h>

//#include <stdio.h>
#include <stdlib.h>
#include <avr\wdt.h>
//#include <math.h>
#include <avr\interrupt.h>  // obsolete #include <avr\signal.h>


//ACHTUNG STELLT OBSOLETE Procedure in header wieder her
//#include <compat\deprecated.h>
//#include <avr\twi.h> /* Note [1] */  // NEUE DATEIVERSION_STR BEUNTZEN
//#include <avr\signal.h> //#include <signal.h>

#include <avr\wdt.h>
//Produziert Fehler...
#include <util\delay.h>    //_delay_loop_1 _delay_loop_2 delay_ms

#include "main.h"        //with Hardware assigns
#ifdef UART_USE_ENABLED
    #include "uart.h"
#endif
#include "2313lcd.h"

#ifdef USE_TOGGLE_FLAG
void ToggleTEST_BIT(uint8_t ucCnt);
#endif

#ifdef UART_USE_ENABLED
void UART_TXRX_Check(void);
void ResetRxBuff(void);
#endif

//CONSTANT ARRAYs IN .TEXT = ROM ARREA   .DATA IST SRAM !! .BSS SRAM
//const char MCA_VERSION[] PROGMEM = VERSION;
#ifdef TEXT_SERVICE_USE_ENABLED
void CheckOrder(char* pcStr);
void PrintCR(void);
#endif

// GLOBALE VARIABLEN

#ifdef UART_USE_ENABLED
volatile char* gpcRxPars;
static char gcaRxStr[RX_STRMAX + 1]; //+1 for the 0
#endif


#ifdef UART_USE_ENABLED
static COMMAND_TYPE gsCmd;
#endif

#ifdef TEXT_SERVICE_USE_ENABLED
//static char gcaNumStr[NUMMAX + 1]; //+1 for the 0
//static char gcaStr[STRMAX + 1]; //+1 for the 0
char gcaNumStr[NUMMAX + 1];
#endif


static uint32_t    gu32_Ticks; //  T2 timeCounter, only NN_Counter for Keypressings
static uint32_t    gu32_Pulszeit; //  T2 timeCounter, only NN_Counter for Keypressings

float gfUmfang;
float gfKmH;
float gfKmSum;

// ****************************************************************
ISR( TIMER0_OVF_vect )
// *******************************************************************
{
gu32_Ticks++;
#ifdef UART_USE_ENABLED
//UART_TXRX_Check();    //IMMER VORNAHANDEN !! IN ALLEN LOOPS DIE ZEIT BRAUCHEN
#endif
};


// ****************************************************************
ISR( INT0_vect )
// *******************************************************************
{
//uint32_t u32PulSDiff;
//cli();
//u32PulSDiff = gu32_Ticks - gu32_Pulszeit;
//GIMSK &= ~_BV( INT0 );     // Eingang stop
//sei();
 // = 31250/Sekunde
//Rechn
gfKmH =  (gfUmfang / ( (gu32_Ticks - gu32_Pulszeit) / F_TICK_PER_SEC ))  * 0.00036;
gu32_Pulszeit = gu32_Ticks;
gfKmSum += (uint16_t)gfUmfang;

if(gfKmH > 25) OC_TRANSITOR_ON();
if(gfKmH < 24) OC_TRANSITOR_OFF();
//(gfKmH > 25) ? OC_TRANSITOR_ON() : OC_TRANSITOR_OFF();
//EIFR |= _BV(INTF0); //Flag weg
//GIMSK |= _BV( INT0 );     // Eingang Scharf
};
 
#ifdef USE_TOGGLE_FLAG
// ****************************************************************
void ToggleTEST_BIT(uint8_t ucCnt)
// ****************************************************************
{ // #include <util\delay.h>  muss da sein
uint8_t ucNN;
for(ucNN=0; ucNN < ucCnt; ucNN++)
    {
    SET_TESTBIT();
    _delay_us(1);
    CLR_TESTBIT();
    _delay_us(1);
    };
};
#endif


#define INT_CONVERT_USED
#ifdef INT_CONVERT_USED
// **********************************************
void IntToNumStr(uint32_t iVal)
// **********************************************
{
ultoa(iVal, gcaNumStr, 10 );
};
#endif


// *****************************************************
int main(void)
// *****************************************************
{
cli();
DDRB = OC_TRANSITOR_BIT | SCK_OUT_BIT;
DDRD = TX_BIT;
//Pullup
PORTB = MISO_BITX;  // PULLUPS //FÜR Select ZOLL
//PORTD = TX_BIT; //| HALLSENS_BIT | DISABLE_BIT;  // PULLUPS RX_BIT | TX_BIT

#ifdef  USE_TOGGLE_FLAG
INIT_TESTBIT_REG();
#endif

lcd_init( LCD_DISP_ON );
//lcd_clrscr();   

wdt_enable(WDTO_2S); //Set 1.9Sec WatchDog ENABLE
wdt_reset();   //WATCHDOG!


#ifdef UART_USE_ENABLED
ResetRxBuff();
uart_init( UART_BAUD_SELECT(UART_BAUD_RATE, F_CPU ));// !! Init UART interface
#endif
sei();


#ifdef UART_USE_ENABLED
uart_puts_p( PSTR("25Km/h Limiter\r") );
uart_puts_p( PSTR("9600 BAUD\r") );
#endif


//INT0
#ifdef HALL_FALLINGEDGE_INT0
MCUCR |= _BV( ISC01 );    //FALLING
#elif
MCUCR |= _BV( ISC01 ) | _BV( ISC01 ); // RISING
#endif
GIMSK |= _BV( INT0 );     // Eingang Scharf
//GIFR |= _BV(INTF0);

TIMSK |= _BV(TOIE0);
TCCR0B = _BV(CS00); //8^6/1/256 = 31250/Sekunde

gfUmfang = MISO_IN() ? F_UMFANG_26Z : F_UMFANG_28Z;

// ************ MAIN LOOP FOR EVER *********************
uint16_t u16SchowLCD;

for(;;)  /* loop forever */
    {   
//DDRD = TX_BIT;
sei();
    wdt_reset();   //WATCHDOG!
       
#ifdef USE_TOGGLE_FLAG
ToggleTEST_BIT(10);
#endif
_delay_us(10);
    //FloatToNumStr( gfKmH );
    //IntToNumStr( gfKmH
//    if( gu32_Ticks  % TICK_PER_SEC)
    if( !(u16SchowLCD++)   )
        {
TX_BIT_ON();
        lcd_gotoxy(0,0);
        lcd_puts_p( PSTR("Speed Km/h:"));
//dtostrf(gfKmH,6,3,gcaNumStr);
        IntToNumStr((uint16_t)gfKmH);
        lcd_puts( gcaNumStr);   

        lcd_gotoxy(0,1);
        lcd_puts_p( PSTR("Strecke Km:"));   
        IntToNumStr( gfKmSum / 1000000UL);
        lcd_puts( gcaNumStr);
TX_BIT_OFF();   
        };
   
    }; // main   END END *************
};


// ******************* MAIN END ********************************************



#ifndef MAIN_HEADER  //Prevents multiple includes
#define MAIN_HEADER

/*
Watchdog kann Interrupt
jede menge ADC eingänge
http://www.rn-wissen.de/index.php/Avr-gcc
*/
//TickCounter  MUSS SEIN !!!
//#define UART_USE_ENABLED
//#define COMMANDS_ENABLED
#define TEXT_SERVICE_USE_ENABLED
//#define UART_ERRORMSG
//#define USE_TOGGLE_FLAG



/*
Jedes Port hat drei Register
DDxN
PORTXn
PINxn
IF PortX ist INPUT an PORTX= set to 1, PullUP IS ENABLED
//sfr |= _BV(bit)  ---  sfr &= ~(_BV(bit))
*/

/*
Text verbraucht Speicher
Statt Pointer geht evtl auch diese Form
PSTR ( "So geht s auch in den Progspeicher" ); // aber ohne Namen)

#define MCA_CRLFSTR (const char) {CR,LF,0}
*/

#define STRMAX        16
#define NUMMAX        16
#define RX_STRMAX    16
#define COMAMNDSIZEMAX  16

#define DELIMITER        ','
#define DELIMITERSTR    ","

//TYPEN DEKLARATION
//Tastatur
typedef struct
    {
    char ucaCmd[COMAMNDSIZEMAX +1];
    unsigned int uiCmdVal_1;
//uint8_t ucCmdID;
    }COMMAND_TYPE;

//Hardwareassignment
//F_CPU  in makefile !!!
//CPU = 8000000UL
//#define UART_BAUD_RATE 1200
#define UART_BAUD_RATE 9600
//#define UART_BAUD_RATE    19200
//#define UART_BAUD_RATE    57600

//WDTCSR
//16mS = 62,5 interrupts/Sekunde =
#define WDT_TICK_SECOND 62
#define WDT_TICK_500MS    31
#define WDT_TICK_100MS    6

#define DISABLE_ALL_PULLUP_MC()    (SFIOR |= _BV(PUD))
#define ENABLE_ALLUP_SCL_MC()    (SFIOR &= ~(_BV(PUD)))


/*
MCUCR |= _BV(PUD); // Pullup OFF
WDTCSR |= _BV(WDIE); // 62,5/Sekunde = 16mS

__enable_interrupt(); //Set gloabl int enable
__Sleep() // sleep, wait vor Int

WDT_off();
MCUCSR |= (1<<WDCE) | (1<<WDE);
WDTCR=0x00;
__enable_interrupt() //Set gloabl int enable
*/



//========================================================================


#define FLOAT_PRAEDIGITS_MAX    5 // minimum field width of the output string (including the '.'
#define FLOAT_DIGITS_MAX        1 // DIgits nach //dtostrf(fVal,NUMMAX, DIGITS_MAX, gcaNumStr);


#define WDTO_2S   7 //WatchDog
//SOFTWARE USED DEFINES

#define ASC_CR    13
#define ASC_LF    10

//COMMAND
#define DELIMITER        ','
#define DELIMITERSTR    ","

#define BITS_PER_BYTE    8
#define PORTB_BYTEs        8
#define PORTD_BYTEs        7


//TEST AND DEBUG SECTION
//#define USE_TOGGLE_FLAG
#ifdef USE_TOGGLE_FLAG
    #define TESTBIT_DIRREG        DDRD
    #define TESTBIT_PORT        PORTD
    #define TESTBIT_BIT            0x01
    #define INIT_TESTBIT_REG()    (TESTBIT_DIRREG |= TESTBIT_BIT);
    #define SET_TESTBIT()        (TESTBIT_PORT |= TESTBIT_BIT);
    #define CLR_TESTBIT()        (TESTBIT_PORT &= ~TESTBIT_BIT);
    extern void ToggleTEST_BIT(uint8_t ucCnt);
#endif



// HARDWARE DEFINITIONEN

#define RX_BIT    0x01
#define TX_BIT    0x02

#define OC_TRANSITOR_DDRX    DDRB
#define OC_TRANSITOR_PORTX    PORTB
#define OC_TRANSITOR_BIT    0x10
#define OC_TRANSITOR_ON() (OC_TRANSITOR_PORTX |= OC_TRANSITOR_BIT)
#define OC_TRANSITOR_OFF() (OC_TRANSITOR_PORTX &= ~OC_TRANSITOR_BIT)


#define HALLSENS_DDRX    DDRD
#define HALLSENS_PORTX    PORTD
#define HALLSENS_PINX    PIND
#define HALLSENS_BIT    0x04
#define HALLSENS_IN() (HALLSENS_PINX & HALLSENS_BIT)
 
#define DISABLE_DDRX    DDRD
#define DISABLE_PORTX    PORTD
#define DISABLE_PINX    PIND
#define DISABLE_BIT        0x08
#define DISABLE_IN() (DISABLE_PINX & DISABLE_BIT)

#define SCK_OUT_DDRX    DDRB
#define SCK_OUT_PORTX    PORTB
#define SCK_OUT_BIT        0x80
#define SCK_OUT_LOW() (SCK_OUT_PORTX &=  ~SCK_OUT_BIT)
#define SCK_OUT_HIGH() (SCK_OUT_PORTX |= SCK_OUT_BIT)

#define MISO_DDRX    DDRB
#define MISO_PORTX    PORTB
#define MISO_PINX    PINB
#define MISO_BITX    0x40

#define MISO_PULLUP() (MISO_PORTX |= MISO_BITX)
#define MISO_IN() (MISO_PINX & MISO_BITX)


#define TICK_PER_SEC 31250 //Sekunde 8MHz/64
#define F_TICK_PER_SEC 31250.0 //Sekunde 8MHz/64

//hall
#define HALL_FALLINGEDGE_INT0

#define    MODE_26ZOLL        0x01
#define    MODE_28ZOLL        0x02

#define F_UMFANG_26Z 2074.707788     //mmeter
#define F_UMFANG_28Z 2234.300695    //mmeter

#define TX_BIT_ON() ( PORTD |= TX_BIT)
#define TX_BIT_OFF() ( PORTD &= ~TX_BIT)


#endif  //MAIN_HEADER



#include <util\delay.h>    //_delay_loop_1 _delay_loop_2 delay_ms

//LCDDAT7 ist mit 1K zu PULL-Downen.
//Somit wird ein Busy Simulatiert,  wenn kein LCD angesteckt ist.
//AUch den evtl. Pullup des Ports bei Readvorgängen schalten, sonst arbeitet Pulldown gegen den intenen Pullup.
//Nach diesem Schritt war das Signal an LCDDat7 bedeutend (..schöner).
//Christof Ermer.....Regensburg 16.12.05


//ABGESTRIPTE SPEICHERSPAR-VERSION..Christof Ermer


// NEU SLOW MODE mit _delay_us(1)

/****************************************************************************
 Title    :   HD44780U LCD library
 Author:    Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury
 File:        $Id: lcd.c,v 1.13.2.5 2005/02/16 19:15:13 Peter Exp $
 Software:  AVR-GCC 3.3
 Target:    any AVR device, memory mapped mode only for AT90S4414/8515/Mega

 DESCRIPTION
       Basic routines for interfacing a HD44780U-based text lcd display

       Originally based on Volker Oth's lcd library,
       changed lcd_init(), added additional constants for lcd_command(),
       added 4-bit I/O mode, improved and optimized code.

       Library can be operated in memory mapped mode (LCD_IO_MODE=0) or in
       4-bit IO port mode (LCD_IO_MODE=1). 8-bit IO port mode not supported.
      
       Memory mapped mode compatible with Kanda STK200, but supports also
       generation of R/W signal through A8 address line.

 USAGE
       See the C include lcd.h file for a description of each function
      
*****************************************************************************/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr\wdt.h>
#include "2313lcd.h"

/*
** constants/macros
*/
//#define DDR(x) (*(&x - 1))      /* address of data direction register of port x */
//if defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
    /* on ATmega64/128 PINF is on port 0x00 and not 0x60 */
// #define PIN(x) ( &PORTF==&(x) ? _SFR_IO8(0x00) : (*(&x - 2)) )
//#else
//#define PIN(x) (*(&x - 2))    /* address of input register of port x          */
//endif


#ifdef SLOWMODE
    #define lcd_e_delay()   _delay_us(1);
#else
#define lcd_e_delay()   __asm__ __volatile__( "rjmp 1f\n 1:" );
#endif

#define lcd_e_high()    LCD_E_PORT  |= _BV(LCD_E_PIN);
#define lcd_e_low()     LCD_E_PORT  &= ~_BV(LCD_E_PIN);
#define lcd_e_toggle()  toggle_e()
#define lcd_rw_high()   LCD_RW_PORT |=  _BV(LCD_RW_PIN)
#define lcd_rw_low()    LCD_RW_PORT &= ~_BV(LCD_RW_PIN)
#define lcd_rs_high()   LCD_RS_PORT |= _BV(LCD_RS_PIN)
#define lcd_rs_low()    LCD_RS_PORT &= ~_BV(LCD_RS_PIN)


#if LCD_LINES==1
#define LCD_FUNCTION_DEFAULT    LCD_FUNCTION_4BIT_1LINE
#else
#define LCD_FUNCTION_DEFAULT    LCD_FUNCTION_4BIT_2LINES
#endif


/*
** function prototypes
*/
static void toggle_e(void);

/*
** local functions
*/

/*************************************************************************
 delay loop for small accurate delays: 16-bit counter, 4 cycles/loop
*************************************************************************/
static inline void _delayFourCycles(unsigned int __count)
{
#ifdef SLOWMODE
_delay_us(1);
#else
    if ( __count == 0 )   
        __asm__ __volatile__( "rjmp 1f\n 1:" );    // 2 cycles
    else
        __asm__ __volatile__ (
            "1: sbiw %0,1" "\n\t"                 
            "brne 1b"                              // 4 cycles/loop
            : "=w" (__count)
            : "0" (__count)
           );

#endif
}


/*************************************************************************
delay for a minimum of <us> microseconds
the number of loops is calculated at compile-time from MCU clock frequency
*************************************************************************/
#define delay(us)  _delayFourCycles( ( ( 1*(XTAL/4000) )*us)/1000 )


/* toggle Enable Pin to initiate write */
static void toggle_e(void)
{
    lcd_e_high()
    lcd_e_delay();
    lcd_e_low();
}



/*************************************************************************
Low-level function to write byte to LCD controller
Input:    data   byte to write to LCD
          rs     1: write data   
                 0: write instruction
Returns:  none
*************************************************************************/
static void lcd_write(uint8_t data,uint8_t rs)
{
    unsigned char dataBits ;   
    if (rs)
        {   /* write data        (RS=1, RW=0) */
        lcd_rs_high();
        }
    else
        {    /* write instruction (RS=0, RW=0) */
        lcd_rs_low();
        };
    lcd_rw_low();
    LCD_DATA_DIRCETION_REG |= 0x0F;    //AS Output       
        /* output high nibble first */
    dataBits =  LCD_DATA_PORT & 0xF0; //Lösche was immer da steht
    LCD_DATA_PORT = dataBits |((data>>4)&0x0F);
    lcd_e_toggle();
        /* output low nibble */
    LCD_DATA_PORT = dataBits | (data&0x0F);
    lcd_e_toggle();
        /* all data pins high (inactive) */
    LCD_DATA_PORT = dataBits | 0x0F; 
};
/* rs==0 -> write instruction to LCD_IO_FUNCTION */
/* rs==1 -> write data to LCD_IO_DATA */


/*************************************************************************
Low-level function to read byte from LCD controller
Input:    rs     1: read data   
                 0: read busy flag / address counter
Returns:  byte read from LCD controller
*************************************************************************/
static uint8_t lcd_read(uint8_t rs)
{
    uint8_t data;
  
    if (rs)
        {
        lcd_rs_high(); /* RS=1: read data      */
        }                          
    else
        {
        lcd_rs_low(); /* RS=0: read busy flag */
        };
    lcd_rw_high();
    LCD_DATA_DIRCETION_REG &= 0xF0;
    LCD_DATA_PORT &= 0xF0; //Lösche Datenbit damit Pullup nicht arbeitet, und Pegel Low wird,
    //LCD_DATA_PORT |= 0x0F;    //MY PULLUP
        //DDR(LCD_DATA0_PORT) &= 0xF0;         /* configure data pins as input */       
    lcd_e_high();
    lcd_e_delay();       
    data = LCD_DATA_PORT_IN << 4;     /* read high nibble first */
    lcd_e_low();
       
    lcd_e_delay();                       /* Enable 500ns low       */
       
    lcd_e_high();
    lcd_e_delay();
    data |= LCD_DATA_PORT_IN & 0x0F;    /* read low nibble        */
    lcd_e_low();
    return data;
}
/* rs==0 -> read instruction from LCD_IO_FUNCTION */
/* rs==1 -> read data from LCD_IO_DATA */


/*************************************************************************
loops while lcd is busy, returns address counter
*************************************************************************/
static uint8_t lcd_waitbusy(void)
{
    register uint8_t c;     
    /* wait until busy flag is cleared */
    while ( (c=lcd_read(0)) & (1<<LCD_BUSY) )
        {       
        wdt_reset();
        };
   
    /* the address counter is updated 4us after the busy flag is cleared */
    delay(2);

    /* now read the address counter */
    return (lcd_read(0));  // return address counter
   
}/* lcd_waitbusy */


/*************************************************************************
Move cursor to the start of next line or to the first line if the cursor
is already on the last line.
*************************************************************************/
static inline void lcd_newline(uint8_t pos)
{
    register uint8_t addressCounter;
#if LCD_LINES==1
    addressCounter = 0;
#endif
#if LCD_LINES==2
    if ( pos < (LCD_START_LINE2) )
        addressCounter = LCD_START_LINE2;
    else
        addressCounter = LCD_START_LINE1;
#endif
#if LCD_LINES==4
    if ( pos < LCD_START_LINE3 )
        addressCounter = LCD_START_LINE2;
    else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE4) )
        addressCounter = LCD_START_LINE3;
    else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE2) )
        addressCounter = LCD_START_LINE4;
    else
        addressCounter = LCD_START_LINE1;
#endif
    lcd_command((1<<LCD_DDRAM)+addressCounter);

}/* lcd_newline */


/*
** PUBLIC FUNCTIONS
*/

/*************************************************************************
Send LCD controller instruction command
Input:   instruction to send to LCD controller, see HD44780 data sheet
Returns: none
*************************************************************************/
void lcd_command(uint8_t cmd)
{
    lcd_waitbusy();
    lcd_write(cmd,0);
}


/*************************************************************************
Send data byte to LCD controller
Input:   data to send to LCD controller, see HD44780 data sheet
Returns: none
*************************************************************************/
void lcd_data(uint8_t data)
{
    lcd_waitbusy();
    lcd_write(data,1);
}



/*************************************************************************
Set cursor to specified position
Input:    x  horizontal position  (0: left most position)
          y  vertical position    (0: first line)
Returns:  none
*************************************************************************/
void lcd_gotoxy(uint8_t x, uint8_t y)
{
#if LCD_LINES==1
    lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
#endif
#if LCD_LINES==2
    if ( y==0 )
        lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
    else
        lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+x);
#endif
#if LCD_LINES==4
    if ( y==0 )
        lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
    else if ( y==1)
        lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+x);
    else if ( y==2)
        lcd_command((1<<LCD_DDRAM)+LCD_START_LINE3+x);
    else /* y==3 */
        lcd_command((1<<LCD_DDRAM)+LCD_START_LINE4+x);
#endif

}/* lcd_gotoxy */


/*************************************************************************
*************************************************************************/
int lcd_getxy(void)
{
    return lcd_waitbusy();
}


/*************************************************************************
Clear display and set cursor to home position
*************************************************************************/
void lcd_clrscr(void)
{
    lcd_command(1<<LCD_CLR);
}


/*************************************************************************
Set cursor to home position
*************************************************************************/
void lcd_home(void)
{
    lcd_command(1<<LCD_HOME);
}


/*************************************************************************
Display character at current cursor position
Input:    character to be displayed                                      
Returns:  none
*************************************************************************/
void lcd_putc( char c)
{
    uint8_t pos;


    pos = lcd_waitbusy();   // read busy-flag and address counter
    if (c=='\n')
    {
        lcd_newline(pos);
    }
    else
    {
#if LCD_WRAP_LINES==1
#if LCD_LINES==1
        if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH )
            lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);
#elif LCD_LINES==2
        if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH )
            lcd_write((1<<LCD_DDRAM)+LCD_START_LINE2,0);   
        else if ( pos == LCD_START_LINE2+LCD_DISP_LENGTH )
            lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);
#elif LCD_LINES==4
        if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH )
            lcd_write((1<<LCD_DDRAM)+LCD_START_LINE2,0);   
        else if ( pos == LCD_START_LINE2+LCD_DISP_LENGTH )
            lcd_write((1<<LCD_DDRAM)+LCD_START_LINE3,0);
        else if ( pos == LCD_START_LINE3+LCD_DISP_LENGTH )
            lcd_write((1<<LCD_DDRAM)+LCD_START_LINE4,0);
        else if ( pos == LCD_START_LINE4+LCD_DISP_LENGTH )
            lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);
#endif
        lcd_waitbusy();
#endif
        lcd_write(c, 1);
    }

}/* lcd_putc */


/*************************************************************************
Display string without auto linefeed
Input:    string to be displayed
Returns:  none
*************************************************************************/
void lcd_puts( char *s)
/* print string on lcd (no auto linefeed) */
{
register char c;

while ( (c = *s++) )
    {
    lcd_putc(c);       
    }

}/* lcd_puts */


/*************************************************************************
Display string from program memory without auto linefeed
Input:     string from program memory be be displayed                                       
Returns:   none
*************************************************************************/
void lcd_puts_p(const char *progmem_s)
/* print string from program memory on lcd (no auto linefeed) */
{
    register char c;

    while ( (c = pgm_read_byte(progmem_s++)) )
        {
        lcd_putc(c);
        };

}/* lcd_puts_p */


/*************************************************************************
Initialize display and select type of cursor
Input:    dispAttr LCD_DISP_OFF            display off
                   LCD_DISP_ON             display on, cursor off
                   LCD_DISP_ON_CURSOR      display on, cursor on
                   LCD_DISP_CURSOR_BLINK   display on, cursor on flashing
Returns:  none
*************************************************************************/
/*
Autor: Tobias Mueller - mikrocontroller(at)email.twam.info
Datum: 07.09.2005 21:44
Bei meinem Display mit KS0073 Chipsatz musste ich damals die lcd_init
Prozedur etwas anpassen. Die letzten Commands hatte ich zu

  lcd_command(0x2C);
  lcd_command(0x0B);
  lcd_command(0x28);
  lcd_command(0x0F);
  lcd_command(0x01);
  lcd_command(0x07);
 geändert.
*/
void lcd_init(uint8_t dispAttr)
{
    /*
     *  Initialize LCD to 4 bit I/O mode
     */
    
   
    /* configure all port bits as output (all LCD lines on same port) */
//    LCD_CTLR_DIRCETION_REG |= 0x7F;  //EVTl schon in INIT...
    LCD_DATA_DIRCETION_REG |= LCD_DATA_DIR_MASK;
    LCD_CTLR_DIRCETION_REG |=  LCD_CTLR_DIR_MASK;  //EVTl schon in INIT...
    delay(16000);        /* wait 16ms or more after power-on       */
   
    /* initial write to lcd is 8bit */
    //LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);  // _BV(LCD_FUNCTION)>>4;
    //LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);  // _BV(LCD_FUNCTION_8BIT)>>4;
    LCD_DATA_PORT |= 0x03;  // _BV(LCD_FUNCTION)>>4;
    lcd_e_toggle();
    delay(4992);         /* delay, busy flag can't be checked here */
  
    /* repeat last command */
    lcd_e_toggle();     
    delay(64);           /* delay, busy flag can't be checked here */
   
    /* repeat last command a third time */
    lcd_e_toggle();     
    delay(64);           /* delay, busy flag can't be checked here */

    /* now configure for 4bit mode */
    //LCD_DATA_PORT &= ~_BV(LCD_DATA0_PIN);   // LCD_FUNCTION_4BIT_1LINE>>4
    LCD_DATA_PORT &= 0xFE;   // LCD_FUNCTION_4BIT_1LINE>>4
    lcd_e_toggle();
    delay(64);           /* some displays need this additional delay */
   
    /* from now the LCD only accepts 4 bit I/O, we can use lcd_command() */   
    lcd_command(LCD_FUNCTION_DEFAULT);      /* function set: display lines  */
    lcd_command(LCD_DISP_OFF);              /* display off                  */
    lcd_clrscr();                           /* display clear                */
    lcd_command(LCD_MODE_DEFAULT);          /* set entry mode               */
    lcd_command(dispAttr);                 /* display/cursor control       */
};/* lcd_init */
//#endif // LCD_4Bit_Module_USED





#ifndef LCD_H
#define LCD_H

#define SLOWMODE        //Pulsedauer ~1 _delay_us

/*
ERFAHRUNG .. sehr schnell, dann geht die LCD nicht, deshalb die 1us delay bremse
*/

/*************************************************************************
 Title    :   C include file for the HD44780U LCD library (lcd.c)
 Author:    Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury
 File:        $Id: lcd.h,v 1.12.2.4 2005/02/28 22:54:41 Peter Exp $
 Software:  AVR-GCC 3.3
 Hardware:  any AVR device, memory mapped mode only for AT90S4414/8515/Mega
***************************************************************************/

/*
 @defgroup pfleury_lcd LCD library
 @code #include <lcd.h> @endcode
 
 @brief Basic routines for interfacing a HD44780U-based text LCD display

 Originally based on Volker Oth's LCD library,
 changed lcd_init(), added additional constants for lcd_command(),
 added 4-bit I/O mode, improved and optimized code.
      
 Library can be operated in memory mapped mode (LCD_IO_MODE=0) or in
 4-bit IO port mode (LCD_IO_MODE=1). 8-bit IO port mode not supported.

 Memory mapped mode compatible with Kanda STK200, but supports also
 generation of R/W signal through A8 address line.
      
 @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury
 
 @see The chapter <a href="http://homepage.sunrise.ch/mysunrise/peterfleury/avr-lcd44780.html" target="_blank">Interfacing a HD44780 Based LCD to an AVR</a>
      on my home page.

*/


#if (__GNUC__ * 100 + __GNUC_MINOR__) < 303
#error "This library requires AVR-GCC 3.3 or later, update to newer AVR-GCC compiler !"
#endif

#include <inttypes.h>
#include <avr/pgmspace.h>

/**
 *  @name  Definitions for MCU Clock Frequency
 *  Adapt the MCU clock frequency in Hz to your target.
 */
#define XTAL F_CPU              /**< clock frequency in Hz, used to calculate delay timer */

/**
 *  @name  Definitions for Display Size
 *  Change these definitions to adapt setting to your display
 */
#define LCD_LINES          2     /**< number of visible lines of the display */
#define LCD_DISP_LENGTH    16     /**< visibles characters per line of the display */
#define LCD_LINE_LENGTH  0x40     /**< internal line length of the display    */
#define LCD_START_LINE1  0x00     /**< DDRAM address of first char of line 1 */
#define LCD_START_LINE2  0x40     /**< DDRAM address of first char of line 2 */
#define LCD_START_LINE3  0x14     /**< DDRAM address of first char of line 3 */
#define LCD_START_LINE4  0x54     /**< DDRAM address of first char of line 4 */
#define LCD_WRAP_LINES      0     /**< 0: no wrap, 1: wrap at end of visibile line */


/**
 *  @name Definitions for 4-bit IO mode
 *  Change LCD_PORT if you want to use a different port for the LCD pins.
 *
 *  The four LCD data lines and the three control lines RS, RW, E can be on the
 *  same port or on different ports.
 *  Change LCD_RS_PORT, LCD_RW_PORT, LCD_E_PORT if you want the control lines on
 *  different ports.
 *
 *  Normally the four data lines should be mapped to bit 0..3 on one port, but it
 *  is possible to connect these data lines in different order or even on different
 *  ports by adapting the LCD_DATAx_PORT and LCD_DATAx_PIN definitions.
 * 
 */
#define LCD_DATA_PORT                PORTB    /* port for the DATA LCD lines   */
#define LCD_DATA_PORT_IN            PINB    /* port for the DATA LCD lines   */
#define LCD_DATA_DIRCETION_REG        DDRB    /* port for the DATA LCD lines   */
#define LCD_DATA_DIR_MASK            0x0F

#define LCD_CTRL_PORT                PORTD    /* port for the CTRL lines   */
#define LCD_CTRL_PORT_IN            PIND    /* port for the CTRL lines   */
#define LCD_CTLR_DIRCETION_REG        DDRD    /* port for the DATA LCD lines   */
#define LCD_CTLR_DIR_MASK            0x70

#define LCD_DATA0_PIN    0           /* pin for 4bit data bit 0  */
#define LCD_DATA1_PIN    1            /* pin for 4bit data bit 1  */
#define LCD_DATA2_PIN     2            /* pin for 4bit data bit 2  */
#define LCD_DATA3_PIN    3            /* pin for 4bit data bit 3  */
#define LCD_RS_PORT      LCD_CTRL_PORT     /* port for RS line         */
#define LCD_RS_PIN       5            /* pin  for RS line         */
#define LCD_RW_PORT      LCD_CTRL_PORT     /**< port for RW line         */
#define LCD_RW_PIN       6           /*pin  for RW line         */
#define LCD_E_PORT       LCD_CTRL_PORT     /* port for Enable line     */
#define LCD_E_PIN        4            /* pin  for Enable line     */

#elif defined(__AVR_AT90S4414__) || defined(__AVR_AT90S8515__) || defined(__AVR_ATmega64__) || \
      defined(__AVR_ATmega8515__)|| defined(__AVR_ATmega103__) || defined(__AVR_ATmega128__) || \
      defined(__AVR_ATmega161__) || defined(__AVR_ATmega162__)
/*
 *  memory mapped mode is only supported when the device has an external data memory interface
 */
#define LCD_IO_DATA      0xC000    /* A15=E=1, A14=RS=1                 */
#define LCD_IO_FUNCTION  0x8000    /* A15=E=1, A14=RS=0                 */
#define LCD_IO_READ      0x0100    /* A8 =R/W=1 (R/W: 1=Read, 0=Write   */
#else
#error "external data memory interface not available for this device, use 4-bit IO port mode"
#endif


/**
 *  @name Definitions for LCD command instructions
 *  The constants define the various LCD controller instructions which can be passed to the
 *  function lcd_command(), see HD44780 data sheet for a complete description.
 */

/* instruction register bit positions, see HD44780U data sheet */
#define LCD_CLR               0    /*    DB0: clear display                  */
#define LCD_HOME              1    /*    DB1: return to home position        */
#define LCD_ENTRY_MODE        2    /*    DB2: set entry mode                 */
#define LCD_ENTRY_INC         1    /*    DB1: 1=increment, 0=decrement         */
#define LCD_ENTRY_SHIFT       0      /*    DB2: 1=display shift on               */
#define LCD_ON                3      /*    DB3: turn lcd/cursor on             */
#define LCD_ON_DISPLAY        2      /*    DB2: turn display on                  */
#define LCD_ON_CURSOR         1      /*    DB1: turn cursor on                   */
#define LCD_ON_BLINK          0      /*    DB0: blinking cursor ?              */
#define LCD_MOVE              4      /*    DB4: move cursor/display            */
#define LCD_MOVE_DISP         3      /*    DB3: move display (0-> cursor) ?      */
#define LCD_MOVE_RIGHT        2      /*    DB2: move right (0-> left) ?          */
#define LCD_FUNCTION          5      /*    DB5: function set                    */
#define LCD_FUNCTION_8BIT     4      /*    DB4: set 8BIT mode (0->4BIT mode)    */
#define LCD_FUNCTION_2LINES   3      /*    DB3: two lines (0->one line)        */
#define LCD_FUNCTION_10DOTS   2      /*    DB2: 5x10 font (0->5x7 font)        */
#define LCD_CGRAM             6      /*    DB6: set CG RAM address                */
#define LCD_DDRAM             7      /*    DB7: set DD RAM address                */
#define LCD_BUSY              7      /* DB7: LCD is busy                    */

/* set entry mode: display shift on/off, dec/inc cursor move direction */
#define LCD_ENTRY_DEC            0x04   /* display shift off, dec cursor move dir */
#define LCD_ENTRY_DEC_SHIFT      0x05   /* display shift on,  dec cursor move dir */
#define LCD_ENTRY_INC_           0x06   /* display shift off, inc cursor move dir */
#define LCD_ENTRY_INC_SHIFT      0x07   /* display shift on,  inc cursor move dir */

/* display on/off, cursor on/off, blinking char at cursor position */
#define LCD_DISP_OFF             0x08   /* display off                            */
#define LCD_DISP_ON              0x0C   /* display on, cursor off                 */
#define LCD_DISP_ON_BLINK        0x0D   /* display on, cursor off, blink char     */
#define LCD_DISP_ON_CURSOR       0x0E   /* display on, cursor on                  */
#define LCD_DISP_ON_CURSOR_BLINK 0x0F   /* display on, cursor on, blink char      */

/* move cursor/shift display */
#define LCD_MOVE_CURSOR_LEFT     0x10   /* move cursor left  (decrement)          */
#define LCD_MOVE_CURSOR_RIGHT    0x14   /* move cursor right (increment)          */
#define LCD_MOVE_DISP_LEFT       0x18   /* shift display left                     */
#define LCD_MOVE_DISP_RIGHT      0x1C   /* shift display right                    */

/* function set: set interface data length and number of display lines */
#define LCD_FUNCTION_4BIT_1LINE  0x20   /* 4-bit interface, single line, 5x7 dots */
#define LCD_FUNCTION_4BIT_2LINES 0x28   /* 4-bit interface, dual line,   5x7 dots */
#define LCD_FUNCTION_8BIT_1LINE  0x30   /* 8-bit interface, single line, 5x7 dots */
#define LCD_FUNCTION_8BIT_2LINES 0x38   /* 8-bit interface, dual line,   5x7 dots */


#define LCD_MODE_DEFAULT     ((1<<LCD_ENTRY_MODE) | (1<<LCD_ENTRY_INC) )

/**
 *  @name Functions
 */


/**
 @brief    Initialize display and select type of cursor
 @param    dispAttr \b LCD_DISP_OFF display off\n
                    \b LCD_DISP_ON display on, cursor off\n
                    \b LCD_DISP_ON_CURSOR display on, cursor on\n
                    \b LCD_DISP_ON_CURSOR_BLINK display on, cursor on flashing            
 @return  none
*/
extern void lcd_init(uint8_t dispAttr);


/**
 @brief    Clear display and set cursor to home position
 @param    void                                       
 @return   none
*/
extern void lcd_clrscr(void);


/**
 @brief    Set cursor to home position
 @param    void                                       
 @return   none
*/
extern void lcd_home(void);


/**
 @brief    Set cursor to specified position
 
 @param    x horizontal position\n (0: left most position)
 @param    y vertical position\n   (0: first line)
 @return   none
*/
extern void lcd_gotoxy(uint8_t x, uint8_t y);


/**
 @brief    Display character at current cursor position
 @param    c character to be displayed                                      
 @return   none
*/
extern void lcd_putc( char c);


/**
 @brief    Display string without auto linefeed
 @param    s string to be displayed                                       
 @return   none
*/
extern void lcd_puts( char *s);


/**
 @brief    Display string from program memory without auto linefeed
 @param    s string from program memory be be displayed                                       
 @return   none
 @see      lcd_puts_P
*/
extern void lcd_puts_p(const char *progmem_s);


/**
 @brief    Send LCD controller instruction command
 @param    cmd instruction to send to LCD controller, see HD44780 data sheet
 @return   none
*/
extern void lcd_command( uint8_t cmd );


/**
 @brief    Send data byte to LCD controller
 
 Similar to lcd_putc(), but without interpreting LF
 @param    data byte to send to LCD controller, see HD44780 data sheet
 @return   none
*/
extern void lcd_data(uint8_t data);


/**
 @brief macros for automatically storing string constant in program memory
*/
#define lcd_puts_P(__s)         lcd_puts_p(PSTR(__s))


make


# Hey Emacs, this is a -*- makefile -*-
#----------------------------------------------------------------------------
# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
#
# Released to the Public Domain
#
# Additional material for this makefile was written by:
# Peter Fleury
# Tim Henigan
# Colin O'Flynn
# Reiner Patommel
# Markus Pfaff
# Sander Pool
# Frederik Rouleau
# Carlos Lamas
#
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device, using avrdude.
#                Please customize the avrdude settings below first!
#
# make debug = Start either simulavr or avarice as specified for debugging,
#              with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
#                   bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------


# MCU name
MCU = attiny2313a


# Processor frequency.
#     This will define a symbol, F_CPU, in all source code files equal to the
#     processor frequency. You can then use this symbol in your source code to
#     calculate timings. Do NOT tack on a 'UL' at the end, this will be done
#     automatically to create a 32-bit value in your source code.
#     Typical values are:
#         F_CPU =  1000000
#         F_CPU =  1843200
#         F_CPU =  2000000
#         F_CPU =  3686400
#         F_CPU =  4000000
#         F_CPU =  7372800
#         F_CPU =  8000000
#         F_CPU = 11059200
#         F_CPU = 14745600
#         F_CPU = 16000000
#         F_CPU = 18432000
#         F_CPU = 20000000
F_CPU = 8000000


# Output format. (can be srec, ihex, binary)
FORMAT = ihex


# Target file name (without extension).
TARGET = main


# Object files directory
#     To put object files in current directory, use a dot (.), do NOT make
#     this an empty or blank macro!
OBJDIR = .


# List C source files here. (C dependencies are automatically generated.)
SRC = $(TARGET).c 2313lcd.c


# List C++ source files here. (C dependencies are automatically generated.)
CPPSRC =


# List Assembler source files here.
#     Make them always end in a capital .S.  Files ending in a lowercase .s
#     will not be considered source files but generated files (assembler
#     output from the compiler), and will be deleted upon "make clean"!
#     Even though the DOS/Win* filesystem matches both .s and .S the same,
#     it will preserve the spelling of the filenames, and gcc itself does
#     care about how the name is spelled on its command-line.
ASRC =


# Optimization level, can be [0, 1, 2, 3, s].
#     0 = turn off optimization. s = optimize for size.
#     (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
OPT = s


# Debugging format.
#     Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
#     AVR Studio 4.10 requires dwarf-2.
#     AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
DEBUG = dwarf-2


# List any extra directories to look for include files here.
#     Each directory must be seperated by a space.
#     Use forward slashes for directory separators.
#     For a directory that has spaces, enclose it in quotes.
EXTRAINCDIRS =


# Compiler flag to set the C Standard level.
#     c89   = "ANSI" C
#     gnu89 = c89 plus GCC extensions
#     c99   = ISO C99 standard (not yet fully implemented)
#     gnu99 = c99 plus GCC extensions
CSTANDARD = -std=gnu99


# Place -D or -U options here for C sources
CDEFS = -DF_CPU=$(F_CPU)UL


# Place -D or -U options here for ASM sources
ADEFS = -DF_CPU=$(F_CPU)


# Place -D or -U options here for C++ sources
CPPDEFS = -DF_CPU=$(F_CPU)UL
#CPPDEFS += -D__STDC_LIMIT_MACROS
#CPPDEFS += -D__STDC_CONSTANT_MACROS



#---------------- Compiler Options C ----------------
#  -g*:          generate debugging information
#  -O*:          optimization level
#  -f...:        tuning, see GCC manual and avr-libc documentation
#  -Wall...:     warning level
#  -Wa,...:      tell GCC to pass this to the assembler.
#    -adhlns...: create assembler listing
CFLAGS = -g$(DEBUG)
CFLAGS += $(CDEFS)
CFLAGS += -O$(OPT)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -Wall
CFLAGS += -Wstrict-prototypes
#CFLAGS += -mshort-calls
#CFLAGS += -fno-unit-at-a-time
#CFLAGS += -Wundef
#CFLAGS += -Wunreachable-code
#CFLAGS += -Wsign-compare
CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst)
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
CFLAGS += $(CSTANDARD)


#---------------- Compiler Options C++ ----------------
#  -g*:          generate debugging information
#  -O*:          optimization level
#  -f...:        tuning, see GCC manual and avr-libc documentation
#  -Wall...:     warning level
#  -Wa,...:      tell GCC to pass this to the assembler.
#    -adhlns...: create assembler listing
CPPFLAGS = -g$(DEBUG)
CPPFLAGS += $(CPPDEFS)
CPPFLAGS += -O$(OPT)
CPPFLAGS += -funsigned-char
CPPFLAGS += -funsigned-bitfields
CPPFLAGS += -fpack-struct
CPPFLAGS += -fshort-enums
CPPFLAGS += -fno-exceptions
CPPFLAGS += -Wall
CPPFLAGS += -Wundef
#CPPFLAGS += -mshort-calls
#CPPFLAGS += -fno-unit-at-a-time
#CPPFLAGS += -Wstrict-prototypes
#CPPFLAGS += -Wunreachable-code
#CPPFLAGS += -Wsign-compare
CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)
CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
#CPPFLAGS += $(CSTANDARD)


#---------------- Assembler Options ----------------
#  -Wa,...:   tell GCC to pass this to the assembler.
#  -adhlns:   create listing
#  -gstabs:   have the assembler create line number information; note that
#             for use in COFF files, additional information about filenames
#             and function names needs to be present in the assembler source
#             files -- see avr-libc docs [FIXME: not yet described there]
#  -listing-cont-lines: Sets the maximum number of continuation lines of hex
#       dump that will be displayed for a given single line of source input.
ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100


#---------------- Library Options ----------------
# Minimalistic printf version
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min

# Floating point printf version (requires MATH_LIB = -lm below)
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt

# If this is left blank, then it will use the Standard printf version.
PRINTF_LIB =
#PRINTF_LIB = $(PRINTF_LIB_MIN)
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)


# Minimalistic scanf version
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min

# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt

# If this is left blank, then it will use the Standard scanf version.
SCANF_LIB =
#SCANF_LIB = $(SCANF_LIB_MIN)
#SCANF_LIB = $(SCANF_LIB_FLOAT)


MATH_LIB = -lm


# List any extra directories to look for libraries here.
#     Each directory must be seperated by a space.
#     Use forward slashes for directory separators.
#     For a directory that has spaces, enclose it in quotes.
EXTRALIBDIRS =



#---------------- External Memory Options ----------------

# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# used for variables (.data/.bss) and heap (malloc()).
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff

# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# only used for heap (malloc()).
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff

EXTMEMOPTS =



#---------------- Linker Options ----------------
#  -Wl,...:     tell GCC to pass this to linker.
#    -Map:      create map file
#    --cref:    add cross reference to  map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
#LDFLAGS += -T linker_script.x



#---------------- Programming Options (avrdude) ----------------

# Programming hardware
# Type: avrdude -c ?
# to get a full listing.
#
AVRDUDE_PROGRAMMER = USBasp   
##jtagmkI

# com1 = serial port. Use lpt1 to connect to parallel port.
AVRDUDE_PORT = usb

AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep


# Uncomment the following if you want avrdude's erase cycle counter.
# Note that this counter needs to be initialized first using -Yn,
# see avrdude manual.
#AVRDUDE_ERASE_COUNTER = -y

# Uncomment the following if you do /not/ wish a verification to be
# performed after programming the device.
#AVRDUDE_NO_VERIFY = -V

# Increase verbosity level.  Please use this when submitting bug
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
# to submit bug reports.
#AVRDUDE_VERBOSE = -v -v

##AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS = -p attiny2313 -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)



#---------------- Debugging Options ----------------

# For simulavr only - target MCU frequency.
DEBUG_MFREQ = $(F_CPU)

# Set the DEBUG_UI to either gdb or insight.
# DEBUG_UI = gdb
DEBUG_UI = insight

# Set the debugging back-end to either avarice, simulavr.
DEBUG_BACKEND = avarice
#DEBUG_BACKEND = simulavr

# GDB Init Filename.
GDBINIT_FILE = __avr_gdbinit

# When using avarice settings for the JTAG
JTAG_DEV = /dev/com1

# Debugging port used to communicate between GDB / avarice / simulavr.
DEBUG_PORT = 4242

# Debugging host used to communicate between GDB / avarice / simulavr, normally
#     just set to localhost unless doing some sort of crazy debugging when
#     avarice is running on a different computer.
DEBUG_HOST = localhost



#============================================================================


# Define programs and commands.
SHELL = sh
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
AR = avr-ar rcs
NM = avr-nm
AVRDUDE = avrdude
REMOVE = rm -f
REMOVEDIR = rm -rf
COPY = cp
WINSHELL = cmd


# Define Messages
# English
MSG_ERRORS_NONE = Errors: none
MSG_BEGIN = -------- begin --------
MSG_END = --------  end  --------
MSG_SIZE_BEFORE = Size before:
MSG_SIZE_AFTER = Size after:
MSG_COFF = Converting to AVR COFF:
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
MSG_FLASH = Creating load file for Flash:
MSG_EEPROM = Creating load file for EEPROM:
MSG_EXTENDED_LISTING = Creating Extended Listing:
MSG_SYMBOL_TABLE = Creating Symbol Table:
MSG_LINKING = Linking:
MSG_COMPILING = Compiling C:
MSG_COMPILING_CPP = Compiling C++:
MSG_ASSEMBLING = Assembling:
MSG_CLEANING = Cleaning project:
MSG_CREATING_LIBRARY = Creating library:




# Define all object files.
OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)

# Define all listing files.
LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)


# Compiler flags to generate dependency files.
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d


# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)





# Default target.
all: begin gccversion sizebefore build sizeafter end

# Change the build target to build a HEX file or a library.
build: elf hex eep lss sym
#build: lib


elf: $(TARGET).elf
hex: $(TARGET).hex
eep: $(TARGET).eep
lss: $(TARGET).lss
sym: $(TARGET).sym
LIBNAME=lib$(TARGET).a
lib: $(LIBNAME)



# Eye candy.
# AVR Studio 3.x does not check make's exit code but relies on
# the following magic strings to be generated by the compile job.
begin:
    @echo
    @echo $(MSG_BEGIN)

end:
    @echo $(MSG_END)
    @echo


# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf

sizebefore:
    @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
    2>/dev/null; echo; fi

sizeafter:
    @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
    2>/dev/null; echo; fi



# Display compiler version information.
gccversion :
    @$(CC) --version



# Program the device. 
program: $(TARGET).hex $(TARGET).eep
    $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)


# Generate avr-gdb config/init file which does the following:
#     define the reset signal, load the target file, connect to target, and set
#     a breakpoint at main().
gdb-config:
    @$(REMOVE) $(GDBINIT_FILE)
    @echo define reset >> $(GDBINIT_FILE)
    @echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
    @echo end >> $(GDBINIT_FILE)
    @echo file $(TARGET).elf >> $(GDBINIT_FILE)
    @echo target remote $(DEBUG_HOST):$(DEBUG_PORT)  >> $(GDBINIT_FILE)
ifeq ($(DEBUG_BACKEND),simulavr)
    @echo load  >> $(GDBINIT_FILE)
endif
    @echo break main >> $(GDBINIT_FILE)

debug: gdb-config $(TARGET).elf
ifeq ($(DEBUG_BACKEND), avarice)
    @echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
    @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
    $(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
    @$(WINSHELL) /c pause

else
    @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
    $(DEBUG_MFREQ) --port $(DEBUG_PORT)
endif
    @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)




# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT = $(OBJCOPY) --debugging
COFFCONVERT += --change-section-address .data-0x800000
COFFCONVERT += --change-section-address .bss-0x800000
COFFCONVERT += --change-section-address .noinit-0x800000
COFFCONVERT += --change-section-address .eeprom-0x810000



coff: $(TARGET).elf
    @echo
    @echo $(MSG_COFF) $(TARGET).cof
    $(COFFCONVERT) -O coff-avr $< $(TARGET).cof


extcoff: $(TARGET).elf
    @echo
    @echo $(MSG_EXTENDED_COFF) $(TARGET).cof
    $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof



# Create final output files (.hex, .eep) from ELF output file.
%.hex: %.elf
    @echo
    @echo $(MSG_FLASH) $@
    $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock $< $@

%.eep: %.elf
    @echo
    @echo $(MSG_EEPROM) $@
    -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
    --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0

# Create extended listing file from ELF output file.
%.lss: %.elf
    @echo
    @echo $(MSG_EXTENDED_LISTING) $@
    $(OBJDUMP) -h -S -z $< > $@

# Create a symbol table from ELF output file.
%.sym: %.elf
    @echo
    @echo $(MSG_SYMBOL_TABLE) $@
    $(NM) -n $< > $@



# Create library from object files.
.SECONDARY : $(TARGET).a
.PRECIOUS : $(OBJ)
%.a: $(OBJ)
    @echo
    @echo $(MSG_CREATING_LIBRARY) $@
    $(AR) $@ $(OBJ)


# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
%.elf: $(OBJ)
    @echo
    @echo $(MSG_LINKING) $@
    $(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)


# Compile: create object files from C source files.
$(OBJDIR)/%.o : %.c
    @echo
    @echo $(MSG_COMPILING) $<
    $(CC) -c $(ALL_CFLAGS) $< -o $@


# Compile: create object files from C++ source files.
$(OBJDIR)/%.o : %.cpp
    @echo
    @echo $(MSG_COMPILING_CPP) $<
    $(CC) -c $(ALL_CPPFLAGS) $< -o $@


# Compile: create assembler files from C source files.
%.s : %.c
    $(CC) -S $(ALL_CFLAGS) $< -o $@


# Compile: create assembler files from C++ source files.
%.s : %.cpp
    $(CC) -S $(ALL_CPPFLAGS) $< -o $@


# Assemble: create object files from assembler source files.
$(OBJDIR)/%.o : %.S
    @echo
    @echo $(MSG_ASSEMBLING) $<
    $(CC) -c $(ALL_ASFLAGS) $< -o $@


# Create preprocessed source for use in sending a bug report.
%.i : %.c
    $(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@


# Target: clean project.
clean: begin clean_list end

clean_list :
    @echo
    @echo $(MSG_CLEANING)
    $(REMOVE) $(TARGET).hex
    $(REMOVE) $(TARGET).eep
    $(REMOVE) $(TARGET).cof
    $(REMOVE) $(TARGET).elf
    $(REMOVE) $(TARGET).map
    $(REMOVE) $(TARGET).sym
    $(REMOVE) $(TARGET).lss
    $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o)
    $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst)
    $(REMOVE) $(SRC:.c=.s)
    $(REMOVE) $(SRC:.c=.d)
    $(REMOVE) $(SRC:.c=.i)
    $(REMOVEDIR) .dep


# Create object files directory
$(shell mkdir $(OBJDIR) 2>/dev/null)


# Include the dependency files.
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)


# Listing of phony targets.
.PHONY : all begin finish end sizebefore sizeafter gccversion \
build elf hex eep lss sym coff extcoff \
clean clean_list program debug gdb-config