diff --git a/Makefile b/Makefile index cf49ad1..677af79 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ RESETPORT = /dev/ttyU0 TARGET = pyrorf -SRC = main.c +SRC = main.c i2c.c lcd.c CXXSRC = ASRC = MCU = atmega32 diff --git a/i2c.c b/i2c.c new file mode 100644 index 0000000..782bdb2 --- /dev/null +++ b/i2c.c @@ -0,0 +1,115 @@ +#include "i2c.h" +#include + +void i2c_init(void) +{ + i2c_sda_hi(); + i2c_scl_hi(); + _delay_us(i2cbitdelay); +} + +void i2c_writebit( uint8_t c ) +{ + if ( c > 0 ) { + i2c_sda_hi(); + } else { + i2c_sda_lo(); + } + + i2c_scl_hi(); + _delay_us(i2cbitdelay); + + i2c_scl_lo(); + _delay_us(i2cbitdelay); + + if ( c > 0 ) { + i2c_sda_lo(); + } + _delay_us(i2cbitdelay); +} + +uint8_t i2c_readbit(void) +{ + i2c_sda_hi(); + i2c_scl_hi(); + _delay_us(i2cbitdelay); + + uint8_t c = bitRead( SDAPORT,SDAPIN); + + i2c_scl_lo(); + _delay_us(i2cbitdelay); + + return c ? 1 : 0; +} + +void i2c_start(void) +{ + i2c_sda_hi(); + i2c_scl_hi(); + + _delay_us(i2cbitdelay); + + i2c_sda_lo(); + _delay_us(i2cbitdelay); + + i2c_scl_lo(); + _delay_us(i2cbitdelay); +} + +void i2c_repstart(void) +{ + i2c_sda_hi(); + i2c_scl_hi(); + + i2c_scl_lo(); // force SCL low + _delay_us(i2cbitdelay); + + i2c_sda_release(); // release SDA + _delay_us(i2cbitdelay); + + i2c_scl_release(); // release SCL + _delay_us(i2cbitdelay); + + i2c_sda_lo(); // force SDA low + _delay_us(i2cbitdelay); +} + +void i2c_stop(void) +{ + i2c_scl_hi(); + _delay_us(i2cbitdelay); + + i2c_sda_hi(); + _delay_us(i2cbitdelay); +} + +uint8_t i2c_write( uint8_t c ) +{ + for ( uint8_t i=0;i<8;i++) { + i2c_writebit( c & 128 ); + c<<=1; + } + + return i2c_readbit(); +} + +uint8_t i2c_read( uint8_t ack ) +{ + uint8_t res = 0; + + for ( uint8_t i=0;i<8;i++) { + res <<= 1; + res |= i2c_readbit(); + } + + if ( ack ) + i2c_writebit( 0 ); + else + i2c_writebit( 1 ); + + _delay_us(i2cbitdelay); + + return res; +} + + diff --git a/i2c.h b/i2c.h new file mode 100644 index 0000000..f067b65 --- /dev/null +++ b/i2c.h @@ -0,0 +1,45 @@ +#ifndef defines_i2c +#define defines_i2c + +#include +#include "defines.h" + +#define i2cbitdelay 50 + +#define I2C_ACK 1 +#define I2C_NAK 0 + +#define SCLPORT PORTD +#define SDAPORT PORTD +#define SDAPIN 7 +#define SCLPIN 8 +#define SCLDDR DDRD +#define SDADDR DDRD + + +#define i2c_scl_release() bitClear(SCLDDR,SCLPIN); +#define i2c_sda_release() bitClear(SDADDR,SDAPIN); + +// sets SCL low and drives output +#define i2c_scl_lo() bitClear(SCLPORT,SCLPIN); bitSet(SCLDDR,SCLPIN); + +// sets SDA low and drives output +#define i2c_sda_lo() bitClear(SDAPORT,SCLPIN); bitSet(SDADDR,SDAPIN); + +// set SCL high and to input (releases pin) (i.e. change to input,turnon pullup) +#define i2c_scl_hi() bitClear(SCLDDR,SCLPIN);bitSet(SCLPORT,SCLPIN); + +// set SDA high and to input (releases pin) (i.e. change to input,turnon pullup) +#define i2c_sda_hi() bitClear(SDADDR,SDAPIN);bitSet(SDAPORT,SDAPIN); + +void i2c_init(void); + +void i2c_writebit( uint8_t c ); +uint8_t i2c_readbit(void); +void i2c_start(void); +void i2c_repstart(void); +void i2c_stop(void); +uint8_t i2c_write( uint8_t c ); +uint8_t i2c_read( uint8_t ack ); + +#endif diff --git a/lcd.c b/lcd.c new file mode 100644 index 0000000..8aa69e3 --- /dev/null +++ b/lcd.c @@ -0,0 +1,252 @@ +#include "lcd.h" +#include "i2c.h" +#include +#include + +#define ENPIN 0 +#define RWPIN 1 +#define RSPIN 2 +#define BLPIN 3 + +#define DATASHIFT 4 + + +uint8_t _numlines; +uint8_t _cols; +uint8_t _En = (1<> 4), mode ); + write4bits( (value & 0x0F), mode); + } +} + +void command(uint8_t value) +{ + send(value, COMMAND); +} + +void lcd_init(uint8_t cols, uint8_t lines) +{ + i2c_init(); + _cols=cols; + _numlines=lines; + _delay_ms(100); + + // this is according to the hitachi HD44780 datasheet + // figure 24, pg 46 + + // we start in 8bit mode, try to set 4 bit mode + // Special case of "Function Set" + send(0x03, FOUR_BITS); + _delay_us(4500); // wait min 4.1ms + + // second try + send ( 0x03, FOUR_BITS ); + _delay_us(150); // wait min 100us + + // third go! + send( 0x03, FOUR_BITS ); + _delay_us(150); // wait min of 100us + + // finally, set to 4-bit interface + send ( 0x02, FOUR_BITS ); + _delay_us(150); // wait min of 100us + + + command(LCD_FUNCTIONSET | LCD_2LINE); +} + +void lcd_clear() +{ + command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero + _delay_us(HOME_CLEAR_EXEC); // this command is time consuming +} + +void lcd_home() +{ + command(LCD_RETURNHOME); // set cursor position to zero + _delay_us(HOME_CLEAR_EXEC); // This command is time consuming +} + +void lcd_setCursor(uint8_t col, uint8_t row) +{ + const uint8_t row_offsetsDef[] = { 0x00, 0x40, 0x14, 0x54 }; // For regular LCDs + const uint8_t row_offsetsLarge[] = { 0x00, 0x40, 0x10, 0x50 }; // For 16x4 LCDs + + if ( row >= _numlines ) + { + row = _numlines-1; // rows start at 0 + } + + // 16x4 LCDs have special memory map layout + // ---------------------------------------- + if ( _cols == 16 && _numlines == 4 ) + { + command(LCD_SETDDRAMADDR | (col + row_offsetsLarge[row])); + } + else + { + command(LCD_SETDDRAMADDR | (col + row_offsetsDef[row])); + } +} + +// Turn the display on/off + +void lcd_noDisplay() +{ + _displaycontrol &= ~LCD_DISPLAYON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +void lcd_display() +{ + _displaycontrol |= LCD_DISPLAYON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// Turns the underline cursor on/off +void lcd_noCursor() +{ + _displaycontrol &= ~LCD_CURSORON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} +void lcd_cursor() +{ + _displaycontrol |= LCD_CURSORON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// Turns on/off the blinking cursor +void lcd_noBlink() +{ + _displaycontrol &= ~LCD_BLINKON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +void lcd_blink() +{ + _displaycontrol |= LCD_BLINKON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// These commands scroll the display without changing the RAM +void lcd_scrollDisplayLeft(void) +{ + command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); +} + +void lcd_scrollDisplayRight(void) +{ + command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); +} + + +// This method moves the cursor one space to the right +void lcd_moveCursorRight(void) +{ + command(LCD_CURSORSHIFT | LCD_CURSORMOVE | LCD_MOVERIGHT); +} + +// This method moves the cursor one space to the left +void lcd_moveCursorLeft(void) +{ + command(LCD_CURSORSHIFT | LCD_CURSORMOVE | LCD_MOVELEFT); +} + + +// This is for text that flows Left to Right +void lcd_leftToRight(void) +{ + _displaymode |= LCD_ENTRYLEFT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// This is for text that flows Right to Left +void lcd_rightToLeft(void) +{ + _displaymode &= ~LCD_ENTRYLEFT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// This will 'right justify' text from the cursor +void lcd_autoscroll(void) +{ + _displaymode |= LCD_ENTRYSHIFTINCREMENT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// This will 'left justify' text from the cursor +void lcd_noAutoscroll(void) +{ + _displaymode &= ~LCD_ENTRYSHIFTINCREMENT; + command(LCD_ENTRYMODESET | _displaymode); +} + + +void lcd_createChar(uint8_t location, const char *charmap) +{ + location &= 0x7; // we only have 8 memory locations 0-7 + + command(LCD_SETCGRAMADDR | (location << 3)); + _delay_us(30); + + for (uint8_t i = 0; i < 8; i++) + { + lcd_write(pgm_read_byte_near(charmap++)); + _delay_us(40); + } +} + +void lcd_write(uint8_t value) +{ + send(value, LCD_DATA); +} diff --git a/lcd.h b/lcd.h new file mode 100644 index 0000000..cf726cf --- /dev/null +++ b/lcd.h @@ -0,0 +1,88 @@ +#ifndef defines_lcd +#define defines_lcd + +#include +#include +#include +#include "i2c.h" + +// LCD Commands +// --------------------------------------------------------------------------- +#define LCD_CLEARDISPLAY 0x01 +#define LCD_RETURNHOME 0x02 +#define LCD_ENTRYMODESET 0x04 +#define LCD_DISPLAYCONTROL 0x08 +#define LCD_CURSORSHIFT 0x10 +#define LCD_FUNCTIONSET 0x20 +#define LCD_SETCGRAMADDR 0x40 +#define LCD_SETDDRAMADDR 0x80 + +// flags for display entry mode +// --------------------------------------------------------------------------- +#define LCD_ENTRYRIGHT 0x00 +#define LCD_ENTRYLEFT 0x02 +#define LCD_ENTRYSHIFTINCREMENT 0x01 +#define LCD_ENTRYSHIFTDECREMENT 0x00 + +// flags for display on/off and cursor control +// --------------------------------------------------------------------------- +#define LCD_DISPLAYON 0x04 +#define LCD_DISPLAYOFF 0x00 +#define LCD_CURSORON 0x02 +#define LCD_CURSOROFF 0x00 +#define LCD_BLINKON 0x01 +#define LCD_BLINKOFF 0x00 + +// flags for display/cursor shift +// --------------------------------------------------------------------------- +#define LCD_DISPLAYMOVE 0x08 +#define LCD_CURSORMOVE 0x00 +#define LCD_MOVERIGHT 0x04 +#define LCD_MOVELEFT 0x00 + +// flags for function set +// --------------------------------------------------------------------------- +#define LCD_8BITMODE 0x10 +#define LCD_4BITMODE 0x00 +#define LCD_2LINE 0x08 +#define LCD_1LINE 0x00 +#define LCD_5x10DOTS 0x04 +#define LCD_5x8DOTS 0x00 + + +// Define COMMAND and DATA LCD Rs (used by send method). +// --------------------------------------------------------------------------- +#define COMMAND 0 +#define LCD_DATA 1 +#define FOUR_BITS 2 + + +#define HOME_CLEAR_EXEC 2000 + +#define LCD_ADDRESS 0x37 + +void lcd_init(uint8_t cols, uint8_t lines); +void lcd_clear(); +void lcd_home(); +void lcd_setCursor(uint8_t col, uint8_t row); +void lcd_write(uint8_t value); + +void lcd_createChar(uint8_t location, const char *charmap); + +void lcd_noDisplay() ; +void lcd_display() ; +void lcd_noCursor() ; +void lcd_cursor() ; +void lcd_noBlink() ; +void lcd_blink() ; +void lcd_scrollDisplayLeft(void) ; +void lcd_scrollDisplayRight(void) ; +void lcd_moveCursorRight(void); +void lcd_moveCursorLeft(void); +void lcd_leftToRight(void) ; +void lcd_rightToLeft(void) ; +void lcd_autoscroll(void) ; +void lcd_noAutoscroll(void); + + +#endif diff --git a/main.c b/main.c index dee3ecc..da16fde 100644 --- a/main.c +++ b/main.c @@ -11,7 +11,18 @@ #include #include "defines.h" +#include "lcd.h" + + +void lcdprint( char* ptr){ + while (*ptr) lcd_write(*ptr); +} int main(void) { + lcd_init(20,4); + lcd_home(); + lcdprint("Hello World"); + lcd_setCursor ( 0, 1 ); + lcdprint("Hello Me"); }