怎么从烧录文件读取stm32 硬件i2c例程

STM32的硬件I2C搞了2天没搞定,换了软件模拟,30分钟就OK了==www.ic37.com
热门型号:
&&&当前位置:
STM32的硬件I2C搞了2天没搞定,换了软件模拟,30分钟就OK了
用户名:qingheworkshop
注册时间: 13:10:00
STM32的硬件I2C搞了2天没搞定,换了软件模拟,30分钟就OK了
STM32的硬件I2C设计的针式异常复杂,我都不明白,别的就那么几个寄存器,照样实现了I2C的所有功能,为什么ST就要设计的这么复杂,还不好用的很。我用I2C2读写铁电,参考了读写的,并且按照本中的方法进行修改,至少试验了3个版本的网上已经调试通过的24C04的例子程序,就是EV5通不过,按照网上的经验,不用库函数,改用读CR1,CR2的方法,仍然不行,折腾了两天,没办法了,换了软件模拟I2C,30分钟就调通了。以前用Phlips的MCU,感觉I2C很简单的,为何ST设计的硬件易用性就不如人家,看了半天文档,资料不全,文档杂乱,例子错误,程序都是While的死循环,不明白ST的程序员就这么个水平,谁敢把都是while的死循环代码用到产品中?当初看看STM的功能,放弃了群星,现在有点后悔了。
用户名:simon21ic
注册时间: 20:15:00
如果是真的话,ST应该多话写功夫解决这个问题
用户名:amingriyue
注册时间: 23:44:00
不会的啊,我一会就搞定了啊,我接的是AT24C01
用户名:ESTM32
注册时间: 9:36:00
我也搞了好长时间没弄好,好像例程都有错误,跳进while就出不来
用户名:Swd21ic
注册时间: 19:43:00
看了半天文档,资料不全,文档杂乱我觉得ST的文档写的确实很乱,要学习学习ATMEL的.
用户名:栏杆
注册时间: 10:05:00
你看看你是不是地址位发送的问题。
用户名:winloop
注册时间: 11:51:00
能给个说法儿不?给SPI和I2C正正身
用户名:lshlin
注册时间: 14:50:00
用起来是比51的麻烦很多,寄存器太多了,习惯了就好。
用户名:香水城
注册时间: 14:56:00
“能给个说法儿不?给SPI和I2C正正身”不管怎样,STM32中设置了这样的硬件模块,为什么不用呢?硬件模块并没有问题,设置好调用函数,以后用起来很方便的。
用户名:zcl_l
注册时间: 22:40:00
会的话,发个例程不就OK了。
用户名:dami
注册时间: 16:19:00
软件模拟我还没搞定呢.发例子大家看看吧.
用户名:dragonbch
注册时间: 13:31:00
好像都是死在EV5上,我到现在也没有查出来有个什么说法!?????
用户名:winloop
注册时间: 15:39:00
贴上我的I2C函数吧,我敢用while()等待,因为我反复试了,软件很健壮,即使死掉在while()里一次,也有狗看着,怕什么
void I2C2_Config(void)
& & GPIO_InitTypeDef GPIO_InitS
& & I2C_InitTypeDef&&I2C_InitS
& & // Configure I2C2 pins: SCL and SDA
& & GPIO_InitStructure.GPIO_Pin& &= GPIO_Pin_10 | GPIO_Pin_11;
& & GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
& & GPIO_InitStructure.GPIO_Mode&&= GPIO_Mode_AF_OD;
& & GPIO_Init(GPIOB, &GPIO_InitStructure);
& & I2C_InitStructure.I2C_Mode& && && && && & = I2C_Mode_I2C;
& & I2C_InitStructure.I2C_DutyCycle& && && &&&= I2C_DutyCycle_2;
& & I2C_InitStructure.I2C_OwnAddress1& && && &= 0xa2;
& & I2C_InitStructure.I2C_Ack& && && && && &&&= I2C_Ack_E
& & I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7
& & I2C_InitStructure.I2C_ClockSpeed& && && & = 100000;
& & I2C_Cmd(I2C2, ENABLE);
& & I2C_Init(I2C2, &I2C_InitStructure);
void I2C_AcknowledgePolling(u8 sla)
& & vu16 SR1_T
& & I2C_ClearFlag(I2C2, I2C_FLAG_ADDR);
& && &&&I2C_GenerateSTART(I2C2, ENABLE);
& && &&&SR1_Tmp = I2C_ReadRegister(I2C2, I2C_Register_SR1);
& && &&&I2C_Send7bitAddress(I2C2, sla, I2C_Direction_Transmitter);
& & }while(!(I2C_ReadRegister(I2C2, I2C_Register_SR1) & I2C_FLAG_ADDR));
& & I2C_ClearFlag(I2C2, I2C_FLAG_AF);
void I2C_SequentialRead_AT24C01A_02(u8 sla, u8 suba, u8 *pHead, u8 len)
& & I2C_AcknowledgePolling(sla);
& & I2C_GenerateSTART(I2C2, ENABLE);
& & while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
& & I2C_Send7bitAddress(I2C2, sla, I2C_Direction_Transmitter);
& & while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
& & I2C_SendData(I2C2, suba);&&
& & while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
& & I2C_GenerateSTART(I2C2, ENABLE);
& & while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
& & I2C_Send7bitAddress(I2C2, sla+1, I2C_Direction_Receiver);
& & while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
& & if(len & 1)
& && &&&for(i=0; i&(len-1); i++)
& && && && &while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED));
& && && && &*pHead++ = I2C_ReceiveData(I2C2);
& && && && &
& && && && &I2C_AcknowledgeConfig(I2C2, ENABLE);
& & while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED));
& & *pHead = I2C_ReceiveData(I2C2);
& & I2C_AcknowledgeConfig(I2C2, DISABLE);
& & I2C_GenerateSTOP(I2C2, ENABLE);
void I2C_PageWrite_AT24C01A_02(u8 sla, u8 suba, u8 *pHead, u8 len)
& & u8 wLen,
& & wLen =
& & addr =
& & ScrollPage: I2C_AcknowledgePolling(sla);
& && && && && & I2C_GenerateSTART(I2C2, ENABLE);
& && && && && & while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
& && && && && & I2C_SendData(I2C2, sla);
& && && && && & while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
& && && && && & I2C_SendData(I2C2, addr);
& && && && && & while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
& && && && && && &
& && && && && & I2C_SendData(I2C2, *pHead++);
& && && && && & while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
& && && && && &
& && && && && & addr++;
& && && && && & wLen--;
& & while(wLen)
& && &&&if(addr%8)
& && && && &I2C_SendData(I2C2, *pHead++);
& && && && &while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
& && && && &
& && && && &addr++;
& && && && &wLen--;
& && &&&else
& && && && &I2C_GenerateSTOP(I2C2, ENABLE);
& && && && &goto ScrollP
& & I2C_GenerateSTOP(I2C2, ENABLE);
用户名:wklove_1124
注册时间: 14:13:00
17# winloop
I2C_Send7bitAddress(I2C2, sla+1, I2C_Direction_Receiver);
& & while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); // Test on EV6
还是在这个while死循环 !?
用户名:wklove_1124
注册时间: 14:14:00
16楼,你的程序是OK的吗?
用户名:winloop
注册时间: 14:36:00
绝对OK的,放心用吧,我都用好久了
用户名:wklove_1124
注册时间: 14:55:00
但是我用的还是在
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
在这里跑死了
用户名:winloop
注册时间: 15:19:00
那是别的原因,把I2C频率降低试试
用户名:午夜霓虹
注册时间: 16:40:00
我用的模拟的,72m的主频,50m的io速度,用i2c硬件的时候也总是死掉,原先用过51的,也不怎么好用,spi可能是用习惯了,觉得还可以,stm32的spi我还没用过,主要是spi的器件价格比较高,而且软件模拟也有好处,超时处理起来比较方便。
用户名:秋天落叶
注册时间: 21:32:00
是的,例程只能参考,不能直接拿来用
用户名:RUNNER
注册时间: 19:04:00
I2C本来就用模拟方式,硬件纯粹多余,Ti的DSP我都直接用模拟,现成程序,用的熟,硬件耗资源
用户名:有意思
注册时间: 0:03:00
真是不敢用ST的所谓库函数,
用户名:dfsa
注册时间: 14:07:00
I2C是比较难调的,要花点时间
用户名:djb
注册时间: 17:15:00
今天用3.0的库函数 用万利的开发板测试I2C,没发现问题,一切OK,估计楼上的出问题是不是哪个配置没配置好哦!
用户名:gaomidu
注册时间: 8:39:00
我也是弄spi弄了好久没搞定,半个小时用模拟的ok了
用户名:yybj
注册时间: 13:01:00
我比较赞成用软件模拟
用户名:wklove_1124
注册时间: 11:47:00
能把你的软件模拟程序发上来参考一下啊
用户名:晴朗005
注册时间: 9:04:00
估计是库的问题造成,30楼可否把你的成功代码给参考一下,我现在要STM32做为IIC从机,模拟IIC从机估计不好搞,还是得用上STM32的硬件IIC功能,或者有硬件IIC成功的朋友给指点一下,谢谢啦,QQ:。
用户名:晴朗005
注册时间: 9:06:00
还有,我这里有模拟IIC的成功程序,需要的朋友可以联系,我发过去给你就行。
用户名:byeyear
注册时间: 10:20:00
不止st一家的i2c不好玩,我早前用pxa255的i2c也照样死掉。
除了st自己例子里说的要把中断设为最高优先级还有些语句要关中断执行以外
本身i2c状态机的设计也是有缺陷的
比如master模式还在跑(成功发出start但是还没有stop),而且没有丢失仲裁,
会在外部干扰比较大的时候跑进slave中断
原因是外部干扰在i2c上引发了start条件,于是进slave了,于是master和slave状态机同时跑,于是死掉了。
我的系统上了os,event超时后复位i2c模块,跑得还行。
比pxa好,pxa的i2c死掉以后复位模块都没有用,得复位cpu
nxp的好,毕竟是娘家,不会出现master slave同时跑的情况
调试的时候火大得想在外面加块nxp的i2c片子算了
用户名:gx_huang
注册时间: 12:51:00
我也调试了好久,终于发现了问题。
ST的例程有错误,对PAGE的边界处理不好。
另外主要错误是设置成了400KHz,原来板上的24C16在3.3V时是100KHz的。
怪不得单步的时候基本是好的,连续跑就死机了。
用户名:mohanwei
注册时间: 13:12:00
一直坚持用I/O模拟的……
用户名:xsgy123
注册时间: 15:14:00
软件模拟本来比硬件实现要简单些
热门型号:查看: 7432|回复: 11
经过一个星期的努力,终于让STM32的硬件I2C跑起来了
主题帖子精华
新手入门, 积分 49, 距离下一级还需 -29 积分
在线时间0 小时
下面是我用寄存器写的读写GT9系列IC的代码。在读数据上还不能连续读取,只能一个地址一个数据的读,请各位大哥指正。
//////////////////////////////////////////////////////i2c_hard.c
#include "i2c_hard.h"
void I2C_Init(void)
////////////////I2C GPIO重映像
&RCC-&APB2ENR |= 1&&0;&&& &&//使能AFIO时钟
&AFIO-&MAPR |= 1&&1;&&&&//控制I2C1的SCL和SDA复用功能在GPIO端口的映像 SCL/PB8,SDA/PB9
////////////////I2C GPIO配置
&RCC-&APB2ENR |= 1&&3;&&& &&//使能PORTB时钟
&GPIOB-&CRH &= 0xFFFFFF00;& &&//I2C1:PB8-&SCL, PB9-&SDL&
&GPIOB-&CRH |= 0x000000FF;& &&//复用开漏输出
&//GPIOB-&CRL &= 0x00FFFFFF;& &&//I2C1:PB6-&SCL, PB7-&SDL&
&//GPIOB-&CRL |= 0xFF000000;& &&//复用开漏输出
////////////////I2C 寄存器配置
&&RCC-&APB1ENR |= 1&&21;&& &&//使能外设I2C1时钟
&RCC-&APB1RSTR |= 1&&21;& &&//复位I2C1
&RCC-&APB1RSTR &= ~(1&&21);&&//复位结束I2C1
&I2C1-&CR2 |= 36;&&&&&&&&&&&&&&& //MHz ... MHz,其他禁用(此处为36MHZ)&
&I2C1-&CCR |= 0&&15;&&&&//I2C主模式& 0:标准模式的I2C&&& 1:快速模式的I2C
&I2C1-&CCR |= 90&&0;&&&&&&&&&& &//时钟控制分频系数 = PCLK1/2/f(f为想得到的频率,此处PCLK1=36MHZ,f=200KHZ)
&I2C1-&TRISE |= 37;&&&&//最大允许SCL上升时间为1000ns,故TRISE[5:0]中必须写入(1000ns/(1000/36)ns = 36+1)
&I2C1-&CR1 |= 1&&10;&&&&&&&&&&&& //打开ACK应答,在接收到一个字节后返回一个应答
&I2C1-&CR1 |= 1&&6;&&&&&&&&&&&&& //广播呼叫使能
&I2C1-&OAR1 |= 0&&15;&&&&&&&&&&& //寻址模式&& 1 响应10位地址& 0& 响应7位地址
&I2C1-&OAR1 |= 1&&14;&&&&&&&&&&& //必须始终由软件保持为 1
&I2C1-&OAR1 |= INTERFACE_ADDR&&1;//设置接口地址的 7~1位(接口地址设为0X30)
&I2C1-&CR2 |= 1&&9;&&&&&&&&&&&&& //事件中断使能
&I2C1-&CR2 |= 1&&8;&&&&&&&&&&&&& //出错中断使能
&I2C1-&CR1 |= 1&&0;&&&&&&&&&&&&& //开启I2C1&&&&&&&
void I2C_Start(void)& &&&&//I2C1产生起始条件
&&& I2C1-&CR1 |= 1&&8;&&&&&&&&&&&&&
void I2C_Stop(void)& &&&&//I2C1产生停止条件
&&& I2C1-&CR1 |= 1&&9;&&&&&&&&&&&&&&&
void I2C_End(void)&&&&&&&&&&&&&&&&& //关闭I2C&&
&I2C1-&CR1 &= ~(1&&0);&&&&&&&
void I2C_Write_U8(u8 data)& &&//I2C1写一个字节
&I2C1-&DR =&
u8 I2C_Read_U8(void)& &&&&//I2C1读一个字节
&while(!RXNE_STATUS);&&&& &&//接收到数据标志位
&return I2C1-&DR;&
u8 I2C_Write(u16 addr, u8* data, u16 length)
&u16 clear = 0;
&u8 addr_l=0, addr_h=0;
&u16 send_
&addr_h = (u8)(addr&&8);
&addr_l = (u8)(addr&0x00FF);
&I2C_Start();
&while(!SB_STATUS);
&I2C_Write_U8(WRITE_ADDR);
&while(!ADDR_STATUS);
&clear =&I2C1-&SR1;
&clear = I2C1-&SR2;
&I2C_Write_U8(addr_h);
&while(!BTF_STATUS);
&I2C_Write_U8(addr_l);
&for(send_loop=0;send_loop&send_loop++)
&&while(!BTF_STATUS);
&&I2C_Write_U8(*data);
&I2C_Stop();
&return 0;
u8* I2C_Read(u16 addr, u8* data, u16 length)
&u16 clear = 0;
&u8 addr_l=0, addr_h=0;
&u16 send_
&for(send_loop=0;send_loop&send_loop++)
&&addr_h = (u8)(addr&&8);
&&addr_l = (u8)(addr&0x00FF);
&&I2C_Start();
&&while(!SB_STATUS);
&&I2C_Write_U8(WRITE_ADDR);
&&while(!ADDR_STATUS);
&&clear = I2C1-&SR2;
&&I2C_Write_U8(addr_h);
&&while(!BTF_STATUS);
&&I2C_Write_U8(addr_l);
&&I2C_Start();
&&while(!SB_STATUS);
&&I2C_Write_U8(READ_ADDR);
&&while(!ADDR_STATUS);
&&clear = I2C1-&SR2;&
&&while(!BTF_STATUS);
&&clear = I2C1-&SR1;
&&*data = I2C_Read_U8();
&&I2C_Stop();
//////////////////////////////////////////////////////i2c_hard.h
#ifndef __I2C_HARD_H
#define __I2C_HARD_H
#include "sys.h"
#include "led.h"
#include "delay.h"
#define WRITE_ADDR 0x28&&&&&&& &&& //从设备(GT9)写数据地址
#define READ_ADDR 0x29&&&& &&& //从设备(GT9)读数据地址
#define INTERFACE_ADDR 0x30&&& &&& //自身地址
#define SB_STATUS (I2C1-&SR1 & 1&&0)& //起始位(主模式)
#define ADDR_STATUS (I2C1-&SR1 & 1&&1)//地址已被发送(主模式)
#define BTF_STATUS&(I2C1-&SR1 & 1&&2)//字节发送结束
#define RXNE_STATUS (I2C1-&SR1 & 1&&6)//数据寄存器非空(接收时)
void I2C_Init(void);
void I2C_Start(void);
void I2C_Stop(void);
void I2C_End(void);
void I2C_Write_U8(u8 data);
u8 I2C_Read_U8(void);
u8 I2C_Write(u16 addr, u8* data, u16 length);
u8* I2C_Read(u16 addr, u8* data, u16 length);
主题帖子精华
新手入门, 积分 49, 距离下一级还需 -29 积分
在线时间0 小时
没有用中断和DMA,C文件中的一下两句忘记删除了:&
&I2C1-&CR2&|=&1&&9;&&&&&&&&&&&&&&//事件中断使能
&I2C1-&CR2&|=&1&&8;&&&&&&&&&&&&&&//出错中断使能
另外多谢好心人的帮忙
&@augustedward
&@login_FAE&
&@jermy_z&
主题帖子精华
初级会员, 积分 77, 距离下一级还需 123 积分
在线时间0 小时
主题帖子精华
金钱122431
在线时间1005 小时
不错,谢谢分享.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺:
微信公众平台:正点原子& &
主题帖子精华
在线时间347 小时
谢谢分享!!!
不能连续读取,怎么破,这样不实际吧,一个地址一个地址来,太慢了,呵呵,我直接一页一页来,速度马上起来了,呵呵
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
主题帖子精华
初级会员, 积分 61, 距离下一级还需 139 积分
在线时间0 小时
牛逼。学习了
主题帖子精华
初级会员, 积分 89, 距离下一级还需 111 积分
在线时间5 小时
感谢分享!!
主题帖子精华
初级会员, 积分 111, 距离下一级还需 89 积分
在线时间11 小时
楼主你好,我用了一下你的代码,发现每次都在&while(!SB_STATUS)这里卡住,这是为什么呢?
主题帖子精华
新手入门, 积分 44, 距离下一级还需 -24 积分
在线时间1 小时
谢谢LZ,我们公司正在调GT911的电容屏,我们也是第一次调,LZ真是帮上了大忙,点赞,谢谢分享
主题帖子精华
在线时间649 小时
谢谢分享,顶一个
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
主题帖子精华
中级会员, 积分 225, 距离下一级还需 275 积分
在线时间35 小时
回复【5楼】八度空间:
---------------------------------
贴出来看看
主题帖子精华
初级会员, 积分 60, 距离下一级还需 140 积分
在线时间12 小时
请问,使用中断或DMA&&没有崩溃,吗??
Powered by随笔 - 55&
文章 - 0&评论 - 10&trackbacks - 0
Ⅰ、写在前面
说到IIC,大家都应该不会陌生,我们初学单片机的时候或多或少都知道或了解过,甚至使用I2C控制过器件。但是,有多少人真正去深入理解,或者深入研究过I2C通信协议呢?
1、我们有必要学习I2C通信吗?
I2C作为常见串行通信的其中一种,在嵌入式领域中占有很重要的地位。原因在于我们嵌入式开发的产品中有很多设备都是使用I2C进行通信的。我们开始学习单片机开发的时候最先接触的应该是使用I2C操作EEPROM(如AT24C08)通信,这也是典型的I2C通信例子。其实还有很多常见的I2C通信设备,如温度芯片、触摸芯片、时钟芯片等,当你工作今后或多或少都会遇到I2C通信的设备。所以,如果你有时间的话,请花一定时间去研究学习一下I2C通信协议,当你以后工作中需要用到I2C设备,而你没有了解过,那个时候再去了解,恐怕项目的进度会因此而受到影响。
2、常见串行通信有哪些,我们又要了解哪些?
常见的串行通信:USART、I2C、SPI、CAN、USB等;我们需要学习哪些?这个问题笔者的建议都要学(在时间、条允许的 情况下)。想要做嵌入式开发,这些通信方式是我们常见的,因此需要掌握。
由于做技术这一行,要学到东西太多,如果你的时间真的有限,那么简单一点的(USART、I2C、SPI)你必须要弄明白,不然你真的有点&水&。这种简单的通信方式应该在面试中是经常问及的问题,如果你是一位刚毕业的大学生,你最好把这些东西你需要弄明白了才去面试。
I2C的读写对时序要求很高,所以,每一个函数都应尽量标准才行,在你自己编写I2C驱动,或借鉴网上的需特别注意(在下面I2C读写函数,我会举例说网上几种常见的不标准的函数)。
本文是使用普通IO软件模拟I2C通信,实现EEPROM(AT24Cxx)串行通信读写数据的文章,将结合I2C通信的时序和软件来讲述这种通信是如何实现的。模拟I2C的好处是移植方便,关于硬件SPI,我计划在下一篇文章讲述(网上说的&ST官网提供的I2C操作EEPROM实例有问题&是事实,有个地方确实存在不足,你知道是哪里吗? 请提前思考一下,下一篇文章揭晓答案)。
提供&简洁版&和&综合版&两个版本的源代码工程供大家下载学习,简洁版内容容易理解一点(本文以此版本讲述),&综合版&相对复杂一点,包含的判断信息更多,感兴趣的朋友可以下载源代码测试。
关于本文的更多详情请往下看。
Ⅱ、实例工程下载
笔者针对于初学者提供的例程都是去掉了许多不必要的功能,精简了官方的代码,对初学者一看就明白,以简单明了的工程供大家学习。
笔者提供的实例工程都是在板子上经过多次测试并没有问题才上传至360云盘,欢迎下载测试、参照学习。
提供下载的软件工程是基于Keil(MDK-ARM) V5版本、STM32F103ZE芯片,但F1其他型号也适用(适用F1其他型号: 关注微信,回复&修改型号&)。
模拟I2C读写EEPROM简洁版(不切换SDA方向、不检测ACK位)实例源代码工程:
模拟I2C读写EEPROM综合版(切换SDA方向、检测ACK位)实例源代码工程:
I2C &EEPROM(AT24xx)资料:
&&访问密码 1099
STM32F1资料:
&&访问密码 ca90
Ⅲ、关于I2C协议
I2C协议的描述请网上搜索,下面将结合时序图+源代码程序一起讲解关于I2C协议中重要的几点。
1.开始和停止条件
SCL时钟电平为高:
SDA数据线由高 -& 低 为总线开始条件;
SDA数据线由低 -& 高 为总线结束条件;
(注意:开始之后将SCL变为低电平,防止误操作SDA使其通信停止,见源代码)
源代码程序:
2.数据位传输
SCL时钟电平为低, 可以改换SDA数据线的电平,在SCL上升沿的过程将SDA数据发送出去。
(切记:请先将SCL变为低电平,再改变SDA电平状态。 主要用于I2C读写Byte函数,这两个函数网上很多人写的不规范,引用需注意,在下面我会举例说明)
发送一位&高&数据流程:
SCL_LOW时钟低&-& &SDA_HIGH数据&-& &SCL_HIGH时钟高
3.应答位信息
I2C是以字节(8位)的方式进行传输,总线上每传输完1字节之后会有一个应答信号,主器件(主机)需要产生对应的一个额外时钟。
应答位产生及接收:
1.在(主机)写数据的时候是从机应答(给主机),主机检测;
2.在(主机)读数据的时候是主机应答(给从机),从机检测;
(这里可以借助I2C读写函数一起理解)
1.时序图(主机写,从机应答,主机读取应答):
2.时序图(主机读,主机产生应答):
4.I2C写一字节
这里说的I2C写,是主机往从机接入1Byte的数据;
&写&要求按照上面的&数据为传输&来操作:在SCL时钟为低电平时准备好,待SCL为高电平时发送出去。
写完一字节(8位)之后,读取从机的应答位:
若为0,表示从机应答,可以继续下一步操作;
若为1,表示从机非应答,不能进行下一步操作。
I2C写一字节不是EEPROM写一字节(需要区分开来)。
&简洁版&没有对应答信号做出检测判断,需要检测应答信号,可参考&综合版&
写一字节时序(前面8位数据 + 最后1为应答):
源代码程序:
I2C写数据(网上常见几种不规范写法&- 或许整个I2C驱动能通信成功,但各个函数之间依赖关系很强,不便理解,也不是标准的函数):
1.首先将SCL置高:
void I2C_WriteByte(uint8_t Data)
&&for(cnt=0; cnt&8; cnt++)
& & I2C_SCL_HIGH;&
&&&&if(Data & 0x80)
&&&&&&I2C_SDA_HIGH;
&&&&&&I2C_SDA_LOW;
&&&&Data &&= 1;
& & I2C_SCL_LOW;
&&I2C_GetAck();
这种程序的写法有一个致命的地方(有可能停止,或重新开始I2C通信):
首先将SCL置高:
A.若之前SDA是低电平,第一位写入高电平,将停止I2C通信。
B.若之前SDA是高电平,第一位写入低电平,将重新开始I2C通信。
2.写完8位数据之后,未将SCL置低(也就是SCL保持高电平状态):
由于写完8位数据之后,将要读取应答信号,也就是要SDA将从输出状态变为输入状态。
这个时候SCL为高,如果SDA最后一位是低且SDA是开漏模式,需要将SDA释放,也就是要将SDA置位高,那么,这个时候就进行了一个停止操作。
3.时序混乱:
void I2C_WriteByte(uint8_t Data)
&&I2C_SCL_HIGH;
&&for(cnt=0; cnt&8; cnt++)
&&&&if(Data & 0x80)
&&&&&&I2C_SDA_HIGH;
&&&&&&I2C_SDA_LOW;
&&&&Data &&= 1;
& & I2C_SCL_LOW;
& & I2C_SCL_HIGH;
&&I2C_GetAck();
多种问题的例子,有可能产生以下问题:
A.有可能多写1位数据;
B.有可能停止I2C通信;
C.有可能重新开始I2C通信。
5.I2C读一字节
I2C的读一字节函数,其实和&写一字节&类似,只是数据传输方向相反,应答的方向也是相反。
读完一字节(8位)之后,由主机产生应答(或非应答)位:
若产生应答,表示可以继续读下一字节操作(从设备地址指向下一字节);
若产生非应答,表示不可以继续读下一字节操作;
网上I2C读数据程序和&写数据&类似,存在很多不标准的版本,参考时请注意。
读一字节时序(主机读取前面8位数据 + 主机产生1为非应答&连续读,主机产生应答位&):
读字节源代码程序:
Ⅳ、EEPROM读写
EEPROM的种类比较多,大多数都遵循I2C协议通信,我们这里就以典型的AT24Cxx为例来讲述通过I2C通信读写AT24Cxx芯片。
EEPROM读(或写)一字节数据需要I2C多次通信过程,下面将讲述几个重要的内容:
1.设备(从机、器件)地址
I2C的开始信号之后的第一步就是发送设备物理地址, AT24Cxx的物理地址的格式如上面:
前面四位固定为:1010
第567位对应A2 A1 A0(有些器件未使用)
第8位是读/写位。
一个设备一般是接地,这就是为什么我们看到A0这个宏定义的来由。
2.数据地址长度
有些芯片数据地址只有8位(如:AT24C01、AT24C02),那么它只发送一字节地址即可;
有些芯片有16位地址,它需要发送两字节地址(看下面读写函数)。
3.EEPROM写一字节数据
EEPROM写数据一般包含下面五步骤(见下面源代码)。这里的写数据,相当于手册中是随机写(任意地址,写一字节数据)。
(未检测应答,需要可以看我提供的另一个源代码程序)
注意两个地方:1.设备地址更加需要看你看引脚的情况;
2.数据地址长度根据芯片不同而不同。
4.EEPROM读一字节数据
EEPROM读数据和写数据相比,要多两个步骤(见下面源代码)。由于要先确定读的地址,所以要先发送地址,使其EEPROM指向对应的地址。(当然,如果当前地址就是需要读取的地址,也可以省略前面发送地址的步骤)。
(在手册中有这么一个步骤&Dummy Write&,有些人把它翻译为&伪操作&,可能很多人不明白它的意思,其实就是确定地址,先要发送地址的意思)
具体请看源代码:(未检测应答,需要可以看我提供的另一个源代码程序)
&&&&跟多关于EEPROM的操作(如:页写、多字节读写等),相对来说复杂一点,当你理解单字节读写操作之后,再去理解就容易的多了。具体内容可以下载我提供的实例参考学习。
EEPROM的读写操作按照I2C标准协议通信,请参看数据手册,有助于提高对I2C的理解。
以上总结仅供参考,若有不对之处,敬请谅解。
更多精彩文章我将第一时间在微信公众号里面分享,对本文有什么疑问可微信留言。
本着免费分享的原则,方便大家手机学习知识,定期在微信平台分享技术知识。如果你觉得分享的内容对你有用,又想了解更多相关的文章,请用微信搜索&EmbeddDeveloper& 或者扫描下面二维码、关注,将有更多精彩内容等着你。
阅读(...) 评论()

我要回帖

更多关于 stm32 硬件i2c例程 的文章

 

随机推荐