【无标题】

I2C


前言

I2C两线式串行总线
EEPROM
非易失性 - 再断电情况下保存存储数据
适合存储配置信息,用户设置和日志记录
容量 - 比较小,几字节到几兆字节
速度 - 读取速度比较快,擦除数据速度比较慢

AT24C02(掉电不丢失)
EEPROM存储器
2Kbit 共计256字节
被分为了32页,每页8字节,每个字节都可以独立的读/写
AT24C02不可以直接跨页写入数据,一旦跨页写入,就会回滚到当前页的第一个字节
接线情况:SCL时钟线 - GPIOB6 SDA数据线 - GPIOB7


一、I2C

初始I2C:

两线式: 说明处理器和外设之间只需两根信号线, 分别是SCL时钟线和SDA数据线

串行: 由于数据线就一根SDA, 必然是串行, 又由于有时钟控制信号线SCL, 所以数据传输是一个时钟周期传输一个bit位

总线: 说明SCL和SDA上可以连接多个外设(理论上也可以连接多个CPU, 场景极其少见)

SCL: 时钟控制信号线永远只能由CPU控制, 用于实现数据的同步, 四个字(低放高取)

SDA: 数据线, 用于传输数据, 双方都可以控制

切记: SCL和SDA必须分别连接一个上拉电阻, 所以他们默认的电平都是高电平
切记: I2C数据传输从高位开始(1001 0101 - 1001 0101), I2C数据传输一次传输一个字节, 如果传输多个字节需要拆开来传

I2C总线基于主从架构, 其中一个设备作为主设备(master), 负责发起和结束通信, 其他设备作为从设备(slave), 负责响应以及数据传输

I2C总线传输速率: 标准模式100kbps, 快速模式400kbps, 高速模式3.4Mbps

START信号: 又称起始信号, 此信号永远只能由CPU发起, 表示CPU开始要访问外设, 时序为: SCL为高电平, SDA由高电平向低电平跳变产生START信号

STOP信号: 又称结束信号, 此信号永远只能由CPU发起, 表示CPU结束对总线的访问, 时序为: SCL为高电平, SDA由低电平向高电平跳变产生STOP信号

从设备地址: I2C的外设都有一个7bit的编号, 用于在一条总线上给不同的外设做区分, 这个编号叫从设备地址, CPU只需向总线上发送某个外设的设备地址, 那么如果该外设在总线上, 那么该外设就会回复ack信号给CPU

读写位(R/W位): 0 - CPU要写数据, 1 - CPU要读数据

设备地址: 从设备地址 + R/W位

读设备地址: 读设备地址 = 设备地址 << 1 | 1

写设备地址: 写设备地址 = 设备地址 << 1 | 0

ack信号: 应答信号, 发送ack信号就是发送一个bit位的低电平

nack信号: 拒绝信号, 发送nack信号就是发送一个bit位的高电平

CPU给外设发送数据: CPU在SCL为低电平时将数据1放到SDA上(拉高), 外设会在同周期SCL为高电平的时候从SDA上获取数据(判断高低电平)

CPU从外设读取数据: 首先CPU将SCL拉低, 然后外设在SCL为低电平的时候将数据放到数据线上, 然后CPU在同周期SCL为高电平时候从SDA上获取数据

发送开始信号: SDA配置为输出, 设置SDA/SCL为高电平, 保持至少4.7us, 设置SDA为低电平, 保持至少4us, 将SCL拉低方便下次传输

发送结束信号: SDA配置为输出, 设置SDA为低电平SCL为高电平, 保持至少4us, 将SDA拉高, 保持至少4.7us, 注意!!!SDA一定在SCL上边

等待外设ACK: 先将SCL拉低, 至少4.7us, 将SDA配置为输入, 将SCL拉高, 至少4us, 等待外设发送ACK

发送ACK: 将SCL拉低, 将SDA配置为输出, 将SDA拉低把0放上去发送ACK, 至少延时4.7us, 将SCL拉高等待外设读取, 至少延时4us, 将SCL拉低方便下一次进行传输

发送NACK: 将SCL拉低, 将SDA配置为输出, 将SDA拉高把1放上去发送NACK, 至少延时4.7us, 将SCL拉高等待外设读取, 至少延时4us, 将SCL拉低方便下一次传输

发送单字节数据: 将SDA配置为输出, 将SDA拉高或者拉低, 至少延时4.7us, 再将SCL拉高, 至少延时4us, 最后将SCL拉低方便下次传输
具体实现: 需要一个参数,参数代表要发送的数据,因为一个字节8bit,循环8次,重点时判断我要发送的数据到底SDA是拉高还是拉低,可以和0x80(1000 0000)做按位与运算,任何数和1做按位与结果都是其本身,然后把要发送的数据每次循环左移一位即可

接收单字节数据: 将SDA配置为输入模式, 将SCL拉低, 至少延时4us让外设放数据在SDA上, 再将SCL拉高取出从外设读到的数据, 至少延时4us
具体实现: 定义一个变量作为返回值,返回从外设读取到的数据, 先将SDA配置为输入, 循环接收数据, 低放高取, 将SCL拉低等待外设放数据, 至少延时4us, 再将SCL拉高, 取出数据放到临时变量中的最后一位(依次往前存)

二、AT24C02

读取单字节实现: 需要一个参数作为读设备地址, 定义一个临时变量作为返回值, 返回读取到的数据, 然后按照时序, ①发送开始信号 ②发送写设备地址 ③等待外设回复ack ④发送要读取数据的寄存器地址 ⑤等待外设回复ack ⑥发送开始信号 ⑦发送读设备地址 ⑧等待外设回复ack ⑨读取单字节数据 + 回复nack ⑩发送结束信号

写入单字节实现: 需要两个参数, 一个作为要写入寄存器的地址, 一个作为要写入的数据, 然后按照时序, ①发送开始信号 ②发送写设备地址 ③等待外设回复ack ④发送要写入的数据 ⑤等待外设回复ack ⑥发送结束信号

读取多字节实现: 需要三个参数, 一个作为要读取的寄存器首地址, 一个作为存储读取到数据的存储区首地址(指针), 一个作为要读取的字节数, 然后按照时序, 和读取单字节前8个一样, 然后就是读取多字节并且根据情况回复ack或者nack, 这里我们可以循环判断, 什么时候读到最后一个字节回复nack即可, 注意要读取字节数自减一定要放在判断下边, 不然读不到最后一位, 最后发送结束信号

写入多字节实现: 需要三个参数, 分别是要读取寄存器的地址, 要写入数据所在存储区的首地址, 要写入的字节数, 然后按照时序, 前5个和写入单字节一样, 然后我们需要判断写入数据跨页出现回滚的情况, 明确无论如何第一次写入一定不会跨页, 直接写发送数据, 然后等待外设回复ack, 之后的每一次都需要判断是否跨页, 查看时序后发现一旦跨页要写入的字节一定是8的倍数, 所以可以判断如果时8的倍数的话, 停止本次数据传输, 并延时5ms, 因为页的写入需要5ms时间, 重新开始一次新的数据传输, 可完美避开跨页回滚情况, 最后发送结束信号, 并延时5ms

在使用GPIO模拟I2C时,如果在定义发送结束信号时将SDA和SCL的位置写反了,可能会导致数据传输错误。这是因为I2C协议规定,在传输数据时,SDA(数据线)需要从高电平跳变到低电平,而SCL(时钟线)则需要从低电平跳变到高电平,才能完成数据的传输。如果将SDA和SCL的位置写反了,就会导致数据传输时序出现问题,从而导致数据传输错误。因此,在使用GPIO模拟I2C时,需要确保SDA和SCL的位置正确,以保证数据传输的正确性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值