STM32的I2C补充说明

1.前言

前面不是开发了F407的i2c嘛,最近做项目有三四个i2c器件,项目要求用f103,于是看了一下f103,发现并没有多大区别,下面我会说一下异同。还有关于接收的过程也有要补充的。

2.F103 VS F407

两者之间几乎没有区别,唯一不同的是GPIO的区别,F103与F407在GPIO寄存器会有点区别,这里稍微改一下就能用了。其他部分基本不用动。

上次关于STM32作为主机接收过程讲的有点不足,这次我在发送的时候没发现什么问题,但是接收的时候出现了问题,下面我来展开讲讲,尤其是长数据接收。

3.数据错误

首先是接收错误的问题,上一篇文章里我说到接收数据的过程

程序没有问题,但是顺序错了,正确的顺序是先等待SR1的第六位到位,再读取数据,否则,读到的数据就会是地址,而非接收的数据。

4.多数据接收

上次因为只做了一个数据的接收,所以问题没有暴露出来,这次我在用传感器的时候要一次性接收6个数据,发现数据接收有问题。最后还是通过读手册来排故的。

首先我们再明确一下读数据的过程。

可以看到在读数据的时候,每读一位都需要一个ACK,直到最后一位数据,而这个ACK是由主机向从机发送的应答。

而在STM32中,控制这个应答的在CR1寄存器中,是第十位

通过给第十位置1来给从机应答

我们来测试一下,这里我通过i2c读取3个数据

i2c_ReadRegist(ADXL345ADDRESS,0x32,data,3);

 我们看一下波形

不对啊,而且停止位没了,传输停止后总线的电平也不对。

这里我们要再看一下手册

注意看一下最后一位的数据传输,比较特殊。手册上说的比较模糊,我个人的建议是在完成上一个数据接收后就立刻给停止位置1,给应答位置0。程序可以这样写

	while(wei<length)
	{
		if(length!=1){I2C1->CR1|=1<<10;}						//多重数据接收时由主机应答
		if(wei==length-1)
		{
			I2C1->CR1&=~(1<<10);					//最后一位无需应答
			I2C1->CR1|=1<<9;							//提前写入停止位
		}
		//等待数据接收完毕
		for(wait=0;(I2C1->SR1&(1<<6))==0;wait++){if(wait>WAITTIME){I2C1->CR1|=1<<9;return;}}
		i2cdata[wei]=I2C1->DR;				//EV8
		wei++;
	}

经过测试,只有这样数据才不会溢出 

我们再来测试一下 

可以看到,波形非常标准。

5.代码

void i2c_ReadRegist(unsigned char i2c_address,unsigned char regaddress,unsigned char* i2cdata,unsigned char length)
{
	
	unsigned int wait;
	unsigned int wei=0;
	
	//发送
	
	I2C1->CR1|=1<<8;							//发出起始信号
	//等待起始信号发送完毕
	for(wait=0;(I2C1->SR1&(1<<0))==0;wait++){if(wait>WAITTIME){I2C1->CR1|=1<<9;return;}}
	
	I2CEV(5);											//EV5
	
	#if ADDRESSBIT==7
	I2C1->DR=i2c_address<<1;			//写入地址
	#else
	I2C1->DR=i2c_address;				//写入地址
	#endif
	
	//等待地址发送完毕
	for(wait=0;(I2C1->SR1&(1<<1))==0;wait++){if(wait>WAITTIME){I2C1->CR1|=1<<9;return;}}
	
	I2CEV(6);	
	I2C1->DR=regaddress;								//EV8
	//等待数据发送完毕	
	for(wait=0;(I2C1->SR1&(1<<7))==0;wait++){if(wait>WAITTIME){I2C1->CR1|=1<<9;return;}}
	
	
	//接收
	I2C1->CR1|=1<<8;							//发出起始信号
	//等待起始信号发送完毕
	for(wait=0;(I2C1->SR1&(1<<0))==0;wait++){if(wait>WAITTIME){I2C1->CR1|=1<<9;return;}}
	
	I2CEV(5);
	
	#if ADDRESSBIT==7
	I2C1->DR=(i2c_address<<1)+1;	//写入地址
	#else
	I2C1->DR=i2c_address;				//写入地址
	#endif
	//等待地址发送完毕
	for(wait=0;(I2C1->SR1&(1<<1))==0;wait++){if(wait>WAITTIME){I2C1->CR1|=1<<9;return;}}
	
	I2CEV(6);

	while(wei<length)
	{
		if(length!=1){I2C1->CR1|=1<<10;}						//多重数据接收时由主机应答
		if(wei==length-1)
		{
			I2C1->CR1&=~(1<<10);					//最后一位无需应答
			I2C1->CR1|=1<<9;							//提前写入停止位
		}
		//等待数据接收完毕
		for(wait=0;(I2C1->SR1&(1<<6))==0;wait++){if(wait>WAITTIME){I2C1->CR1|=1<<9;return;}}
		i2cdata[wei]=I2C1->DR;				//EV8
		wei++;
	}
}

6.总结

前面写i2c程序还是大意了,这两天测试的时候才发现问题,不过写好的i2c用起来还是很舒服的,几乎没有卡顿(中间的空白是在跑FFT算法,不是i2c的问题)

我这接收大量数据并且直接裸机跑在死循环里也没有出错,真不错。

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值