How to make talking Voltmeter at home

 Homemade talking voltmeter using Arduino

 It's easy to make a simple digital voltmeter using an Arduino, Audio amplifier and Speaker

It's relatively simple to use an Arduino to measure voltages. The Arduino has several analog input pins that connect to an analog-to-digital converter (ADC) inside the Arduino. The Arduino ADC is a ten-bit converter, meaning that the output value will range from 0 to 1023. We will obtain this value by using the analogRead() function. If you know the reference voltage--in this case we will use 5 V--you can easily calculate the voltage present at the analog input.

 

Requirement

1. Arduino uno/nano.

2. Audio amplifier.

3. Speaker.

4. 100K ohm resistor.

5. battery .


Circuit Diagram 


Pin mapping table for different platforms

 

 * Platform     Normal      Inverted    8kHz timer  PWM timer

 * -------------------------------------------------------

 * AVR          3           11          1           2

 * ATmega2560   6/PH3       7/PH4       1           4

 * Leonardo     9/PB5       10/PB6      1           4

 * ProMicro     5/PC6       %           1           4 - or Adafruit Circuit Playground Classic

 * Esplora      6/PD7       %           1           4

 * Zero (SAMD)  A0          %           TC5         DAC0

 * ESP32        25          %           hw_timer_t  DAC0

 * BluePill     3           %           timer3      analogWrite Roger Clarks core

 * BluePill     PA3         %           timer4      analogWrite STM core

 * Teensy       12/14721    %         IntervalTimer analogWrite

 *

 *  As default both inverted and not inverted outputs are enabled for AVR to increase volume if speaker is attached between them.

 *  Use Talkie Voice(true, false); if you only need not inverted pin or if you want to use SPI on ATmega328 which needs pin 11.

 *

 *  The outputs can drive headphones directly, or add a simple audio amplifier to drive a loudspeaker.


Arduino Code

main code.


#include <Arduino.h>


#include <Talkie.h>


#include <TalkieUtils.h>

#include <Vocab_Special.h>


#if defined(__AVR__)

#include "ADCUtils.h" // for getVCCVoltage()

#elif defined(ARDUINO_ARCH_SAMD)

// On the Zero and others we switch explicitly to SerialUSB

#define Serial SerialUSB

#endif


#if defined(ESP32)

/*

 * Send serial info over Bluetooth

 * Use the Serial Bluetooth Terminal app and connect to ESP32_Talkie

 */

#include "BluetoothSerial.h"

BluetoothSerial SerialBT;

#define Serial SerialBT // redirect all Serial output to Bluetooth

#endif


/*

 * Voice PWM output pins for different ATmegas:

 *  ATmega328 (Uno and Nano): non inverted at pin 3, inverted at pin 11.

 *  ATmega2560: non inverted at pin 6, inverted at pin 7.

 *  ATmega32U4 (Leonardo): non inverted at pin 10, inverted at pin 9.

 *  ATmega32U4 (CircuitPlaygound): only non inverted at pin 5.

 *

 *  As default both inverted and not inverted outputs are enabled to increase volume if speaker is attached between them.

 *  Use Talkie Voice(true, false); if you only need not inverted pin or if you want to use SPI on ATmega328 which needs pin 11.

 *

 *  The outputs can drive headphones directly, or add a simple audio amplifier to drive a loudspeaker.

 */

Talkie Voice;

//Talkie Voice(true, false);

void setup() {

//    pinMode(LED_BUILTIN, OUTPUT);


#if defined(ESP32) && defined(Serial)

    Serial.begin("ESP32_Talkie", false);

#else

    Serial.begin(115200);

#endif

#if defined(__AVR_ATmega32U4__) || defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL)  || defined(ARDUINO_attiny3217) || (defined (USBCON) && defined(USBD_USE_CDC))

    delay(4000); // To be able to connect Serial monitor after reset or power up and before first print out. Do not wait for an attached Serial Monitor!

#endif

    // Just to know which program is running on my Arduino

    Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_TALKIE));


#if defined(TEENSYDUINO)

    pinMode(5, OUTPUT);

    digitalWrite(5, HIGH); //Enable Amplified PROP shield

#elif defined(ARDUINO_ARCH_SAMD)

    analogReadResolution(12);

#endif

    Serial.print(F("Voice queue size is: "));

    Serial.flush();

    Serial.println(Voice.sayQ(spPAUSE1)); // this initializes the queue and the hardware

#if defined(ARDUINO_ARCH_SAMD)

    Serial.println(F("Read voltage at pin A1"));

#else

    Serial.println(F("Read voltage at pin A0"));

#endif


    Serial.print(F("Speech output at pin "));

#if defined(ARDUINO_ARCH_STM32)

    Serial.println("PA3"); // the internal pin numbers are crazy for the STM32 Boards library

#elif defined(ARDUINO_ARCH_SAMD)

    Serial.println("A0"); // DAC0 is at PIN 14/A0

#else

    Serial.print(Voice.NonInvertedOutputPin);

#endif


    if (Voice.InvertedOutputPin && Voice.InvertedOutputPin != TALKIE_USE_PIN_FLAG) {

        Serial.print(F(" and inverted output at pin "));

        Serial.print(Voice.InvertedOutputPin);

    }

    Serial.println();

    Serial.flush();

}


void loop() {


#if defined(__AVR__)

    float tVCCVoltage = getVCCVoltage();

    Serial.print(tVCCVoltage);

    Serial.println(" volt VCC");


    int tVoltage = analogRead(A0) * tVCCVoltage / 1.023;

#elif defined(ESP32)

    int tVoltage = analogRead(A0) * 3.3 / 4.096;

#elif defined(__STM32F1__) || defined(ARDUINO_ARCH_STM32F1)

    int tVoltage = analogRead(0) * 3.3 / 4.096;

#elif defined(ARDUINO_ARCH_SAMD)

    int tVoltage = analogRead(A1) * 3.3 / 4.096; // A0 is DAC output

#else

    int tVoltage = analogRead(0) * 3.3 / 1.023;

#endif


    Serial.print(tVoltage);

    Serial.println(" mV input");

    Serial.flush();

//    sayQVoltageMilliVolts(&Voice, tVoltage);

    float tVoltageFloat = tVoltage / 1000.0;

    sayQVoltageVolts(&Voice, tVoltageFloat);

    // Using .say() here is another way to block the sketch here and wait for end of speech as you can easily see in the source code of say().

    Voice.sayQ(spPAUSE1);

    while (Voice.isTalking()) {

        ;

    }

    delay(200);

}


ADCUtils.cpp


#include "ADCUtils.h"

#if defined(__AVR__) && defined(ADATE)


// Union to speed up the combination of low and high bytes to a word

// it is not optimal since the compiler still generates 2 unnecessary moves

// but using  -- value = (high << 8) | low -- gives 5 unnecessary instructions

union Myword {

    struct {

        uint8_t LowByte;

        uint8_t HighByte;

    } byte;

    uint16_t UWord;

    int16_t Word;

    uint8_t *BytePointer;

};


/*

 * Conversion time is defined as 0.104 milliseconds for 16 MHz Arduino by ADC_PRESCALE in ADCUtils.h.

 */

uint16_t readADCChannel(uint8_t aChannelNumber) {

    Myword tUValue;

    ADMUX = aChannelNumber | (DEFAULT << SHIFT_VALUE_FOR_REFERENCE);


    // ADCSRB = 0; // Only active if ADATE is set to 1.

    // ADSC-StartConversion ADIF-Reset Interrupt Flag - NOT free running mode

    ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADIF) | ADC_PRESCALE);


    // wait for single conversion to finish

    loop_until_bit_is_clear(ADCSRA, ADSC);


    // Get value

    tUValue.byte.LowByte = ADCL;

    tUValue.byte.HighByte = ADCH;

    return tUValue.UWord;

    //    return ADCL | (ADCH <<8); // needs 4 bytes more

}


/*

 * Conversion time is defined as 0.104 milliseconds for 16 MHz Arduino by ADC_PRESCALE in ADCUtils.h.

 */

uint16_t readADCChannelWithReference(uint8_t aChannelNumber, uint8_t aReference) {

    Myword tUValue;

    ADMUX = aChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE);


    // ADCSRB = 0; // Only active if ADATE is set to 1.

    // ADSC-StartConversion ADIF-Reset Interrupt Flag - NOT free running mode

    ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADIF) | ADC_PRESCALE);


    // wait for single conversion to finish

    loop_until_bit_is_clear(ADCSRA, ADSC);


    // Get value

    tUValue.byte.LowByte = ADCL;

    tUValue.byte.HighByte = ADCH;

    return tUValue.UWord;

}


/*

 * @return original ADMUX register content for optional later restoring values

 * All experimental values are acquired by using the ADCSwitchingTest example from this library

 */

uint8_t checkAndWaitForReferenceAndChannelToSwitch(uint8_t aChannelNumber, uint8_t aReference) {

    uint8_t tOldADMUX = ADMUX;

    /*

     * Must wait >= 7 us if reference has to be switched from 1.1 volt/INTERNAL to VCC/DEFAULT (seen on oscilloscope)

     * This is done after the 2 ADC clock cycles required for Sample & Hold :-)

     *

     * Must wait >= 7600 us for Nano board  >= 6200 for Uno board if reference has to be switched from VCC/DEFAULT to 1.1 volt/INTERNAL

     * Must wait >= 200 us if channel has to be switched to 1.1 volt internal channel if S&H was at 5 Volt

     */

    uint8_t tNewReference = (aReference << SHIFT_VALUE_FOR_REFERENCE);

    ADMUX = aChannelNumber | tNewReference;

    if ((tOldADMUX & MASK_FOR_ADC_REFERENCE) != tNewReference && aReference == INTERNAL) {

        /*

         * Switch reference from DEFAULT to INTERNAL

         */

        delayMicroseconds(8000); // experimental value is >= 7600 us for Nano board and 6200 for UNO board

    } else if ((tOldADMUX & 0x0F) != aChannelNumber) {

        if (aChannelNumber == ADC_1_1_VOLT_CHANNEL_MUX) {

            /*

             * Internal 1.1 Volt channel requires  <= 200 us for Nano board

             */

            delayMicroseconds(200);

        } else {

            /*

             * 100 kOhm requires < 100 us, 1 MOhm requires 120 us S&H switching time

             */

            delayMicroseconds(120); // experimental value is <= 1100 us for Nano board

        }

    }

    return tOldADMUX;

}


uint16_t readADCChannelWithOversample(uint8_t aChannelNumber, uint8_t aOversampleExponent) {

    return readADCChannelWithReferenceOversample(aChannelNumber, DEFAULT, aOversampleExponent);

}


/*

 * Conversion time is defined as 0.104 milliseconds for 16 MHz Arduino by ADC_PRESCALE in ADCUtils.h.

 */

uint16_t readADCChannelWithReferenceOversample(uint8_t aChannelNumber, uint8_t aReference, uint8_t aOversampleExponent) {

    uint16_t tSumValue = 0;

    ADMUX = aChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE);


    ADCSRB = 0; // Free running mode. Only active if ADATE is set to 1.

    // ADSC-StartConversion ADATE-AutoTriggerEnable ADIF-Reset Interrupt Flag

    ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIF) | ADC_PRESCALE);


    for (uint8_t i = 0; i < _BV(aOversampleExponent); i++) {

        /*

         * wait for free running conversion to finish.

         * Do not wait for ADSC here, since ADSC is only low for 1 ADC Clock cycle on free running conversion.

         */

        loop_until_bit_is_set(ADCSRA, ADIF);


        ADCSRA |= _BV(ADIF); // clear bit to enable recognizing next conversion has finished

        // Add value

        tSumValue += ADCL | (ADCH << 8); // using myWord does not save space here

        // tSumValue += (ADCH << 8) | ADCL; // this does NOT work!

    }

    ADCSRA &= ~_BV(ADATE); // Disable auto-triggering (free running mode)

    return (tSumValue >> aOversampleExponent);

}


/*

 * Use ADC_PRESCALE32 which gives 26 us conversion time and good linearity for 16 MHz Arduino

 */

uint16_t readADCChannelWithReferenceOversampleFast(uint8_t aChannelNumber, uint8_t aReference, uint8_t aOversampleExponent) {

    uint16_t tSumValue = 0;

    ADMUX = aChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE);


    ADCSRB = 0; // Free running mode. Only active if ADATE is set to 1.

    // ADSC-StartConversion ADATE-AutoTriggerEnable ADIF-Reset Interrupt Flag

    ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIF) | ADC_PRESCALE32);


    for (uint8_t i = 0; i < _BV(aOversampleExponent); i++) {

        /*

         * wait for free running conversion to finish.

         * Do not wait for ADSC here, since ADSC is only low for 1 ADC Clock cycle on free running conversion.

         */

        loop_until_bit_is_set(ADCSRA, ADIF);


        ADCSRA |= _BV(ADIF); // clear bit to enable recognizing next conversion has finished

        // Add value

        tSumValue += ADCL | (ADCH << 8); // using myWord does not save space here

        // tSumValue += (ADCH << 8) | ADCL; // this does NOT work!

    }

    ADCSRA &= ~_BV(ADATE); // Disable auto-triggering (free running mode)

    return (tSumValue >> aOversampleExponent);

}


/*

 * Returns sum of all sample values

 * Conversion time is defined as 0.104 milliseconds for 16 MHz Arduino by ADC_PRESCALE in ADCUtils.h.

 */

uint16_t readADCChannelWithReferenceMultiSamples(uint8_t aChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples) {

    uint16_t tSumValue = 0;

    ADMUX = aChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE);


    ADCSRB = 0; // Free running mode. Only active if ADATE is set to 1.

    // ADSC-StartConversion ADATE-AutoTriggerEnable ADIF-Reset Interrupt Flag

    ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIF) | ADC_PRESCALE);


    for (uint8_t i = 0; i < aNumberOfSamples; i++) {

        /*

         * wait for free running conversion to finish.

         * Do not wait for ADSC here, since ADSC is only low for 1 ADC Clock cycle on free running conversion.

         */

        loop_until_bit_is_set(ADCSRA, ADIF);


        ADCSRA |= _BV(ADIF); // clear bit to enable recognizing next conversion has finished

        // Add value

        tSumValue += ADCL | (ADCH << 8); // using myWord does not save space here

        // tSumValue += (ADCH << 8) | ADCL; // this does NOT work!

    }

    ADCSRA &= ~_BV(ADATE); // Disable auto-triggering (free running mode)

    return tSumValue;

}


/*

 * use ADC_PRESCALE32 which gives 26 us conversion time and good linearity

 * @return the maximum of aNumberOfSamples measurements.

 */

uint16_t readADCChannelWithReferenceMax(uint8_t aChannelNumber, uint8_t aReference, uint16_t aNumberOfSamples) {

    uint16_t tADCValue = 0;

    uint16_t tMaximum = 0;

    ADMUX = aChannelNumber | (aReference << SHIFT_VALUE_FOR_REFERENCE);


    ADCSRB = 0; // Free running mode. Only active if ADATE is set to 1.

    // ADSC-StartConversion ADATE-AutoTriggerEnable ADIF-Reset Interrupt Flag

    ADCSRA = (_BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIF) | ADC_PRESCALE32);


    for (uint16_t i = 0; i < aNumberOfSamples; i++) {

        /*

         * wait for free running conversion to finish.

         * Do not wait for ADSC here, since ADSC is only low for 1 ADC Clock cycle on free running conversion.

         */

        loop_until_bit_is_set(ADCSRA, ADIF);


        ADCSRA |= _BV(ADIF); // clear bit to enable recognizing next conversion has finished

        // check value

        tADCValue = ADCL | (ADCH << 8);

        if (tADCValue > tMaximum) {

            tMaximum = tADCValue;

        }

    }

    ADCSRA &= ~_BV(ADATE); // Disable auto-triggering (free running mode)

    return tMaximum;

}


/*

 * use ADC_PRESCALE32 which gives 26 us conversion time and good linearity

 */

uint16_t readADCChannelWithReferenceMaxMicros(uint8_t aChannelNumber, uint8_t aReference, uint16_t aMicrosecondsToAquire) {

    uint16_t tNumberOfSamples = aMicrosecondsToAquire / 26;

    return readADCChannelWithReferenceMax(aChannelNumber, aReference, tNumberOfSamples);

}


/*

 * aMaxRetries = 255 -> try forever

 * @return (tMax + tMin) / 2

 */

uint16_t readUntil4ConsecutiveValuesAreEqual(uint8_t aChannelNumber, uint8_t aDelay, uint8_t aAllowedDifference,

        uint8_t aMaxRetries) {

    int tValues[4];

    int tMin;

    int tMax;


    tValues[0] = readADCChannel(aChannelNumber);

    for (int i = 1; i < 4; ++i) {

        delay(aDelay); // Only 3 delays!

        tValues[i] = readADCChannel(aChannelNumber);

    }


    do {

        // find min and max

        tMin = 1024;

        tMax = 0;

        for (int i = 0; i < 4; ++i) {

            if (tValues[i] < tMin) {

                tMin = tValues[i];

            }

            if (tValues[i] > tMax) {

                tMax = tValues[i];

            }

        }

        /*

         * check for terminating condition

         */

        if ((tMax - tMin) <= aAllowedDifference) {

            break;

        } else {

//            Serial.print("Difference=");

//            Serial.println(tMax - tMin);


            // move values

            for (int i = 0; i < 3; ++i) {

                tValues[i] = tValues[i + 1];

            }

            // and wait

            delay(aDelay);

            tValues[3] = readADCChannel(aChannelNumber);

        }

        if (aMaxRetries != 255) {

            aMaxRetries--;

        }

    } while (aMaxRetries > 0);


    return (tMax + tMin) / 2;

}


/*

 * !!! Function without handling of switched reference and channel.!!!

 * Use it ONLY if you only call getVCCVoltageSimple() or getVCCVoltageMillivoltSimple() in your program.

 * !!! Resolution is only 20 millivolt !!!

 */

float getVCCVoltageSimple(void) {

    // use AVCC with (optional) external capacitor at AREF pin as reference

    float tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4);

    return ((1023 * 1.1 * 4) / tVCC);

}


/*

 * !!! Function without handling of switched reference and channel.!!!

 * Use it ONLY if you only call getVCCVoltageSimple() or getVCCVoltageMillivoltSimple() in your program.

 * !!! Resolution is only 20 millivolt !!!

 */

uint16_t getVCCVoltageMillivoltSimple(void) {

    // use AVCC with external capacitor at AREF pin as reference

    uint16_t tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4);

    return ((1023L * 1100 * 4) / tVCC);

}


/*

 * !!! Function without handling of switched reference and channel.!!!

 * Use it ONLY if you only use INTERNAL reference (call getTemperatureSimple()) in your program.

 */

float getTemperatureSimple(void) {

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)

    return 0.0;

#else

// use internal 1.1 volt as reference

    float tTemp = (readADCChannelWithReferenceMultiSamples(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL, 4) - 317);

    return (tTemp * (4 / 1.22));

#endif

}


float getVCCVoltage(void) {

    return (getVCCVoltageMillivolt() / 1000.0);

}


/*

 * Read value of 1.1 volt internal channel using VCC as reference.

 * Handles reference and channel switching by introducing the appropriate delays.

 * !!! Resolution is only 20 millivolt !!!

 */

uint16_t getVCCVoltageMillivolt(void) {

    uint8_t tOldADMUX = checkAndWaitForReferenceAndChannelToSwitch(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT);

    uint16_t tVCC = readADCChannelWithReferenceOversample(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 2);

    ADMUX = tOldADMUX;

    /*

     * Do not wait for reference to settle here, since it may not be necessary

     */

    return ((1023L * 1100) / tVCC);

}


void printVCCVoltageMillivolt(Print *aSerial) {

    aSerial->print(F("VCC="));

    aSerial->print(getVCCVoltageMillivolt());

    aSerial->println(" mV");

}


/*

 * Handles reference and channel switching by introducing the appropriate delays.

 */

float getTemperature(void) {

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)

    return 0.0;

#else

    // use internal 1.1 volt as reference

    uint8_t tOldADMUX = checkAndWaitForReferenceAndChannelToSwitch(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL);

    float tTemp = (readADCChannelWithReferenceOversample(ADC_TEMPERATURE_CHANNEL_MUX, INTERNAL, 2) - 317);

    ADMUX = tOldADMUX;

    return (tTemp / 1.22);

#endif

}

#elif defined(ARDUINO_ARCH_APOLLO3)

    void ADCUtilsDummyToAvoidBFDAssertions(){

        ;

    }

#endif // defined(__AVR__)


ADCUtils.h


#ifndef SRC_ADCUTILS_H_

#define SRC_ADCUTILS_H_


#if defined(__AVR__) && (! defined(__AVR_ATmega4809__))

#include <Arduino.h>

#if defined(ADATE)


// PRESCALE4 => 13 * 4 = 52 microseconds per ADC conversion at 1 MHz Clock => 19,2 kHz

#define ADC_PRESCALE2    1 // 26 microseconds per ADC conversion at 1 MHz

#define ADC_PRESCALE4    2 // 52 microseconds per ADC conversion at 1 MHz

// PRESCALE8 => 13 * 8 = 104 microseconds per ADC sample at 1 MHz Clock => 9,6 kHz

#define ADC_PRESCALE8    3 // 104 microseconds per ADC conversion at 1 MHz

#define ADC_PRESCALE16   4 // 13/208 microseconds per ADC conversion at 16/1 MHz - degradations in linearity at 16 MHz

#define ADC_PRESCALE32   5 // 26/416 microseconds per ADC conversion at 16/1 MHz - very good linearity at 16 MHz

#define ADC_PRESCALE64   6 // 52 microseconds per ADC conversion at 16 MHz

#define ADC_PRESCALE128  7 // 104 microseconds per ADC conversion at 16 MHz --- Arduino default


// definitions for 0.1 ms conversion time

#if (F_CPU == 1000000)

#define ADC_PRESCALE ADC_PRESCALE8

#elif (F_CPU == 8000000)

#define ADC_PRESCALE ADC_PRESCALE64

#elif (F_CPU == 16000000)

#define ADC_PRESCALE ADC_PRESCALE128

#endif


/*

 * Reference shift values are complicated for ATtinyX5 since we have the extra register bit REFS2

 * in ATTinyCore, this bit is handled programmatical and therefore the defines are different.

 * To keep my library small, I use the changed defines.

 * After including this file you can not call the ATTinyCore readAnalog functions reliable, if you specify references other than default!

 */

#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)

// defines are for ADCUtils.cpp, they can be used WITHOUT bit reordering

#undef DEFAULT

#undef EXTERNAL

#undef INTERNAL1V1

#undef INTERNAL

#undef INTERNAL2V56

#undef INTERNAL2V56_EXTCAP


#define DEFAULT 0

#define EXTERNAL 4

#define INTERNAL1V1 8

#define INTERNAL INTERNAL1V1

#define INTERNAL2V56 9

#define INTERNAL2V56_EXTCAP 13


#define SHIFT_VALUE_FOR_REFERENCE REFS2

#define MASK_FOR_ADC_REFERENCE (_BV(REFS0) | _BV(REFS1) | _BV(REFS2))

#else // AVR_ATtiny85

#define SHIFT_VALUE_FOR_REFERENCE REFS0

#define MASK_FOR_ADC_REFERENCE (_BV(REFS0) | _BV(REFS1))

#endif


// Temperature channel definitions - 1 LSB / 1 degree Celsius

#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)

#define ADC_TEMPERATURE_CHANNEL_MUX 15

#define ADC_1_1_VOLT_CHANNEL_MUX    12

#define ADC_GND_CHANNEL_MUX         13


#elif defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)

#define ADC_ISCR_CHANNEL_MUX         3

#define ADC_TEMPERATURE_CHANNEL_MUX 11

#define ADC_1_1_VOLT_CHANNEL_MUX    12

#define ADC_GND_CHANNEL_MUX         14

#define ADC_VCC_4TH_CHANNEL_MUX     13


#elif defined(__AVR_ATmega328P__)

#define ADC_TEMPERATURE_CHANNEL_MUX  8

#define ADC_1_1_VOLT_CHANNEL_MUX    14

#define ADC_GND_CHANNEL_MUX         15


#elif defined(__AVR_ATmega32U4__)

#define ADC_TEMPERATURE_CHANNEL_MUX 0x27

#define ADC_1_1_VOLT_CHANNEL_MUX    0x1E

#define ADC_GND_CHANNEL_MUX         0x1F


#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)

#define ADC_1_1_VOLT_CHANNEL_MUX    0x1E

#define ADC_GND_CHANNEL_MUX         0x1F

#define INTERNAL INTERNAL1V1


#else

#error "No temperature channel definitions specified for this AVR CPU"

#endif


uint16_t readADCChannel(uint8_t aChannelNumber);

uint16_t readADCChannelWithReference(uint8_t aChannelNumber, uint8_t aReference);

uint16_t readADCChannelWithOversample(uint8_t aChannelNumber, uint8_t aOversampleExponent);

uint16_t readADCChannelWithReferenceOversample(uint8_t aChannelNumber, uint8_t aReference, uint8_t aOversampleExponent);

uint16_t readADCChannelWithReferenceOversampleFast(uint8_t aChannelNumber, uint8_t aReference, uint8_t aOversampleExponent);

uint16_t readADCChannelWithReferenceMultiSamples(uint8_t aChannelNumber, uint8_t aReference, uint8_t aNumberOfSamples);

uint16_t readADCChannelWithReferenceMax(uint8_t aChannelNumber, uint8_t aReference, uint16_t aNumberOfSamples);

uint16_t readADCChannelWithReferenceMaxMicros(uint8_t aChannelNumber, uint8_t aReference, uint16_t aMicrosecondsToAquire);

uint16_t readUntil4ConsecutiveValuesAreEqual(uint8_t aChannelNumber, uint8_t aDelay, uint8_t aAllowedDifference,

        uint8_t aMaxRetries);


uint8_t checkAndWaitForReferenceAndChannelToSwitch(uint8_t aChannelNumber, uint8_t aReference);


float getVCCVoltageSimple(void);

uint16_t getVCCVoltageMillivoltSimple(void);

float getTemperatureSimple(void);

float getVCCVoltage(void);

uint16_t getVCCVoltageMillivolt(void);

void printVCCVoltageMillivolt(Print* aSerial);

float getTemperature(void);


#endif // defined(ADATE)

#endif //  defined(__AVR__)

#endif /* SRC_ADCUTILS_H_ */


#pragma once

Comments

Popular posts from this blog

how to make taking distance measurement device using Arduino and ultrasonic sensor

How to make voltmeter using Arduino