rgbyteclock-code/lcd.c

204 lines
3.7 KiB
C
Raw Normal View History

2014-03-01 03:50:09 +01:00
/*
* "THE BEER-WARE LICENSE" (Revision 42):
* Martin Wenger <martin.wenger@arcormail.de> and Stefan Rupp <struppi@struppi.name>
* wrote this file. As long as you retain this notice you can do whatever you want
* with this stuff. If we meet some day, and you think this stuff is worth it,
* you can buy me/us a beer in return.
* (c) 2005-2010 Martin Wenger, Stefan Rupp
* (c) 2014 Stefan Rupp
*/
#include <avr/io.h>
#include <inttypes.h>
#include <string.h>
#include <compat/ina90.h> // ==> _NOP()
#include "timer.h"
#include "lcd.h"
#define WAIT_250_ns() _NOP()
#define LCD_DATA_MODE() (PORTC |= (1<<PC4))
#define LCD_CMD_MODE() (PORTC &= ~(1<<PC4))
#define LCD_SET_ENABLE() (PORTC |= (1<<PC5))
#define LCD_RESET_ENABLE() (PORTC &= ~(1<<PC5))
// !!!!!!!
#define LCD_SET_READ() DDRC &= ~(0x0f);PORTC &= ~(0x0f);PORTB |= (1<<PB0)
#define LCD_SET_WRITE() PORTB &= ~(1<<PB0);DDRC |= 0x0f
#define LCD_BUSY_FLAG (0x80)
// !!!!!!!
static inline uint8_t lcd_read_byte(uint8_t RS)
{
uint8_t byte;
if (RS)
LCD_DATA_MODE();
else
LCD_CMD_MODE();
LCD_SET_READ();
LCD_SET_ENABLE();
WAIT_250_ns();
byte = (PINC<<4);
LCD_RESET_ENABLE();
WAIT_250_ns();
WAIT_250_ns();
LCD_SET_ENABLE();
WAIT_250_ns();
byte |= PINC & 0x0f;
LCD_RESET_ENABLE();
return byte;
}
static inline void lcd_wait_while_busy(void)
{
uint8_t byte;
do {
byte = lcd_read_byte(0);
} while (byte & LCD_BUSY_FLAG);
return;
}
static inline void send_nibble(uint8_t nibble)
{
LCD_SET_WRITE();
PORTC = (PORTC & 0xf0) | (0x0f & nibble);
LCD_SET_ENABLE();
WAIT_250_ns();
LCD_RESET_ENABLE();
}
/**
* Send one byte to the LCD
* \param byte The byte to send to the LCD
* \param RS specifies whether byte sent is data (RS==1) or command (RS==0)
*/
static inline void lcd_send_byte(uint8_t byte, uint8_t RS)
{
lcd_wait_while_busy();
if (RS)
LCD_DATA_MODE();
else
LCD_CMD_MODE();
send_nibble(byte >> 4);
_NOP();
send_nibble(0x0f & byte);
}
int lcd_get(void)
{
lcd_wait_while_busy();
return lcd_read_byte(1);
}
int lcd_put(char c)
{
lcd_send_byte(c, 1);
return 0;
}
void lcd_puts(char *s)
{
while (*s) {
//lcd_put(*s++);
lcd_send_byte(*s++, 1);
}
}
void lcd_cursor(uint8_t blink)
{
if (blink) {
// enable display with cursor + blinking
lcd_send_byte(0x0f, 0);
}
else {
// enable display, no cursor, no blinking
lcd_send_byte(0x0c, 0);
return;
}
}
void lcd_init(void)
{
/* Initialize both ATmega and Dsiplay
* After return from this function,
* display we be set to 4-bit data mode
*/
// wait until LCD gets ready to accept instructions.
timer_wait(50);
// set CONTROL Pins as outputs:
DDRC = 0x3f;
DDRB |= (1<<PB0);
LCD_CMD_MODE();
LCD_SET_WRITE();
// set LCD to 8-bit mode
send_nibble(0x03);
timer_wait(5);
send_nibble(0x03);
timer_wait(5);
send_nibble(0x03);
// LCD definitely is in 8-bit mode now
// set module to 4-bit mode now
// Remember! As we're in 8-bit mode now,
// send_nibble is the right thing, not send_byte!
timer_wait(5);
send_nibble(0x02);
timer_wait(5);
// set to 5 x 8 dots per character,
// 16 characters per line, 2 lines
lcd_send_byte(0x28, 0);
// enable display, no cursor, no blinking
//lcd_send_byte(0x0c, 0);
// enable display with cursor + blinking
//lcd_send_byte(0x0f, 0);
lcd_cursor(1);
// Set display to
// + Move cursor (and do not shift display)
// + Move right
lcd_send_byte(0x04, 0);
// clear dislay
lcd_clear();
return;
}
void lcd_clear(void)
{
lcd_send_byte(0x01, 0);
}
void lcd_locate(uint8_t row, uint8_t col)
{
if (row)
col += 0x40;
lcd_send_byte(0x80 + col, 0);
}