Digispark ATtiny85调用analogRead()读取低电压时OLED死机问题
问题分析与解决方案
核心问题
- 引脚功能冲突:ATtiny85的PB0(对应A0)同时是I2C的SDA引脚(用于OLED通信)和ADC0输入引脚。你在程序中同时使用该引脚进行ADC读取和OLED的I2C通信,会导致硬件模式冲突:当执行
analogRead(A0)时,引脚被切换为ADC输入模式,直接中断OLED的I2C通信,引发死机。 - ADC配置被覆盖:Arduino的
analogRead()函数会完全重置ADMUX寄存器,你在setup中手动设置的1.1V内部参考电压和ADC通道配置会被覆盖,导致实际ADC工作状态不符合预期。
解决方案
1. 更换无冲突的ADC引脚
选择ATtiny85上不与I2C引脚(PB0=SDA、PB2=SCL)冲突的ADC通道:
- A2(PB4,对应ADC2)
- A3(PB3,对应ADC3)
将被测电压的分压电路连接到上述引脚之一,比如A3。
2. 正确配置ADC参考电压
使用Arduino官方的analogReference()函数设置参考电压,避免手动修改寄存器被analogRead()覆盖:
analogReference(INTERNAL1V1); // 设置ADC参考为内部1.1V
3. 修改代码适配新引脚
以下是调整后的完整代码(以A3为例):
#include <Wire.h> #include <Tiny4kOLED.h> void setup() { // 设置ADC参考电压为内部1.1V analogReference(INTERNAL1V1); oled.begin(); oled.setFont(FONT8X16); oled.clear(); oled.on(); oled.switchRenderFrame(); } void loop() { updateDisplay(); delay(50); } void updateDisplay() { oled.clear(); // 读取A3引脚的ADC值 int sensorValue = analogRead(A3); // 计算实际电压:(sensorValue * 1100) / 1023 得到毫伏值 long mVolt = (sensorValue * 1100L) / 1023; float volt = mVolt / 1000.0; oled.setCursor(0, 0); oled.print(F("Cable Volts: ")); oled.print(volt, 2); // 保留两位小数显示 oled.switchFrame(); }
额外说明
- 如果必须使用A0引脚,需要在每次ADC读取后手动恢复I2C引脚的功能,但这种方法容易出错,不推荐。
- 确保分压电路的输出电压不超过ADC参考电压(1.1V),否则会导致ADC读数饱和。
内容的提问来源于stack exchange,提问作者Jake Passolt
相关产品推荐
相关产品推荐

