In this post, I read the VCC voltage level to the ATtiny85 and save certain state values to the EEPROM if the voltage level is found to fall below a certain value. But this way of reading the VCC uses delay() and is found to interfere with I2C communication. So a better way needs to be found.
After much experimentation, I found the following code to work reliably:
Initially, the ADC register is read in the ISR. But even that takes long enough to interfere with I2C. So a flag adc_ready is set in the ISR, and the actual reading takes place in loop().
The counter adc_countdown makes sure we don't run the ADC too frequently to conserve power (currently set to every 5 seconds).
After much experimentation, I found the following code to work reliably:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | volatile byte adc_countdown = 5; volatile bool adc_ready = false; // adc_countdown is decremented elsewhere every second if (adc_ready) { adc_ready = false; vcc = 1125300L / ADC; // Calculate VCC (in mV); 1125300 = 1.1*1023*1000 adc_countdown = 5; } else if (!bit_is_set(ADCSRA, ADSC) && adc_countdown == 0) { ADMUX = bit(MUX3) | bit(MUX2); // Measure VCC using internal bandgap as reference ADCSRA = bit(ADEN) | bit(ADSC) | bit(ADIE) | bit(ADPS2) | bit(ADPS1) | bit(ADPS0); // Start conversion } ISR(ADC_vect) { adc_ready = true; } |
Initially, the ADC register is read in the ISR. But even that takes long enough to interfere with I2C. So a flag adc_ready is set in the ISR, and the actual reading takes place in loop().
The counter adc_countdown makes sure we don't run the ADC too frequently to conserve power (currently set to every 5 seconds).
Comments
Post a Comment