#include <REG52.H>

// EXAMPLE Port & Pin definitions to match the 8052.com Tutorial
sbit LCD_EN = P3^7;
sbit LCD_RS = P3^6;
sbit LCD_RW = P3^5;
#define LCD_PORT P0

// Funtion prototype
void lcd_data(unsigned char dat);


/*
 * this routine displays the supplied 8-bit unsigned number
 * in hexadecimal notation.
 *
 * The hexadecimal display is achieved by sending two ASCII-coded
 * characters to the LCD; eg the number 0xA4 is displayed by sending 
 * a '4' character followed by an 'A' character.
 */ 
void hex2lcd( unsigned char number ) 
{ 
  unsigned char MSD; // used to extract the Most-Significant  (MS) Hex Digit of the number
  unsigned char LSD; // used to extract the Least-Significant (LS) Hex Digit of the number

  MSD = (number&0xf0) >>4; // extract the MS Hex Digit; ie the top 4 bits
  LSD = (number&0x0f);     // extract the LS Hex Digit; ie the bottom 4 bits

  // First, obtain the character to represent the MS Hex digit
  // Note that the conversion differs slightly depending on whether the value is 0x0-0x9 or 0xA-0xF
  if( MSD < 0xA )
  { 
	// The MS Digit is less than 0xA; ie it is in the range 0x0-0x9
	// Convert it to the corresponding ASCII character code '0' to '9'.
	// This conversion is easy, as we just have to add the value of the digit, 0x0-0x9,
	// to the value of the ASCII code for a '0' character
    MSD += '0'; 
  }
  else 
  {
	// The MS Digit is not less than 0xA; ie it is in the range 0xA-0xF
	// Convert it to the corresponding ASCII character code 'A' to 'F'
	// This conversion is slightly more complicated, as the values we are converting
	// are in the range 0xA-0xF; so we cannot simply add the value to be converted
	// to the ASCII code for an 'A' character - hence the subtraction of 0xA
	// (note that a decent compiler will do the subtraction at compile-time, and 
	//  will not generate code to work it out every time this line is executed!)
    MSD += ('A' - 0xA); 
  }

  // Now obtain the character to represent the LS Hex digit
  // The process is exactly the same as for the MS digit
  // Note that, since we have the MS and LS Digits in separate variables, it doesn't
  // matter in which order we convert the digits.
  if( LSD < 0xA )
  { 
    LSD += '0'; 
  }
  else 
  {
    LSD += ('A' - 0xA); 
  }

  // Now send the two characters forming the hex representation to the display
  // Note that it is now important that we send them in the correct order!
  lcd_data( MSD ); 
  lcd_data( LSD ); 
} 

/*
 * this routine displays the supplied 8-bit unsigned number
 * in decimal notation, with leading zeros; ie "000" to "255"
 *
 * The decimal display is achieved by sending three ASCII-coded
 * characters to the LCD; eg the number 0x78 (123 decimal) is displayed by 
 * sending  a '1' character followed by a '2' character followed by a '3' character.
 */ 
void dec2lcd(unsigned char number) 
{ 
  unsigned char h=0; // used to extract the "hundreds" Digit of the number in decimal notation
  unsigned char t=0; // used to extract the "tens"     Digit of the number in decimal notation

  // First, determine the number of "hundreds" in the number.
  // We do this by repeatedly subtracting 100 until the number falls below 100, 
  // and counting how many times we subtracted 100
  while( number >= 100 ) 
  { 
    number -= 100; 
    h++; 			// Count another "hundred"
  } 

  // The number now has no "hundreds" - either it had none to start with, or
  // they have all just been subtracted. 
  // Next, determine the number of "tens" in the number.
  // Again, we do this by repeatedly subtracting 10 until the number falls below 10, 
  // and counting how many times we subtracted 10
  while(number>=10) 
  { 
    number -= 10; 
    t++; 
  } 

  // The number now has no "hundreds" and no "tens" - either it had none to start with, or
  // they have all just been subtracted. 
  // All that is now left is the units!
  // Now send the 3 digits - "hundreds", "tens", and "units" - to the display as ASCII-Coded
  // Characters.
  // Because each digit must be in the range 0-9, the corresponding ASCII code is found by
  // adding the digit value to the value of the ASCII code for a '0' character 
  lcd_data(      h + '0' ); // hundreds
  lcd_data(      t + '0' ); // tens
  lcd_data( number + '0' ); // units (remember: number was left containing just units)
} 

/* 
 * This Routine sends the supplied byte to the LCD
 *
 * Note that you must supply appropriate definitions for the port pins
 * used by the LCD, and these must be bit-addressable
 *
 * Note also that the LCD must be properly initialised, and the control lines
 * in their proper states,  before calling this function.
 *
 * Note also that a software delay loop is used to set the length of the
 * Enable pulse - YOU WILL ALMOST CERTAINLY NEED TO MODIFY THIS TO MATCH
 * YOUR PARTICULAR CLOCK FREQUENCY, CHIP INSTRUCTION TIMINGS, COMPILER
 * SETTINGS, etc. (in fact, it would be better to write a separate assembler
 * delay routine).
 *
 */
void lcd_data( unsigned char dat) 
{ 
  unsigned char a; // Loop counter for the delay loop - YOU MAY NEED TO MODIFY THIS!

  LCD_RS=1;           // Set the Register Select line high indicating data for display
  LCD_RW=0; 		  // Set the Read/Write line low indicating a Write to the display
  LCD_PORT=( dat );   // Write the supplied byte to the LCD port

  // Now pulse the Enable line so that the LCD will see the data
  LCD_EN=1; 		      // Set the EN line high
  for( a=0; a<0xf; a++ ); // Pause a while - YOU WILL NEED TO MODIFY THIS!
  LCD_EN=0; 		      // Set the EN line low
} 