ATtiny 85 Analog read issue

Hey everyone! So I have been expiriemtning with an attiny 85 to make a simple 1 cell battery voltage monitor. I want it to simply beep and show an LED when the voltage gets below a specified value. The only problem is, whenever I try to run my code, it doesn’t do anything even when the voltage is below the threshold value. I think it might be becuase of the analogRead part. I am supplying the battery voltage to the attiny 85’s vcc pin, and also supplying the battery’s voltage to the analog pin I am reading from, is this ok or could this be causing the problem?

Here is the code

//A1 is battery input pin
int buzzerPin = 0; //pin the buzzer is on
int ledPin = 3; //pin the LED is on
float batteryVoltage; //initialize the variable for battery voltage


void setup() {
  pinMode(buzzerPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(A1, INPUT);
}

void loop() {
  batteryVoltage = (analogRead(A1)) * (5.0 / 1023.0); //read pin the batery is on, then convert to volts
  delay(5);
   
if (batteryVoltage <= 3.7){    //make noise and show LED if the voltage is 3.7 volts or below
    digitalWrite(buzzerPin, HIGH);
    digitalWrite(ledPin, HIGH);
    }
  else {
    digitalWrite(buzzerPin, LOW); // do not beep or light LED if the voltage is above 3.7
    digitalWrite(ledPin, LOW);
    }
}

A flawed approach I'm sorry to say, analogRead() returns a value proportional to Vcc, so will always return a maximum value.

There is a way which involves reading an internal reference voltage and calculating Vcc from that, but I've not tried it with ATtiny85's. Have a search for "attiny85 read vcc"

Martin-X:
A flawed approach I'm sorry to say, analogRead() returns a value proportional to Vcc, so will always return a maximum value.

There is a way which involves reading an internal reference voltage and calculating Vcc from that, but I've not tried it with ATtiny85's. Have a search for "attiny85 read vcc"

Ah ok yeah that makes sense. I was looking into it, and it seems I should use the analogRefrence() function to set the reference voltage and then go from there, I'm not 100% sure if that works on the attiny though. Only one way to find out!

The only way to find out is to look at the data sheet.

Ok so I found this which seems relevant (attached image). I’m not really sure what it means though. If I do analogRefrence(DEFAULT) would that set the internal reference to 1.1 volts?

It's not a matter of setting the reference voltage to 1.1, it's using ADMUX to read that reference voltage against Vcc.

This page has the code for a Uno, which cites this forum as the source: Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors, scroll down to 'Detecting low voltage'. You'll need to check the datasheet for the correct bit-values and port names, trial and error may result in smoke.

Martin-X:
It's not a matter of setting the reference voltage to 1.1, it's using ADMUX to read that reference voltage against Vcc.

This page has the code for a Uno, which cites this forum as the source: Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors, scroll down to 'Detecting low voltage'. You'll need to check the datasheet for the correct bit-values and port names, trial and error may result in smoke.

Ok thanks, that page has lots of useful info.

Don't know if this works on an ATtiny85.
http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/
Leo..

Wawa:
Don’t know if this works on an ATtiny85.

It does.

However, there are two mistakes with the solution from that link. This describes the correct way to read VCC using the bandgap…

Now I have added a 5 volt boost converter in the circuit which is supplying a steady 5v to the ATtiny so that I don't need to mess around with infernal reference voltages.

Sadly this will not be the last time I post this ... Post a schematic if you want help.

I have done this before I think, just give me a second, I'll find it hopefully.

EmanEric:
Yeah the thing is though, that I have a 5 volt boost converter in the circuit which is supplying a steady 5v to the ATtiny so that I don't need to mess around with infernal reference voltages.

Yes you do unless you want the measurements to be referenced to the possibly failing output of your converter circuit.

Well, measuring Vcc versus internal reference from one of my projects:

long readVcc() {//this function was taken from: http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
  ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
  ADMUX = _BV(MUX3) | _BV(MUX2);
#else
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif  

  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH  
  uint8_t high = ADCH; // unlocks both

  long result = (high<<8) | low;

  result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  
  ADMUX&=~(REFS0);
  ADMUX&=~(REFS1);
  
  return result; // Vcc in millivolts
}

Grumpy_Mike:
Yes you do unless you want the measurements to be referenced to the possibly failing output of your converter circuit.

Don't quote me on it, but I do not believe that you can have your reference higher than your vcc...

Plus it's generally a (really) bad idea to have a boost converter as a voltage reference. Those things aren't usually designed to operate at light loads. Not to mention the switching noise and stuff.

but I do not believe that you can have your reference higher than your vcc

That is correct. However the default value for the reference IS the power pin. Therefore my point that you NEED to use some sort of stabilised referance and the internal band gap diode is a cheap option.

Grumpy_Mike:
That is correct. However the default value for the reference IS the power pin. Therefore my point that you NEED to use some sort of stabilised referance and the internal band gap diode is a cheap option.

Whoopsie, I have quoted the wrong guy

Meant to quote this:

Yeah the thing is though, that I have a 5 volt boost converter in the circuit which is supplying a steady 5v to the ATtiny so that I don't need to mess around with infernal reference voltages.

thegoodhen:
Well, measuring Vcc versus internal reference from one of my projects:

long readVcc() {//this function was taken from: http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/

// Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
#if defined(AVR_ATmega32U4) || defined(AVR_ATmega1280) || defined(AVR_ATmega2560)
  ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (AVR_ATtiny24) || defined(AVR_ATtiny44) || defined(AVR_ATtiny84)
  ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (AVR_ATtiny25) || defined(AVR_ATtiny45) || defined(AVR_ATtiny85)
  ADMUX = _BV(MUX3) | _BV(MUX2);
#else
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif

delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH 
  uint8_t high = ADCH; // unlocks both

long result = (high<<8) | low;

result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.110231000
 
  ADMUX&=~(REFS0);
  ADMUX&=~(REFS1);
 
  return result; // Vcc in millivolts
}

Ok thanks for that, will try to implement that code tonight and see how it goes.

Ok so I used the code from http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/. The code is working, and it is correctly beeping when a battery is below the threshold voltage, but one last thing is that my button to stop the ringing doesn’t work. When it is ringing, pressing the button does nothing. The way I have tried to implement this feature is by having the ATtiny just run an infinite loop if the button pin is read as HIGH, but it doesn’t seem to like it. Thanks for all the help and explanation though!

Updated Code:

int buzzerPin = 0; //active buzzer on pin 0
int buttonPin = 3; //button connected to vcc and to pin 3. Pin 3 also has a pulldown resistor
int stopBuzz = LOW; //variable to store if the button is pushed or not
long batteryAlertThreshhold = 3500; //alert value in mV


void setup() {
  pinMode(buzzerPin, OUTPUT); //set the buzzer pin as output
}

void loop() {
  
  
  stopBuzz = digitalRead(buttonPin); //reads the button to see if the buzzing should stop

  if (stopBuzz==HIGH){ //if the button is pushed
      while(true); //run this empty loop
  }
  
  if ((getVoltage() <= batteryAlertThreshhold) && (stopBuzz == LOW)){ // if the battery is below the threshold and the button wasnt pressed, then beep
    digitalWrite(buzzerPin, HIGH); 
  }
  else{  //dont sound the buzzer
    digitalWrite(buzzerPin, LOW);
  }

}

long getVoltage() {//this function was taken from: http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/
  
  ADMUX = _BV(MUX3) | _BV(MUX2);
  
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH  
  uint8_t high = ADCH; // unlocks both

  long result = (high<<8) | low;

  result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  
  ADMUX&=~(REFS0);
  ADMUX&=~(REFS1);
  
  return result; // Vcc in millivolts
}

EmanEric:
Ok so I used the code from http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/. The code is working, and it is correctly beeping when a battery is below the threshold voltage, but one last thing is that my button to stop the ringing doesn’t work. When it is ringing, pressing the button does nothing. The way I have tried to implement this feature is by having the ATtiny just run an infinite loop if the button pin is read as HIGH, but it doesn’t seem to like it. Thanks for all the help and explanation though!

Updated Code:

int buzzerPin = 0; //active buzzer on pin 0

int buttonPin = 3; //button connected to vcc and to pin 3. Pin 3 also has a pulldown resistor
int stopBuzz = LOW; //variable to store if the button is pushed or not
long batteryAlertThreshhold = 3500; //alert value in mV

void setup() {
  pinMode(buzzerPin, OUTPUT); //set the buzzer pin as output
}

void loop() {
 
 
  stopBuzz = digitalRead(buttonPin); //reads the button to see if the buzzing should stop

if (stopBuzz==HIGH){ //if the button is pushed
      while(true); //run this empty loop
  }
 
  if ((getVoltage() <= batteryAlertThreshhold) && (stopBuzz == LOW)){ // if the battery is below the threshold and the button wasnt pressed, then beep
    digitalWrite(buzzerPin, HIGH);
  }
  else{  //dont sound the buzzer
    digitalWrite(buzzerPin, LOW);
  }

}

long getVoltage() {//this function was taken from: http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/
 
  ADMUX = _BV(MUX3) | _BV(MUX2);
 
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH 
  uint8_t high = ADCH; // unlocks both

long result = (high<<8) | low;

result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.110231000
 
  ADMUX&=~(REFS0);
  ADMUX&=~(REFS1);
 
  return result; // Vcc in millivolts
}

Where are you setting the button as input?

Edit: although that means the DDRx is 0, which it probably is by default…

Well, but where are you turning the buzzer off?