打印

关于stm32 I2C的问题

[复制链接]
8716|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
关于stm32 I2C的问题用的是stm32的I2C硬件,这是我的配置过程,有些是从网上抄的,但是调不通啊,请大家看看那里有毛病,假如**作的是24c02
I2C_InitStructure.I2C_OwnAddress1 应该配置成什么啊; 这个地址应该是主机的吧,我看有些例子写得是0x00,这是为什么
还有后面写24c02的地址在发送从机的7位地址的时候 EEPROM_ADDRESS应该是是0xA2吗,那为什么我找过的一些例子吗,他们操作的是24c02,但这里却写得是0xa0那
另外在写数据的起始字节地址时,因为AT24C02容量为2048bits,所以地址范围应该是0x00~0xff吧,那我写0xfe,应该是正确的吧

void I2C_Configuration(void)
{
I2C_InitTypeDef I2C_InitStructure;
/* I2C configuration */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //Tlow/Thigh=2
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;//使能I2C的应答
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//应答7位地址,这里是从机的地址
I2C_InitStructure.I2C_ClockSpeed = 400000;//I2C速率为400KHz(快速模式),该值不能高于400KHz

/* Apply I2C configuration after enabling it */
I2C_Init(I2C1, &I2C_InitStructure);

/* I2C Peripheral Enable */
I2C_Cmd(I2C1, ENABLE);

}


void I2C_EE_Init()
{
/* GPIO configuration */
GPIO_Configuration();//GPIO端口配置

/* I2C configuration */
I2C_Configuration();

}


void I2C_EE_SequentialWrite(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite)
{
u8 NumOfPage = 0; //页数
u8 NumOfSingle = 0; //不足一页字节数
u8 Addr = 0; //字节地址
u8 count = 0; //字节计数器

Addr = WriteAddr % I2C_PageSize; //字节地址(不到一页)
count = I2C_PageSize - Addr; //一页中的剩余字节数
NumOfPage = NumByteToWrite / I2C_PageSize; //欲写入数据所占的页数
NumOfSingle = NumByteToWrite % I2C_PageSize; //欲写入数据所占的字节数(不足一页)

/* If WriteAddr is I2C_PageSize aligned */
if(Addr == 0) //起始地址为某页的第一个字节地址处
{
/* If NumByteToWrite < I2C_PageSize */
if(NumOfPage == 0)//写入的数据字节数不足一页
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();//等待EEPROM自编程结束
}
/* If NumByteToWrite > I2C_PageSize */
else//写入的数据超过一页
{
while(NumOfPage--)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
I2C_EE_WaitEepromStandbyState();
WriteAddr += I2C_PageSize;//下一页起始地址
pBuffer += I2C_PageSize;
}

if(NumOfSingle!=0) //写入余下不足一页的数据
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();
}
}
}
/* If WriteAddr is not I2C_PageSize aligned 写入数据的起始地址不在页的开始处 */
else
{
/* If NumByteToWrite < I2C_PageSize */
if(NumOfPage== 0)//不足一页的,直接写入。注意:当写到页边界时,将从该页的起始地址继续写入数据
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();
}
/* If NumByteToWrite > I2C_PageSize */
else
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / I2C_PageSize;
NumOfSingle = NumByteToWrite % I2C_PageSize;

if(count != 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, count); //将WriteAddr所在页的剩余空间写满
I2C_EE_WaitEepromStandbyState();
WriteAddr += count; //地址指向下一页的起始处
pBuffer += count;
}

while(NumOfPage--)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
I2C_EE_WaitEepromStandbyState();
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
if(NumOfSingle != 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle); //写入余下不足一页的数据
I2C_EE_WaitEepromStandbyState();
}
}
}
}
void I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr)
{
/* While the bus is busy */
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));//等待I2C总线空闲

/* Send STRAT condition */
I2C_GenerateSTART(I2C1, ENABLE); //发送START后,MCU自动从从机模式变成主机模式

/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //等待START产生成功

/* Send EEPROM address for write 发送从机器件地址*/
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);

/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

/* Send the EEPROM's internal address to write to发送从机预写入的内部字节地址 */
I2C_SendData(I2C1, WriteAddr);

/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

/* Send the byte to be written */
I2C_SendData(I2C1, *pBuffer);

/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

/* Send STOP condition */
I2C_GenerateSTOP(I2C1, ENABLE);
}

void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite) //看主发送器的时序图
{
/* While the bus is busy */
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));//等待I2C总线空闲

/* Send START condition */
I2C_GenerateSTART(I2C1, ENABLE);//产生START后,MCU自动从从机模式变成主机模式

/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //等待START产生成功

/* Send EEPROM address for write */
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);

/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

/* Send the EEPROM's internal address to write to */
I2C_SendData(I2C1, WriteAddr);

/* Test on EV8 and clear it等待发送数据寄存器空,即收到ACK */
while(! I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

/* While there is data to be written */
while(NumByteToWrite--)
{
/* Send the current byte */
I2C_SendData(I2C1, *pBuffer);

/* Point to the next byte to be written */
pBuffer++;

/* Test on EV8 and clear it */
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}

/* Send STOP condition */
I2C_GenerateSTOP(I2C1, ENABLE);//发送停止传输指令
}


void I2C_EE_SequentialRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)
{
/* While the bus is busy */
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

/* Send START condition */
I2C_GenerateSTART(I2C1, ENABLE);

/* Test on EV5 and clear it 等待开始信号发送成功*/
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

/* Send EEPROM address for write */
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);

/* Test on EV6 and clear it等待设备地址发送成功 */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

/* Clear EV6 by setting again the PE bit */
I2C_Cmd(I2C1, ENABLE);

/* Send the EEPROM's internal address to write to */
I2C_SendData(I2C1, ReadAddr);

/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

/* Send STRAT condition a second time */
I2C_GenerateSTART(I2C1, ENABLE);

/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

/* Send EEPROM address for read */
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);

/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

/* While there is data to be read */
while(NumByteToRead)
{
if(NumByteToRead == 1)
{
/* Disable Acknowledgement */
I2C_AcknowledgeConfig(I2C1, DISABLE);

/* Send STOP Condition */
I2C_GenerateSTOP(I2C1, ENABLE);
}

/* Test on EV7 and clear it 接收数据寄存器非空*/
if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
{
/* Read a byte from the EEPROM */
*pBuffer = I2C_ReceiveData(I2C1);

/* Point to the next location where the byte read will be saved */
pBuffer++;

/* Decrement the read bytes counter */
NumByteToRead--;
}
}

/* Enable Acknowledgement to be ready for another reception */
I2C_AcknowledgeConfig(I2C1, ENABLE);//每接收到一个字节数据向从机发送一个ACK
}
沙发
weicz| | 2012-4-28 15:51 | 只看该作者
都说STM32 的硬件IIC很难用啊,劝楼主改用IO模拟吧,很方便的

使用特权

评论回复
板凳
03318xglhc| | 2012-4-28 16:24 | 只看该作者
1# dong130300

使用特权

评论回复
地板
PowerSource| | 2012-4-29 00:03 | 只看该作者
本帖最后由 PowerSource 于 2012-4-29 09:30 编辑

1、24C04的地址由其A0 A1 A2引脚确定,如果3个引脚均接地,则其地址为0xA0,(1010 000 x),前4位由厂家确定,接着3位就是地址,一共7位;还有1位,表示I2C读写标志位),你要根据你的原理图确定地址;
2、关于I2C_InitStructure.I2C_OwnAddress1参数,这个参数是主机地址;
3、写数据的起始字节地址时,写0xfe,应该是正确的

使用特权

评论回复
5
dong130300|  楼主 | 2012-4-29 08:41 | 只看该作者
谢谢了,那我再问一句,**纵24c02,那么24C02就应该是从机了吧,那他的地址是不是还是0xa0啊,但是有些例子为什么写的是0x00啊,

使用特权

评论回复
6
PowerSource| | 2012-4-29 09:36 | 只看该作者
我修改了一下4楼的回答。
查了一下资料,I2C_InitStructure.I2C_OwnAddress1参数是主机地址:“STM32芯片I2C接口初始化固件I2C_Init中这个参数I2C_OwnAddress1 是指当STM32作为从设备时的地址,主设备访问通过该地址就可以访问STM32,并且STM32会对该地址的访问做应答。
如果你的应用中STM32是作为I2C主设备,该值不用理会。例如STM32芯片为I2C主设备,EEPROM芯片为I2C从设备,此时I2C_OwnAddress1值无效,无须理会。”
参考:http://www.armjishu.com/bbs/forum.php?mod=viewthread&tid=17
读写24C02,24C02就是从机,地址是0xA0(3根地址线均接地,否则不是0xA0),此时I2C_OwnAddress1就无关紧要了。

使用特权

评论回复
7
dong130300|  楼主 | 2012-4-29 11:25 | 只看该作者
谢谢你了,明白了

使用特权

评论回复
8
jy02326166| | 2013-1-27 13:48 | 只看该作者
找了好久,原来答案在这里~

使用特权

评论回复
9
wuguoyan| | 2013-6-30 17:49 | 只看该作者
PowerSource 发表于 2012-4-29 09:36
我修改了一下4楼的回答。
查了一下资料,I2C_InitStructure.I2C_OwnAddress1参数是主机地址:“STM32芯片I2 ...

学习了,谢谢。。。

使用特权

评论回复
10
windwithgone| | 2013-8-13 18:54 | 只看该作者
谢谢,今天正在调这个模块,也运到了这个问题

使用特权

评论回复
11
文峰聊书斋| | 2013-9-3 17:09 | 只看该作者

使用特权

评论回复
12
outstanding| | 2013-9-3 17:24 | 只看该作者
那么多代码

使用特权

评论回复
13
zeluo| | 2013-9-3 19:45 | 只看该作者
问题解决了就好   楼主   多逛221ic   问题   都会很快就能解决的

使用特权

评论回复
14
女神不美| | 2013-12-11 14:20 | 只看该作者
刚入门必须mark一下

使用特权

评论回复
15
善水盈渊| | 2013-12-11 15:22 | 只看该作者
最近可能要用到 I2C mark备用

使用特权

评论回复
16
fengdingkusong| | 2013-12-11 16:57 | 只看该作者
STM32的IIC库里面有很多循环等待的地方,条件不满足的话就死在那了,自己要做好超时处理

使用特权

评论回复
17
hugo0chen| | 2014-2-18 09:09 | 只看该作者
mark·

使用特权

评论回复
18
潜龙伏渊| | 2015-10-3 14:50 | 只看该作者
楼主好写得好详细,一下子就看明白了,棒棒的

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

35

帖子

0

粉丝