//Project: Compass Module HMC6352 Example
//Programmer: Shahrulnizam Mat Rejab
//PIC: PIC16F877A
//Crystal Frequency: 20MHz
//Compiler: HI-TECH ANSI C
//Last Modified: 30 June 2011
//Website: http://shahrulnizam.com

#include <pic.h>
#include <htc.h>
__CONFIG(0x3F32);
#define	LCD_RS 		RD0
#define LCD_RW		RD1
#define LCD_EN 		RD2
#define LCD_LIGHT	RD3
#define LCD_DATA 	PORTD		//D7-D4
#define	LCD_PULSE() ((LCD_EN=1),(LCD_EN=0))
#define HMC_ADDRESS	0b01000010
#define _XTAL_FREQ 	20000000

void pic_init(void);
void lcd_init(void);
void lcd_write(unsigned char);
void lcd_clear(void);
void lcd_goto(unsigned char pos);
void lcd_string(const char *s);
void i2c_start(void);
void i2c_stop(void);
void i2c_wait(void);
int hmc_data(char address);
void convert(int no, char base);
void display(char number);

char di[10];

main(void)
{
int i,heading;
pic_init();					//initialize PIC
lcd_init();					//initialize LCD
lcd_goto(0x00);					//select first line
lcd_string("  HMC6352 EXAMPLE   ");		//display string
lcd_goto(0x40);					//select second line
lcd_string("                    ");		//display string
lcd_goto(0x14);					//select third line
lcd_string("                    ");		//display string
lcd_goto(0x54);					//select fourth line
lcd_string("                    ");		//display string

i2c_start();
SSPBUF=HMC_ADDRESS;				//write
i2c_wait();
SSPBUF='O';					//update bridge offsets
i2c_wait();
i2c_stop();
for(;;){
	heading=hmc_data(HMC_ADDRESS);

	lcd_goto(0x14);
	lcd_string("  Heading = ");
	convert(heading,10);
	for(i=3;i>=1;i--) display(di[i]);
	lcd_string(".");
	display(di[0]);
	lcd_write(0);
	lcd_string("  ");
	__delay_ms(100);
}}

void pic_init(void)
{
TRISA=0b00000000;
TRISB=0b00000000;
TRISC=0b00000000;
TRISD=0b00000000;
TRISE=0b00000000;
ADCON1=0b00000110;			
PORTA=0b00000000;
PORTB=0b00000000;
PORTC=0b00000000;
PORTD=0b00000000;
PORTE=0b00000000;
//I2C Initialize
TRISC3=1;
TRISC4=1;
SSPADD=40;
SSPCON=0b00101000;			//Master mode	
}

/* initialise the LCD - put into 4 bit mode */
void lcd_init(void)
{
__delay_ms(15);				//delay for LCD Power Up
lcd_write(0x28); 			//function set
lcd_write(0x0C); 			//display on/off control
lcd_clear();				//clear screen
lcd_write(0x06); 			//entry mode set
LCD_LIGHT=1;

LCD_RS=0;
lcd_write(0x40);
LCD_RS=1;
lcd_write(0b01110);
lcd_write(0b01010);
lcd_write(0b01110);
lcd_write(0b00000);
lcd_write(0b00000);
lcd_write(0b00000);
lcd_write(0b00000);
lcd_write(0b00000);
}

/* write a byte to the LCD in 4 bit mode */
void lcd_write(unsigned char c)
{
LCD_DATA=(LCD_DATA&0x0F)|(c&0xF0);
LCD_PULSE();
LCD_DATA=(LCD_DATA&0x0F)|((c<<4)&0xF0);
LCD_PULSE();
__delay_us(40);
}

/* clear LCD and goto home */
void lcd_clear(void)
{
LCD_RS=0;
lcd_write(0x1);
__delay_ms(2);
}

/* write a string of chars to the LCD */
void lcd_string(const char *s)
{
LCD_RS=1;				// write characters
while(*s)
lcd_write(*s++);
}

/* go to the specified position */
void lcd_goto(unsigned char pos)
{
LCD_RS=0;
lcd_write(0x80+pos);
LCD_RS=1;
}

void i2c_start(void){
SEN=1;
while(SSPIF==0) continue;
SSPIF=0;
}

void i2c_stop(void){
PEN=1;
while(SSPIF==0) continue;
SSPIF=0;
}

void i2c_wait(void){
while(SSPIF==0) continue;
SSPIF=0;
}

int hmc_data(char address){
int data;
i2c_start();
SSPBUF=address;				//write
i2c_wait();
SSPBUF='A';
i2c_wait();
i2c_stop();

i2c_start();
SSPBUF=address+1;			//read		
i2c_wait();	
RCEN=1;					//enable reception
i2c_wait();
data=SSPBUF;
ACKDT=0;
ACKEN=1;				//send acknowledgement
i2c_wait();
RCEN=1;					//enable reception
i2c_wait();
data=256*data+SSPBUF;
ACKDT=1;
ACKEN=1;				//send acknowledgement
i2c_wait();
i2c_stop();
return data;
}

void convert(int no, char base)
{char i;
for(i=0;i<=9;i++) di[i]=0;
i=0;
do{
	di[i]=no%base;
	no=no/base;
	i=i+1;}
while(no!=0);
}

void display(char number)
{switch(number){
case 0:{lcd_string("0");break;}
case 1:{lcd_string("1");break;}
case 2:{lcd_string("2");break;}
case 3:{lcd_string("3");break;}
case 4:{lcd_string("4");break;}
case 5:{lcd_string("5");break;}
case 6:{lcd_string("6");break;}
case 7:{lcd_string("7");break;}
case 8:{lcd_string("8");break;}
case 9:{lcd_string("9");break;}
case 10:{lcd_string("A");break;}
case 11:{lcd_string("B");break;}
case 12:{lcd_string("C");break;}
case 13:{lcd_string("D");break;}
case 14:{lcd_string("E");break;}
case 15:{lcd_string("F");break;}
default:{lcd_string("?");break;}
}}