Added skel and stepper
This commit is contained in:
parent
0c1bda9e7e
commit
2673d7fd8b
|
|
@ -0,0 +1,76 @@
|
|||
##############################################################################
|
||||
# #
|
||||
# AVR-GCC skeleton #
|
||||
# #
|
||||
# by Triffid Hunter #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# Change these to suit your application #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
PROGRAM = yourprogramnamehere
|
||||
|
||||
SOURCES = $(PROGRAM).c ringbuffer.c serial.c lcd.c
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# Change these to suit your hardware #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
MCU_TARGET = atmega168
|
||||
F_CPU = 16000000L
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# These defaults should be ok, change if you need to #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
ARCH = avr-
|
||||
OPTIMIZE = -Os
|
||||
CFLAGS = -g -Wall -Wstrict-prototypes $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(F_CPU) $(DEFS) -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -ffunction-sections -save-temps
|
||||
LDFLAGS = -Wl,-u,vfprintf -lprintf_min -Wl,--as-needed -Wl,--gc-sections -finline-functions-called-once
|
||||
|
||||
CC = $(ARCH)gcc
|
||||
OBJDUMP = $(ARCH)objdump
|
||||
OBJCOPY = $(ARCH)objcopy
|
||||
AVRDUDE = avrdude -F
|
||||
|
||||
PROGPORT = /dev/arduino
|
||||
PROGBAUD = 19200
|
||||
|
||||
OBJ = $(patsubst %.c,%.o,${SOURCES})
|
||||
|
||||
.PHONY: all program clean
|
||||
.PRECIOUS: %.o %.elf
|
||||
|
||||
all: $(PROGRAM).hex $(PROGRAM).lst
|
||||
|
||||
program: $(PROGRAM).hex
|
||||
stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT)
|
||||
@stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT)
|
||||
$(AVRDUDE) -cstk500v1 -b$(PROGBAUD) -p$(MCU_TARGET) -P$(PROGPORT) -C/etc/avrdude.conf -U flash:w:$^
|
||||
stty -hup -echo < $(PROGPORT)
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.al
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) -Wa,-adhlns=$(<:.c=.al) -o $@ $^
|
||||
|
||||
%.elf: $(OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
%.lst: %.elf
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
%.hex: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -O ihex $< $@
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -O binary $< $@
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
#ifndef _ARDUINO_H
|
||||
#define _ARDUINO_H
|
||||
|
||||
#define PIN_DIO0 PD0
|
||||
#define RPORT_DIO0 PIND
|
||||
#define WPORT_DIO0 PORTD
|
||||
#define DDR_DIO0 DDRD
|
||||
|
||||
#define PIN_DIO1 PD1
|
||||
#define RPORT_DIO1 PIND
|
||||
#define WPORT_DIO1 PORTD
|
||||
#define DDR_DIO1 DDRD
|
||||
|
||||
#define PIN_DIO2 PD2
|
||||
#define RPORT_DIO2 PIND
|
||||
#define WPORT_DIO2 PORTD
|
||||
#define DDR_DIO2 DDRD
|
||||
|
||||
#define PIN_DIO3 PD3
|
||||
#define RPORT_DIO3 PIND
|
||||
#define WPORT_DIO3 PORTD
|
||||
#define DDR_DIO3 DDRD
|
||||
|
||||
#define PIN_DIO4 PD4
|
||||
#define RPORT_DIO4 PIND
|
||||
#define WPORT_DIO4 PORTD
|
||||
#define DDR_DIO4 DDRD
|
||||
|
||||
#define PIN_DIO5 PD5
|
||||
#define RPORT_DIO5 PIND
|
||||
#define WPORT_DIO5 PORTD
|
||||
#define DDR_DIO5 DDRD
|
||||
|
||||
#define PIN_DIO6 PD6
|
||||
#define RPORT_DIO6 PIND
|
||||
#define WPORT_DIO6 PORTD
|
||||
#define DDR_DIO6 DDRD
|
||||
|
||||
#define PIN_DIO7 PD7
|
||||
#define RPORT_DIO7 PIND
|
||||
#define WPORT_DIO7 PORTD
|
||||
#define DDR_DIO7 DDRD
|
||||
|
||||
#define PIN_DIO8 PB0
|
||||
#define RPORT_DIO8 PINB
|
||||
#define WPORT_DIO8 PORTB
|
||||
#define DDR_DIO8 DDRB
|
||||
|
||||
#define PIN_DIO9 PB1
|
||||
#define RPORT_DIO9 PINB
|
||||
#define WPORT_DIO9 PORTB
|
||||
#define DDR_DIO9 DDRB
|
||||
|
||||
#define PIN_DIO10 PB2
|
||||
#define RPORT_DIO10 PINB
|
||||
#define WPORT_DIO10 PORTB
|
||||
#define DDR_DIO10 DDRB
|
||||
|
||||
#define PIN_DIO11 PB3
|
||||
#define RPORT_DIO11 PINB
|
||||
#define WPORT_DIO11 PORTB
|
||||
#define DDR_DIO11 DDRB
|
||||
|
||||
#define PIN_DIO12 PB4
|
||||
#define RPORT_DIO12 PINB
|
||||
#define WPORT_DIO12 PORTB
|
||||
#define DDR_DIO12 DDRB
|
||||
|
||||
#define PIN_DIO13 PB5
|
||||
#define RPORT_DIO13 PINB
|
||||
#define WPORT_DIO13 PORTB
|
||||
#define DDR_DIO13 DDRB
|
||||
|
||||
#define PIN_AIO0 PC0
|
||||
#define RPORT_AIO0 PINC
|
||||
#define WPORT_AIO0 PORTC
|
||||
#define DDR_AIO0 DDRC
|
||||
|
||||
#define PIN_AIO1 PC1
|
||||
#define RPORT_AIO1 PINC
|
||||
#define WPORT_AIO1 PORTC
|
||||
#define DDR_AIO1 DDRC
|
||||
|
||||
#define PIN_AIO2 PC2
|
||||
#define RPORT_AIO2 PINC
|
||||
#define WPORT_AIO2 PORTC
|
||||
#define DDR_AIO2 DDRC
|
||||
|
||||
#define PIN_AIO3 PC3
|
||||
#define RPORT_AIO3 PINC
|
||||
#define WPORT_AIO3 PORTC
|
||||
#define DDR_AIO3 DDRC
|
||||
|
||||
#define PIN_AIO4 PC4
|
||||
#define RPORT_AIO4 PINC
|
||||
#define WPORT_AIO4 PORTC
|
||||
#define DDR_AIO4 DDRC
|
||||
|
||||
#define PIN_AIO5 PC5
|
||||
#define RPORT_AIO5 PINC
|
||||
#define WPORT_AIO5 PORTC
|
||||
#define DDR_AIO5 DDRC
|
||||
|
||||
#endif /* _ARDUINO_H */
|
||||
|
|
@ -0,0 +1,595 @@
|
|||
/****************************************************************************
|
||||
Title : HD44780U LCD library
|
||||
Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
|
||||
File: $Id: lcd.c,v 1.14.2.1 2006/01/29 12:16:41 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 "lcd.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
|
||||
|
||||
|
||||
#if LCD_IO_MODE
|
||||
#define lcd_e_delay() __asm__ __volatile__( "rjmp 1f\n 1:" );
|
||||
#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)
|
||||
#endif
|
||||
|
||||
#if LCD_IO_MODE
|
||||
#if LCD_LINES==1
|
||||
#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE
|
||||
#else
|
||||
#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES
|
||||
#endif
|
||||
#else
|
||||
#if LCD_LINES==1
|
||||
#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_1LINE
|
||||
#else
|
||||
#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_2LINES
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if LCD_CONTROLLER_KS0073
|
||||
#if LCD_LINES==4
|
||||
#define KS0073_EXTENDED_FUNCTION_REGISTER_ON 0x24 /* |0|010|0100 4-bit mode extension-bit RE = 1 */
|
||||
#define KS0073_EXTENDED_FUNCTION_REGISTER_OFF 0x20 /* |0|000|1001 4 lines mode */
|
||||
#define KS0073_4LINES_MODE 0x09 /* |0|001|0000 4-bit mode, extension-bit RE = 0 */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** function prototypes
|
||||
*/
|
||||
#if LCD_IO_MODE
|
||||
static void toggle_e(void);
|
||||
#endif
|
||||
|
||||
/*
|
||||
** local functions
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
delay loop for small accurate delays: 16-bit counter, 4 cycles/loop
|
||||
*************************************************************************/
|
||||
static inline void _delayFourCycles(unsigned int __count)
|
||||
{
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
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 )
|
||||
|
||||
|
||||
#if LCD_IO_MODE
|
||||
/* toggle Enable Pin to initiate write */
|
||||
static void toggle_e(void)
|
||||
{
|
||||
lcd_e_high();
|
||||
lcd_e_delay();
|
||||
lcd_e_low();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
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
|
||||
*************************************************************************/
|
||||
#if LCD_IO_MODE
|
||||
static void lcd_write(uint8_t data,uint8_t rs)
|
||||
{
|
||||
if (rs) { /* write data (RS=1, RW=0) */
|
||||
lcd_rs_high();
|
||||
} else { /* write instruction (RS=0, RW=0) */
|
||||
lcd_rs_low();
|
||||
}
|
||||
lcd_rw_low();
|
||||
|
||||
if (
|
||||
(&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT)
|
||||
&& (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3)
|
||||
)
|
||||
{
|
||||
/* configure data pins as output */
|
||||
DDR(LCD_DATA0_PORT) |= 0x0F;
|
||||
|
||||
/* output high nibble first */
|
||||
LCD_DATA0_PORT = (LCD_DATA0_PORT & 0xF0) | ((data >> 4) & 0x0F);
|
||||
lcd_e_toggle();
|
||||
|
||||
/* output low nibble */
|
||||
LCD_DATA0_PORT = (LCD_DATA0_PORT & 0xF0) | (data & 0x0F);
|
||||
lcd_e_toggle();
|
||||
|
||||
/* all data pins high (inactive) */
|
||||
LCD_DATA0_PORT = (LCD_DATA0_PORT & 0xF0) | 0x0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure data pins as output */
|
||||
DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN);
|
||||
DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN);
|
||||
DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN);
|
||||
DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN);
|
||||
|
||||
/* output high nibble first */
|
||||
LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);
|
||||
LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);
|
||||
LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);
|
||||
LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);
|
||||
if(data & 0x80) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
|
||||
if(data & 0x40) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
|
||||
if(data & 0x20) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
|
||||
if(data & 0x10) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
|
||||
lcd_e_toggle();
|
||||
|
||||
/* output low nibble */
|
||||
LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);
|
||||
LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);
|
||||
LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);
|
||||
LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);
|
||||
if(data & 0x08) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
|
||||
if(data & 0x04) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
|
||||
if(data & 0x02) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
|
||||
if(data & 0x01) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
|
||||
lcd_e_toggle();
|
||||
|
||||
/* all data pins high (inactive) */
|
||||
LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
|
||||
LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
|
||||
LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
|
||||
LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define lcd_write(d,rs) if (rs) *(volatile uint8_t*)(LCD_IO_DATA) = d; else *(volatile uint8_t*)(LCD_IO_FUNCTION) = d;
|
||||
/* rs==0 -> write instruction to LCD_IO_FUNCTION */
|
||||
/* rs==1 -> write data to LCD_IO_DATA */
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
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
|
||||
*************************************************************************/
|
||||
#if LCD_IO_MODE
|
||||
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(); /* RW=1 read mode */
|
||||
|
||||
if (
|
||||
(&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT)
|
||||
&& (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3)
|
||||
)
|
||||
{
|
||||
DDR(LCD_DATA0_PORT) &= 0xF0; /* configure data pins as input */
|
||||
|
||||
lcd_e_high();
|
||||
lcd_e_delay();
|
||||
data = PIN(LCD_DATA0_PORT) << 4; /* read high nibble first */
|
||||
lcd_e_low();
|
||||
|
||||
lcd_e_delay(); /* Enable 500ns low */
|
||||
|
||||
lcd_e_high();
|
||||
lcd_e_delay();
|
||||
data |= PIN(LCD_DATA0_PORT) & 0x0F; /* read low nibble */
|
||||
lcd_e_low();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure data pins as input */
|
||||
DDR(LCD_DATA0_PORT) &= ~_BV(LCD_DATA0_PIN);
|
||||
DDR(LCD_DATA1_PORT) &= ~_BV(LCD_DATA1_PIN);
|
||||
DDR(LCD_DATA2_PORT) &= ~_BV(LCD_DATA2_PIN);
|
||||
DDR(LCD_DATA3_PORT) &= ~_BV(LCD_DATA3_PIN);
|
||||
|
||||
/* read high nibble first */
|
||||
lcd_e_high();
|
||||
lcd_e_delay();
|
||||
data = 0;
|
||||
if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x10;
|
||||
if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x20;
|
||||
if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x40;
|
||||
if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x80;
|
||||
lcd_e_low();
|
||||
|
||||
lcd_e_delay(); /* Enable 500ns low */
|
||||
|
||||
/* read low nibble */
|
||||
lcd_e_high();
|
||||
lcd_e_delay();
|
||||
if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x01;
|
||||
if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x02;
|
||||
if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x04;
|
||||
if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x08;
|
||||
lcd_e_low();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
#else
|
||||
#define lcd_read(rs) (rs) ? *(volatile uint8_t*)(LCD_IO_DATA+LCD_IO_READ) : *(volatile uint8_t*)(LCD_IO_FUNCTION+LCD_IO_READ)
|
||||
/* rs==0 -> read instruction from LCD_IO_FUNCTION */
|
||||
/* rs==1 -> read data from LCD_IO_DATA */
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
loops while lcd is busy, returns address counter
|
||||
*************************************************************************/
|
||||
static uint8_t lcd_waitbusy(void)
|
||||
{
|
||||
/* wait until busy flag is cleared */
|
||||
for (; lcd_read(0) & (1 << LCD_BUSY); );
|
||||
|
||||
/* 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 KS0073_4LINES_MODE
|
||||
if ( pos < LCD_START_LINE2 )
|
||||
addressCounter = LCD_START_LINE2;
|
||||
else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE3) )
|
||||
addressCounter = LCD_START_LINE3;
|
||||
else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE4) )
|
||||
addressCounter = LCD_START_LINE4;
|
||||
else
|
||||
addressCounter = LCD_START_LINE1;
|
||||
#else
|
||||
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
|
||||
#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(const 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
|
||||
*************************************************************************/
|
||||
void lcd_init(uint8_t dispAttr)
|
||||
{
|
||||
#if LCD_IO_MODE
|
||||
/*
|
||||
* Initialize LCD to 4 bit I/O mode
|
||||
*/
|
||||
|
||||
if (
|
||||
( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )
|
||||
&& ( &LCD_RS_PORT == &LCD_DATA0_PORT) && ( &LCD_RW_PORT == &LCD_DATA0_PORT) && (&LCD_E_PORT == &LCD_DATA0_PORT)
|
||||
)
|
||||
{
|
||||
/* configure all port bits as output (all LCD lines on same port) */
|
||||
DDR(LCD_DATA0_PORT) |= (1 << LCD_DATA0_PIN) | (1 << LCD_DATA1_PIN) | (1 << LCD_DATA2_PIN) | (1 << LCD_DATA3_PIN) | (1 << LCD_RS_PIN) | (1 << LCD_RW_PIN) | (1 << LCD_E_PIN);
|
||||
}
|
||||
else if (
|
||||
( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )
|
||||
)
|
||||
{
|
||||
/* configure all port bits as output (all LCD data lines on same port, but control lines on different ports) */
|
||||
DDR(LCD_DATA0_PORT) |= (1 << LCD_DATA0_PIN) | (1 << LCD_DATA1_PIN) | (1 << LCD_DATA2_PIN) | (1 << LCD_DATA3_PIN);
|
||||
DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);
|
||||
DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);
|
||||
DDR(LCD_E_PORT) |= _BV(LCD_E_PIN);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure all port bits as output (LCD data and control lines on different ports */
|
||||
DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);
|
||||
DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);
|
||||
DDR(LCD_E_PORT) |= _BV(LCD_E_PIN);
|
||||
DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN);
|
||||
DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN);
|
||||
DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN);
|
||||
DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN);
|
||||
}
|
||||
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_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_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); // 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() */
|
||||
#else
|
||||
/*
|
||||
* Initialize LCD to 8 bit memory mapped mode
|
||||
*/
|
||||
|
||||
/* enable external SRAM (memory mapped lcd) and one wait state */
|
||||
MCUCR = _BV(SRE) | _BV(SRW);
|
||||
|
||||
/* reset LCD */
|
||||
delay(16000); /* wait 16ms after power-on */
|
||||
lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
|
||||
delay(4992); /* wait 5ms */
|
||||
lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
|
||||
delay(64); /* wait 64us */
|
||||
lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
|
||||
delay(64); /* wait 64us */
|
||||
#endif
|
||||
|
||||
#if KS0073_4LINES_MODE
|
||||
/* Display with KS0073 controller requires special commands for enabling 4 line mode */
|
||||
lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_ON);
|
||||
lcd_command(KS0073_4LINES_MODE);
|
||||
lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_OFF);
|
||||
#else
|
||||
lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */
|
||||
#endif
|
||||
|
||||
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 */
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
#ifndef LCD_H
|
||||
#define LCD_H
|
||||
/*************************************************************************
|
||||
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.13.2.2 2006/01/30 19:51:33 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 Definition for LCD controller type
|
||||
* Use 0 for HD44780 controller, change to 1 for displays with KS0073 controller.
|
||||
*/
|
||||
#define LCD_CONTROLLER_KS0073 0 /**< Use 0 for HD44780 controller, 1 for KS0073 controller */
|
||||
|
||||
/**
|
||||
* @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 */
|
||||
|
||||
#define LCD_IO_MODE 1 /**< 0: memory mapped mode, 1: IO port mode */
|
||||
|
||||
#if LCD_IO_MODE
|
||||
/**
|
||||
* @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_PORT PORTB /**< port for the LCD lines */
|
||||
#define LCD_DATA0_PORT LCD_PORT /**< port for 4bit data bit 0 */
|
||||
#define LCD_DATA1_PORT LCD_PORT /**< port for 4bit data bit 1 */
|
||||
#define LCD_DATA2_PORT LCD_PORT /**< port for 4bit data bit 2 */
|
||||
#define LCD_DATA3_PORT LCD_PORT /**< port for 4bit data bit 3 */
|
||||
#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 PORTD /**< port for RS line */
|
||||
#define LCD_RS_PIN 2 /**< pin for RS line */
|
||||
#define LCD_RW_PORT PORTD /**< port for RW line */
|
||||
#define LCD_RW_PIN 3 /**< pin for RW line */
|
||||
#define LCD_E_PORT PORTD /**< 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
|
||||
*/
|
||||
void lcd_init(uint8_t dispAttr);
|
||||
|
||||
|
||||
/**
|
||||
@brief Clear display and set cursor to home position
|
||||
@param void
|
||||
@return none
|
||||
*/
|
||||
void lcd_clrscr(void);
|
||||
|
||||
|
||||
/**
|
||||
@brief Set cursor to home position
|
||||
@param void
|
||||
@return none
|
||||
*/
|
||||
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
|
||||
*/
|
||||
void lcd_gotoxy(uint8_t x, uint8_t y);
|
||||
|
||||
|
||||
/**
|
||||
@brief Display character at current cursor position
|
||||
@param c character to be displayed
|
||||
@return none
|
||||
*/
|
||||
void lcd_putc(char c);
|
||||
|
||||
|
||||
/**
|
||||
@brief Display string without auto linefeed
|
||||
@param s string to be displayed
|
||||
@return none
|
||||
*/
|
||||
void lcd_puts(const 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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))
|
||||
|
||||
/*@}*/
|
||||
#endif //LCD_H
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
#include "ringbuffer.h"
|
||||
|
||||
uint16_t _rb_mod(uint16_t num, uint16_t denom)
|
||||
{
|
||||
for (; num >= denom; num -= denom);
|
||||
return num;
|
||||
}
|
||||
|
||||
void ringbuffer_init(ringbuffer *buf, int bufsize)
|
||||
{
|
||||
buf->read_pointer = 0;
|
||||
buf->write_pointer = 0;
|
||||
buf->size = bufsize - sizeof(ringbuffer);
|
||||
}
|
||||
|
||||
uint16_t ringbuffer_canread(ringbuffer *buf)
|
||||
{
|
||||
return _rb_mod(buf->write_pointer + buf->size + buf->size - buf->read_pointer, buf->size);
|
||||
}
|
||||
|
||||
uint16_t ringbuffer_canwrite(ringbuffer *buf)
|
||||
{
|
||||
return _rb_mod(buf->read_pointer + buf->size + buf->size - buf->write_pointer - 1, buf->size);
|
||||
}
|
||||
|
||||
uint8_t ringbuffer_readchar(ringbuffer *buf)
|
||||
{
|
||||
uint8_t r = 0;
|
||||
if (ringbuffer_canread(buf))
|
||||
{
|
||||
r = buf->data[buf->read_pointer];
|
||||
buf->read_pointer = _rb_mod(buf->read_pointer + 1, buf->size);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void ringbuffer_writechar(ringbuffer *buf, uint8_t data)
|
||||
{
|
||||
if (ringbuffer_canwrite(buf))
|
||||
{
|
||||
buf->data[buf->write_pointer] = data;
|
||||
buf->write_pointer = _rb_mod(buf->write_pointer + 1, buf->size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t ringbuffer_peekchar(ringbuffer *buf, uint16_t index)
|
||||
{
|
||||
return buf->data[_rb_mod(buf->read_pointer + index, buf->size)];
|
||||
}
|
||||
|
||||
uint16_t ringbuffer_readblock(ringbuffer *buf, uint8_t *newbuf, int size)
|
||||
{
|
||||
uint16_t nc, i;
|
||||
uint8_t *rp, *ms;
|
||||
if ((nc = ringbuffer_canread(buf)) < size)
|
||||
size = nc;
|
||||
if (size)
|
||||
{
|
||||
for (i = 0, rp = buf->data + buf->read_pointer, ms = buf->data + buf->size; i < size; i++, rp++)
|
||||
{
|
||||
if (rp >= ms)
|
||||
rp = buf->data;
|
||||
newbuf[i] = *rp;
|
||||
}
|
||||
buf->read_pointer = rp - buf->data;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
uint16_t ringbuffer_writeblock(ringbuffer *buf, uint8_t *data, int size)
|
||||
{
|
||||
uint16_t nc, i;
|
||||
uint8_t *wp, *ms;
|
||||
|
||||
if ((nc = ringbuffer_canwrite(buf)) < size)
|
||||
size = nc;
|
||||
if (size)
|
||||
{
|
||||
for (i = 0, wp = buf->write_pointer + buf->data, ms = buf->data + buf->size; i < size; i++, wp++)
|
||||
{
|
||||
if (wp >= ms)
|
||||
wp = buf->data;
|
||||
*wp = data[i];
|
||||
}
|
||||
buf->write_pointer = wp - buf->data;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef _RINGBUFFER_H
|
||||
#define _RINGBUFFER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t read_pointer;
|
||||
uint16_t write_pointer;
|
||||
uint16_t size;
|
||||
uint8_t data[];
|
||||
} ringbuffer;
|
||||
|
||||
void ringbuffer_init(ringbuffer *buf, int bufsize);
|
||||
|
||||
uint16_t ringbuffer_canread(ringbuffer *buf);
|
||||
uint16_t ringbuffer_canwrite(ringbuffer *buf);
|
||||
|
||||
uint8_t ringbuffer_readchar(ringbuffer *buf);
|
||||
uint8_t ringbuffer_peekchar(ringbuffer *buf, uint16_t index);
|
||||
uint16_t ringbuffer_readblock(ringbuffer *buf, uint8_t *newbuf, int size);
|
||||
|
||||
void ringbuffer_writechar(ringbuffer *buf, uint8_t data);
|
||||
uint16_t ringbuffer_writeblock(ringbuffer *buf, uint8_t *data, int size);
|
||||
|
||||
#endif /* _RINGBUFFER_H */
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
#include "serial.h"
|
||||
|
||||
#include "ringbuffer.h"
|
||||
|
||||
#define BUFSIZE 64 + sizeof(ringbuffer)
|
||||
#define BAUD 19200
|
||||
|
||||
volatile uint8_t _rx_buffer[BUFSIZE];
|
||||
volatile uint8_t _tx_buffer[BUFSIZE];
|
||||
|
||||
void serial_init(uint16_t baud)
|
||||
{
|
||||
ringbuffer_init(rx_buffer, BUFSIZE);
|
||||
ringbuffer_init(tx_buffer, BUFSIZE);
|
||||
|
||||
UCSR0A = 0;
|
||||
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
|
||||
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
|
||||
|
||||
UBRR0 = ((F_CPU / 16) / baud) - 1;
|
||||
|
||||
UCSR0B |= (1 << RXCIE0) | (1 << UDRIE0);
|
||||
}
|
||||
|
||||
ISR(USART_RX_vect)
|
||||
{
|
||||
ringbuffer_writechar(rx_buffer, UDR0);
|
||||
}
|
||||
|
||||
ISR(USART_UDRE_vect)
|
||||
{
|
||||
if (ringbuffer_canread(tx_buffer))
|
||||
{
|
||||
UDR0 = ringbuffer_readchar(tx_buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
UCSR0B &= ~(1 << UDRIE0);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t serial_rxchars()
|
||||
{
|
||||
return ringbuffer_canread(rx_buffer);
|
||||
}
|
||||
|
||||
uint16_t serial_txchars()
|
||||
{
|
||||
return ringbuffer_canread(tx_buffer);
|
||||
}
|
||||
|
||||
uint8_t serial_popchar()
|
||||
{
|
||||
return ringbuffer_readchar(rx_buffer);
|
||||
}
|
||||
|
||||
uint16_t serial_recvblock(uint8_t *block, int blocksize)
|
||||
{
|
||||
return ringbuffer_readblock(rx_buffer, block, blocksize);
|
||||
}
|
||||
|
||||
void serial_writechar(uint8_t data)
|
||||
{
|
||||
ringbuffer_writechar(tx_buffer, data);
|
||||
UCSR0B |= (1 << UDRIE0);
|
||||
}
|
||||
|
||||
void serial_writeblock(uint8_t *data, int datalen)
|
||||
{
|
||||
ringbuffer_writeblock(tx_buffer, data, datalen);
|
||||
UCSR0B |= (1 << UDRIE0);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef _SERIAL_H
|
||||
#define _SERIAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <avr/io.h>
|
||||
|
||||
#define rx_buffer ((ringbuffer *) _rx_buffer)
|
||||
#define tx_buffer ((ringbuffer *) _tx_buffer)
|
||||
|
||||
extern volatile uint8_t _rx_buffer[];
|
||||
extern volatile uint8_t _tx_buffer[];
|
||||
|
||||
void serial_init(uint16_t baud);
|
||||
|
||||
uint16_t serial_rxchars(void);
|
||||
uint16_t serial_txchars(void);
|
||||
|
||||
uint8_t serial_popchar(void);
|
||||
void serial_writechar(uint8_t data);
|
||||
|
||||
uint16_t serial_recvblock(uint8_t *block, int blocksize);
|
||||
void serial_writeblock(uint8_t *data, int datalen);
|
||||
|
||||
#endif /* _SERIAL_H */
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "serial.h"
|
||||
#include "lcd.h"
|
||||
|
||||
// write to lcd function for fdev_setup_stream
|
||||
static int lcd_putc_fdev(char c, FILE *stream)
|
||||
{
|
||||
lcd_putc(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serial_putc_fdev(char c, FILE *stream)
|
||||
{
|
||||
serial_writechar((uint8_t) c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serial_getc_fdev(FILE *stream)
|
||||
{
|
||||
for (;serial_rxchars() == 0;);
|
||||
return (int) serial_popchar();
|
||||
}
|
||||
|
||||
static FILE lcdo = FDEV_SETUP_STREAM(lcd_putc_fdev, NULL, _FDEV_SETUP_WRITE);
|
||||
static FILE serio = FDEV_SETUP_STREAM(serial_putc_fdev, serial_getc_fdev, _FDEV_SETUP_RW);
|
||||
|
||||
int main (void)
|
||||
{
|
||||
// set up LCD
|
||||
lcd_init(LCD_DISP_ON_CURSOR);
|
||||
|
||||
lcd_puts_P("Starting...");
|
||||
|
||||
// set up STDIN/OUT/ERR
|
||||
stdin = &serio;
|
||||
stdout = &lcdo;
|
||||
stderr = &lcdo;
|
||||
|
||||
// set up serial
|
||||
serial_init(19200);
|
||||
|
||||
sei();
|
||||
|
||||
lcd_gotoxy(0, 0);
|
||||
fprintf(&lcdo, "MyProject OK");
|
||||
|
||||
for (;;)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
##############################################################################
|
||||
# #
|
||||
# AVR-GCC skeleton #
|
||||
# #
|
||||
# by Triffid Hunter #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# Change these to suit your application #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
PROGRAM = stepper
|
||||
|
||||
SOURCES = $(PROGRAM).c ringbuffer.c serial.c lcd.c
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# Change these to suit your hardware #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
MCU_TARGET = atmega168
|
||||
F_CPU = 16000000L
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# These defaults should be ok, change if you need to #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
ARCH = avr-
|
||||
OPTIMIZE = -Os
|
||||
CFLAGS = -g -Wall -Wstrict-prototypes $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(F_CPU) $(DEFS) -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -ffunction-sections -save-temps
|
||||
LDFLAGS = -Wl,-u,vfprintf -lprintf_min -Wl,--as-needed -Wl,--gc-sections -finline-functions-called-once
|
||||
|
||||
CC = $(ARCH)gcc
|
||||
OBJDUMP = $(ARCH)objdump
|
||||
OBJCOPY = $(ARCH)objcopy
|
||||
AVRDUDE = avrdude -F
|
||||
|
||||
PROGPORT = /dev/arduino
|
||||
PROGBAUD = 19200
|
||||
|
||||
OBJ = $(patsubst %.c,%.o,${SOURCES})
|
||||
|
||||
.PHONY: all program clean
|
||||
.PRECIOUS: %.o %.elf
|
||||
|
||||
all: $(PROGRAM).hex $(PROGRAM).lst
|
||||
|
||||
program: $(PROGRAM).hex
|
||||
stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT)
|
||||
@stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT)
|
||||
$(AVRDUDE) -cstk500v1 -b$(PROGBAUD) -p$(MCU_TARGET) -P$(PROGPORT) -C/etc/avrdude.conf -U flash:w:$^
|
||||
stty -hup -echo < $(PROGPORT)
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.al
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) -Wa,-adhlns=$(<:.c=.al) -o $@ $^
|
||||
|
||||
%.elf: $(OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
%.lst: %.elf
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
%.hex: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -O ihex $< $@
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -O binary $< $@
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
#ifndef _ARDUINO_H
|
||||
#define _ARDUINO_H
|
||||
|
||||
#define PIN_DIO0 PD0
|
||||
#define RPORT_DIO0 PIND
|
||||
#define WPORT_DIO0 PORTD
|
||||
#define DDR_DIO0 DDRD
|
||||
|
||||
#define PIN_DIO1 PD1
|
||||
#define RPORT_DIO1 PIND
|
||||
#define WPORT_DIO1 PORTD
|
||||
#define DDR_DIO1 DDRD
|
||||
|
||||
#define PIN_DIO2 PD2
|
||||
#define RPORT_DIO2 PIND
|
||||
#define WPORT_DIO2 PORTD
|
||||
#define DDR_DIO2 DDRD
|
||||
|
||||
#define PIN_DIO3 PD3
|
||||
#define RPORT_DIO3 PIND
|
||||
#define WPORT_DIO3 PORTD
|
||||
#define DDR_DIO3 DDRD
|
||||
|
||||
#define PIN_DIO4 PD4
|
||||
#define RPORT_DIO4 PIND
|
||||
#define WPORT_DIO4 PORTD
|
||||
#define DDR_DIO4 DDRD
|
||||
|
||||
#define PIN_DIO5 PD5
|
||||
#define RPORT_DIO5 PIND
|
||||
#define WPORT_DIO5 PORTD
|
||||
#define DDR_DIO5 DDRD
|
||||
|
||||
#define PIN_DIO6 PD6
|
||||
#define RPORT_DIO6 PIND
|
||||
#define WPORT_DIO6 PORTD
|
||||
#define DDR_DIO6 DDRD
|
||||
|
||||
#define PIN_DIO7 PD7
|
||||
#define RPORT_DIO7 PIND
|
||||
#define WPORT_DIO7 PORTD
|
||||
#define DDR_DIO7 DDRD
|
||||
|
||||
#define PIN_DIO8 PB0
|
||||
#define RPORT_DIO8 PINB
|
||||
#define WPORT_DIO8 PORTB
|
||||
#define DDR_DIO8 DDRB
|
||||
|
||||
#define PIN_DIO9 PB1
|
||||
#define RPORT_DIO9 PINB
|
||||
#define WPORT_DIO9 PORTB
|
||||
#define DDR_DIO9 DDRB
|
||||
|
||||
#define PIN_DIO10 PB2
|
||||
#define RPORT_DIO10 PINB
|
||||
#define WPORT_DIO10 PORTB
|
||||
#define DDR_DIO10 DDRB
|
||||
|
||||
#define PIN_DIO11 PB3
|
||||
#define RPORT_DIO11 PINB
|
||||
#define WPORT_DIO11 PORTB
|
||||
#define DDR_DIO11 DDRB
|
||||
|
||||
#define PIN_DIO12 PB4
|
||||
#define RPORT_DIO12 PINB
|
||||
#define WPORT_DIO12 PORTB
|
||||
#define DDR_DIO12 DDRB
|
||||
|
||||
#define PIN_DIO13 PB5
|
||||
#define RPORT_DIO13 PINB
|
||||
#define WPORT_DIO13 PORTB
|
||||
#define DDR_DIO13 DDRB
|
||||
|
||||
#define PIN_AIO0 PC0
|
||||
#define RPORT_AIO0 PINC
|
||||
#define WPORT_AIO0 PORTC
|
||||
#define DDR_AIO0 DDRC
|
||||
|
||||
#define PIN_AIO1 PC1
|
||||
#define RPORT_AIO1 PINC
|
||||
#define WPORT_AIO1 PORTC
|
||||
#define DDR_AIO1 DDRC
|
||||
|
||||
#define PIN_AIO2 PC2
|
||||
#define RPORT_AIO2 PINC
|
||||
#define WPORT_AIO2 PORTC
|
||||
#define DDR_AIO2 DDRC
|
||||
|
||||
#define PIN_AIO3 PC3
|
||||
#define RPORT_AIO3 PINC
|
||||
#define WPORT_AIO3 PORTC
|
||||
#define DDR_AIO3 DDRC
|
||||
|
||||
#define PIN_AIO4 PC4
|
||||
#define RPORT_AIO4 PINC
|
||||
#define WPORT_AIO4 PORTC
|
||||
#define DDR_AIO4 DDRC
|
||||
|
||||
#define PIN_AIO5 PC5
|
||||
#define RPORT_AIO5 PINC
|
||||
#define WPORT_AIO5 PORTC
|
||||
#define DDR_AIO5 DDRC
|
||||
|
||||
#endif /* _ARDUINO_H */
|
||||
|
|
@ -0,0 +1,595 @@
|
|||
/****************************************************************************
|
||||
Title : HD44780U LCD library
|
||||
Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
|
||||
File: $Id: lcd.c,v 1.14.2.1 2006/01/29 12:16:41 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 "lcd.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
|
||||
|
||||
|
||||
#if LCD_IO_MODE
|
||||
#define lcd_e_delay() __asm__ __volatile__( "rjmp 1f\n 1:" );
|
||||
#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)
|
||||
#endif
|
||||
|
||||
#if LCD_IO_MODE
|
||||
#if LCD_LINES==1
|
||||
#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE
|
||||
#else
|
||||
#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES
|
||||
#endif
|
||||
#else
|
||||
#if LCD_LINES==1
|
||||
#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_1LINE
|
||||
#else
|
||||
#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_2LINES
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if LCD_CONTROLLER_KS0073
|
||||
#if LCD_LINES==4
|
||||
#define KS0073_EXTENDED_FUNCTION_REGISTER_ON 0x24 /* |0|010|0100 4-bit mode extension-bit RE = 1 */
|
||||
#define KS0073_EXTENDED_FUNCTION_REGISTER_OFF 0x20 /* |0|000|1001 4 lines mode */
|
||||
#define KS0073_4LINES_MODE 0x09 /* |0|001|0000 4-bit mode, extension-bit RE = 0 */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** function prototypes
|
||||
*/
|
||||
#if LCD_IO_MODE
|
||||
static void toggle_e(void);
|
||||
#endif
|
||||
|
||||
/*
|
||||
** local functions
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
delay loop for small accurate delays: 16-bit counter, 4 cycles/loop
|
||||
*************************************************************************/
|
||||
static inline void _delayFourCycles(unsigned int __count)
|
||||
{
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
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 )
|
||||
|
||||
|
||||
#if LCD_IO_MODE
|
||||
/* toggle Enable Pin to initiate write */
|
||||
static void toggle_e(void)
|
||||
{
|
||||
lcd_e_high();
|
||||
lcd_e_delay();
|
||||
lcd_e_low();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
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
|
||||
*************************************************************************/
|
||||
#if LCD_IO_MODE
|
||||
static void lcd_write(uint8_t data,uint8_t rs)
|
||||
{
|
||||
if (rs) { /* write data (RS=1, RW=0) */
|
||||
lcd_rs_high();
|
||||
} else { /* write instruction (RS=0, RW=0) */
|
||||
lcd_rs_low();
|
||||
}
|
||||
lcd_rw_low();
|
||||
|
||||
if (
|
||||
(&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT)
|
||||
&& (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3)
|
||||
)
|
||||
{
|
||||
/* configure data pins as output */
|
||||
DDR(LCD_DATA0_PORT) |= 0x0F;
|
||||
|
||||
/* output high nibble first */
|
||||
LCD_DATA0_PORT = (LCD_DATA0_PORT & 0xF0) | ((data >> 4) & 0x0F);
|
||||
lcd_e_toggle();
|
||||
|
||||
/* output low nibble */
|
||||
LCD_DATA0_PORT = (LCD_DATA0_PORT & 0xF0) | (data & 0x0F);
|
||||
lcd_e_toggle();
|
||||
|
||||
/* all data pins high (inactive) */
|
||||
LCD_DATA0_PORT = (LCD_DATA0_PORT & 0xF0) | 0x0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure data pins as output */
|
||||
DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN);
|
||||
DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN);
|
||||
DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN);
|
||||
DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN);
|
||||
|
||||
/* output high nibble first */
|
||||
LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);
|
||||
LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);
|
||||
LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);
|
||||
LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);
|
||||
if(data & 0x80) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
|
||||
if(data & 0x40) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
|
||||
if(data & 0x20) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
|
||||
if(data & 0x10) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
|
||||
lcd_e_toggle();
|
||||
|
||||
/* output low nibble */
|
||||
LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);
|
||||
LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);
|
||||
LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);
|
||||
LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);
|
||||
if(data & 0x08) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
|
||||
if(data & 0x04) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
|
||||
if(data & 0x02) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
|
||||
if(data & 0x01) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
|
||||
lcd_e_toggle();
|
||||
|
||||
/* all data pins high (inactive) */
|
||||
LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
|
||||
LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
|
||||
LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
|
||||
LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define lcd_write(d,rs) if (rs) *(volatile uint8_t*)(LCD_IO_DATA) = d; else *(volatile uint8_t*)(LCD_IO_FUNCTION) = d;
|
||||
/* rs==0 -> write instruction to LCD_IO_FUNCTION */
|
||||
/* rs==1 -> write data to LCD_IO_DATA */
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
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
|
||||
*************************************************************************/
|
||||
#if LCD_IO_MODE
|
||||
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(); /* RW=1 read mode */
|
||||
|
||||
if (
|
||||
(&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT)
|
||||
&& (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3)
|
||||
)
|
||||
{
|
||||
DDR(LCD_DATA0_PORT) &= 0xF0; /* configure data pins as input */
|
||||
|
||||
lcd_e_high();
|
||||
lcd_e_delay();
|
||||
data = PIN(LCD_DATA0_PORT) << 4; /* read high nibble first */
|
||||
lcd_e_low();
|
||||
|
||||
lcd_e_delay(); /* Enable 500ns low */
|
||||
|
||||
lcd_e_high();
|
||||
lcd_e_delay();
|
||||
data |= PIN(LCD_DATA0_PORT) & 0x0F; /* read low nibble */
|
||||
lcd_e_low();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure data pins as input */
|
||||
DDR(LCD_DATA0_PORT) &= ~_BV(LCD_DATA0_PIN);
|
||||
DDR(LCD_DATA1_PORT) &= ~_BV(LCD_DATA1_PIN);
|
||||
DDR(LCD_DATA2_PORT) &= ~_BV(LCD_DATA2_PIN);
|
||||
DDR(LCD_DATA3_PORT) &= ~_BV(LCD_DATA3_PIN);
|
||||
|
||||
/* read high nibble first */
|
||||
lcd_e_high();
|
||||
lcd_e_delay();
|
||||
data = 0;
|
||||
if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x10;
|
||||
if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x20;
|
||||
if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x40;
|
||||
if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x80;
|
||||
lcd_e_low();
|
||||
|
||||
lcd_e_delay(); /* Enable 500ns low */
|
||||
|
||||
/* read low nibble */
|
||||
lcd_e_high();
|
||||
lcd_e_delay();
|
||||
if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x01;
|
||||
if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x02;
|
||||
if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x04;
|
||||
if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x08;
|
||||
lcd_e_low();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
#else
|
||||
#define lcd_read(rs) (rs) ? *(volatile uint8_t*)(LCD_IO_DATA+LCD_IO_READ) : *(volatile uint8_t*)(LCD_IO_FUNCTION+LCD_IO_READ)
|
||||
/* rs==0 -> read instruction from LCD_IO_FUNCTION */
|
||||
/* rs==1 -> read data from LCD_IO_DATA */
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
loops while lcd is busy, returns address counter
|
||||
*************************************************************************/
|
||||
static uint8_t lcd_waitbusy(void)
|
||||
{
|
||||
/* wait until busy flag is cleared */
|
||||
for (; lcd_read(0) & (1 << LCD_BUSY); );
|
||||
|
||||
/* 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 KS0073_4LINES_MODE
|
||||
if ( pos < LCD_START_LINE2 )
|
||||
addressCounter = LCD_START_LINE2;
|
||||
else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE3) )
|
||||
addressCounter = LCD_START_LINE3;
|
||||
else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE4) )
|
||||
addressCounter = LCD_START_LINE4;
|
||||
else
|
||||
addressCounter = LCD_START_LINE1;
|
||||
#else
|
||||
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
|
||||
#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(const 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
|
||||
*************************************************************************/
|
||||
void lcd_init(uint8_t dispAttr)
|
||||
{
|
||||
#if LCD_IO_MODE
|
||||
/*
|
||||
* Initialize LCD to 4 bit I/O mode
|
||||
*/
|
||||
|
||||
if (
|
||||
( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )
|
||||
&& ( &LCD_RS_PORT == &LCD_DATA0_PORT) && ( &LCD_RW_PORT == &LCD_DATA0_PORT) && (&LCD_E_PORT == &LCD_DATA0_PORT)
|
||||
)
|
||||
{
|
||||
/* configure all port bits as output (all LCD lines on same port) */
|
||||
DDR(LCD_DATA0_PORT) |= (1 << LCD_DATA0_PIN) | (1 << LCD_DATA1_PIN) | (1 << LCD_DATA2_PIN) | (1 << LCD_DATA3_PIN) | (1 << LCD_RS_PIN) | (1 << LCD_RW_PIN) | (1 << LCD_E_PIN);
|
||||
}
|
||||
else if (
|
||||
( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )
|
||||
)
|
||||
{
|
||||
/* configure all port bits as output (all LCD data lines on same port, but control lines on different ports) */
|
||||
DDR(LCD_DATA0_PORT) |= (1 << LCD_DATA0_PIN) | (1 << LCD_DATA1_PIN) | (1 << LCD_DATA2_PIN) | (1 << LCD_DATA3_PIN);
|
||||
DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);
|
||||
DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);
|
||||
DDR(LCD_E_PORT) |= _BV(LCD_E_PIN);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* configure all port bits as output (LCD data and control lines on different ports */
|
||||
DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);
|
||||
DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);
|
||||
DDR(LCD_E_PORT) |= _BV(LCD_E_PIN);
|
||||
DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN);
|
||||
DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN);
|
||||
DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN);
|
||||
DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN);
|
||||
}
|
||||
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_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_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); // 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() */
|
||||
#else
|
||||
/*
|
||||
* Initialize LCD to 8 bit memory mapped mode
|
||||
*/
|
||||
|
||||
/* enable external SRAM (memory mapped lcd) and one wait state */
|
||||
MCUCR = _BV(SRE) | _BV(SRW);
|
||||
|
||||
/* reset LCD */
|
||||
delay(16000); /* wait 16ms after power-on */
|
||||
lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
|
||||
delay(4992); /* wait 5ms */
|
||||
lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
|
||||
delay(64); /* wait 64us */
|
||||
lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
|
||||
delay(64); /* wait 64us */
|
||||
#endif
|
||||
|
||||
#if KS0073_4LINES_MODE
|
||||
/* Display with KS0073 controller requires special commands for enabling 4 line mode */
|
||||
lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_ON);
|
||||
lcd_command(KS0073_4LINES_MODE);
|
||||
lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_OFF);
|
||||
#else
|
||||
lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */
|
||||
#endif
|
||||
|
||||
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 */
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
#ifndef LCD_H
|
||||
#define LCD_H
|
||||
/*************************************************************************
|
||||
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.13.2.2 2006/01/30 19:51:33 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 Definition for LCD controller type
|
||||
* Use 0 for HD44780 controller, change to 1 for displays with KS0073 controller.
|
||||
*/
|
||||
#define LCD_CONTROLLER_KS0073 0 /**< Use 0 for HD44780 controller, 1 for KS0073 controller */
|
||||
|
||||
/**
|
||||
* @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 */
|
||||
|
||||
#define LCD_IO_MODE 1 /**< 0: memory mapped mode, 1: IO port mode */
|
||||
|
||||
#if LCD_IO_MODE
|
||||
/**
|
||||
* @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_PORT PORTB /**< port for the LCD lines */
|
||||
#define LCD_DATA0_PORT LCD_PORT /**< port for 4bit data bit 0 */
|
||||
#define LCD_DATA1_PORT LCD_PORT /**< port for 4bit data bit 1 */
|
||||
#define LCD_DATA2_PORT LCD_PORT /**< port for 4bit data bit 2 */
|
||||
#define LCD_DATA3_PORT LCD_PORT /**< port for 4bit data bit 3 */
|
||||
#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 PORTD /**< port for RS line */
|
||||
#define LCD_RS_PIN 2 /**< pin for RS line */
|
||||
#define LCD_RW_PORT PORTD /**< port for RW line */
|
||||
#define LCD_RW_PIN 3 /**< pin for RW line */
|
||||
#define LCD_E_PORT PORTD /**< 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
|
||||
*/
|
||||
void lcd_init(uint8_t dispAttr);
|
||||
|
||||
|
||||
/**
|
||||
@brief Clear display and set cursor to home position
|
||||
@param void
|
||||
@return none
|
||||
*/
|
||||
void lcd_clrscr(void);
|
||||
|
||||
|
||||
/**
|
||||
@brief Set cursor to home position
|
||||
@param void
|
||||
@return none
|
||||
*/
|
||||
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
|
||||
*/
|
||||
void lcd_gotoxy(uint8_t x, uint8_t y);
|
||||
|
||||
|
||||
/**
|
||||
@brief Display character at current cursor position
|
||||
@param c character to be displayed
|
||||
@return none
|
||||
*/
|
||||
void lcd_putc(char c);
|
||||
|
||||
|
||||
/**
|
||||
@brief Display string without auto linefeed
|
||||
@param s string to be displayed
|
||||
@return none
|
||||
*/
|
||||
void lcd_puts(const 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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))
|
||||
|
||||
/*@}*/
|
||||
#endif //LCD_H
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
#include "ringbuffer.h"
|
||||
|
||||
uint16_t _rb_mod(uint16_t num, uint16_t denom)
|
||||
{
|
||||
for (; num >= denom; num -= denom);
|
||||
return num;
|
||||
}
|
||||
|
||||
void ringbuffer_init(ringbuffer *buf, int bufsize)
|
||||
{
|
||||
buf->read_pointer = 0;
|
||||
buf->write_pointer = 0;
|
||||
buf->size = bufsize - sizeof(ringbuffer);
|
||||
}
|
||||
|
||||
uint16_t ringbuffer_canread(ringbuffer *buf)
|
||||
{
|
||||
return _rb_mod(buf->write_pointer + buf->size + buf->size - buf->read_pointer, buf->size);
|
||||
}
|
||||
|
||||
uint16_t ringbuffer_canwrite(ringbuffer *buf)
|
||||
{
|
||||
return _rb_mod(buf->read_pointer + buf->size + buf->size - buf->write_pointer - 1, buf->size);
|
||||
}
|
||||
|
||||
uint8_t ringbuffer_readchar(ringbuffer *buf)
|
||||
{
|
||||
uint8_t r = 0;
|
||||
if (ringbuffer_canread(buf))
|
||||
{
|
||||
r = buf->data[buf->read_pointer];
|
||||
buf->read_pointer = _rb_mod(buf->read_pointer + 1, buf->size);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void ringbuffer_writechar(ringbuffer *buf, uint8_t data)
|
||||
{
|
||||
if (ringbuffer_canwrite(buf))
|
||||
{
|
||||
buf->data[buf->write_pointer] = data;
|
||||
buf->write_pointer = _rb_mod(buf->write_pointer + 1, buf->size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t ringbuffer_peekchar(ringbuffer *buf, uint16_t index)
|
||||
{
|
||||
return buf->data[_rb_mod(buf->read_pointer + index, buf->size)];
|
||||
}
|
||||
|
||||
uint16_t ringbuffer_readblock(ringbuffer *buf, uint8_t *newbuf, int size)
|
||||
{
|
||||
uint16_t nc, i;
|
||||
uint8_t *rp, *ms;
|
||||
if ((nc = ringbuffer_canread(buf)) < size)
|
||||
size = nc;
|
||||
if (size)
|
||||
{
|
||||
for (i = 0, rp = buf->data + buf->read_pointer, ms = buf->data + buf->size; i < size; i++, rp++)
|
||||
{
|
||||
if (rp >= ms)
|
||||
rp = buf->data;
|
||||
newbuf[i] = *rp;
|
||||
}
|
||||
buf->read_pointer = rp - buf->data;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
uint16_t ringbuffer_writeblock(ringbuffer *buf, uint8_t *data, int size)
|
||||
{
|
||||
uint16_t nc, i;
|
||||
uint8_t *wp, *ms;
|
||||
|
||||
if ((nc = ringbuffer_canwrite(buf)) < size)
|
||||
size = nc;
|
||||
if (size)
|
||||
{
|
||||
for (i = 0, wp = buf->write_pointer + buf->data, ms = buf->data + buf->size; i < size; i++, wp++)
|
||||
{
|
||||
if (wp >= ms)
|
||||
wp = buf->data;
|
||||
*wp = data[i];
|
||||
}
|
||||
buf->write_pointer = wp - buf->data;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef _RINGBUFFER_H
|
||||
#define _RINGBUFFER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t read_pointer;
|
||||
uint16_t write_pointer;
|
||||
uint16_t size;
|
||||
uint8_t data[];
|
||||
} ringbuffer;
|
||||
|
||||
void ringbuffer_init(ringbuffer *buf, int bufsize);
|
||||
|
||||
uint16_t ringbuffer_canread(ringbuffer *buf);
|
||||
uint16_t ringbuffer_canwrite(ringbuffer *buf);
|
||||
|
||||
uint8_t ringbuffer_readchar(ringbuffer *buf);
|
||||
uint8_t ringbuffer_peekchar(ringbuffer *buf, uint16_t index);
|
||||
uint16_t ringbuffer_readblock(ringbuffer *buf, uint8_t *newbuf, int size);
|
||||
|
||||
void ringbuffer_writechar(ringbuffer *buf, uint8_t data);
|
||||
uint16_t ringbuffer_writeblock(ringbuffer *buf, uint8_t *data, int size);
|
||||
|
||||
#endif /* _RINGBUFFER_H */
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
#include "serial.h"
|
||||
|
||||
#include "ringbuffer.h"
|
||||
|
||||
#define BUFSIZE 64 + sizeof(ringbuffer)
|
||||
#define BAUD 19200
|
||||
|
||||
volatile uint8_t _rx_buffer[BUFSIZE];
|
||||
volatile uint8_t _tx_buffer[BUFSIZE];
|
||||
|
||||
void serial_init(uint16_t baud)
|
||||
{
|
||||
ringbuffer_init(rx_buffer, BUFSIZE);
|
||||
ringbuffer_init(tx_buffer, BUFSIZE);
|
||||
|
||||
UCSR0A = 0;
|
||||
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
|
||||
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
|
||||
|
||||
UBRR0 = ((F_CPU / 16) / baud) - 1;
|
||||
|
||||
UCSR0B |= (1 << RXCIE0) | (1 << UDRIE0);
|
||||
}
|
||||
|
||||
ISR(USART_RX_vect)
|
||||
{
|
||||
ringbuffer_writechar(rx_buffer, UDR0);
|
||||
}
|
||||
|
||||
ISR(USART_UDRE_vect)
|
||||
{
|
||||
if (ringbuffer_canread(tx_buffer))
|
||||
{
|
||||
UDR0 = ringbuffer_readchar(tx_buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
UCSR0B &= ~(1 << UDRIE0);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t serial_rxchars()
|
||||
{
|
||||
return ringbuffer_canread(rx_buffer);
|
||||
}
|
||||
|
||||
uint16_t serial_txchars()
|
||||
{
|
||||
return ringbuffer_canread(tx_buffer);
|
||||
}
|
||||
|
||||
uint8_t serial_popchar()
|
||||
{
|
||||
return ringbuffer_readchar(rx_buffer);
|
||||
}
|
||||
|
||||
uint16_t serial_recvblock(uint8_t *block, int blocksize)
|
||||
{
|
||||
return ringbuffer_readblock(rx_buffer, block, blocksize);
|
||||
}
|
||||
|
||||
void serial_writechar(uint8_t data)
|
||||
{
|
||||
ringbuffer_writechar(tx_buffer, data);
|
||||
UCSR0B |= (1 << UDRIE0);
|
||||
}
|
||||
|
||||
void serial_writeblock(uint8_t *data, int datalen)
|
||||
{
|
||||
ringbuffer_writeblock(tx_buffer, data, datalen);
|
||||
UCSR0B |= (1 << UDRIE0);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef _SERIAL_H
|
||||
#define _SERIAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <avr/io.h>
|
||||
|
||||
#define rx_buffer ((ringbuffer *) _rx_buffer)
|
||||
#define tx_buffer ((ringbuffer *) _tx_buffer)
|
||||
|
||||
extern volatile uint8_t _rx_buffer[];
|
||||
extern volatile uint8_t _tx_buffer[];
|
||||
|
||||
void serial_init(uint16_t baud);
|
||||
|
||||
uint16_t serial_rxchars(void);
|
||||
uint16_t serial_txchars(void);
|
||||
|
||||
uint8_t serial_popchar(void);
|
||||
void serial_writechar(uint8_t data);
|
||||
|
||||
uint16_t serial_recvblock(uint8_t *block, int blocksize);
|
||||
void serial_writeblock(uint8_t *data, int datalen);
|
||||
|
||||
#endif /* _SERIAL_H */
|
||||
|
|
@ -0,0 +1,396 @@
|
|||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "serial.h"
|
||||
#include "lcd.h"
|
||||
|
||||
#include "arduino.h"
|
||||
|
||||
// *** pin assignments ***
|
||||
|
||||
// step input
|
||||
#define PIN_STEP PIN_AIO2
|
||||
#define PORT_STEP WPORT_AIO2
|
||||
#define READ_STEP RPORT_AIO2
|
||||
#define DDR_STEP DDR_AIO2
|
||||
|
||||
// direction input
|
||||
#define PIN_DIR PIN_AIO3
|
||||
#define PORT_DIR WPORT_AIO3
|
||||
#define READ_DIR RPORT_AIO3
|
||||
#define DDR_DIR DDR_AIO3
|
||||
|
||||
// outputs (PWM) - dir lines only below, en lines MUST connect to OCR0A/B (DIO 5/6)
|
||||
#define PIN_DIR1 PIN_AIO0
|
||||
#define PORT_DIR1 WPORT_AIO0
|
||||
#define DDR_DIR1 DDR_AIO0
|
||||
|
||||
#define PIN_DIR2 PIN_AIO1
|
||||
#define PORT_DIR2 WPORT_AIO1
|
||||
#define DDR_DIR2 DDR_AIO1
|
||||
|
||||
|
||||
// *** machine-specific constants ***
|
||||
|
||||
// 1/2 step, NSTEPPING=2, for 1/4 step, NSTEPPING = 4 etc
|
||||
#define NSTEPPING 8
|
||||
// FULL steps per mm (calculate from 200 steps/rev)
|
||||
#define FULL_STEPS_PER_MM 5
|
||||
|
||||
// calculations
|
||||
#define PRESCALER 256
|
||||
#define STEPS_PER_MM (FULL_STEPS_PER_MM * NSTEPPING)
|
||||
|
||||
// units
|
||||
#define MM * STEPS_PER_MM
|
||||
#define MM_PER_SEC * STEPS_PER_MM
|
||||
|
||||
#define US * F_CPU / 1000000 / PRESCALER
|
||||
#define MS * F_CPU / 1000 / PRESCALER
|
||||
#define S * F_CPU / 1 / PRESCALER
|
||||
|
||||
// *** tunables ***
|
||||
|
||||
#define SPEED (15 MM_PER_SEC)
|
||||
|
||||
// *** step table ***
|
||||
// sinstepi MUST satisfy 2^n for integer values of n where n = 2 for 1/2 step, 4 for 1/4 step etc
|
||||
// generate with:
|
||||
// perl -e 'my $n = 4; my @st; for (0..$n) { push @st, sprintf "%i", sin($_ * 90 * 3.1415926535897932384626433832795029 * 2 / 360 / $n) * 255 }; print "#define sinstepi $n\nstatic uint8_t sintable[sinstepi + 1] = { "; print join ", ", @st; print " };\n";';
|
||||
|
||||
#if NSTEPPING == 1
|
||||
#define sinstepi 1
|
||||
static const uint8_t sintable[sinstepi + 1] = { 0, 255 };
|
||||
|
||||
#elif NSTEPPING == 2
|
||||
#define sinstepi 2
|
||||
static const uint8_t sintable[sinstepi + 1] = { 0, 180, 255 };
|
||||
|
||||
#elif NSTEPPING == 4
|
||||
#define sinstepi 4
|
||||
static uint8_t sintable[sinstepi + 1] = { 0, 97, 180, 235, 255 };
|
||||
|
||||
#elif NSTEPPING == 8
|
||||
#define sinstepi 8
|
||||
static uint8_t sintable[sinstepi + 1] = { 0, 49, 97, 141, 180, 212, 235, 250, 255 };
|
||||
|
||||
#elif NSTEPPING == 16
|
||||
#define sinstepi 16
|
||||
static uint8_t sintable[sinstepi + 1] = { 0, 24, 49, 74, 97, 120, 141, 161, 180, 197, 212, 224, 235, 244, 250, 253, 255 };
|
||||
|
||||
#elif NSTEPPING == 32
|
||||
#define sinstepi 32
|
||||
static uint8_t sintable[sinstepi + 1] = { 0, 12, 24, 37, 49, 61, 74, 85, 97, 109, 120, 131, 141, 151, 161, 171, 180, 188, 197, 204, 212, 218, 224, 230, 235, 240, 244, 247, 250, 252, 253, 254, 255 };
|
||||
|
||||
#else
|
||||
#error Invalid NSTEPPING value
|
||||
|
||||
#endif
|
||||
|
||||
// recalculations - don't touch!
|
||||
#define STEP_TIME F_CPU / SPEED / PRESCALER
|
||||
#define MIN_STEP_TIME F_CPU / 1000 / PRESCALER
|
||||
#define sinstepi2 (sinstepi * 2)
|
||||
#define sinstepi3 (sinstepi * 3)
|
||||
#define sinstepi4 (sinstepi * 4)
|
||||
#define sinsteplast (sinstepi4 - 1)
|
||||
|
||||
// utilities
|
||||
#define MASK(a) (1 << a)
|
||||
#define PORT_OUT_MASK (0xF << PIN_LSB_OUT)
|
||||
#define abs(a) (((a) >= 0)?(a):-(a))
|
||||
|
||||
// write to lcd function for fdev_setup_stream
|
||||
static int lcd_putc_fdev(char c, FILE *stream)
|
||||
{
|
||||
lcd_putc(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serial_putc_fdev(char c, FILE *stream)
|
||||
{
|
||||
serial_writechar((uint8_t) c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serial_getc_fdev(FILE *stream)
|
||||
{
|
||||
for (;serial_rxchars() == 0;);
|
||||
return (int) serial_popchar();
|
||||
}
|
||||
|
||||
static FILE lcdo = FDEV_SETUP_STREAM(lcd_putc_fdev, NULL, _FDEV_SETUP_WRITE);
|
||||
static FILE serio = FDEV_SETUP_STREAM(serial_putc_fdev, serial_getc_fdev, _FDEV_SETUP_RW);
|
||||
|
||||
volatile int32_t pos;
|
||||
volatile int32_t npos;
|
||||
volatile uint16_t speed;
|
||||
volatile uint16_t speed_sync;
|
||||
volatile uint8_t superstep; // for disabling microstep during high speed runs
|
||||
volatile uint8_t superstep_sync;
|
||||
volatile int step1;
|
||||
volatile int step2;
|
||||
// uint8_t power0;
|
||||
// uint8_t power1;
|
||||
|
||||
// integer sine approximation
|
||||
int sinstep(uint8_t sequence) {
|
||||
while (sequence >= sinstepi4)
|
||||
sequence -= sinstepi4;
|
||||
if (sequence < (sinstepi + 1))
|
||||
return sintable[sequence];
|
||||
if ((sequence >= (sinstepi + 1)) && (sequence < (sinstepi2 + 1)))
|
||||
return sintable[sinstepi2 - sequence];
|
||||
if ((sequence >= (sinstepi2 + 1)) && (sequence < (sinstepi3 + 1)))
|
||||
return -sintable[sequence - sinstepi2];
|
||||
//if ((sequence >= (sinstepi3 + 1)) && (sequence < (sinstepi4 + 1)))
|
||||
return -sintable[sinstepi4 - sequence];
|
||||
}
|
||||
|
||||
// generate appropriate stepper signals for a sequence number
|
||||
void stepperseq(uint8_t sequence) {
|
||||
step1 = sinstep(sequence);
|
||||
step2 = sinstep(sequence + sinstepi);
|
||||
|
||||
// set directions
|
||||
if (step1 >= 0)
|
||||
PORT_DIR1 |= MASK(PIN_DIR1);
|
||||
else {
|
||||
PORT_DIR1 &= ~MASK(PIN_DIR1);
|
||||
}
|
||||
|
||||
// PORT_DIR1 = (PORT_DIR1 & ~MASK(PIN_DIR1)) | ((((step1 >= 0)?255:0) ^ wx) & MASK(PIN_DIR1));
|
||||
|
||||
if (step2 >= 0)
|
||||
PORT_DIR2 |= MASK(PIN_DIR2);
|
||||
else {
|
||||
PORT_DIR2 &= ~MASK(PIN_DIR2);
|
||||
}
|
||||
|
||||
// PORT_DIR2 = (PORT_DIR2 & ~MASK(PIN_DIR2)) | ((((step2 >= 0)?255:0) ^ wx) & MASK(PIN_DIR2));
|
||||
|
||||
// set power
|
||||
TCNT0 = 0xFD;
|
||||
OCR0A = ((uint8_t) abs(step1));
|
||||
OCR0B = ((uint8_t) abs(step2));
|
||||
}
|
||||
|
||||
// // PWM reset interrupt
|
||||
// ISR(TIMER0_OVF_vect) {
|
||||
// // now that our counter is at zero, load new power levels
|
||||
// OCR0A = power0;
|
||||
// OCR0B = power1;
|
||||
// }
|
||||
|
||||
// next step interrupt
|
||||
ISR(TIMER1_COMPA_vect) {
|
||||
uint8_t i;
|
||||
|
||||
// toggle "L" led
|
||||
PINB = MASK(PB5);
|
||||
|
||||
// update position
|
||||
if (npos > pos)
|
||||
pos += MASK(superstep_sync);
|
||||
else if (npos < pos)
|
||||
pos -= MASK(superstep_sync);
|
||||
|
||||
// write new position
|
||||
i = pos & sinsteplast;
|
||||
stepperseq(i);
|
||||
// if we're at a sync point and we're changing microstep rate
|
||||
if ((i & (sinstepi2 - 1)) == 0)
|
||||
// do the change now
|
||||
superstep_sync = superstep;
|
||||
// update speed
|
||||
OCR1A = speed << superstep_sync;
|
||||
}
|
||||
|
||||
void startstep(void) {
|
||||
if ((TIMSK1 & MASK(OCIE1A)) == 0)
|
||||
{
|
||||
OCR1A = speed;
|
||||
// while ((OCR1A < MIN_STEP_TIME) && (superstep < sinstepi)) {
|
||||
// OCR1A <<= 1;
|
||||
// superstep <<= 1;
|
||||
// }
|
||||
// while (((OCR1A > (MIN_STEP_TIME * 2)) && (superstep > 1)) || (abs(npos - pos) < superstep)) {
|
||||
// OCR1A >>= 1;
|
||||
// superstep >>= 1;
|
||||
// }
|
||||
TCNT1 = 0;
|
||||
}
|
||||
|
||||
// it's possible that the mask is enabled during the check above, but disabled by the time we get here - always set it to avoid a race condition
|
||||
TIMSK1 |= MASK(OCIE1A);
|
||||
}
|
||||
|
||||
// main, where it all happens
|
||||
int main (void)
|
||||
{
|
||||
// set up LCD
|
||||
lcd_init(LCD_DISP_ON_CURSOR);
|
||||
|
||||
lcd_puts_P("Starting...");
|
||||
|
||||
// set up STDIN/OUT/ERR
|
||||
stdin = &serio;
|
||||
stdout = &lcdo;
|
||||
stderr = &lcdo;
|
||||
|
||||
// set up serial
|
||||
serial_init(19200);
|
||||
|
||||
// variables
|
||||
pos = 0;
|
||||
uint8_t stepdebounce = 0;
|
||||
uint16_t spinner = 0;
|
||||
int r;
|
||||
int32_t rv;
|
||||
int rs;
|
||||
|
||||
// setup inputs
|
||||
DDR_STEP &= ~MASK(PIN_STEP);
|
||||
DDR_DIR &= ~MASK(PIN_DIR);
|
||||
|
||||
// pull-ups
|
||||
PORT_STEP |= MASK(PIN_STEP);
|
||||
PORT_DIR |= MASK(PIN_DIR);
|
||||
|
||||
// direction pins to h-bridge
|
||||
DDR_DIR1 |= MASK(PIN_DIR1);
|
||||
DDR_DIR2 |= MASK(PIN_DIR2);
|
||||
// enable pins to h-bridge - must be DIO5/6 for PWM operation
|
||||
DDR_DIO5 |= MASK(PIN_DIO5);
|
||||
DDR_DIO6 |= MASK(PIN_DIO6);
|
||||
|
||||
// setup timer 0 (PWM timer)
|
||||
TCCR0A = MASK(COM0A1) | MASK(COM0B1) | MASK(WGM01) | MASK(WGM00); // enable PWM output pins (DIO5/6), fast PWM
|
||||
TCCR0B = MASK(CS00); // prescaler = 1 (max speed)
|
||||
|
||||
// setup timer 1 (step timer)
|
||||
TCCR1A = 0;
|
||||
TCCR1B = MASK(WGM12);
|
||||
#if PRESCALER == 1
|
||||
TCCR1B |= MASK(CS10);
|
||||
#elif PRESCALER == 8
|
||||
TCCR1B |= MASK(CS11);
|
||||
#elif PRESCALER == 64
|
||||
TCCR1B |= MASK(CS11) | MASK(CS10);
|
||||
#elif PRESCALER == 256
|
||||
TCCR1B |= MASK(CS12);
|
||||
#elif PRESCALER == 1024
|
||||
TCCR1B |= MASK(CS12) | MASK(CS10);
|
||||
#else
|
||||
#error Invalid PRESCALER value: must be one of 1, 8, 64, 256 or 1024
|
||||
#endif
|
||||
|
||||
// disable interrupt
|
||||
TIMSK1 = 0;
|
||||
// set speed
|
||||
speed = STEP_TIME;
|
||||
OCR1A = speed << superstep;
|
||||
|
||||
// initialize stepper drive
|
||||
//PORT_OUT = (PORT_OUT & ~PORT_OUT_MASK) | ((steps[0] ^ wmod) << PIN_LSB_OUT);
|
||||
stepperseq(0);
|
||||
|
||||
// enable interrupts
|
||||
sei();
|
||||
|
||||
// main loop start
|
||||
lcd_gotoxy(0, 0);
|
||||
fprintf(&lcdo, "Stepper OK ");
|
||||
|
||||
// main loop
|
||||
for (;;)
|
||||
{
|
||||
// check logic inputs
|
||||
if ((READ_STEP & MASK(PIN_STEP)) == 0) {
|
||||
if (stepdebounce >= 32) {
|
||||
if (stepdebounce == 32) {
|
||||
if (READ_DIR & MASK(PIN_DIR))
|
||||
npos++;
|
||||
else
|
||||
npos--;
|
||||
stepdebounce++;
|
||||
}
|
||||
}
|
||||
else
|
||||
stepdebounce++;
|
||||
}
|
||||
else
|
||||
stepdebounce = 0;
|
||||
|
||||
// check serial input
|
||||
if (serial_rxchars()) {
|
||||
uint8_t c = getchar();
|
||||
switch (c) {
|
||||
case '>':
|
||||
npos++;
|
||||
break;
|
||||
case '<':
|
||||
npos--;
|
||||
break;
|
||||
case '?':
|
||||
fprintf(&serio, "pos:%li\n", pos);
|
||||
break;
|
||||
case '+':
|
||||
r = scanf("%li", &rv);
|
||||
if (r == 0)
|
||||
npos++;
|
||||
else
|
||||
npos += rv;
|
||||
break;
|
||||
case '-':
|
||||
r = scanf("%li", &rv);
|
||||
if (r == 0)
|
||||
npos--;
|
||||
else
|
||||
npos -= rv;
|
||||
break;
|
||||
case 'g':
|
||||
r = scanf("%li", &rv);
|
||||
if (r != 0)
|
||||
npos = rv;
|
||||
break;
|
||||
case 's':
|
||||
r = scanf("%li", &rv);
|
||||
if (r != 0)
|
||||
speed = rv;
|
||||
break;
|
||||
case 'h':
|
||||
npos = 0;
|
||||
break;
|
||||
case 'x':
|
||||
r = scanf("%i", &rs);
|
||||
if (r != 0)
|
||||
superstep = rs;
|
||||
break;
|
||||
case 'R':
|
||||
npos = pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((npos != pos) && ((TIMSK1 & MASK(OCIE1A)) == 0))
|
||||
startstep();
|
||||
|
||||
if (((spinner++) & 0x0FFF) == 0) {
|
||||
lcd_clrscr();
|
||||
printf("p:%7li", pos);
|
||||
lcd_gotoxy(8, 0);
|
||||
printf("s:%i", speed);
|
||||
lcd_gotoxy(0, 1);
|
||||
printf("t:%7li", npos);
|
||||
lcd_gotoxy(8, 1);
|
||||
// printf("p:%i", PORT_STEP);
|
||||
printf("%i %i", step1, step2);
|
||||
// printf("%02X", READ_STEP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
// generate with:
|
||||
// perl -e 'my $n = 16; my @st; for (0..($n - 1)) { push @st, sprintf "%i", sin($_ * 90 * 3.141592653 * 2 / 360 / ($n - 1)) * 255 }; print "#define sinsteps $n\nstatic uint8_t sintable[sinsteps] = { "; print join ", ", @st; print " };\n";';
|
||||
// #define sinsteps 16
|
||||
// static uint8_t sintable[sinsteps] = { 0, 26, 53, 78, 103, 127, 149, 170, 189, 206, 220, 232, 242, 249, 253, 255 };
|
||||
|
||||
#define sinsteps 5
|
||||
static uint8_t sintable[sinsteps] = { 0, 97, 180, 235, 255 };
|
||||
|
||||
#define sinstepi (sinsteps - 1)
|
||||
#define sinstepi2 (sinstepi * 2)
|
||||
#define sinstepi3 (sinstepi * 3)
|
||||
#define sinstepi4 (sinstepi * 4)
|
||||
|
||||
int sinstep(uint8_t sequence) {
|
||||
while (sequence >= sinstepi4)
|
||||
sequence -= sinstepi4;
|
||||
if (sequence < (sinstepi + 1))
|
||||
return sintable[sequence];
|
||||
if ((sequence >= (sinstepi + 1)) && (sequence < (sinstepi2 + 1)))
|
||||
return sintable[sinstepi2 - sequence];
|
||||
if ((sequence >= (sinstepi2 + 1)) && (sequence < (sinstepi3 + 1)))
|
||||
return -sintable[sequence - sinstepi2];
|
||||
if ((sequence >= (sinstepi3 + 1)) && (sequence < (sinstepi4 + 1)))
|
||||
return -sintable[sinstepi4 - sequence];
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ((sinstepi * 4) * 3); i++)
|
||||
{
|
||||
printf("%2i: %+4i %+4i\n", i, sinstep(i), sinstep(i + sinstepi));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
Loading…
Reference in New Issue