I2C EEPROMs, 2432, 2465, 24128, 24256 - CCS PCM Compiler


// Program 24_256_1.C (CCS Info PCM Compiler - PIC16F84)
//
// Illustrates how to write a byte to an address and read a byte from an
// an address.  
//
// May be used for the following EEPROMs;
// 
//	2432 (max adr 0x0fff)
//	2465 (max adr 0x1fff)
//	24128 (max adr 0x3fff)
//	24256 (max adr 0x7fff)
//
// Program writes the 16 values 0xff, 0xfe, etc to locations beginning
// at memory adr 0x0700.  Reads them back and displays on serial LCD.
//
//    PIC16F84                            24LC256
//
// RB1 (term 7) ------------------- SCL (term 6) ----- To Other
// RB2 (term 8) ------------------- SDA (term 5) ----- I2C Devices
//
// Note that the slave address is determined by A2 (term 3), A1
// (term 2) and A0 (term 1) on the 24LC256.  The above SCL and SDA leads
// may be multipled to eight group "1010" devices, each strapped for a
// unique A2 A1 A0 setting.
//
// 10K pullup resistors to +5VDC are required on both signal leads.
//
// Serial LCD is connected to RA0.  Serial data is 9600 baud, inverted.
//
//
// copyright, Peter H. Anderson, Scotland Co, NC, Mar, '99

#case

#include <16f84.h>
#include <string.h>
#include <defs_f84.h>	// See Notes

// routines used for 24LC256
void random_write(byte dev_adr, long mem_adr, byte dat);
byte random_read(byte dev_adr, long mem_adr);

// common i2c routines
byte i2c_in_byte(void);
void i2c_out_byte(byte o_byte);
void i2c_nack(void);
void i2c_ack(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_high_sda(void);
void i2c_low_sda(void);
void i2c_high_scl(void);
void i2c_low_scl(void);

// LCD routines
void delay_ms(long t);
void delay_10us(int t);
void lcd_init(void);
void out_RAM_str(int *s);
void lcd_hex_byte(int val);
void lcd_dec_byte(int val, int digits);
int num_to_char(int val);
void lcd_char(int ch);
void lcd_new_line(void);

#define TxData 0	// RA.0 for serial LCD
#define SDA_PIN rb2	// RB.2
#define SCL_PIN rb1	// RB.1

#define SDA_DIR trisb2
#define SCL_DIR trisb1

void main(void)
{
   long mem_adr;
   byte dat, n;
while(1)
{
   mem_adr=0x0700;
   for(n=0; n<16; n++)
   {
      dat = 0xff-n;
      random_write(0x00, mem_adr, dat);
      ++mem_adr;
   }
	// now, read the data back and display
   lcd_init();
   mem_adr=0x0700;
   for(n=0; n<16; n++)
   {
      if ((n!=0) && ((n%4) == 0))
      {
         lcd_new_line();
      }
      dat = random_read(0x00, mem_adr);
      lcd_hex_byte(dat);
      lcd_char(' ');
      ++mem_adr;
   }
   delay_ms(500);
} // end of while
}

void random_write(byte dev_adr, long mem_adr, byte dat)
{
   i2c_start();
   i2c_out_byte(0xa0 | (dev_adr << 1));
   i2c_nack();
   i2c_out_byte((mem_adr >> 8) & 0xff);	// high byte of memory address
   i2c_nack();
   i2c_out_byte(mem_adr & 0xff);	// low byte of mem address
   i2c_nack();
   i2c_out_byte(dat);			// and finally the data
   i2c_nack();
   i2c_stop();
   delay_ms(25); // allow for the programming of the eeprom
}

byte random_read(byte dev_adr, long mem_adr)
{
   byte y;
   i2c_start();
   i2c_out_byte(0xa0 | (dev_adr << 1));
   i2c_nack();
   i2c_out_byte((mem_adr >> 8) & 0xff);
   i2c_nack();
   i2c_out_byte(mem_adr & 0xff);
   i2c_nack();
   i2c_start();				// no intermediate stop
   i2c_out_byte(0xa1 | (dev_adr << 1));	// read operation
   i2c_nack();
   y=i2c_in_byte();
   i2c_stop();
   return(y);
}

// Common I2C Routines

byte i2c_in_byte(void)
{
   byte i_byte, n;
   i2c_high_sda();
   for (n=0; n<8; n++)
   {
      i2c_high_scl();

      if (SDA_PIN)
      {
         i_byte = (i_byte << 1) | 0x01; // msbit first
      }
      else
      {
         i_byte = i_byte << 1;
      }
      i2c_low_scl();
   }
   return(i_byte);
}

void i2c_out_byte(byte o_byte)
{
   byte n;
   for(n=0; n<8; n++)
   {
      if(o_byte&0x80)
      {
         i2c_high_sda();
      }
      else
      {
         i2c_low_sda();
      }
      i2c_high_scl();
      i2c_low_scl();
      o_byte = o_byte << 1;
   }
   i2c_high_sda();
}

void i2c_nack(void)
{
   i2c_high_sda();	// data at one
   i2c_high_scl();	// clock pulse
   i2c_low_scl();
}

void i2c_ack(void)
{
   i2c_low_sda();	// bring data low and clock
   i2c_high_scl();
   i2c_low_scl();
   i2c_high_sda();
}


void i2c_start(void)
{
   i2c_low_scl();
   i2c_high_sda();
   i2c_high_scl();	// bring SDA low while SCL is high
   i2c_low_sda();
   i2c_low_scl();
}

void i2c_stop(void)
{
   i2c_low_scl();
   i2c_low_sda();
   i2c_high_scl();
   i2c_high_sda();  // bring SDA high while SCL is high
   // idle is SDA high and SCL high
}

void i2c_high_sda(void)
{
   // bring SDA to high impedance
   SDA_DIR = 1;
   delay_10us(5);
}

void i2c_low_sda(void)
{
   SDA_PIN = 0;
   SDA_DIR = 0;  // output a hard logic zero
   delay_10us(5);
}

void i2c_high_scl(void)
{
   SCL_DIR = 1;   // high impedance
   delay_10us(5);
}

void i2c_low_scl(void)
{
   SCL_PIN = 0;
   SCL_DIR = 0;
   delay_10us(5);
}

// LCD routines

void delay_10us(int t)
{
#asm
      BCF STATUS, RP0
DELAY_10US_1:
      CLRWDT
      NOP
      NOP
      NOP
      NOP
      NOP
      NOP
      DECFSZ t, F
      GOTO DELAY_10US_1
#endasm
}

void delay_ms(long t)	// delays t millisecs
{
   do
   {
     delay_10us(100);
   } while(--t);
}

int num_to_char(int val)	// converts val to hex character
{
   int ch;
   if (val < 10)
   {
     ch=val+'0';
   }
   else
   {
     val=val-10;
     ch=val + 'A';
   }
   return(ch);
}

void lcd_char(int ch)	// serial output to PIC-n-LCD, 9600 baud
{
   int n, dly;
   		// start bit + 8 data bits

  #asm
       BCF STATUS, RP0
       MOVLW 9
       MOVWF n
       BCF STATUS, C

  LCD_CHAR_1:

       BTFSS STATUS, C
       BSF PORTA, TxData
       BTFSC STATUS, C
       BCF PORTA, TxData
       MOVLW 32
       MOVWF dly

  LCD_CHAR_2:
       DECFSZ dly, F
       GOTO LCD_CHAR_2
       RRF ch, F
       DECFSZ n, F
       GOTO LCD_CHAR_1

       BCF PORTA, TxData
       CLRWDT
       MOVLW 96
       MOVWF dly

  LCD_CHAR_3:
       DECFSZ dly, F
       GOTO LCD_CHAR_3
       CLRWDT
   #endasm
}

// LCD routines

void lcd_init(void)	// sets TxData in idle state and resets PIC-n-LCD
{
  #asm
        BCF STATUS, RP0
        BCF PORTA, TxData
        BSF STATUS, RP0
        BCF TRISA, TxData
        BCF STATUS, RP0
   #endasm
   lcd_char(0x0c);
   delay_ms(250);
}

void lcd_new_line(void)	// outputs 0x0d, 0x0a
{
   lcd_char(0x0d);
   delay_ms(10);	// give the PIC-n-LCD time to perform the
   lcd_char(0x0a);	// new line function
   delay_ms(10);
}


void out_RAM_str(int *s)
{
   while(*s)
   {
      lcd_char(*s);
      ++s;
   }
}

void lcd_hex_byte(int val) // displays val in hex format
{
   int ch;
   ch = num_to_char((val>>4) & 0x0f);
   lcd_char(ch);
   ch = num_to_char(val&0x0f);
   lcd_char(ch);
}

void lcd_dec_byte(int val, int digits)
// displays byte in decimal as either 1, 2 or 3 digits
{
   int d;
   int ch;
   if (digits == 3)
   {
      d=val/100;
      ch=num_to_char(d);
      lcd_char(ch);
   }
   if (digits >1)	// take the two lowest digits
   {
       val=val%100;
       d=val/10;
       ch=num_to_char(d);
       lcd_char(ch);
   }
   if (digits == 1)	// take the least significant digit
   {
       val = val%100;
   }

   d=val % 10;
   ch=num_to_char(d);
   lcd_char(ch);
}