如果需要少量的存储数据,24C02是个可选的方案。24C02是I2C接口,由于I2C接口是个低速通讯接口,既可以采用GPIO模拟的方式,也可以使用芯片硬件的I2C接口。
本例程首先接受GPIO模拟的方式,这个例程具有一定的通用性,其他单片机也可以移植过去使用。读写24C02有两个需要注意的地方,一个是24C02可以通过电路配置I2C的读写地址,编写驱动程序的时候需要核对原理图,错误的地址是没有办法读写数据的。另一个需要注意的地方,就是24系列芯片不同容量的型号,页大小是不一样的。比如24C02是8字节每页,24C04/08/16则是16字节每页。
例程分为三个部分:
1 GPIO模拟I2C接口
bool I2C_Start(void)
{
I2C_delay();
SDA_H;
SCL_H;
I2C_delay();
if(!SDA_read) return FALSE; //SDAÏßΪµÍµçƽ×ÜÏß棬Í˳ö
SDA_L;
I2C_delay();
if(SDA_read) return FALSE; //SDAÏßΪ¸ßµçƽÔò×ÜÏß³ö´í£¬Í˳ö
SDA_L;
I2C_delay();
return TRUE;
}
void I2C_Stop(void)
{
SCL_L;
I2C_delay();
SDA_L;
I2C_delay();
SCL_H;
I2C_delay();
SDA_H;
I2C_delay();
}
void I2C_Ack(void)
{
SCL_L;
I2C_delay();
SDA_L;
I2C_delay();
SCL_H;
I2C_delay();
SCL_L;
I2C_delay();
}
void I2C_NoAck(void)
{
SCL_L;
I2C_delay();
SDA_H;
I2C_delay();
SCL_H;
I2C_delay();
SCL_L;
I2C_delay();
}
bool I2C_WaitAck(void) //·µ»ØΪ£º-1ÓÐACK£¬ =0 ÎÞACK
{
bool bstatus;
SCL_L;
I2C_delay();
SDA_H;
I2C_delay();
SCL_H;
I2C_delay();
if(SDA_read) {
bstatus = FALSE;
} else {
bstatus = TRUE;
}
SCL_L;
return bstatus;
}
2 I2C数据读写接口
void I2C_SendByte(u8 SendByte) //Êý¾Ý´Ó¸ßλµ½µÍλ
{
u8 i = 8;
while(i--) {
SCL_L;
I2C_delay();
if(SendByte & 0x80)
SDA_H;
else
SDA_L;
SendByte <<= 1;
I2C_delay();
SCL_H;
I2C_delay();
}
SCL_L;
}
u8 I2C_ReceiveByte(void) //Êý¾Ý´Ó¸ßλµ½µÍλ
{
u8 i = 8;
u8 ReceiveByte = 0;
SDA_H;
while(i--) {
ReceiveByte <<= 1;
SCL_L;
I2C_delay();
SCL_H;
I2C_delay();
if(SDA_read) {
ReceiveByte |= 0x01;
}
}
SCL_L;
return ReceiveByte;
}
//дÈë1×Ö½ÚÊý¾Ý £¨´úдÈëÊý¾Ý£¬´ýдÈëµØÖ·£¬Æ÷¼þÀàÐÍ£©
bool EEPROM_ByteWrite(u8 SendByte, u16 WriteAddress, u8 DeviceAddress)
{
if(!I2C_Start()) return FALSE;
I2C_SendByte(((WriteAddress & 0x0700) >> 7) | (DeviceAddress & 0xFE)); //ÉèÖøßÆðʼµØÖ· + Æ÷¼þµØÖ·
if(!I2C_WaitAck()) {
I2C_Stop();
return FALSE;
}
I2C_SendByte((u8)(WriteAddress & 0x00FF)); //ÉèÖõÍÆðʼµØÖ·
I2C_WaitAck();
I2C_SendByte(SendByte);
I2C_WaitAck();
I2C_Stop();
//×¢Ò⣺ÒòΪÕâÀïÒªµÈ´ýEERPOMдÍê³É£¬¿ÉÒÔ²ÉÓòéѯ »òÑÓʱ·½Ê½£¨10ms£©
Systick_Delay_1ms(10);
return TRUE;
}
//×¢Òâ²»ÄÜ¿çҳд
//дÈë1´®Êý¾Ý£¨´ýдÈëÊý×éµØÖ·£¬´ýдÈ볤¶È£¬´ýдÈëµØÖ·£¬Æ÷¼þÀàÐÍ£©
bool EEPROM_PageWrite(u8 *pBuffer, u8 length, u16 WriteAddress, u8 DeviceAddress)
{
if((length + WriteAddress % I2C_PageSize) > I2C_PageSize) return FALSE;
if(!I2C_Start()) return FALSE;
I2C_SendByte(((WriteAddress & 0x0700) >> 7) | (DeviceAddress & 0xFE)); //ÉèÖøßÆðʼµØÖ· + Æ÷¼þµØÖ·
if(!I2C_WaitAck()) {
I2C_Stop();
return FALSE;
}
I2C_SendByte((u8)(WriteAddress & 0x00FF)); //ÉèÖõÍÆðʼµØÖ·
I2C_WaitAck();
while(length--) {
I2C_SendByte(*pBuffer);
I2C_WaitAck();
pBuffer++;
}
I2C_Stop();
//×¢Ò⣺ÒòΪÕâÀïÒªµÈ´ýEERPOMдÍê³É£¬¿ÉÒÔ²ÉÓòéѯ »òÑÓʱ·½Ê½£¨10ms£©
Systick_Delay_1ms(10);
return TRUE;
}
//¿çҳдÈë1´®Êý¾Ý£¨´ýдÈëÊý×éµØÖ·£¬´ýдÈ볤¶È£¬´ýдÈëµØÖ·£¬Æ÷¼þÀàÐÍ£©
void EEPROM_BufferWrite(u8 *pBuffer, u16 length, u16 WriteAddress, u8 DeviceAddress )
{
u16 i;
u16 Addr = 0, count = 0;
Addr = WriteAddress % I2C_PageSize; //дÈëµØÖ·ÊÇ¿ªÊ¼Ò³µÄµÚ¼¸Ò³
count = I2C_PageSize - Addr; //ÔÚ¿ªÊ¼Ò³ÒªÐ´ÈëµÄ¸öÊý
if(length <= count) {
EEPROM_PageWrite(pBuffer, length, WriteAddress, DeviceAddress); //½öдһҳµÄÊý¾Ý
} else {
EEPROM_PageWrite(pBuffer, count, WriteAddress, DeviceAddress); //ÏÈдµÚÒ»Ò³µÄÊý¾Ý
if((length - count) <= I2C_PageSize) {
EEPROM_PageWrite(pBuffer + count, length - count, WriteAddress + count, DeviceAddress); //½öÔÙдһҳµÄÊý¾Ý½áÊø
} else {
for(i = 0; i < ((length - count) / I2C_PageSize); i++) {
EEPROM_PageWrite(pBuffer + count + i * I2C_PageSize, I2C_PageSize, WriteAddress + count + i * I2C_PageSize, DeviceAddress);
}
if( ((length - count) % I2C_PageSize) != 0 ) {
EEPROM_PageWrite(pBuffer + count + i * I2C_PageSize, ((length - count) % I2C_PageSize), WriteAddress + count + i * I2C_PageSize, DeviceAddress);
}
}
}
}
//¶Á³ö1×Ö½ÚÊý¾Ý£¨´æ·Å¶Á³öÊý¾Ý£¬´ý¶Á³ö³¤¶È£¬´ø¶Á³öµØÖ·£¬Æ÷¼þÀàÐÍ£©
bool EEPROM_RandomRead(u8 *pByte, u16 ReadAddress, u8 DeviceAddress)
{
if(!I2C_Start()) return FALSE;
I2C_SendByte(((ReadAddress & 0x0700) >> 7) | (DeviceAddress & 0xFE)); //ÉèÖøßÆðʼµØÖ·+Æ÷¼þµØÖ·
if(!I2C_WaitAck()) {
I2C_Stop();
return FALSE;
}
I2C_SendByte((u8)(ReadAddress & 0x00FF));//ÉèÖõÍÆðʼµØÖ·
I2C_WaitAck();
I2C_Start();
I2C_SendByte(((ReadAddress & 0x0700) >> 7) | (DeviceAddress | 0x0001));
I2C_WaitAck();
*pByte = I2C_ReceiveByte();
I2C_NoAck();
I2C_Stop();
return TRUE;
}
//¶Á³ö1´®Êý¾Ý£¨´æ·Å¶Á³öÊý¾Ý£¬´ý¶Á³ö³¤¶È£¬´ø¶Á³öµØÖ·£¬Æ÷¼þÀàÐÍ£©
bool EEPROM_SequentialRead(u8 *pBuffer, u8 length, u16 ReadAddress, u8 DeviceAddress)
{
if(!I2C_Start()) return FALSE;
I2C_SendByte(((ReadAddress & 0x0700) >> 7) | (DeviceAddress & 0xFE)); //ÉèÖøßÆðʼµØÖ·+Æ÷¼þµØÖ·
if(!I2C_WaitAck()) {
I2C_Stop();
return FALSE;
}
I2C_SendByte((u8)(ReadAddress & 0x00FF));//ÉèÖõÍÆðʼµØÖ·
I2C_WaitAck();
I2C_Start();
I2C_SendByte(((ReadAddress & 0x0700) >> 7) | (DeviceAddress | 0x0001));
I2C_WaitAck();
while(length) {
*pBuffer = I2C_ReceiveByte();
if(length == 1) I2C_NoAck();
else I2C_Ack();
pBuffer++;
length--;
}
I2C_Stop();
return TRUE;
}
void I2CEEPROMWriteany(u16 addr, u8* ptr, u16 cnt)
{
EEPROM_BufferWrite(ptr, cnt, addr, 0xA0);
}
3 main函数
int main(void)
{
u16 i;
u16 temp;
delay_init();
LED_Init();
/*
Use I2C1 Port to connect external I2C interface type EEPROM 24C02;
run Write and Read series bytes Data;
*/
//Initial I2C
I2C_Initialize();
//Write 8 bytes from buffer0[128] to 0x10 of EEPROM
I2CEEPROMWrite(0x10, buffer0, 0x08);
//Read 8 bytes from 0x10 of EEPROM to buffer1[128]
I2CEEPROMRead(0x10, buffer1, 0x08);
for(i = 0; i < 0x08; i++) {
buffer0[i] = i;
}
I2CEEPROMWriteany(0x20, buffer0, 0x8);
I2CEEPROMRead(0x20, buffer1, 0x08);
I2CEEPROMWriteany(0x20 + 0x8, buffer0, 0x8 + 0x8);
I2CEEPROMRead(0x20 + 0x8, buffer1, 0x8 + 0x8);
I2CEEPROMRead(0x20, buffer1, 0x8 + 0x8);
temp = 0;
for(i = 0; i < 0x08; i++) {
if((buffer0[i]) == (buffer1[i])) {
temp++;
}
}
while(1) {
LED1_TOGGLE();
if(temp < 0x08) {
delay_ms(100);
}
else {
delay_ms(500);
}
}
}
程序写8个字节到0x10地址,然后读取8个字节,比较读写的数据是否一致,如果一致则LED指示灯慢闪,否则LED指示灯慢闪。
官方例程的修正已基本完成,需要程序的同学可以到百度网盘下载。
提取码:0o5i