赞
踩
在单片机开发中,经常使用EEPROM作为存储设备保存数据,如何根据数据手册编写驱动,我们以24LC16为例进行分析。
一.分析数据手册
1.1容量的计算
解释:16 Kbit 是多少字节的容量 ,1K是1024 16*1024/8=16*128=2048字节。
所以:24C01 容量 1*128=128字节
24C02 容量 2*128=256字节 24C08 容量 8*128=1024字节
1.2 地址空间
24LC16有2048个字节的地址空间,用户在分配地址范围时,地址范围为0x0--0x7ff,手册中写到2048个字节被分成8个块,每个块256字节。那么地址范围中的(9-11位)0-7代表着8个块地址。
二.看写操作时序
开始->写控制字->ACK->写字节地址->ACK- >数据->ACK->结束
1.开始位的时序
根据上图可知:
I2C开始条件:SCL高电平, SDA 由高变低
I2C结束条件:SCL高电平, SDA 由低变高
- void I2CStart()
- {
- SDA_OUT_high();
- SCL_high();
- I2CDelay();
- SDA_OUT_low();
- I2CDelay();
- SCL_low();
- }
-
2.写控制字:告诉机是读操作,还是写操作,读写那个块地址
用户编码地址范围(0-0x7ff)共2048个字节,那么地址0x700的地址,7就是块地址,写控制字时要将块地址写入从机。
2.1 写函数
- static unsigned char I2C_WriteByte(unsigned char byte)
- {
- unsigned char i;
- SDA_OUT();
- for(i=0;i<8;i++)
- {
- if(byte & 0x80)
- {
- SDA_OUT_high();
- }
- else
- {
- SDA_OUT_low();
- }
- I2CDelay();
- SCL_high();
- I2CDelay();
- SCL_LOW(); //scl=0 data change
- byte <<= 1;
- }
- SDA_in(); //SDA PORT input
- I2CDelay();
- SCL_high();
- I2CDelay();
- if(I2C_SDA == 1) //ACK read SDA port
- {
- SCL_high(); no ack
- return 0;
- }
- SCL_LOW();
- I2CDelay();
- return 1;
- }
使用 I2C_WriteByte()函数 写入控制字I2C_WriteByte(addr);
3.ACK 应答位
当主机给从机写入地址后,要求从机在接收一个字节后产生一个应答,因此主机会产生一个时钟
在这个时钟期间,从机必须把SDA 拉低,并在SCL高电平期间保持住。如果SDA没有拉低就是没有ACK,即NOACK。
- static void I2CACK(void)
- {
- SDA_OUT(); //SDA置输出口
- SDA_OUT_low();
- I2CDelay();
- SCL_high();
- I2CDelay();
- SCL_low();
- I2CDelay();
- }
- static void I2C_NOACK(void)
- {
- SDA_OUT(); //SDA置输出口
- SDA_OUT_high();
- I2CDelay();
- SCL_high();
- I2CDelay();
- SCL_low();
- I2CDelay();
- }
4.写地址 将数据放在EE的地址, I2C_WriteByte(data);
5. I2结束
- void I2CStop()
- {
- SDA_OUT_low();
- SCL_high();
- I2CDelay();
- SDA_OUT_hight();
- I2CDelay();
- SCL_low();
- }
-
6.一个完整的写函数
- static unsigned char write_eeprom(unsigned int addr, void const *buf, unsigned int len)
- {
- unsigned char w_wait,e2page,SlaveAddr;
- unsigned char const *src=(unsigned char *)buf;
- e2page = 16;
- I2CDelay();
- reStart:
- SlaveAddr = 0xA0 + (unsigned char)((addr & 0x0700)>>7);
-
- I2CStart();
- I2C_WriteByte(SlaveAddr);
-
- I2C_WriteByte((unsigned char)(addr%0x100)))
-
- while(len--)
- {
- I2C_WriteByte(*src++))
- addr++;
- if((addr % e2page) == 0)
- {
- break;
- }
- }
- I2CStop();
- DelayMs(5);
- if(len != 0xffff)
- {
- goto reStart;
- }
-
- I2CDelay();
- SCL_low();
- retrun 1;
- }
三.看读操作时序进行EE读操作
读操作时,先写入芯片,要读的地址,然后在读,如上述标计:
1,2步写入写操作控制字及要读的地址;第3步是写入读控制字,数据就可以读出。
读函数代码:
- static unsigned char I2C_Recv_byte(void)
- {
- unsigned char byte;
- unsigned char i = 0;
- SDA_IN(); //SDA 置输入口
- for(i=0;i<8;i++)
- {
- byte <<= 1;
- SCL_high();
- I2CDelay();
- if(SDA == 1)
- {
- byte |= 0x01;
- }
- SCL_LOW();
- I2CDelay();
- }
- return(byte);
- }
-
- static unsigned char read_eeprom(unsigned int addr, void *buf, unsigned int len)
- {
- unsigned char w_wait,SlaveAddr;
- unsigned char *dest=(unsigned char *)buf;
- I2CDelay();
- SlaveAddr = 0xA0 + (unsigned char)((addr & 0x0700)>>7);
-
- I2CStart();
- I2C_WriteByte(SlaveAddr))
- I2C_WriteByte((unsigned char)(addr%0x100)))
-
- I2CStart();
- I2C_WriteByte((SlaveAddr+1)) //read
-
- while(len--)
- {
- *dest++ = I2C_Recv_byte();
- if(n != 0)
- {
- I2CACK();
- }
- addr++;
- }
- I2CNOACK();
- I2CStop();
- DelayMs(1);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。