☰
硬件I2C与软件I2C深度对比:从原理到实战的选型指南
2026/10/3 16:46:14 网站建设 项目流程

1. 从一次深夜调试说起:为什么I2C总在关键时刻掉链子

凌晨两点,示波器上那根SDA线还在倔强地拉低,屏幕上的OLED纹丝不动。这大概是我第无数次在I2C上栽跟头了。从最早用51单片机软件模拟I2C驱动EEPROM,到后来在STM32上折腾硬件I2C外设,再到ESP32休眠唤醒后I2C总线莫名锁死,这条路踩过的坑足够写一本小册子。所以当有人问我“硬件I2C和软件I2C到底谁更坑”的时候,我的回答从来都是:看场景,看芯片,看你愿意把命交给谁。

I2C这个协议本身不复杂,两根线——SCL时钟线和SDA数据线,加上上拉电阻,就能挂一堆设备。但恰恰是这种“简单”,让很多人低估了它的脾气。硬件I2C是芯片厂商给你造好的一台精密机器,你按它的规矩喂参数,它帮你跑时序;软件I2C是你自己拿GPIO一根一根翻转电平,时序全凭你的代码和CPU节奏。两者没有绝对的优劣,只有适不适合你当前这颗芯片、这个项目阶段、这版PCB。

这篇文章我打算把硬件I2C和软件I2C从底层原理到实操细节彻底拆一遍,包括GPIO模式怎么选、时序怎么算、常见故障怎么排查,以及那些只有真正调过几十块板子才会知道的“玄学”问题。不管你是刚接触I2C的新手,还是被某个诡异Bug卡住的老手,应该都能从里面找到点有用的东西。

2. 先搞明白I2C到底在干什么

2.1 两根线背后的通信逻辑

I2C全称Inter-Integrated Circuit,中文叫集成电路总线。它的物理层极其精简:SCL负责节拍,SDA负责数据,所有设备都挂在这两根线上,靠设备地址区分彼此。通信永远是主机发起、从机响应,主机产生时钟,从机不能主动拉时钟(时钟拉伸是另一回事,后面会讲)。

一次完整的I2C传输包含几个固定环节:起始条件、从机地址加读写位、应答位、数据字节、应答位、停止条件。起始条件是SCL高电平期间SDA从高变低,停止条件是SCL高电平期间SDA从低变高。这两个条件必须由主机产生,而且时序要严格符合规范,否则从机根本不认。

数据位的传输规则是:SCL低电平期间SDA可以变化,SCL高电平期间SDA必须保持稳定。这个规则是I2C能可靠工作的基石,也是软件I2C最容易翻车的地方——如果你的代码在SCL拉高之后才去改SDA,从机采样到的就是错误数据。

应答位是接收方在收到8位数据后,把SDA拉低表示“我收到了”。如果主机发完地址后没有收到应答,说明从机不在线或者地址错了。很多初学者调试I2C时第一步就卡在这里,示波器上看波形一切正常,但就是没应答,这时候要优先检查从机地址和上拉电阻。

2.2 上拉电阻不是随便选的

I2C总线是开漏输出,这意味着任何设备只能把线拉低,不能主动拉高。线要变高,全靠上拉电阻。这个电阻的取值直接影响通信质量和功耗。

阻值太大,上升沿变缓,高速通信时波形还没到高电平就被下一个下降沿打断了;阻值太小,低电平时灌电流太大,可能超过GPIO的驱动能力,而且功耗上去了。经验公式是:上升时间Tr ≈ 0.847 × R × C,其中C是总线电容。标准模式100kHz下Tr要小于1000ns,快速模式400kHz下Tr要小于300ns。

实际选型时,4.7kΩ是最常见的默认值,适合大多数3.3V或5V、总线电容不大的场景。如果挂的设备多、走线长,电容可能到200pF以上,这时候4.7k可能就不够了,得降到2.2k甚至1k。但降太狠又会让低电平灌电流超标,一般GPIO的灌电流能力在3mA到20mA之间,3.3V除以1k就是3.3mA,已经接近很多MCU的极限了。

我一般会先用4.7k打样,然后用示波器看上升沿。如果上升沿明显圆钝,再并联一个电阻降低总阻值。注意是并联不是替换,这样调试起来方便。

2.3 时钟拉伸:从机的“等一下”

时钟拉伸是I2C协议里一个容易被忽略但很关键的机制。从机如果处理不过来,可以在应答位之后把SCL拉低,强制主机等待。主机必须检测SCL的实际电平,如果发现自己释放了SCL但线还是低的,就要继续等。

硬件I2C外设通常会自动处理时钟拉伸,但软件I2C如果只是简单地在SCL上写1然后立刻读SDA,就会忽略从机的拉伸请求,导致数据错误。这也是为什么有些设备用软件I2C死活读不出来,换硬件I2C就正常——不是软件I2C不行,是你的软件I2C没实现时钟拉伸检测。

3. 硬件I2C:厂商给的精密机器,但说明书很厚

3.1 硬件I2C到底帮你做了什么

硬件I2C是MCU内部的一个独立外设,它有自己的移位寄存器、时钟发生器、地址比较器和状态机。你只需要配置好时钟频率、从机地址、传输方向,然后把数据扔进数据寄存器,剩下的时序翻转、应答检测、起始停止条件生成,全由硬件自动完成。

以STM32的I2C外设为例,它的工作流程大致是:你设置CR2寄存器的START位,硬件产生起始条件;你把从机地址写入DR寄存器,硬件自动发送并等待应答;你写入数据字节,硬件自动移位输出并采样应答;最后你设置STOP位,硬件产生停止条件。整个过程CPU只需要在几个关键节点查询状态标志或者等中断,不用一直盯着GPIO。

这种方式的优势很明显:时序精确,不受中断延迟影响;CPU占用低,可以去做别的事;支持时钟拉伸、仲裁丢失检测、错误状态上报。但代价是配置复杂,不同厂商的I2C外设行为差异很大,而且有些芯片的硬件I2C存在已知的硬件Bug。

3.2 STM32硬件I2C的“著名”问题

STM32的硬件I2C在圈子里名声不太好,尤其是F1系列,早期版本存在总线锁死、状态机卡住的问题。具体表现是:在某些异常情况下(比如从机在传输中途掉电),I2C外设会进入一个死锁状态,SCL或SDA被永久拉低,软件复位外设也没用,必须断电重启。

这个问题的根源在于STM32的I2C状态机在某些错误分支下没有正确释放总线。ST后来在F4、F7、H7等系列上做了改进,但F1的阴影一直留在老工程师心里。我个人的经验是:F1系列能用硬件I2C,但要做好错误恢复机制,比如检测到总线锁死后,把I2C引脚临时切换成普通GPIO,手动翻转SCL九个脉冲把从机的移位寄存器清空,再重新初始化I2C外设。

具体操作是:关闭I2C外设,把SCL和SDA配置成推挽输出,先拉低SDA,然后SCL翻转九个周期,最后产生一个停止条件,再把引脚恢复成复用开漏模式,重新初始化I2C。这套流程我写成函数放在项目里,每次I2C通信超时就调用一次,能解决大部分锁死问题。

3.3 硬件I2C的配置要点

以STM32 HAL库为例,初始化I2C的代码大概长这样:

hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 400000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; HAL_I2C_Init(&hi2c1);

几个关键参数:ClockSpeed设成400kHz就是快速模式,DutyCycle选2表示SCL高低电平时间比是2:1,NoStretchMode要Disable以支持时钟拉伸。OwnAddress1是主机自己的地址,做主机时可以随便填,做从机时才需要匹配。

读写操作分阻塞、中断、DMA三种方式。阻塞方式最简单,但会卡住CPU;中断方式适合数据量不大的场景;DMA方式适合大批量数据传输,比如向OLED刷屏。我一般用阻塞方式做初始化配置,用DMA方式刷显示数据。

注意:STM32 HAL库的I2C阻塞传输函数有超时参数,默认是HAL_MAX_DELAY,也就是无限等待。如果从机不在线,程序会永远卡在这里。建议改成具体数值,比如100ms,超时后走错误处理流程。

4. 软件I2C:自己动手,丰衣足食,但别把自己埋了

4.1 软件I2C的本质就是GPIO翻转

软件I2C没有任何魔法,就是按照I2C时序规范,用代码控制两个GPIO引脚的高低电平变化。起始条件就是SDA先拉低再拉低SCL,发送一个位就是设置SDA然后拉高再拉低SCL,读一个位就是拉高SCL然后读SDA。

这种方式的优势是:不挑引脚,任何GPIO都能用;不受硬件外设Bug影响;移植性极强,换芯片只需要改GPIO操作宏;调试方便,可以在任意位置打断点看波形。代价是:时序精度依赖CPU和中断环境,高速通信时CPU占用高,需要自己处理时钟拉伸和错误恢复。

4.2 GPIO模式怎么选

软件I2C的GPIO配置有两种常见方案:开漏输出和推挽输出。

开漏输出是I2C的标准配置,引脚只能拉低不能拉高,高电平靠外部上拉电阻。这种方式的优点是天然支持多设备共享总线,不会出现两个设备同时输出高电平导致短路的情况。缺点是上升沿依赖上拉电阻,波形可能不够陡峭。

推挽输出可以主动拉高拉低,波形陡峭,适合高速通信。但推挽输出不能直接用在多设备总线上,因为如果两个设备同时输出相反电平,会烧毁引脚。如果总线上只有一个主机和一个从机,而且从机不会主动拉低SCL(不搞时钟拉伸),推挽输出是可以用的。

我的建议是:除非你有特殊需求,否则老老实实用开漏输出加上拉电阻。这是最安全、最符合I2C规范的做法。STM32配置开漏输出的代码:

GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

注意Mode是GPIO_MODE_OUTPUT_OD,OD就是Open-Drain。Pull选上拉,这样即使外部上拉电阻没焊,内部弱上拉也能让线保持高电平(但内部上拉阻值大,上升沿会很慢,正式产品还是要外部上拉)。

4.3 软件I2C的延时怎么算

软件I2C的通信速率由代码中的延时决定。假设你的GPIO翻转函数执行一次需要1微秒,那么一个完整的SCL周期(高电平加低电平)至少2微秒,对应500kHz。但实际速率还要考虑函数调用开销、循环判断、中断打断等因素。

我一般会写一个简单的延时函数,用NOP或者空循环实现,然后根据示波器实测调整。比如要100kHz,SCL周期是10微秒,高低电平各5微秒。如果GPIO操作本身占了1微秒,那延时函数只需要补4微秒。

但这里有个坑:如果系统开了中断,而且中断服务程序执行时间较长,软件I2C的时序会被打断。从机如果对时序要求严格(比如某些高速ADC),就可能通信失败。解决办法是在I2C传输期间关中断,但关中断时间太长又会影响系统实时性。所以软件I2C适合低速场景,100kHz以下比较稳妥。

4.4 软件I2C的代码骨架

一个典型的软件I2C写字节函数大概是这样:

void I2C_WriteByte(uint8_t data) { for (int i = 0; i < 8; i++) { SDA_OUT(); if (data & 0x80) { SDA_HIGH(); } else { SDA_LOW(); } data <<= 1; delay_us(2); SCL_HIGH(); delay_us(5); SCL_LOW(); delay_us(2); } SDA_IN(); delay_us(2); SCL_HIGH(); delay_us(5); // 读取应答位 if (SDA_READ()) { // NACK } else { // ACK } SCL_LOW(); delay_us(2); }

注意在发送数据位之前要把SDA切换成输出模式,在读取应答位之前要切换成输入模式。这个切换动作很多初学者会忘记,导致读到的应答位永远是0或者永远是1。

5. 硬件I2C和软件I2C的正面交锋

5.1 速度与CPU占用的对比

硬件I2C在400kHz快速模式下,CPU只需要在每次传输前后配置寄存器,传输过程中可以处理其他任务。以传输100字节为例,硬件I2C的CPU占用时间可能只有几十微秒,其余时间都在等硬件完成。

软件I2C在同样速率下,CPU需要全程参与每一个位的翻转。100字节就是800个位,每个位至少两次GPIO操作加延时,CPU占用时间可能达到几毫秒。如果系统还有其他实时任务,软件I2C会明显拖慢整体响应。

但软件I2C的速度上限不一定比硬件低。如果你用72MHz的STM32,GPIO翻转函数优化到极致,软件I2C跑到1MHz也不是不可能。而硬件I2C的最高速率受限于芯片规格,比如STM32F1的I2C最高只有400kHz。所以在某些需要高速通信的场景,软件I2C反而更快。

5.2 稳定性与抗干扰能力

硬件I2C的时序由硬件保证,不受中断和任务调度影响,在复杂电磁环境下更稳定。而且硬件I2C通常有总线错误检测、仲裁丢失检测、超时检测等机制,出问题时能给出明确的状态标志。

软件I2C的时序完全依赖代码执行,任何中断、任务切换、甚至编译器优化都可能导致时序偏差。而且软件I2C通常没有完善的错误检测,通信失败时只能靠超时判断,排查起来更困难。

但硬件I2C也不是万能的。前面提到的STM32 F1锁死问题就是典型例子。而且有些芯片的硬件I2C外设存在硅Bug,比如某些型号在特定条件下会丢失应答位,或者时钟拉伸处理不正确。这些问题在Errata Sheet里有记录,但很多人不会去看。

5.3 移植性与灵活性

软件I2C的移植性是无敌的。只要芯片有GPIO,就能跑软件I2C。换芯片、换引脚、换项目,只需要改几个宏定义。而且软件I2C可以轻松实现多主机、多总线、引脚复用等硬件I2C不容易做到的事情。

硬件I2C的移植性就差很多。不同厂商的I2C外设寄存器不同,HAL库的API也不同。STM32的HAL_I2C_Transmit和NXP的I2C_MasterSendData完全不一样。换芯片往往意味着重写整个I2C驱动层。

5.4 一张表看清两者差异

对比维度硬件I2C软件I2C
时序精度高,硬件保证依赖CPU和中断环境
CPU占用低高
最高速率受芯片规格限制理论上可超过硬件
引脚选择固定复用引脚任意GPIO
移植性差,换芯片需重写好,改宏定义即可
错误检测完善,有状态标志需自己实现
多设备支持好好
时钟拉伸自动处理需手动实现
调试难度高,依赖寄存器手册低,可打断点看波形
已知Bug部分芯片有硬件Bug无,问题都在代码里

6. 那些年我踩过的I2C坑

6.1 上拉电阻没焊导致通信失败

有一次打样回来,OLED死活不亮。示波器看SCL和SDA都是低电平,以为芯片烧了。查了半天发现PCB上上拉电阻的封装画错了,实际没焊上去。I2C总线没有上拉,开漏输出永远拉不高,自然通信不了。

这个坑的教训是:每次新板子回来,先量SCL和SDA的静态电平。正常应该是高电平(被上拉电阻拉高),如果是低电平或者浮空,先查上拉电阻和焊接。

6.2 从机地址搞错

I2C从机地址是7位,但很多数据手册写的是8位(包含读写位)。比如某EEPROM手册写设备地址是0xA0,这是8位格式,实际7位地址是0x50。如果你直接把0xA0传给HAL库的7位地址参数,肯定通信失败。

判断方法:看手册里地址是7位还是8位。如果地址是偶数(最低位为0),很可能是8位格式,右移一位就是7位地址。如果不确定,用逻辑分析仪抓一下波形,看主机发出来的第一个字节是什么。

6.3 软件I2C忘记切换输入输出模式

前面提过,读应答位之前要把SDA从输出切换成输入。我见过很多初学者写的软件I2C,SDA一直配置成输出,读出来的应答位永远是0(因为输出寄存器里存的是0)。这种问题用示波器看不出来,因为波形上SDA确实被从机拉低了,但你的代码读的是输出寄存器的值,不是引脚的实际电平。

解决办法:读SDA之前一定要把引脚配置成输入模式,或者用寄存器直接读IDR。STM32的HAL库有HAL_GPIO_ReadPin函数,但它读的是IDR,前提是引脚配置成了输入。如果配置成输出,读IDR读到的是输出寄存器的值。

6.4 ESP32休眠唤醒后I2C锁死

ESP32在深度休眠时,I2C外设会断电,但总线上挂的设备可能还有电。如果休眠前I2C传输没完成,SDA可能被从机拉低。唤醒后重新初始化I2C,发现总线是低的,通信失败。

解决办法:唤醒后先检查SCL和SDA电平,如果SDA是低的,手动翻转SCL九个脉冲,让从机释放SDA。然后再初始化I2C外设。这个流程和前面说的STM32锁死恢复是一样的。

6.5 OLED的I2C兼容性问题

0.9寸OLED和0.96寸OLED的I2C时序可能略有不同。有些0.9寸OLED对起始条件的保持时间要求更严格,软件I2C如果延时不够,就会初始化失败。我遇到过一批0.9寸OLED,用硬件I2C正常,用软件I2C死活不亮,后来把起始条件的延时从1微秒加到5微秒就好了。

这说明一个问题:不是所有I2C设备都完全符合标准时序。有些设备对时序的容忍度很低,需要你在标准基础上留更多余量。调试时如果通信不稳定,先试着放慢速度,确认能通之后再逐步提速。

7. 常见问题速查与排查思路

7.1 I2C通信失败排查流程

遇到I2C不通,我一般按这个顺序排查:

  1. 量SCL和SDA静态电平,应该是高电平。如果是低,查上拉电阻和总线短路。
  2. 用逻辑分析仪抓波形,看起始条件、地址、应答位是否正常。
  3. 确认从机地址是7位还是8位,是否和代码一致。
  4. 检查GPIO模式,软件I2C确认开漏输出,硬件I2C确认复用开漏。
  5. 降低通信速率,排除时序问题。
  6. 换一个从机设备,排除从机损坏。
  7. 检查电源,有些I2C设备对供电电压要求严格。

7.2 常见问题速查表

现象可能原因解决方法
无应答从机地址错误确认7位/8位地址格式
无应答从机未供电检查从机电源和地
波形上升沿圆钝上拉电阻太大减小上拉电阻或降低速率
通信偶尔失败中断打断时序关中断或改用硬件I2C
总线锁死从机异常拉低手动翻转SCL九个脉冲
读数据全0或全1GPIO模式错误读之前切换输入模式
高速通信失败总线电容太大减小上拉电阻或降低速率
休眠唤醒后失败总线状态异常唤醒后重新初始化并恢复总线

7.3 逻辑分析仪是必备工具

调试I2C没有逻辑分析仪基本等于盲人摸象。示波器只能看模拟波形,逻辑分析仪能直接解码出I2C的地址、数据、应答位,一眼就能看出问题在哪。几百块的入门级逻辑分析仪就够用,配合开源软件可以轻松解码I2C、SPI、UART等协议。

我习惯在代码里加一个宏,调试时打开,在每个I2C操作前后翻转一个空闲GPIO。这样逻辑分析仪上就能看到代码执行到哪一步,和I2C波形对应起来,排查效率翻倍。

8. 到底选哪个:我的实际选择策略

8.1 优先用硬件I2C的场景

如果芯片的硬件I2C外设没有已知严重Bug,而且引脚够用,我优先用硬件I2C。原因很简单:CPU占用低,时序稳定,代码量少。特别是需要高速通信或者系统任务多的时候,硬件I2C的优势很明显。

比如用STM32F4驱动OLED刷屏,硬件I2C加DMA可以做到几乎不占CPU,刷屏流畅。用软件I2C的话,刷一屏要几毫秒,期间CPU什么都干不了。

8.2 必须用软件I2C的场景

以下几种情况我会毫不犹豫选软件I2C:

  • 芯片没有硬件I2C外设,或者硬件I2C引脚被其他功能占用了。
  • 硬件I2C有已知严重Bug,比如STM32F1的锁死问题,而且项目对稳定性要求极高。
  • 需要挂多个I2C总线,硬件外设数量不够。
  • 从机设备时序特殊,硬件I2C无法满足(比如需要特殊的起始条件保持时间)。
  • 项目处于快速原型阶段,软件I2C调试更方便。

8.3 混合方案:硬件做主机,软件做从机

有些场景下,我会同时用硬件I2C和软件I2C。比如一个项目里,STM32作为主机通过硬件I2C读取传感器,同时作为从机通过软件I2C响应另一个主机的查询。这种混合方案可以充分利用两者的优势。

但要注意,软件I2C做从机比做主机难得多。从机需要实时响应主机的时钟和数据,对中断延迟极其敏感。如果CPU还在处理其他中断,很可能错过主机的起始条件。所以软件I2C做从机一般只用在低速场景,而且要做好中断优先级管理。

8.4 我的默认选择

如果让我给一个默认建议:新手先用软件I2C,因为调试方便,出问题容易定位;产品阶段如果硬件I2C没问题就换硬件I2C,降低CPU占用;如果硬件I2C有Bug或者引脚冲突,再换回软件I2C并做好错误恢复。

这个策略的核心逻辑是:软件I2C的可控性最高,任何问题都能通过代码解决;硬件I2C的稳定性最好,但一旦出问题往往需要查手册、查Errata、甚至换芯片。先用软件I2C把功能跑通,再根据实际需求决定是否切换。

9. 几个进阶技巧和注意事项

9.1 用DMA刷OLED

如果你用硬件I2C驱动OLED,一定要试试DMA。以SSD1306为例,刷一屏是1024字节,用阻塞方式传输要几毫秒,用DMA只需要配置好传输长度,然后CPU就可以去干别的。等DMA传输完成中断来了再处理下一帧。

配置DMA时注意:I2C的DMA请求要在I2C初始化之后使能,传输方向是内存到外设,数据宽度是字节。STM32 HAL库的HAL_I2C_Mem_Write_DMA函数可以直接用,但要注意它每次传输都会产生起始和停止条件,刷屏时最好用HAL_I2C_Master_Transmit_DMA连续传输。

9.2 软件I2C的代码优化

软件I2C的GPIO操作可以用宏定义直接操作寄存器,比HAL库函数快很多。比如:

#define SCL_HIGH() GPIOB->BSRR = GPIO_PIN_6 #define SCL_LOW() GPIOB->BRR = GPIO_PIN_6 #define SDA_HIGH() GPIOB->BSRR = GPIO_PIN_7 #define SDA_LOW() GPIOB->BRR = GPIO_PIN_7 #define SDA_READ() ((GPIOB->IDR & GPIO_PIN_7) != 0)

这样每个操作只有一条指令,比HAL_GPIO_WritePin快一个数量级。延时函数也可以用DWT周期计数器实现纳秒级精度,比空循环准确得多。

9.3 注意I2C设备的电源时序

有些I2C设备对电源时序有要求,比如某些传感器要求VDD先上电,然后VDDIO再上电,否则内部保护二极管会漏电,导致I2C总线被拉低。这种问题在示波器上表现为SCL或SDA在设备上电后一直是低电平。

解决办法:查设备手册的Power-Up Sequence章节,用GPIO控制设备的电源引脚,确保上电顺序正确。如果设备没有独立电源引脚,可以在I2C线上串一个电阻限流,但这样会影响上升沿。

9.4 长距离I2C的注意事项

I2C设计初衷是板级通信,不适合长距离传输。如果非要用在长距离场景(比如几米的排线),需要降低速率、减小上拉电阻、使用屏蔽线,甚至加I2C缓冲器或中继器。我试过用普通杜邦线传I2C,超过30厘米就开始不稳定,超过1米基本不能用。

如果项目确实需要长距离通信,建议改用RS485或CAN,不要硬扛I2C。I2C的物理层决定了它不适合这种场景。

9.5 调试时先降速

这是我反复强调的一点:I2C调不通的时候,先把速率降到100kHz甚至更低。很多时序问题在低速下会消失,确认能通之后再逐步提速,找到稳定工作的最高速率。不要一上来就400kHz,然后花几个小时排查一个本来降速就能解决的问题。

我个人在实际操作中的体会是,I2C的坑大多不在协议本身,而在细节:一个上拉电阻、一个GPIO模式、一个延时参数、一个地址格式。硬件I2C和软件I2C谁更坑,取决于你更愿意面对哪种问题。硬件I2C的坑在手册和Errata里,软件I2C的坑在你自己的代码里。把两者的脾气都摸清楚,根据项目需求灵活选择,才是正道。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询