#include <pic18fregs.h>
#include <delay.h>
#include <stdlib.h>

#pragma stack 0x80 32

code char at __CONFIG1H _conf0 = _OSC_XT_1H &_FCMEN_OFF_1H;
code char at __CONFIG2L _conf1 = _BODEN_OFF_2L & _PUT_OFF_2L;
code char at __CONFIG2H _conf2 = _WDT_DISABLED_CONTROLLED_2H;
code char at __CONFIG4L _conf4 = _LVP_OFF_4L & _BACKBUG_OFF_4L & _STVR_OFF_4L;

// DEFINITIONS FOR SENSIRION SHT11
#define	WAIT(void)  	{ delay10tcy( 1 ); }
#define	SCK   			LATCbits.LATC1
#define	DATA_DIR		TRISCbits.TRISC0
#define	DATA_OUT  		LATCbits.LATC0
#define	DATA_IN	  		PORTCbits.RC0
#define	DATA_DIR_IN		1
#define	DATA_DIR_OUT	0
#define	REQ_TEMPERATURE 0x03
#define	REQ_HUMIDITY	0x05

// DEFINITIONS FOR LCD
#define LCD_RS			LATBbits.LATB7		// 0 = COMMAND; 1 = DATA
#define LCD_WR			LATBbits.LATB6		// 0 = WRITE; 1 = READ
#define LCD_ENABLE		LATBbits.LATB5
#define LCD_D4			LATBbits.LATB4
#define LCD_D5			LATBbits.LATB3
#define LCD_D6			LATBbits.LATB2
#define LCD_D7			LATBbits.LATB1
#define lcd_cmd_clear			0x01
#define lcd_cmd_home			0x02
#define lcd_cmd_4bits			0x28
#define lcd_cmd_display_on		0x0C
#define lcd_cmd_display_off		0x08
#define lcd_cmd_cursor_on		0x0E
#define lcd_cmd_cursor_off		0x0C
#define set_lcd_write() { LCD_WR = 0; delay10tcy( 5 ); }
#define set_lcd_read() { LCD_WR = 1; delay10tcy( 5 ); }
#define set_lcd_cmd() { LCD_RS = 0; delay10tcy( 5 ); }
#define set_lcd_data() { LCD_RS = 1; delay10tcy( 5 ); }
#define set_lcd_enable() { LCD_ENABLE = 1; delay10tcy( 5 ); }
#define set_lcd_disable() { LCD_ENABLE = 0; delay10tcy( 5 ); }


// FUNCTIONS FOR LCD
void lcd_write_8bits( unsigned char byte ) {
	set_lcd_write();
	LCD_D4 = ( byte & 0x10 ) >> 4;
	LCD_D5 = ( byte & 0x20 ) >> 5;
	LCD_D6 = ( byte & 0x40 ) >> 6;
	LCD_D7 = ( byte & 0x80 ) >> 7;
	delay10tcy( 5 );
	set_lcd_enable();
	set_lcd_disable();
}

void lcd_write_4bits( unsigned char byte ) {
	set_lcd_write();
	LCD_D4 = ( byte & 0x10 ) >> 4;
	LCD_D5 = ( byte & 0x20 ) >> 5;
	LCD_D6 = ( byte & 0x40 ) >> 6;
	LCD_D7 = ( byte & 0x80 ) >> 7;
	delay10tcy( 5 );
	set_lcd_enable();
	set_lcd_disable();
	delay10tcy( 5 );
	LCD_D4 = ( byte & 0x01 ) >> 0;
	LCD_D5 = ( byte & 0x02 ) >> 1;
	LCD_D6 = ( byte & 0x04 ) >> 2;
	LCD_D7 = ( byte & 0x08 ) >> 3;
	delay10tcy( 5 );
	set_lcd_enable();
	set_lcd_disable();
}

void lcd_init( void ) {
	set_lcd_cmd();
	lcd_write_8bits( 0x30 );
	lcd_write_8bits( 0x30 );
	lcd_write_8bits( 0x30 );
	lcd_write_8bits( lcd_cmd_4bits );
	lcd_write_4bits( lcd_cmd_display_off );
	lcd_write_4bits( lcd_cmd_cursor_off );
	lcd_write_4bits( lcd_cmd_clear );
	lcd_write_4bits( lcd_cmd_home );
}

void lcd_write_cmd( unsigned char byte ) {
	set_lcd_cmd();
	lcd_write_4bits( byte );
}

void lcd_write_char( unsigned char c ) {
	set_lcd_data();
	lcd_write_4bits( c );
}

void lcd_move_cursor( unsigned char lin, unsigned char col ) {
	set_lcd_cmd();
	lcd_write_4bits( 0x80 + (lin * 0x40) + col );
}

void lcd_write_string( unsigned char *str_ptr ) {
	unsigned char i = 0;
	while ( str_ptr[ i ] != 0 )
		lcd_write_char( str_ptr[ i++ ] );
}

void lcd_write_int( int val ) {
	const unsigned char buf[16];
	itoa( val, buf, 10 );
	lcd_write_string( buf );
}

void lcd_write_float( int valInt, unsigned int valDec ) {
	lcd_write_int( valInt );
	lcd_write_char( '.' );
	lcd_write_int( valDec );
}

// FUNCTION FOR SENSIRION SHT11
unsigned int shtXX_getData( unsigned char value ) wparam {
	unsigned int val = 0;  
	unsigned int i = 0;
	unsigned char error = 0;
	DATA_DIR = DATA_DIR_OUT;
	DATA_OUT = 1; SCK = 0;  
	WAIT();
	SCK = 1;
	WAIT();
	DATA_OUT = 0;
	WAIT();
	SCK = 0;  
	WAIT(); WAIT(); WAIT();
	SCK = 1;
	WAIT();
	DATA_OUT = 1;		   
	WAIT();
	SCK = 0;		
////////////////////////////////////////////////////////////////////
	for ( i=0x80; i>0; i/=2 ) { 
		if ( i & value ) 
			DATA_OUT = 1;
		else 
			DATA_OUT = 0;                        
		SCK = 1;                    
	    WAIT(); WAIT(); WAIT();     
	    SCK = 0;
	}
	DATA_OUT = 1;                 
	DATA_DIR = DATA_DIR_IN;
	SCK = 1;                      
	error = DATA_IN;              
	SCK = 0;        
////////////////////////////////////////////////////////////////////
	for ( i=0; i<65535; i++ ) {
		if( DATA_IN == 0 ) 
			break;
	}
////////////////////////////////////////////////////////////////////
	DATA_DIR = DATA_DIR_OUT;
	DATA_OUT = 1;                 
	DATA_DIR = DATA_DIR_IN;
	val = 0;
	for ( i=0x80; i>0; i/=2 ) { 
		SCK = 1;                    
		if ( DATA_IN ) 
			val = ( val | i ); 
		SCK = 0;  					 
	}
	DATA_DIR = DATA_DIR_OUT;
	DATA_OUT = 0;                 
	SCK = 1;                      
	WAIT(); WAIT(); WAIT();       
	SCK = 0;						    
	DATA_OUT = 1;
	val = val << 8;
////////////////////////////////////////////////////////////////////
	DATA_DIR = DATA_DIR_OUT;
	DATA_OUT = 1;                 
	DATA_DIR = DATA_DIR_IN;
	for ( i=0x80; i>0; i/=2 ) {
		SCK = 1;                    
		if ( DATA_IN )
			val = ( val | i ); 
		SCK = 0;  					 
	}
	DATA_DIR = DATA_DIR_OUT;
	DATA_OUT = 1;                 
	SCK = 1;                      
	WAIT(); WAIT(); WAIT();       
	SCK = 0;						    
	DATA_OUT = 1; 

	return val;
}

// MAIN
void main(void) {
	unsigned int value;
	float realValue;
	ADCON1 = 0x0E;
	TRISA  = 0x31;
	TRISC  = 0x00;
	TRISB  = 0x01;
	delay1mtcy( 1 );
	lcd_init();
	lcd_move_cursor( 0, 0 );
	lcd_write_string( "-= SENSIRION =-" );

	INTCON = 0xC0;  
	INTCONbits.T0IE = 1;
	T0CONbits.T0CS = 0;
	T0CONbits.T08BIT = 0;
	T0CONbits.TMR0ON = 1;
	while ( 1 )	{
		LATAbits.LATA2 = 1;
		lcd_move_cursor( 1, 0 );
		value = shtXX_getData( REQ_TEMPERATURE );
		realValue = -39.6 + ( 0.01 * (float) value );
		value = (int) ( ( (float) realValue - (float) ( (int) realValue ) ) * 100 );
		lcd_write_float( (int) realValue, value ); // if changed to an integer value (15, for example), it compiles OK
		lcd_write_string( "oC " );
		value = shtXX_getData( REQ_HUMIDITY );
		realValue = -4 + ( 0.0405 * (float) value ) + ( ( -0.0000028 ) * (float) value * (float) value );
		value = (int) ( ( (float) realValue - (float) ( (int) realValue ) ) * 100 );
//		lcd_write_float( (int) realValue, value );
//		lcd_write_string( "%RH" );
		LATAbits.LATA2 = 0;
		delay1mtcy( 5 );
	}

}



