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