首页/文章/ 详情

嵌入式学习(十八)—I2C协议介绍(二)

9月前浏览10032

文章概述

一、简要介绍SMBus与I2C区别

二、STM32F407的I2C寄存器

三、编程方法

这篇文章介绍一下STM32F407芯片的I2C资源,从而进一步了解I2C通讯协议。

这里再提一下SMBus总线。从概念上来讲,SMBus(系统管理总线)是一个双线制接口,器件之间可以通讯,它是以I2C工作原理为基础,SMBus可针对系统和电源管理相关的任务提供控制总线。系统管理总线规范涉及三类器件。(1)从器件,用于接收或响应命令。(2)主器件,用于发出命令、生成时钟和中止传输。(3)主机,专用的主器件,可提供连接系统 CPU 的主接口。主机必须具有 主 - 从设备功能,并且必须支持 SMBus 主机通知协议。系统中只允许存在一个主机。

SMBus与I2C的相似之处:

  • 简单明了,2条线的协议:数据*1+时钟*1

  • 通讯方式都是主从通讯,且主器件提供时钟

  • 多主

  • 两者的地址格式(7bit)相似

有相似就有区别,以下是区别:

STM32F407的硬件外设包含了3个硬件I2C资源,硬件I2C的速度比软件I2C快,通常可以达到几百kHz设置更高的速度,软件I2C达到几十kHz。

二、STM32F407的I2C相关的寄存器

2.1. I2C控制寄存器1(I2C_CR1)

位15: SWRST:软件复位

当置 1 时,I2C 处于复位状态。在复位此位之前,确保 I2C 线已释放且总线空闲。0:I2C 外设未处于复位状态 ,1:I2C 外设处于复位状态

位13:ALERT:SMBus报警
此位由软件置 1 和清零,并可在 PE=0 时由硬件清零。0:释放 SMBA 引脚使其变成高电平。报警响应地址头后跟 NACK。1:驱动 SMBA 引脚使其变成低电平。报警响应地址头后跟 ACK
位12:数据包错误校验
此位由软件置 1 和清零,并可在 PEC 传输完成时由硬件清零,或者在 PE=0 时或在检测到起 始位或停止位时由硬件清零。0:不传输 PEC1:PEC 传输(在 Tx 或 Rx 模式下)注意:PEC 计算会因仲裁丢失而失效。
位11:POS:应答/PEC位置
此位由软件置 1 和清零,并可在 PE=0 时由硬件清零。0:ACK 位控制移位寄存器中当前正在接收的字节的 (N)ACK。PEC 位指示移位寄存器中的 当前字节是一个 PEC。1:ACK 位控制移位寄存器中要接收的下一个字节的 (N)ACK。PEC 位指示移位寄存器的下 一个字节是一个 PEC。注意:POS 位只能用于主设备接收 2 个字节时
位10:应答使能
此位由软件置 1 和清零,并可在 PE=0 时由硬件清零。0:不返回应答1:在接收一个字节(匹配地址或数据)之后返回应答
位9:STOP 生成停止位
该位由软件置 1 和清零,也可在检测到停止位时由硬件清零,在检测到超时错误时由硬件 置 1。在主模式下:0:不生成停止位。1:在传输当前字节或发送当前起始位后生成停止位。在从模式下:0:不生成停止位。1:完成当前字节传输后释放 SCL 和 SDA 线。

位 8 START:生成起始位 

此位由软件置 1 和清零,并可在起始位发送完成后或 PE=0 时由硬件清零。在主模式下:0:不生成起始位 1:生成重复起始位在从模式下:0:不生成起始位 1:在总线空闲时生成起始位

位 7 NOSTRETCH:禁止时钟延长 (从模式) 

在从模式下,当 ADDR 或 BTF 标志置 1 时,此位用于禁止时钟延长,直到软件将其复位为止。0:使能时钟延长 1:禁止时钟延长

位 6 ENGC:广播呼叫使能 (General call enable)

0:禁止广播呼叫。不对地址 00h 应答。1:使能广播呼叫。对地址 00h 应答。 

位 5 ENPEC:PEC 使能 (PEC enable)

0:禁止 PEC 计算1:使能 PEC 计算 

位 4 ENARP:ARP 使能 (ARP enable)

0:禁止 ARP1:使能 ARPSMBTYPE=0 时识别 SMBus 器件默认地址SMBTYPE=1 时识别 SMBus 主机地址 

位 3 SMBTYPE:SMBus 类型 (SMBus type) 

0:SMBus 器件 1:SMBus 主机

位 1 SMBUS:SMBus 模式 (SMBus mode) 

0:I2C 模式 1:SMBus 模式 

位 0 PE:外设使能 (Peripheral enable) 

0:禁止外设 1:使能外设 

注意:如果此位在通信进行过程中复位,在结束本次通信后会带 IDLE 状态,外设被禁止。由于通信结束时 PE=0,所有位均会复位。在主模式下,此位不能在通信结束之前复位。

2.2. I2C控制寄存器2(I2C_CR2)

位 12 LAST:最后一次 DMA 传输 (DMA last transfer)

0:下一个 DMA EOT 不是最后一次传输 1:下一个 DMA EOT 是最后一次传输注意:此位用于主接收模式,可对最后接收的数据生成 NACK

位 11 DMAEN:DMA 请求使能 (DMA requests enable) 

0:禁止 DMA 请求 1:当 TxE=1 或 RxNE =1 时使能 DMA 请求

位 10 ITBUFEN:缓冲中断使能 (Buffer interrupt enable)0:TxE = 1 或 RxNE = 1 时不生成任何中断。1:TxE = 1 或 RxNE = 1 时生成事件中断(与 DMAEN 状态无关)

位 9 ITEVTEN:事件中断使能 (Event interrupt enable)

0:禁止事件中断 1:使能事件中断满足以下条件时将生成此中断:—SB = 1(主模式)—ADDR = 1(主/从模式)—ADD10= 1(主模式)—STOPF = 1(从模式)—BTF = 1,无 TxE 或 RxNE 事件—ITBUFEN = 1 且 TxE 事件置 1—ITBUFEN = 1 且 RxNE 事件置 1

位 8 ITERREN:错误中断使能 (Error interrupt enable)

0:禁止错误中断 1:使能错误中断满足以下条件时将生成此中断:

 BERR = 1 

 ARLO = 

1AF = 1 

OVR = 1 

PECERR = 1

TIMEOUT = 1 

SMBALERT = 1

位 5:0 FREQ[5:0]:外设时钟频率 (Peripheral clock frequency) 

外设时钟频率必须使用 APB 时钟频率进行配置(I2C 外设连接到 APB)。允许的最小频率为 2 MHz,最大频率则受限于 APB 最大频率 (42 MHz) 和固有极限频率 46 MHz。0b000000:不允许0b000001:不允许0b000010:2 MHz...0b101010:42 MHz大于 0b101010:不允许

2.2. I2C自有地址寄存器1(I2C_OAR1)

位 15 ADDMODE 寻址模式 (Addressing mode)(从模式)

0:7 位从地址(无法应答 10 位地址)1:10 位从地址(无法应答 7 位地址)位 14 应通过软件始终保持为 1

位 9:8 ADD[9:8]:接口地址 

7 位寻址模式:无意义10 位寻址模式:地址的第 9:8 位 

位 7:1 ADD[7:1]:接口地址 

地址的第 7:1 位 

位 0 ADD0:接口地址

7 位寻址模式:无意义10 位寻址模式:地址的第 0 位

2.2. I2C自有地址寄存器1(I2C_OAR1)

2.3. I2C数据寄存器(I2C_DR)

位 7:0 DR[7:0] 8 位数据寄存器 

接收的字节或者要发送到总线的字节。—发送模式:在 DR 寄存器中写入第一个字节时自动开始发送字节。如果在启动传送 (TxE=1) 后立即将下一个要传送的数据置于 DR 中,则可以保持连续的传送流—接收模式:将接收到的字节复 制到 DR 中 (RxNE=1)。如果在接收下一个数据字节 (RxNE=1) 之前读取 DR,则可保持连续的传送流。注意:在从模式下,地址并不会复 制到 DR 中。注意:硬件不对写冲突进行管理(TxE=0 时也可对 DR 执行写操作)。注意:如果发出 ACK 脉冲时出现 ARLO 事件,则不会将接收到的字节复 制到 DR 寄存器,因而 也无法读取字节。

2.3. I2C状态寄存器1(I2C_SR1)

位 15 SMBALERT:SMBus 报警 (SMBus alert) 

在 SMBus 主机模式下:0:无 SMBALERT1:引脚上发生 SMBALERT 事件在 SMBus 从模式下:0:无 SMBALERT 响应地址头 1:接收到指示 SMBALERT 低电平的 SMBALERT 响应地址头— 由软件写入 0 来清零,或在 PE=0 时由硬件清零。

位 14 TIMEOUT:超时或 Tlow 错误 (Timeout or Tlow error) 

0:无超时错误 1:SCL 低电平时长持续 25 ms(超时)或主器件累计时钟低电平延长时间超过 10 ms (Tlow:mext)或从器件累计时钟低电平延长时间超过 25 ms (Tlow:sext)— 在从模式下置 1 时:从器件复位通信且硬件释放数据线— 在主模式下置 1 时:由硬件发送停止位— 由软件写入 0 来清零,或在 PE=0 时由硬件清零。注意:此功能仅在 SMBus 模式下可用

位 12 PECERR:接收期间 PEC 错误 (PEC Error in reception) 

0:无 PEC 错误:接收器在接收 PEC 后返回 ACK(如果 ACK=1)1:PEC 错误:接收器在接收 PEC 后返回 NACK(无论 ACK 什么值)—由软件写入 0 来清零,或在 PE=0 时由硬件清零。—注意:接收到错误的 CRC 时,如果在结束 CRC 接收之前 PEC 控制位没有置 1,则 PECERR 位在从模式下不会置 1。不过可以通过读取 PEC 值来判定接收到的 CRC 是否正确。

位 11 OVR:上溢/下溢 (Overrun/Underrun) 

0:未发生上溢/下溢 1:上溢或下溢—在从模式下由硬件置 1,前提是满足 NOSTRETCH=1 且:—接收过程中接收到一个新字节(包括 ACK 脉冲)但尚未读取 DR 寄存器。新接收的字节将 丢失。—发送过程中将发送一个新字节但尚未向 DR 寄存器写入数据。同一字节发送两次。—由软件写入 0 来清零,或在 PE=0 时由硬件清零。注意:如果 DR 写操作时间与出现 SCL 上升沿的时间非常接近,则发出的数据不确定,并且出 现数据保持时间错误。

位 10 AF:应答失败 (Acknowledge failure)

0:未发生应答失败 1:应答失败—无应答返回时由硬件置 1。—由软件写入 0 来清零,或在 PE=0 时由硬件清零

位 9 ARLO:仲裁丢失 (Arbitration lost)(主模式)

0:未检测到仲裁丢失 1:检测到仲裁丢失当接口在竞争总线是输给另一个主设备时,由硬件将该位置 1—由软件写入 0 来清零,或在 PE=0 时由硬件清零。发生 ARLO 事件后,接口会自动切换回从模式 (M/SL=0)。注意:在 SMBUS 中,从模式下的数据仲裁仅发生在数据阶段或发送确认期间(不适用于地址 确认)。

位 8 BERR:总线错误 (Bus error)

0:无误放的起始或停止位 1:存在误放的起始或停止位—SCL 为高电平时,若接口在字节传输期间检测到某个无效位置出现 SDA 上升沿或下降沿, 则会由硬件将该位置 1。—由软件写入 0 来清零,或在 PE=0 时由硬件清零

位 7 TxE:数据寄存器为空 (Data register empty)(发送器) 

0:数据寄存器非空 1:数据寄存器为空—发送过程中 DR 为空时该位置 1。TxE 不会在地址阶段置 1。—由软件写入 DR 寄存器来清零,或在出现起始、停止位或者 PE=0 时由硬件清零。如果接收到 NACK 或要发送的下一个字节为 PEC (PEC=1),TxE 将不会置 1注意:写入第一个要发送的数据或在 BTF 置 1 时写入数据都无法将 TxE 清零,因为这两种情况 下数据寄存器仍为空。

位 6 RxNE:数据寄存器非空 (Data register not empty)(接收器) 

0:数据寄存器为空 1:数据寄存器非空—接收模式下数据寄存器非空时置 1。RxNE 不会在地址阶段置 1。—由软件读取或写入 DR 寄存器来清零,或在 PE=0 时由硬件清零。发生 ARLO 事件时 RxNE 不会置 1。注意:BTF 置 1 时无法通过读取数据将 RxNE 清零,因为此时数据寄存器仍为满.

位 4 STOPF:停止位检测 (Stop detection)(从模式) 

0:未检测到停止位 1:检测到停止位—从设备在应答脉冲后(如果 ACK=1)检测到停止位,由硬件置 1。—由软件分别对 SR1 寄存器和 CR1 寄存器执行读操作和写操作来清零,或在 PE=0 时由硬件 清零。注意:收到 NACK 后 STOPF 位不会置 1。建议在 STOPF 置 1 后执行完整的清零序列(首先读取 SR1,然后写入 CR1)。

位 3 ADD10:发送 10 位头(主模式)

0:未发生 ADD10 事件。1:主器件已发送第一个地址字节(头)。—主器件在 10 位地址模式下已发送第一个字节时由硬件置 1。—由软件在读取 SR1 寄存器后在 DR 寄存器中写入第二个地址字节来清零,或在 PE=0 时由硬 件清零

位 2 BTF:字节传输完成 (Byte transfer finished) 

0:数据字节传输未完成 1:数据字节传输成功完成—由硬件置 1,前提是满足 NOSTRETCH=0 且:—接收过程中接收到一个新字节(包括 ACK 脉冲)但尚未读取 DR 寄存器 (RxNE=1)。—发送过程中将发送一个新字节但尚未向 DR 寄存器写入数据 (TxE=1)。—由软件读或写 DR 寄存器来清零,或在发送过程中出现起始或停止位后由硬件清零,也可 以在 PE=0 时由硬件清零。注意:收到 NACK 后 BTF 位不会置 1如果下一个要发送的字节为 PEC(I2C_SR2 寄存器中的 TRA=1,I2C_CR1 寄存器中的 PEC=1),则 BTF 位不会置 1

位 1 ADDR:地址已发送(主模式)/地址匹配(从模式) 

由软件在读取 SR1 寄存器后读取 SR2 寄存器来清零,或在 PE=0 时由硬件清零。

地址匹配(从模式):0:地址不匹配或未接收到地址。1:接收到的地址匹配。—当接收到的从地址与 OAR 寄存器内容、广播呼叫地址或 SMBus 器件默认地址匹配时,或者 识别到 SMBus 主机或 SMBus 报警时,该位由硬件置 1。(根据配置确定何时使能)。

地址已发送(主模式)0:地址发送未结束 1:地址发送结束—在 10 位寻址模式下,接收到第二个地址字节的 ACK 后该位置 1。—在 7 位寻址模式下,接收到地址字节的 ACK 后该位置 1。注意:收到 NACK 后 ADDR 位不会置 1

位 0 SB:起始位 (Start bit)(主模式)

0:无起始位 1:起始位已经发送。—生成启动条件时置 1。—由软件在读取 SR1 寄存器后写入 DR 寄存器来清零,或在 PE=0 时由硬件清零

2.4. I2C状态寄存器2(I2C_SR2)

位 15:8 PEC[7:0] 数据包错误校验寄存器

ENPEC=1 时,此寄存器包含内部 PEC。

位 7 DUALF:双标志 (Dual flag)(从模式)

0:接收到的地址与 OAR1 匹配 1:接收到的地址与 OAR2 匹配—出现停止位、重复起始位或 PE=0 时由硬件清零。 

位 6 SMBHOST:SMBus 主机头 (SMBus host header)(从模式)

0:无 SMBus 主机地址 1:SMBTYPE=1 且 ENARP=1 时接收到 SMBus 主机地址。—出现停止位、重复起始位或 PE=0 时由硬件清零。 

位 5 SMBDEFAULT:SMBus 器件默认地址 (SMBus device default address)(从模式)

0:无 SMBus 器件默认地址 1:ENARP=1 时接收到 SMBus 器件默认地址—出现停止位、重复起始位或 PE=0 时由硬件清零。 

位 4 GENCALL:广播呼叫地址 (General call address)(从模式)0:无广播呼叫 1:ENGC=1 时接收到广播呼叫地址—出现停止位、重复起始位或 PE=0 时由硬件清零。

位 3 保留,必须保持复位值 

位 2 TRA:发送器/接收器 (Transmitter/receiver)

0:接收器 1:发送器此位在整个地址阶段的结尾处根据地址字节的 R/W 位状态进行置 1。同样,检测到停止位 (STOPF=1)、重复起始位、总线仲裁丢失 (ARLO=1) 或当 PE=0 时该位 也由硬件清零。 

位 1 BUSY:总线忙碌 (Bus busy) 

0:总线上无通信 1:总线正在进行通信—检测到 SDA 或 SCL 低电平时由硬件置 1 —检测到停止位时由硬件清零。该位指示总线上是否正在进行通信。即使禁止接口 (PE=0) 后此信息也会更新。 

位 0 MSL:主/从模式 (Master/slave) 

0:从模式 1:主模式—接口进入主模式时 (SB=1) 由硬件置 1。—检测到总线上的停止位、仲裁丢失 (ARLO=1) 或当 PE=0 时由硬件清零

2.5. I2C时钟控制寄存器(I2C_CCR)

位 15 F/S:I2C 主模式选择 (I2C master mode selection

0:标准模式 I2C1:快速模式 I2C

位 14 DUTY:快速模式占空比 (Fast mode duty cycle

0:快速模式 tlow/thigh = 21:快速模式 tlow/thigh = 16/9

位 11:0 CCR[11:0]:快速/标准模式下的时钟控制寄存器 (Clock control register in Fast/Standard mode)(主模式)

控制主模式下的 SCL 时钟。

标准模式或 SMBus 模式:Thigh = CCR * TPCLK1Tlow = CCR * TPCLK1

快速模式:如果 DUTY = 0:Thigh = CCR * TPCLK1Tlow = 2 * CCR * TPCLK1

如果 DUTY = 1:(达到 400 kHz) Thigh = 9 * CCR * TPCLK1Tlow = 16 * CCR * TPCLK1

例如:要在标准模式下生成 100 kHz 的 SCL 频率:如果 FREQR = 08,TPCLK1 = 125 ns,则必须将 CCR 编程为 0x28(0x28 <=> 40d x 125 ns = 5000 ns)。

注意:1.允许的最小值为 0x04,但快速占空比模式例外,其最小值为 0x01.这些时间均未经过滤波。.CCR 寄存器必须仅在禁止 I2C (PE = 0) 的情况下配置。

2.6.  I2C TRISE寄存器(I2C_TRISE)


这些位必须编程为 I2C 总线规范中给定的最大 SCL 上升时间加 1。例如:标准模式下允许的最大 SCL 上升时间为 1000 ns。如果 I2C_CR2 寄存器中 FREQ[5:0] 位的值等于 0x08 且 TPCLK1 = 125 ns,则 TRISE[5:0] 位 必须编程为 09h。(1000 ns / 125 ns = 8 + 1)滤波器值也可以叠加到 TRISE[5:0]。如果结果不为整数,则 TRISE[5:0] 必须编程为整数部分,以符合 tHIGH 参数要求。注意:TRISE[5:0] 必须仅在禁止 I2C (PE = 0) 的情况下配置

2.7.  I2C FLTR寄存器(I2C_FLTR)

位 4 ANOFF:模拟噪声滤波器关闭 (Analog noise filter OFF)0:使

能模拟噪声滤波器1:禁止模拟噪声滤波器注意:ANOFF 必须仅在禁止 I2C (PE = 0) 的情况下配置。 

位 3:0 DNF[3:0]:数字噪声滤波器 (Digital noise filter) 

这些位用于配置 SDA 和 SCL 输入端的数字噪声滤波器。数字滤波器可抑制脉宽达 DNF[3:0] * TPCLK1 以下的尖峰。

0000:禁止数字噪声滤波器 

0001:使能数字噪声滤波器,滤波能力可达 1* TPCLK1。

... 

1111:使能数字噪声滤波器,滤波能力可达 15* TPCLK1。 

注意:DNF[3:0] 必须仅在禁止 I2C (PE = 0) 的情况下配置。如果模拟滤波器也已使能,则需将 数字滤波器添加到模拟滤波器中。

三、编程方法

编程方法主要是写代码测试两个I2C设备进行的通讯是否正常,由于STM32系列的硬件I2C不是很好用,容易卡死发不出来数据,所以我们下面的代码是用软件模拟I2C通讯过程。

首先说编程步骤:

第一步,引脚初始化操作,使能对应的GPIO时钟(若使用硬件I2C需要同时使能I2C时钟),配置相应的GPIO为输出开漏模式(也可以将CLK引脚配置为GPIO为推挽模式);

第二步,根据I2C时序写对应的函数:比如I2C_Start(),I2C_Stop(),I2C_Wait_Ack(),I2C_Ack(),I2C_Nack(),

第三步,写读写函数I2C_Send_Byte(u8 data),u8 I2C_Read_Byte(u8 ack),

向I2C从设备中写数据的步骤

1)启动通信,调用I2C_Start()函数,发送Start信号,启动i2c通信;

2)发送设备地址和写操作位;

3)等待应答,等待从设备发送应答信号ACK确认地址已经成功接收,如果没有收到应答,则可能出现问题或者设备故障

4)发送寄存器地址,发送要写入的寄存器地址给从设备,指明要将数据写入到哪个寄存器中;

5)等待应答,等待从设备发送应答信号ACK确认寄存器地址已成功接收;

6)发送数据,将写入的数据发送到从设备的寄存器中

7)等待应答,等待从设备发送应答信号ACK确认数据已经成功接收;

8)如果要连续写入多个寄存器,重复步骤4-7,每次发送新的寄存器地址和相应的数据

9)结束通信,发送停止信号stop来结束I2C通信。

要从从设备寄存器中读取数据的步骤

1)启动通信,调用I2C_Start()函数,发送Start信号,启动i2c通信;

2)发送设备地址和写操作位;

3)等待应答,等待从设备发送应答信号ACK确认地址已经成功接收;

4)发送寄存器地址,告诉从设备从它的那个寄存器中读取数据,

5)等待应答,等待从设备发送应答信号ACK确认寄存器地址已成功接收;

6)重新启动通信,发送重新启动信号,把通信转为读操作

7)送从设备地址和读操作位,

8)等待应答,等待从设备发送应答信号ACK确认寄存器地址已成功接收;

9)从设备读取数据,从从设备中读取读取寄存器的数据;根据从设备的规格和寄存器的数据格式,确定正确的读取方式,如读取一个字节或者多个字节;

10)发送不应答信号,如果只读取一个字节数据,可以发送不应答信号NACK告诉从设备这是最后一个要读取的字节;

11)结束通信,发送停止信号stop来结束I2C通信。

以下是一些关键代码实现:






















































































































void IIC_Init(void){  RCC->AHB1ENR|=1<<1;//使能PORTB时钟  GPIO_Set(GPIOB,PIN8,GPIO_MODE_OUT,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PD);  GPIO_Set(GPIOB,PIN9,GPIO_MODE_OUT,GPIO_OTYPE_OD,GPIO_SPEED_50M,GPIO_PUPD_PD);  IIC_SDA=1;  IIC_SCL=1;}void IIC_Start(void){  SDA_OUT();  IIC_SDA=1;  IIC_SCL=1;  delay_us(4);  IIC_SDA=0;  delay_us(4);  IIC_SCL=0;               //钳住IIC总线,准备发送或接收数据}void IIC_Stop(void){  SDA_OUT();  IIC_SCL=0;  IIC_SDA=0;  delay_us(4);  IIC_SCL=1;  IIC_SDA=1;  delay_us(4);}u8 IIC_Wait_Ack(void){  u8 ucErrTtime=0;  SDA_IN();  IIC_SDA=1;  delay_us(1);  IIC_SCL=1;  delay_us(1);  while(READ_SDA)  {    ucErrTtime++;    if(ucErrTtime>250)    {      IIC_Stop();      return 1;    }  }  IIC_SCL=0;  return 0;}void IIC_Ack(void){  IIC_SCL=0;  SDA_OUT();  IIC_SDA=0;  delay_us(2);  IIC_SCL=1;  delay_us(2);  IIC_SCL=0;}void IIC_NAck(void){  IIC_SCL=0;  SDA_OUT();  IIC_SDA=1;  delay_us(2);  IIC_SCL=1;  delay_us(2);  IIC_SCL=0;}//IIC发送一个字节//返回从机有无应答//1:有应答  0,无应答void IIC_Send_Byte(u8 txd){  u8 i;  SDA_OUT();  IIC_SCL=0;  for(i=0;i<8;i++)  {    IIC_SDA=(txd&0x80)>>7;    txd<<=1;    delay_us(2);    IIC_SCL=1;    delay_us(2);    IIC_SCL=0;    delay_us(2);  }}//读一个字节  ack=1;发送ACK,ack=0,发送NAcku8 IIC_Read_Byte(unsigned char ack){  unsigned char i,receive=0;  SDA_IN();  for(i=0;i<8;i++)  {    IIC_SCL=0;    delay_us(2);    IIC_SCL=1;    if(READ_SDA==1)  //总线上是1    {      receive|=(0x80>>i);    }    else    {      receive&=~(0x80>>i);    }//    receive<<=1;//    if(READ_SDA)//    {receive++;}    delay_us(1);  }  if(!ack)    IIC_NAck();  else     IIC_Ack();  return receive;}



来源:不懂幽默的秦二
电源芯片通信控制SCLFAST
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2024-03-03
最近编辑:9月前
点墨设计
本科 | 高级硬件工程... 十年饮冰,难凉热血!
获赞 0粉丝 7文章 48课程 0
点赞
收藏
未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习计划 福利任务
下载APP
联系我们
帮助与反馈