ATTiny85 analogRead returns allways 0

Hi there!

Im building a little i2c device with an ATTIny85.

I want to read an analog value from a photoresistor (later a battery reading) and transfer it via i2c to a master device. I connected the photoresitor on the tiny physical pin 2 so it should be "A3" in the IDE.

If I transfer the bytes like this:

// Fill the register buffer
int val = 512;
byte buf[2];
uInt16ToBytes(val, buf);
REGISTERS[REG_BATTERYL] = buf[0];
REGISTERS[REG_BATTERYH] = buf[1];

void uInt16ToBytes(uint16_t integer, byte *buf)
{
  buf[0] = integer >> 8;
  buf[1] = integer;
}

void requestEvent()
{  
  TinyWireS.send(REGISTERS[REGISTER_POINTER]);
  REGISTER_POINTER++;
  if (REGISTER_POINTER >= REGISTER_SIZE)
  {
    REGISTER_POINTER = 0;
  }
}

Everything works just fine. The bytes are transfered and the int value gets printed on my master device. So it must be the analogRead somehow. The circuit is fine since if I read it on the UNO I get correct values according to the environment light.

BUT if I do it like this:

// Fill the register buffer
int val = analogRead(PIN_BATTERY);
byte buf[2];
uInt16ToBytes(val, buf);
REGISTERS[REG_BATTERYL] = buf[0];
REGISTERS[REG_BATTERYH] = buf[1];

The bytes allways return 0 and therefore an int of 0.

The full code is here:

#include <TinyWireS.h>
#include <avr/sleep.h>
#include <avr/wdt.h>

// ---------------------------------------------------------------
// CONSTANTS -----------------------------------------------------
// ---------------------------------------------------------------

#define PIN_POWER   PB4
#define PIN_BATTERY A3
#define PIN_ERROR   PB1

#define I2C_ADDRESS  0x13 

#define MODE_WRITE 0x50
#define MODE_READ  0x51

#define REG_SETTINGS    0x00
#define REG_POWER       0x01
#define REG_SLEEPTIMER  0x02
#define REG_ONTIMER     0x03
#define REG_BATTERYL    0x04
#define REG_BATTERYH    0x05


#define REGISTER_SIZE 6

byte REGISTERS[] = 
{
  0x01, // RSETT, General purpose register (Bit 0 = Power Pin, Bit 1 = Auto sleep, Bit 2 = N/A etc.)
  0x01, // PWRRG, Power register
  0x02, // SLDUR, Sleep duration 8x2 = 16Sec
  0x10, // ONTMR, On timer, 0 = unlimited (Turn off via power bit)
  0x00, // BATTR, Battery level low byte
  0x00, // BATTR, Battery level high byte
};



// ---------------------------------------------------------------
// VARIABLES -----------------------------------------------------
// ---------------------------------------------------------------

byte I2C_MODE         = MODE_READ;
byte REGISTER_POINTER = REG_POWER;

uint8_t timer         = 2; //10min // 8x2=16 10min = 600 Sek = 600 / 8 = 75
volatile boolean on   = true;
uint8_t currentTimer  = 0;

byte i2cBuffer[4];



// ---------------------------------------------------------------
// SETUP ---------------------------------------------------------
// ---------------------------------------------------------------

void setup()
{
  pinMode(PIN_POWER, OUTPUT);
  pinMode(PIN_BATTERY, INPUT);
  TinyWireS.begin(I2C_ADDRESS);
  TinyWireS.onRequest(requestEvent);
  TinyWireS.onReceive(recieveEvent);
}



// ---------------------------------------------------------------
// LOOP ----------------------------------------------------------
// ---------------------------------------------------------------

void loop()
{
  if(currentTimer < timer-1)
  {
    currentTimer++;
  } else {
    tws_delay(10000);
    currentTimer = 0;
  }
  watchdogSleep();
  TinyWireS_stop_check();
} 


void enablePowerPin()
{
  digitalWrite (PIN_POWER, 1);
  tws_delay(10000);
  digitalWrite (PIN_POWER, 0);
}

void blinky(byte count, int speed)
{
  for(int i=0; i<count;i++)
  {
    digitalWrite (PIN_POWER, 1);
    tws_delay(speed);
    digitalWrite (PIN_POWER, 0);
    tws_delay(speed);
  }
}



// ---------------------------------------------------------------
// I2C -----------------------------------------------------------
// ---------------------------------------------------------------

void recieveEvent(uint8_t byteCount)
{  
  // Sanity check
  if(byteCount < 1 || byteCount > 4)
  {
    return;
  }
  
  // Transfer recieved bytes into local I2C buffer
  for(int i = 0; i<byteCount; i++)
  {
    i2cBuffer[i] = TinyWireS.receive();
  }
  
  handleI2CCommand();
  clearI2CBuffer();
}


void handleI2CCommand()
{
  switch(i2cBuffer[0])
  {
    case MODE_WRITE:
      switch(i2cBuffer[1])
      {
        case REG_POWER:
          REGISTERS[REG_POWER] = i2cBuffer[2];
          digitalWrite (PIN_POWER, bitRead(REGISTERS[REG_POWER],0));
          digitalWrite (PIN_ERROR, bitRead(REGISTERS[REG_POWER],1));
          break;
        case REG_SLEEPTIMER:
          break;
      }
      break;
    case MODE_READ:
      REGISTER_POINTER = i2cBuffer[1];
      switch(i2cBuffer[1])
      {
        case REG_BATTERYL:
          int batteryValue = analogRead(PIN_BATTERY);
          byte buf[2];
          uInt16ToBytes(batteryValue, buf);
          REGISTERS[REG_BATTERYL] = buf[0];
          REGISTERS[REG_BATTERYH] = buf[1];
          break;
      }
      break;
  }
}

void uInt16ToBytes(uint16_t integer, byte *buf)
{
  buf[0] = integer >> 8;
  buf[1] = integer;
}

void clearI2CBuffer()
{
  for(int i = 0; i<4; i++)
  {
    i2cBuffer[i] = 0;
  }
}


void requestEvent()
{  
  TinyWireS.send(REGISTERS[REGISTER_POINTER]);
  REGISTER_POINTER++;
  if (REGISTER_POINTER >= REGISTER_SIZE)
  {
    REGISTER_POINTER = 0;
  }
}



// ---------------------------------------------------------------
// WATCHDOG ------------------------------------------------------
// ---------------------------------------------------------------

void watchdogSleep()
{
   //myWatchdogEnable (0b10001);
  if (WDTCR&1<<WDIE) 
  {   //still waiting for WDT interrupts, simply go sleep
    sleep_bod_disable();
    sleep_mode();
  } else { 
    //WDT interrupt is disabled (from WDT ISR)
    myWatchdogEnable (0b100001);  // 8 second
  }
}

ISR(WDT_vect)
{
  on = !on;
  wdt_disable();
}

// sleep bit patterns:
//  1 second:  0b000110
//  2 seconds: 0b000111
//  4 seconds: 0b100000
//  8 seconds: 0b100001
void myWatchdogEnable(const byte interval)
{
  noInterrupts();
  wdt_reset();
  MCUSR = 0;                          // reset various flags
  WDTCR |= 0b00011000;               // see docs, set WDCE, WDE
  WDTCR =  0b01000110 | interval;    // set WDIE, and appropriate delay
  ADCSRA &= ~_BV(ADEN);
  set_sleep_mode (SLEEP_MODE_PWR_DOWN); //SLEEP_MODE_PWR_DOWN, SLEEP_MODE_IDLE
  sleep_bod_disable();
  interrupts();
  sleep_mode();    
}

Thanks for your time and help!

Try writing a minimal program that illustrates the problem. First, this will identify if something else in your program is interfering.

Second, can you provide a photo or an accurate diagram of your circuit? Seems more likely this is a hardware issue than a software bug.

I suppose the risk is that your are somewhere getting the wrong parts of the integer in the wrong place:

void uInt16ToBytes(uint16_t integer, byte *buf)
{
  buf[0] = integer >> 8;
  buf[1] = integer;
}

Maybe look at lowByte() and highByte()

Thanks for your reply!

I suppose the risk is that your are somewhere getting the wrong parts of the integer in the wrong place:

Since I get the correct value when I just type any integer before the conversion I think the method seems to be fine.

Try writing a minimal program that illustrates the problem. First, this will identify if something else in your program is interfering.

You are right. I tried to make a simple program and it works:

#include <TinyWireS.h>

#define PIN_BATTERY A3

int REGISTER_SIZE = 2;
int REGISTER_POINTER = 0;

byte REGISTERS[] = 
{
  0x00,
  0x00,
};

void setup() {
  // put your setup code here, to run once:
  TinyWireS.begin(0x13);
  TinyWireS.onRequest(requestEvent);
  //TinyWireS.onReceive(recieveEvent);
}

void loop() {
  // put your main code here, to run repeatedly:
  TinyWireS_stop_check();
}

void requestEvent()
{  
  int batteryValue = analogRead(PIN_BATTERY);
  byte buf[2];
  uInt16ToBytes(batteryValue, buf);
  REGISTERS[0] = buf[0];
  REGISTERS[1] = buf[1];
  
  TinyWireS.send(REGISTERS[REGISTER_POINTER]);
  REGISTER_POINTER++;
  if (REGISTER_POINTER >= REGISTER_SIZE)
  {
    REGISTER_POINTER = 0;
  }
}

void uInt16ToBytes(uint16_t integer, byte *buf)
{
  buf[0] = integer >> 8;
  buf[1] = integer;
}

Later the device should go to sleep when sending a specific command or a timer timed out.

Maybe my watchdog routine interfering with the analog reading?

Ok. You have connected the pin A3 at the midpoint of a potential divider consisting of the photo resistor and say a 10k resistor?