历史上的今天
今天是:2025年04月01日(星期二)
2019年04月01日 | STM32之I2C模块调试总结
2019-04-01 来源:eefocus
前一段时间对STM32的I2C模块进行了调试,今天做一个总结。关于I2C协议的知识,这里就不再赘述,网上有很多介绍I2C协议的文章。目前实现I2C协议的方式有两种,一是采用GPIO口来模拟I2C协议,另外一种是使用STM32自带的I2C模块。虽说使用GPIO口模拟I2C协议较为复杂,需要详细了解I2C协议的内容,但是实现这种方式的资料也非常多,网上都有对应的源码实现,只需要简单修改,就可以实现功能。而针对使用STM32自带的I2C模块,网络上贬斥的声音较多,说是模块本身自带bug,容易出问题,甚至还有人说是史上最难调的I2C模块。当然了,这些问题我自己目前还没有遇到,可能需要以后来验证了。好了,言归正传,今天主要记录一下调试过程以及需要注意的地方。
//功能:初始化IIC接口
void SSX1207_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
//GPIOB6,B7初始化设置,PB6=SCL,PB7=SDA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;//开漏模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_I2C1);//将PB6连接到SCL
GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1);//将PB7连接到SDA
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//使能I2C1时钟
//配置I2C参数
I2C_InitStructure.I2C_Mode=I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2;
I2C_InitStructure.I2C_ClockSpeed=I2C_Standard_Speed;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C1,&I2C_InitStructure);//初始化
I2C_Cmd(I2C1,ENABLE);//使能I2C
}
该函数完成对I2C模块的初始化,首先要确定使用的GPIO口,然后对GPIO口的参数进行配置,这一部分也是参数网上的一下资料进行配置的,需要注意的是GPIO_Mode要配置成复用模式,GPIO_OType要配置成开漏模式,如果使用别的库可能对应的参数有差异,但基本功能应该是一样的,需要将GPIO口配置成复用开漏模式。上面只是对要使用到的GPIO口的配置,还需要配置I2C的参数,这部分只需要注意一下OwnAddress1即可,该参数只需要跟总线上的其他I2C设备的地址不一样就行了,是用户自己定义的。
初始化函数记录完成之后,下面记录主I2C设备对从I2C设备写数据的过程。
//功能:将指定数量的数据写入到IIC设备中
//参数:
// pBuffer--要写入的数据数组
// NumToWrite--写入数据的个数
void SSX1207_WriteByteArray(u8 *pBuffer,u16 NumToWrite)
{
uint32_t flag=0;
I2C_AcknowledgeConfig(I2C1,ENABLE);//ACK置1
I2C_GenerateSTART(I2C1,ENABLE);//产生一个启动信号
timeout=0x1000;
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT))//EV5事件
{
if((--timeout)==0)
{
printf("EV5 fail\r\n");
break;
}
}
flag = I2C_GetLastEvent(I2C1);
printf("flag=%x\r\n",flag);
if(timeout!=0)
printf("EV5 sucess\r\n");
I2C_Send7bitAddress(I2C1,0X50,I2C_Direction_Transmitter);//发送安全芯片地址和写命令
timeout=0x1000;
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))//EV6事件
{
if((--timeout)==0)
{
printf("EV6 fail\r\n");
break;
}
}
flag = I2C_GetLastEvent(I2C1);
printf("flag=%x\r\n",flag);
if(timeout!=0)
printf("EV6 sucess\r\n");
while(NumToWrite--)
{
timeout=0x1000;
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING))//EV8事件
{
if((--timeout)==0)
{
printf("EV8 fail\r\n");
break;
}
}
flag = I2C_GetLastEvent(I2C1);
printf("flag=%x\r\n",flag);
if(timeout!=0)
printf("EV8 sucess\r\n");
I2C_SendData(I2C1,*pBuffer);
pBuffer++;
}
timeout=0x1000;
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED))//EV8_2事件
{
if((--timeout)==0)
{
printf("EV8_2 fail\r\n");
break;
}
}
flag = I2C_GetLastEvent(I2C1);
printf("flag=%x\r\n",flag);
if(timeout!=0)
printf("EV8_2 sucess\r\n");
I2C_GenerateSTOP(I2C1,ENABLE);//产生一个停止信号
}
该函数是将指定数量的数据写入到I2C从设备中,整个流程是参照手册的上的流程来编码的。

//功能:从IIC设备读取指定长度的数据
//参数:
// pBuffer:要读取数据的存放数组
// NumToRead:读取数据的数量
void SSX1207_ReadByteArray(u8 *pBuffer,u16 NumToRead)
{
uint32_t flag=0;
u16 NumToRead_FLAG=NumToRead;
if(NumToRead_FLAG==8)
{
I2C_GenerateSTART(I2C1,ENABLE);//产生一个启动信号
timeout=0x1000;
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT))//EV5事件
{
if((--timeout)==0)
{
printf("EV5 fail!\r\n");
break;
}
}
flag = I2C_GetLastEvent(I2C1);
printf("flag=%x\r\n",flag);
if(timeout!=0)
printf("EV5 sucess!\r\n");
I2C_Send7bitAddress(I2C1,0X50,I2C_Direction_Receiver);//发送安全芯片地址和读命令
timeout=0x1000;
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))//EV6事件
{
if((--timeout)==0)
{
printf("EV6 fail!\r\n");
break;
}
}
flag = I2C_GetLastEvent(I2C1);
printf("flag=%x\r\n",flag);
if(timeout!=0)
printf("EV6 sucess!\r\n");
}
while(NumToRead)
{
printf("len=%d\r\n",NumToRead);
NumToRead--;
if((NumToRead==2)&&(NumToRead_FLAG!=8))
{
I2C_AcknowledgeConfig(I2C1,DISABLE);//ACK位清零
}
if((NumToRead==1)&&(NumToRead_FLAG!=8))
{
I2C_GenerateSTOP(I2C1,ENABLE);//产生一个停止信号
}
timeout=0x1000;
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED))//EV7事件
{
if((--timeout)==0)
{
printf("EV7 fail!\r\n");
break;
}
}
*pBuffer=I2C_ReceiveData(I2C1);
flag = I2C_GetLastEvent(I2C1);
printf("flag=%x\r\n",flag);
if(timeout!=0)
printf("EV7 sucess! *pBuffer=%02x\r\n",*pBuffer);
pBuffer++;
}
printf("NumToRead=%d\r\n",NumToRead);
}
该函数是主设备向从I2C设备读取指定长度的数据。整个流程也是参考手册的流程来实现的。
读取数据的过程主要是注意要读取的数据还剩三个字节的时候CR1寄存器中ACK位和STOP位的变化情况,这里所说的情况是要读取的数据大于两个字节的情况。
如代码中红色标注的所示,此时倒数第三个字节在DR寄存器中,需要将ACK复位,然后读取该字节,但STOP位不能置1(务必要注意这一点,网上有在此时就将STOP位置1的,导致后续的操作失败)。当要读取倒数第二个字节时,将STOP位置1,如代码中紫色标注的部分。另外,为了后续正常读写数据,需要将ACK位再次置1,本次是在写数据函数内实现的。以上是操作I2C设备的三个重要的函数,针对测试的主函数就不再记录了。
史海拾趣
|
今天,科学家们介绍了一种新型的电子电路。这种电路可以模仿人脑的运动,如果用在计算机上,计算机就能象人一样进行思维。人的大脑皮层是人的思维中心,是由神经元组成的复杂的网状结构,有灵敏的反应力。来自麻省理工学院(MIT)、新泽西朗讯公司 ...… 查看全部问答> |
|
序言: “不是在中发,就是在去中发的路上,”用这句话形容西门,似乎一点儿也不为过。 常年混迹于中发的西门,在那里拥有为数众多的好朋友,与经常去那里的工程师相比,他更像其中一员,就差摆个摊铺坐在那里了。这样一位“圈内”人士, ...… 查看全部问答> |
|
大家好,学生以前接触的硬件类比较多,这次需要在2440板子下跑wince,用串口读数据,我找了很多资料,发现都是直接给代码的,学生求助,是在什么环境下编译?PB吗?如果是PB的话,就是改PB里哪里的程序呢???学生很疑惑,学生其实是想用VS2005中 ...… 查看全部问答> |
|
68013A端点EP6OUT的BULK写失败求助,急!! 易用专业的PCI、USB、LED方案正在对68013A采用slavefifo方式进行bulk读写操作 我用EP2做in端点,1024字节,2从缓冲 用EP6做OUT端点,512字节,4从缓冲 我写好了68013A的固件,用CYPRESS的开发工具 ...… 查看全部问答> |
|
我的新书《ARM Cortex-M0从这里开始》已经出版,即将上市,希望大家多多支持。在这里先谢谢大家了。。。。。。。。。。。。。 前言和目录: 已经上市 北航:http://www.buaapress.com.cn/bookdetai ...… 查看全部问答> |
|
本帖最后由 dontium 于 2015-1-23 13:10 编辑 器件型号:RDK_BLDC DRV8312-C2-KIT (电机控制评估套件) &nbs ...… 查看全部问答> |
|
ls -bash: ls: command not found . 原因:在设置环境变量时,编辑profile文件没有写正确,导致在命令行下ls等命令不能够识别。 解决方案: exportPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin… 查看全部问答> |
|
在做CC2530串口通信的实验时,CC debugger 安装完好,可是win7\"设备管理器“里面没有了”端口“选项,无法再串口调试助手里面选择com口,以前用win8系统还是正常的,自从换成win7后就没有显示了,笔记本型号戴尔Inspiron_5537… 查看全部问答> |
|
STM8/STM32哪位大侠推荐一款好用的烧录器啊?因为是工厂烧录的,所以需要的是烧录器,不是仿真器。还有要能烧录STM32L158VT这颗IC的,我找过很多烧录器,都不能烧录这颗IC。… 查看全部问答> |




