The multi-byte reading of EEPROM under I2C bus is not difficult, basically a little change on the basis of one byte reading, so let's review the function of reading a single byte and see what he means at each step.
The read data explained here are all optional reads under EEPROM24C02: The time series is as follows
The timing analysis is as follows: the first step starts the bus, the second step addressing the device, the third step sends an answer signal, the fourth step addressing the device, the fifth step sends an answer signal, the sixth step reads the data, and the seventh step sends a stop signal.
******************************************************************************** Function name: E2ReadByte() Return parameter: Returns a byte read from the machine Parameter List: The first parameter is the device address I2C_Add Provide an address for device addressing, The second parameter is the device subaddress addr Yes, the function will start reading data from this address *********************************************************************************/ uchar E2ReadByte(uchar I2C_Add,uchar addr) { uchar dat; I2C_Start();//Start Bus I2C_WriteByte(I2C_Add<<1);//Device Addressing, Writing I2C_WriteByte(addr);//Sub-device addressing tells the device where to start reading I2C_Start();//Start Bus I2C_WriteByte((I2C_Add<<1)|(0x01));//Sub-device addressing, read operation dat=I2C_ReadByte(); SendACK(1);//Response to a NOACK I2C_Stop();//End signal return dat; }
Let's first analyze what the above code means.
Each time the I2C bus writes to a data device, it needs to send an answer signal, so I encapsulate the function that receives ACK inside the I2C data write function, and then I will release the code.
This is a code function that reads EEPROM24C02 in a single byte, starting with the following steps
1. Invoke the I2C bus startup function to start the bus.
2. Call I2C bus for device addressing, assign the address of the device to a function, the direction of which is the pseudo-operation, the meaning of pseudo-writing is to facilitate the operation of the sub-devices below.
3. Call the I2C bus for addressing the sub-device, which is related to step 3. The meaning of this sub-device addressing is to tell the device that it needs to start reading from this address, which is equivalent to writing the sub-device address to the device.
4. The next step is to read the data, because the third step is a pseudo-write operation, that is, a write operation, and the direction changes when the data is read next, the bus needs to be restarted.
5. Call the I2C read data function again to tell the host the address of the sub-device and the direction is read.
6. After reading the data, the host needs to give an answer signal to the slave machine, telling the device that I do not need to read the data now, 1 is NO ACK, 0 is ACK.
7. End bus operation completed.
Okay, now on the way, multibyte read from the EEPROM of the I2C bus
Place code first:
/******************************************************************************** Function name: E2nReadByte() Return parameters: Parameter List: The first parameter is the device address I2C_Add provides address for device addressing, The second parameter is the device subaddress addr, from which the function will start reading data The third parameter is a pointer that receives an array of Buf s to access the read data, and the fourth parameter, len, represents how many bytes to read *********************************************************************************/ void E2nReadByte(uchar I2C_Add,uchar addr,uchar *buf,uint len) { I2C_Start();//Start Bus I2C_WriteByte(I2C_Add<<1);//Device addressing, write operations, internal operations from machine I2C_WriteByte(addr);//Sub-device addressing tells the device where to start reading I2C_Start();//Start Bus I2C_WriteByte((I2C_Add<<1)|(0x01));//Sub-device addressing, directed toward read operation while(len>1) { *buf++=I2C_ReadByte();//Read a byte SendACK(0);//The host sends an ACK telling the slave that I still need to read data len--; } *buf=I2C_ReadByte();//Last byte SendACK(1);//Response to a NOACK I2C_Stop();//End signal }
Here are just a few minor modifications, adding a while loop, and using a buf array to save data, since bytes are read continuously, remember to send an ACK answer signal to the slave after each byte read, telling it that I need to read the data again.
Below is the accompanying I2C bus code:
bit I2C_WriteByte(uchar dat) { uchar temp; bit ack; for(temp=0x80;temp!=0;temp>>=1)//1010 0000 {//0000 0000 if( (temp&dat) ==0)//Check if current is 0 or 1 SDA=0; else SDA=1; I2C_delay();//Pull up the clock line after a delay of at least 4.7us SCL=1; I2C_delay();//Delay keeps pulling up at least 4us SCL=0;//Pull down after keeping pulling up at least 4us } ack=I2C_Ack();//Receive an ACK return ack; }
bit I2C_Ack() { bit ack; SDA=1;//Host actively releases SDA in preparation for ACK reading I2C_delay();//Delay at least 4.7us for SCL low level SCL=1;//Raise level after delay ack=SDA;//Read ACK I2C_delay();//Delay at least 4us for SCL high level SCL=0;//Lower SCL, release return ack; }
//Send an ACK response to the device void SendACK(bit ACk) { SDA=ACk;//Release Bus I2C_delay();//Keep ACK down at least 4.7us SCL=1; I2C_delay(); SCL=0; }