关于STM32系列单片机I2C通信的问题,求教各位大牛

lishi_1991 2014-03-05 06:12:12
最近再做一个关于STM32F103系列单片机I2C通信的项目,因为以前没有玩过单片机所以有一些东西实在搞不懂,也没人可以咨询,所以来求教各位大牛了
先贴我的第一个问题:下面是一个简单的I2C写数据以及读数据的函数
void I2C_WriteByte(unsigned char write_address,unsigned char byte)
{
I2C_GenerateSTART(I2C2,ENABLE);
//产生起始条件
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
//等待ACK
I2C_Send7bitAddress(I2C2,EEPROM_ADDR,I2C_Direction_Transmitter);
//向设备发送设备地址
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
//等待ACK
I2C_SendData(I2C2, write_address);
//寄存器地址
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
//等待ACK
I2C_SendData(I2C2, byte);
//发送数据
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
//发送完成
I2C_GenerateSTOP(I2C2, ENABLE);
//产生结束信号
}

void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)//将EEPROM的数据读入缓冲器
{

I2C_GenerateSTART(I2C1, ENABLE);//产生 I2Cx传输 START条件
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));//检查最近一次 I2C事件是否是输入的事件

/* In the case of a single data transfer disable ACK before reading the data */
if(NumByteToRead==1)
{
I2C_AcknowledgeConfig(I2C1, DISABLE);//使能或者失能指定 I2C的应答功能
}
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);//向指定的从 I2C设备传送地址字,选择发送方向
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//检查最近一次 I2C事件是否是输入的事件
I2C_Cmd(I2C1, ENABLE);//使能或者失能 I2C外设
I2C_SendData(I2C1, ReadAddr); //通过外设 I2Cx发送读取地址()
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//检查最近一次 I2C事件是否是输入的事件
I2C_GenerateSTART(I2C1, ENABLE);//产生 I2Cx传输 START条件
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));//检查最近一次 I2C事件是否是输入的事件
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);//向指定的从 I2C设备传送地址字,选择接收方向
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));//检查最近一次 I2C事件是否是输入的事件
/* While there is data to be read */
while(NumByteToRead)
{
/* Test on EV7 and clear it */
if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) //检查最近一次 I2C事件是否是输入的事件
{
if(NumByteToRead == 2)
{
I2C_AcknowledgeConfig(I2C1, DISABLE);//使能或者失能指定 I2C的应答功能
}
if(NumByteToRead == 1)
{
I2C_GenerateSTOP(I2C1, ENABLE);//产生 I2Cx传输 STOP条件
}
*pBuffer = I2C_ReceiveData(I2C1);//返回通过 I2Cx最近接收的数据
pBuffer++;
NumByteToRead--;
}
}
/* Enable Acknowledgement to be ready for another reception */
I2C_AcknowledgeConfig(I2C1, ENABLE);//使能或者失能指定 I2C的应答功能

}

我查资料说STM32和器件通信有以下步骤:
写:检测SDA是否空闲;
->按I2C协议发出起始讯号;
->发出7位器件地址和写模式;
->要写入的存储区首地址;
->用页写入方式或字节写入方式写入数据;

读:检测SDA是否空闲;
->按I2C协议发出起始讯号;
->发出7位器件地址和写模式(伪写);
->发出要读取的存储区首地址;
->重发起始讯号;
->发出7位器件地址和读模式;
->接收数据;
无论读和写在发送完要写入或者读取的器件地址后都要再发送一个要写入或者读取的存储区地址,我的疑问是,这个地址读和写分别如何确定的呢?
还有一个疑问是:STM32有I2C1和I2C2两个I2C,如果我想做一下自回环,即I2C1给I2C2发送一个数据,I2C2收到后在传给I2C1一个数据,其中I2C1做主设备,I2C2做从设备,那么I2C1给I2C2发数据的时候器件地址是什么呢,I2C2给I2C1回数据的时候器件地址又是什么呢
东西有点多,跪求大神给解答!谢谢了
...全文
3438 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
lizuotb 2016-10-12
  • 打赏
  • 举报
回复
多谢分享!!!只是楼主的工具不是用的KEIL
wacyyqq 2016-09-26
  • 打赏
  • 举报
回复
多谢楼主分享!
lishi_1991 2014-04-17
  • 打赏
  • 举报
回复
结贴吧 stm32问题差不多都解决了,感谢各位大牛,顺便也回馈社会一下 我把工程和相关资料都上传了 地址是:http://download.csdn.net/detail/lishi_1991/7202649 有什么问题可以联系我,资源里面有我的联系方式 能解答的一定尽量解答
lishi_1991 2014-03-28
  • 打赏
  • 举报
回复
结贴了,到现在模模糊糊大致搞明白了 再发送一个要写入或者读取的存储区地址的意义,这个是跟通信的EEPROM有关,选择要写入或者要读取的器件的存放数据的寄存器地址,如果i2c跟i2c通信就不需要这个。 如果自回环的话,器件地址自己设定就行了,也就是配置i2c的时候,作为从设备的 配置 I2C_InitStructure.I2C_OwnAddress1 = 0 0xD4; 作为主设备的i2c就往这个地址读写就行了。 不过i2c到现在依然没有搞定,单次通信没问题,一循环从设备就会卡在匹配地址地方。
lishi_1991 2014-03-28
  • 打赏
  • 举报
回复
引用 6 楼 u010629523 的回复:
你照着单片机datasheet上的操作去配置寄存器就是你贴出来的程序。你说的EEPROM的地址,是因为这些器件内部已经有了通讯协议,你只需按照通讯协议去操作就会读/写对应地址的值。你如果想用单片机模拟这种协议,只需在地址后再加一条命令(即寄存器地址),就是你看到的EEPROM的操作。 你说的循环会有问题,估计是你的开始或停止信号时序有问题。
谢谢热心解答,虽然EEPROM的地址这一块大致了解了,可是循环问题还是有点头大,大部分情况都是两个i2c一主一从互相读写循环几次会卡住,偶尔出现一上电就卡住的情形,并且都是卡在主设备已经发送出去地址,而从设备却无法匹配地址。估计还是开始时序问题,对通信协议理解不透彻。 看网上很多人都说stm32的硬件i2c不好用,建议采用软件模拟,总是不死心,还觉得这么牛叉的公司出一个小小的i2c功能不会做的有多差。
u010629523 2014-03-28
  • 打赏
  • 举报
回复
你照着单片机datasheet上的操作去配置寄存器就是你贴出来的程序。你说的EEPROM的地址,是因为这些器件内部已经有了通讯协议,你只需按照通讯协议去操作就会读/写对应地址的值。你如果想用单片机模拟这种协议,只需在地址后再加一条命令(即寄存器地址),就是你看到的EEPROM的操作。 你说的循环会有问题,估计是你的开始或停止信号时序有问题。
mangoalx 2014-03-05
  • 打赏
  • 举报
回复
引用 楼主 lishi_1991 的回复:
我查资料说STM32和器件通信有以下步骤: 写:检测SDA是否空闲; ->按I2C协议发出起始讯号; ->发出7位器件地址和写模式; ->要写入的存储区首地址; ->用页写入方式或字节写入方式写入数据; 读:检测SDA是否空闲; ->按I2C协议发出起始讯号; ->发出7位器件地址和写模式(伪写); ->发出要读取的存储区首地址; ->重发起始讯号; ->发出7位器件地址和读模式; ->接收数据; 无论读和写在发送完要写入或者读取的器件地址后都要再发送一个要写入或者读取的存储区地址,我的疑问是,这个地址读和写分别如何确定的呢? 还有一个疑问是:STM32有I2C1和I2C2两个I2C,如果我想做一下自回环,即I2C1给I2C2发送一个数据,I2C2收到后在传给I2C1一个数据,其中I2C1做主设备,I2C2做从设备,那么I2C1给I2C2发数据的时候器件地址是什么呢,I2C2给I2C1回数据的时候器件地址又是什么呢 东西有点多,跪求大神给解答!谢谢了
器件的地址要查器件手册,I2C 地址常用7位,最低位是读写标志,合成8位一个字节。 I2C_Send7bitAddress(I2C2,EEPROM_ADDR,I2C_Direction_Transmitter); 这里第三个参数就是读写控制,所以就通过这个函数控制就行了。
lishi_1991 2014-03-05
  • 打赏
  • 举报
回复
没人回答吗?

27,375

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 单片机/工控
社区管理员
  • 单片机/工控社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧