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);
}