因为论坛里看到STM的I2C有点小bug,所以这里采用的是模拟I2C时序
【注】m0.6us表示的是这一段时间最小不能小于为0.6us,M0.6us表示的是这一段时间最大为0.6us
对AT24C16的操作有读和写,读又分为CURRENT ADDRESS READ、RANDOM READ、SEQUENTIAL READ
,写又分为BYTE WRITE、PAGE WRITE。
先研究写操作
先研究写操作中的 Byte Write,它的时序如下
下面分步实现 BYTE WRITE。
首先是 START 和 STOP,具体时序如下
其中的时间要求如下(下图是START为例)
程序实现:
/******************************************
函数名:START
描 述 :产生起始条件,在SCL高电平期间,SDA从高到低表示通信开始
*******************************************/
static void START(void)
{
SCL_H;
SDA_H; /* 为产生 START 做铺垫 */
I2C_delay(1); /* tSU.STA=m0.6us */
SDA_L; /* SDA线从高到低,START */
I2C_delay(1); /* tHD.STA=m0.6us */
SCL_L;
}
/******************************************
函数名:STOP
描 述 :产生结束命令
*******************************************/
static void STOP(void)
{
SCL_L;
SDA_L; /* 为产生 STOP 做铺垫 */
I2C_delay(1);
SCL_H;
I2C_delay(1);
SDA_H; /* SDA线从低到高,STOP */
I2C_delay(1);
SCL_H;
}
接下来就是发送 DEVICE ADDRESS,因为DEVICE ADDRESS、WORD ADDRESS以及DATA的发送都是一样的操作,所以就写了一个统一的函数——SendByte,其操作具体的一个位时序如下
程序实现如下
/******************************************
函数名:SendByte
描 述 :发送一字节数据,数据位从高位到低位顺序发送
输 入 :-sendbyte:要发送的字节
*@nate:
在进入SendByte函数的时候,会先把SCL拉低
在退出SendByte函数的时候,也会把SCL拉低
*******************************************/
static ErrorStatus SendByte(u8 sendbyte)
{
u8 i,data;
data=sendbyte;
for(i=0;i<8;i++){
SCL_L;
I2C_delay(1); //tHD.DAT=m0us
if((data&0x80)==0x80){//高位优先发送
SDA_H; //1
}
else{
SDA_L;
}
I2C_delay(1);//tSU.DAT=m100ns
SCL_H;
I2C_delay(1);
data=data<<1;
}
/** 第9个周期,读取ACK **/
SCL_L;
SDA_H;//先把内部的输出置高,后读取
I2C_delay(1);
SCL_H;//SCL=1期间是DATA STABLE,也就是数据有效期
I2C_delay(1);
if(READ_SDA==1){
SCL_L;//出去前先把SCL拉低总没错
return ERROR;
}
else {//ACK=0
SCL_L;//出去前先把SCL拉低总没错
return SUCCESS;
}
}
所以 BYTE WRITE的程序就简单了
/******************************************
函数名:EE_ByteWrite
描 述 :写入一个字节到存储器里
输 入 :deviceAddr:器件地址,3位,0-7
wordAddr :数据字地址
data :要写入的数据
输 出 :无
返回值:是否成功写入
*@nate:tWR=M5ms,所以两次写操作之间,要间隔5ms以上
*******************************************/
ErrorStatus EE_ByteWrite(u8 deviceAddr,u8 wordAddr,u8 data)
{
u8 deviceaddr;
deviceaddr=0xa0+(deviceAddr<<1)+EEPROM_WRITE;
START(); //START
SendByte(deviceaddr);//DEVICE ADDRESS
SendByte(wordAddr); //WORD ADDRESS
SendByte(data); //DATA
STOP(); //STOP
I2C_delay(5000); //tWR=M5ms
return SUCCESS;
}
PAGE WRITE 时序如下
程序:
/******************************************
函数名:EE_PageWrite
描 述 :写入一页的数据(一页16个字节)
输 入 :deviceAddr:器件地址,3位,0-7
wordAddr :数据字地址
*data :要写入的数据首地址
cnt :要写入的数据字节数
输 出 :无
返回值:无
*@nate:The address “roll over” during write is from the last
byte of the current page to the first byte ofthe same page.
*******************************************/
ErrorStatus EE_PageWrite(u8 deviceAddr,u8 wordAddr,u8 *data,u8 cnt)
{
u8 deviceaddr,i=0;
deviceaddr=0xa0+(deviceAddr<<1)+EEPROM_WRITE;
START();
SendByte(deviceaddr);
SendByte(wordAddr);
for(i=0;i
是不是有点奇怪BYTE WRITE 和 PAGE WRITE 后的“tWR=M5ms”?
Note: 1. The write cycle time tWR is the time from a valid stop condition of a write sequence to the end of the internal clear/write cycle.
再研究读操作
/******************************************
函数名:EE_CurrentAddrRead
描 述 :产生起始条件,在SCL高电平期间,SDA从高到低表示通信开始
输 入 :deviceAddr:器件地址,3位,0-7
wordAddr :数据字地址
输 出 :无
返回值:无
*******************************************/
u8 EE_CurrentAddrRead(u8 deviceAddr)
{
u8 deviceaddr,data;
deviceaddr=0xa0+(deviceAddr<<1)+EEPROM_READ;
START();
SendByte(deviceaddr);
data=ReadByte(DISABLE);
STOP();
return data;
}
/******************************************
函数名:EE_RandomRead
描 述 :产生起始条件,在SCL高电平期间,SDA从高到低表示通信开始
输 入 :deviceAddr:器件地址,3位,0-7
输 出 :无
返回值:无
*******************************************/
u8 EE_RandomRead(u8 deviceAddr,u8 wordAddr)
{
u8 deviceaddr,data;
deviceaddr=0xa0+(deviceAddr<<1)+EEPROM_WRITE;
START();
SendByte(deviceaddr);
SendByte(wordAddr);
deviceaddr=0xa0+(deviceAddr<<1)+EEPROM_READ;
START();
SendByte(deviceaddr);
data=ReadByte(DISABLE);
STOP();
return data;
}
/******************************************
函数名:EE_SequentialRead
描 述 :顺序读取(一页16个字节)
输 入 :deviceAddr:器件地址,3位,0-7
输 出 :无
返回值:无
*@nate:The address “roll over” during read is from
the last byte of the last memory page to
the first byte of the first page
*******************************************/
u8 EE_SequentialRead(u8 deviceAddr,u8 wordAddr,u8* dataAddr,u8 cnt)
{
u8 deviceaddr,i;
deviceaddr=0xa0+(deviceAddr<<1)+EEPROM_WRITE;
START();
SendByte(deviceaddr);
SendByte(wordAddr);
deviceaddr=0xa0+(deviceAddr<<1)+EEPROM_READ;
START();
SendByte(deviceaddr);
for(i=0;i
源代码:http://www.openedv.com/forum.php?mod=viewthread&tid=288334&page=1&extra=#pid931498
Q:STM32的引脚怎么才能既输入又输出呢,另外从SDA引脚读取数据时,需不需要先输出高电平再读取数据?
A:STM32的引脚怎么才能即输入又输出呢
https://blog.csdn.net/qq_35629563/article/details/87710101
Q:1K的存储器能存多少东西,怎么算的?
A:首先:1k= 2^10 bit
芯片手册上这样写的:
The AT24C01A provides 1024 bits of serial electrically erasable and rogrammable read-only memory (EEPROM) organized as 128 words of 8 bits each.
AT24C01A, 1K SERIAL EEPROM: Internally organized with 16 pages of 8 bytes each,the 1K requires a 7-bit data word address for random word addressing.
计算过程:
16页8字节
16= 2^4, 8= 2^3, 1 byte= 2^3 bit
16页8字节 = 2^7字节 = 2^10 bit
所以芯片上的1K是1k个bit,1K能存放128个字节
Q:page write先写的是低字节还是高字节,Sequential Read先读的是低字节还是高字节?
A:都是先对低字节的数据进行操作的