/*-----------------------------------------------------------------
 * LCDLib.c
 * Funcions de control d'un LCD de 4 bits, 2 línies, 16 caracters i
 * 5x10 punts per caràcter
 * Novembre de 2003
 * -------------------------------------------------------------------*/

#include <8051.h>
#include "lcd.h"
#ifndef NOP
#define NOP _asm nop _endasm
#endif
#define LCD_RS P1_0
#define LCD_RW P1_1
#define LCD_CE P1_2
#define LCD_DB4 P1_3
#define LCD_DB5 P1_4
#define LCD_DB6 P1_5
#define LCD_DB7 P1_6
#define WAIT_CYCLES 4000
#define LCD_CTRL 0
#define LCD_DATA 1

//Taula amb les adreces de les posicions del LCD
static const unsigned char code adrecesLCD[2][16] = {
	{0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F},
	{0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF}
};

/*
Inicialització de l'LCD a 4 bits, 2 linies y 5x10 punts per caracter
*/
void initLCD() {
	//Esperam a que Vdd=4.5 v. i realitzam les primeres inicialitzacions
	retart(WAIT_CYCLES);
	enviarLCD(0x03, LCD_CTRL);
	retart(WAIT_CYCLES);
	enviarLCD(0x03, LCD_CTRL);
	retart(WAIT_CYCLES);
	enviarLCD(0x03, LCD_CTRL);
	retart(WAIT_CYCLES);
	enviarLCD(0x02, LCD_CTRL);
	retart(WAIT_CYCLES);
	//configuració del LCD : 4bits, 2 línies i 5x10 punts (Function Set)
	enviarLCD8(0x2C, LCD_CTRL);
	// Desactivar el Display (Display OFF Control).
	esperaLCD();
	enviarLCD8(0x08, LCD_CTRL);
	borrarLCD();
	//Configuració del mode d'entrada increment (Entry Mode Set)
	esperaLCD();
	enviarLCD8(0x06, LCD_CTRL);
	// Activar el display amb parpelleig i cursor (Display ON Control).
	esperaLCD();
	enviarLCD8(0x0C, LCD_CTRL);
	esperaLCD();
}

/*
Espera un determinat nombre de cicles.
- a: nombre de cicles que ha de esperar
*/
void retart(int a) {
	int i=0;
	for (i=0;i<a;i++) {
		NOP;
	}
}

/*
Espera que l'LCD estigui lliure. Realitza una espera activa fins que el bit
de ocupat de l'LCD (LCD_DB7) estigui a 1.
Aquesta funció es fa servir per a esperar abans de enviar dades a l'LCD.
*/
void esperaLCD() {
	bit b = 1;
	LCD_CE = 0;
	LCD_DB7 = 1;
	LCD_RW=1;
	LCD_RS=0;
	while (b) {
		LCD_CE=1;
		NOP;
		b=LCD_DB7;
		LCD_CE=0;
		//Part Baixa, no la feim servir
		NOP;
		LCD_CE=1;
		NOP;
		LCD_CE=0;
	}
}

/*
Envia una dada o una instrucció de control cap a l'LCD (només escriu en els 4 bits baixos).
- com: dada/instrucció que s'envia.
- tipus: indica si el que se envia és una dada (LCD_DATA) o
una instrucció de control (LCD_CTRL)
*/
void enviarLCD(unsigned char com, bit tipus) {
	LCD_CE=0;
	LCD_DB4=(com & 0x01);
	LCD_DB5=(com & 0x02);
	LCD_DB6=(com & 0x04);
	LCD_DB7=(com & 0x08);
	LCD_RS=tipus;
	LCD_RW=0; //Mode Escriptura
	NOP;
	LCD_CE=1;
	NOP;
	NOP;
	LCD_CE=0;
}

/*
Laboratori de Sistemes LCD
Envia una dada de 8 bits cap a l'LCD
*/
void enviarLCD8(char c, bit tipus) {
	enviarLCD((c & 0xF0)>>4, tipus); //Enviem la part alta del caracter
	enviarLCD((c & 0x0F), tipus); //Enviem la part baixa del caracter
}

void borrarLCD() {
	esperaLCD();
	enviarLCD8(0x01, LCD_CTRL);
}

/*
Situa el cursor a la posició x,y del LCD
*/
void posicionarLCD(unsigned char x, unsigned char y) {
	esperaLCD();
	enviarLCD8(adrecesLCD[x][y], LCD_CTRL);
}

/*
Escriu un caracter a l'LCD
- c: caracter a escriure
*/
void escriuCharLCD(char c) {
	esperaLCD();
	enviarLCD8(c, LCD_DATA);
}

/*
Escriu un string a l'LCD
- ps: punter a la cadena que es vol escriure
*/
void escriuStrLCD(char *ps) {
	while (*ps) {
		escriuCharLCD(*ps++);
	}
}

/*
---------------------------------------------------
exempleLCD1.c - Exemple d'utilització de la llibreira LCDLib per a
escriure el texte "Test LCD"
Novembre 2003
---------------------------------------------------
*/
/*#include <8051.h>
#include "LCDLib.h"
void main() {
	initLCD();
	posicionarLCD(0, 0);
	escriuStrLCD("Test LCD");
}*/

