OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2701|回复: 10

stm32 iic协议在读字节时最后会多读一个字节

[复制链接]

5

主题

13

帖子

0

精华

初级会员

Rank: 2

积分
58
金钱
58
注册时间
2019-4-4
在线时间
13 小时
发表于 2019-4-10 16:30:50 | 显示全部楼层 |阅读模式
1金钱
为什么读数据时会多读一个字节?怎么解决这个问题?(具体情况看图片)
iic初始化.PNG

逻辑分析仪测得波形

逻辑分析仪测得波形

读取数据代码

读取数据代码

最佳答案

查看完整内容[请看2#楼]

I2C1->DR = Address; while ((I2C1->SR1&0x0002) != 0x0002); // 等待ADDR __disable_irq(); temp = I2C1->SR2; // Clr ADDR Flag I2C1->CR1 &= CR1_ACK_Reset; // 清ACK __enable_irq(); while ((I2Cx->SR1 & 0x00004) != 0x000004); // 等待BTF __disable_irq(); I2C_GenerateSTOP(I2C1, ENABLE); // Stop temp[0] = I2C1->DR; // 读 __enable_irq(); temp[1] = I2C1->DR; ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2019-4-10 16:30:51 | 显示全部楼层
肖涛xiao 发表于 2019-4-11 10:47
是不是stop要写在最后一个接收的字节之前,ACK/NOACK要写在每一个接受的字节之前?像我这样写对吗?

I ...

I2C1->DR = Address;
while ((I2C1->SR1&0x0002) != 0x0002);                // 等待ADDR

__disable_irq();
temp = I2C1->SR2;                                                        // Clr ADDR Flag
I2C1->CR1 &= CR1_ACK_Reset;                                        // 清ACK
__enable_irq();
while ((I2Cx->SR1 & 0x00004) != 0x000004);        // 等待BTF

__disable_irq();         
I2C_GenerateSTOP(I2C1, ENABLE);                                // Stop
temp[0] = I2C1->DR;                                                //        读       
__enable_irq();

temp[1] = I2C1->DR;                                                //        读       
while ((I2Cx->CR1&0x200) == 0x200);                 // STOPF

I2C1->CR1  |= CR1_ACK_Set;
I2C1->CR1  &= CR1_POS_Reset;
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2019-4-10 17:42:20 | 显示全部楼层
接收一个字节, 与两个字节, 或多于两个字节的流程是不一样的
如果只是接收一个字节, 要在完成Device address(即收到ADDR)后, 清ACK标志位, 设Stop, 之后等Rxne后读数据
回复

使用道具 举报

5

主题

13

帖子

0

精华

初级会员

Rank: 2

积分
58
金钱
58
注册时间
2019-4-4
在线时间
13 小时
 楼主| 发表于 2019-4-10 18:24:18 | 显示全部楼层
edmund1234 发表于 2019-4-10 17:42
接收一个字节, 与两个字节, 或多于两个字节的流程是不一样的
如果只是接收一个字节, 要在完成Device ad ...

那接收两个或两个以上的字节呢?
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2019-4-10 19:14:40 | 显示全部楼层
肖涛xiao 发表于 2019-4-10 18:24
那接收两个或两个以上的字节呢?

接收两个是, 发完地址, 等ADDR, reset Ack,等BTF, Set Stop, 读DR, Dealy1~2us 再读DR
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2019-4-10 19:24:26 | 显示全部楼层
接收5个Byte, 发完地址, 等ADDR, 等BTF, 接收1~3个Byte, set stop,  读DR(4), 等RXNE, 读DR(5)
回复

使用道具 举报

5

主题

13

帖子

0

精华

初级会员

Rank: 2

积分
58
金钱
58
注册时间
2019-4-4
在线时间
13 小时
 楼主| 发表于 2019-4-10 19:35:05 | 显示全部楼层
edmund1234 发表于 2019-4-10 19:24
接收5个Byte, 发完地址, 等ADDR, 等BTF, 接收1~3个Byte, set stop,  读DR(4), 等RXNE, 读DR(5)

不明白你们所说的等ADDR,等BTF,等RXNE是指的什么。set stop是发送结束信号吗?如果是那么之后从设备就不会再往外发送数据了,sda线会维持高电平状态。接收5个字节的数据为什么需要先接收1~3个字节,再接收第4、第5个字节?
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2019-4-10 19:41:36 | 显示全部楼层
ADDR,BTF,RXNE 都是 I2C->SR1的标志位

最后一个数据要NACK, 告诉从机, 我写完了, 但这个清除ACK标志位的动作, 不能等你收完最后一个字节才去清, 都是接收前一个字节后就先清ACK, STOP也同理
回复

使用道具 举报

5

主题

13

帖子

0

精华

初级会员

Rank: 2

积分
58
金钱
58
注册时间
2019-4-4
在线时间
13 小时
 楼主| 发表于 2019-4-11 10:47:13 | 显示全部楼层
edmund1234 发表于 2019-4-10 19:41
ADDR,BTF,RXNE 都是 I2C->SR1的标志位

最后一个数据要NACK, 告诉从机, 我写完了, 但这个清除ACK标 ...

是不是stop要写在最后一个接收的字节之前,ACK/NOACK要写在每一个接受的字节之前?像我这样写对吗?

I2C_GenerateSTART(I2C1,ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));       

I2C_Send7bitAddress(I2C1, addr, I2C_Direction_Receiver );
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

I2C_AcknowledgeConfig(I2C1,ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED));
tmp[0] = I2C_ReceiveData(I2C1);       
       
I2C_GenerateSTOP(I2C1,ENABLE );
       
I2C_AcknowledgeConfig(I2C1,DISABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED));
tmp[1] = I2C_ReceiveData(I2C1);               
回复

使用道具 举报

5

主题

13

帖子

0

精华

初级会员

Rank: 2

积分
58
金钱
58
注册时间
2019-4-4
在线时间
13 小时
 楼主| 发表于 2019-4-11 12:56:00 | 显示全部楼层
edmund1234 发表于 2019-4-11 11:19
I2C1->DR = Address;
while ((I2C1->SR1&0x0002) != 0x0002);                // 等待ADDR

__disable_irq();
__enable_irq();
这两句话是干什么用的?
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2019-4-11 13:24:31 | 显示全部楼层
肖涛xiao 发表于 2019-4-11 12:56
__disable_irq();
__enable_irq();
这两句话是干什么用的?

中断禁能, 中断使能
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-22 19:23

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表