├── .github └── workflows │ ├── arduino-lint.yml │ ├── jsoncheck.yml │ └── arduino_test_runner.yml ├── library.properties ├── .arduino-ci.yml ├── keywords.txt ├── src ├── CPUVolt.h └── CPUVolt.cpp ├── LICENSE ├── examples └── CPUVolt │ └── CPUVolt.ino └── README.md /.github/workflows/arduino-lint.yml: -------------------------------------------------------------------------------- 1 | name: Arduino-lint 2 | 3 | on: [push, pull_request] 4 | jobs: 5 | lint: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | - uses: arduino/arduino-lint-action@v2 10 | with: 11 | library-manager: update 12 | compliance: strict 13 | -------------------------------------------------------------------------------- /.github/workflows/jsoncheck.yml: -------------------------------------------------------------------------------- 1 | name: JSON check 2 | 3 | on: 4 | push: 5 | paths: 6 | - '**.json' 7 | pull_request: 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: json-syntax-check 15 | uses: limitusus/json-syntax-check@v1 16 | with: 17 | pattern: "\\.json$" 18 | -------------------------------------------------------------------------------- /.github/workflows/arduino_test_runner.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Arduino CI 3 | 4 | on: [push, pull_request] 5 | 6 | jobs: 7 | runTest: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v3 12 | - uses: ruby/setup-ruby@v1 13 | with: 14 | ruby-version: 2.6 15 | - run: | 16 | gem install arduino_ci 17 | arduino_ci.rb 18 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=CPUVolt 2 | version=1.0.3 3 | author=Trent M. Wyatt 4 | maintainer=Trent M. Wyatt 5 | sentence=Calculate the processors Vcc voltage using only the internal registers 6 | paragraph=Ideal for measuring battery drain. Calculate the processors Vcc voltage using nothing more than the micro controller itself. NO external components. 7 | category=Sensors 8 | url=https://github.com/ripred/CPUVolt 9 | architectures=* 10 | includes=CPUVolt.h 11 | -------------------------------------------------------------------------------- /.arduino-ci.yml: -------------------------------------------------------------------------------- 1 | platforms: 2 | rpipico: 3 | board: rp2040:rp2040:rpipico 4 | package: rp2040:rp2040 5 | gcc: 6 | features: 7 | defines: 8 | - ARDUINO_ARCH_RP2040 9 | warnings: 10 | flags: 11 | 12 | packages: 13 | rp2040:rp2040: 14 | url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json 15 | 16 | compile: 17 | platforms: 18 | - uno 19 | # - m4 20 | # - esp32 21 | # - esp8266 22 | # - rpipico 23 | libraries: 24 | - "SoftwareSerial" 25 | - "ArduinoJson" 26 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ################################################# 2 | # Syntax Coloring Map for Arduino CPUVolt Library 3 | ################################################# 4 | # https://github.com/ripred/CPUVolt 5 | ################################################# 6 | # Datatypes (KEYWORD1) 7 | ################################################# 8 | 9 | ################################################# 10 | # Methods and Functions (KEYWORD2) 11 | ################################################# 12 | readVcc KEYWORD2 13 | readPercent KEYWORD2 14 | 15 | ################################################# 16 | # Constants (LITERAL1) 17 | ################################################# 18 | -------------------------------------------------------------------------------- /src/CPUVolt.h: -------------------------------------------------------------------------------- 1 | /*\ ========================================================================= 2 | |*| 3 | |*| Library to use the internal registers in the ATMega cpu to calculate 4 | |*| the processor's Vcc voltage or the battery charge percentage. 5 | |*| 6 | |*| version 1.0: 2022, ++trent m. wyatt 7 | |*| version 1.1: 3, Dec, 2022, ++trent m. wyatt 8 | |*| version 1.3: 3, Dec, 2023, ++trent m. wyatt 9 | |*| 10 | |*| ========================================================================= 11 | \*/ 12 | 13 | #ifndef CPUVOLT_H_INC 14 | #define CPUVOLT_H_INC 15 | 16 | long readVcc(); 17 | float readPercent(float min_volt, float max_volt); 18 | float readPercent(float max_volt = 5000); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Trent M. Wyatt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/CPUVolt/CPUVolt.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * CPUVolt.ino 3 | * 4 | * Example Arduino sketch showing the use of the CPUVolt library. 5 | * Updated to show the use of the new readPercent(...) methods. 6 | * 7 | */ 8 | #include 9 | 10 | void setup() { 11 | Serial.begin(115200); 12 | 13 | /* 14 | * Read the current voltage level and convert it 15 | * to an easier to read floating point value 16 | */ 17 | float mv = readVcc() / 1000.0; 18 | 19 | // Show the voltage with 2 decimal places 20 | Serial.print("Voltage: "); 21 | Serial.println(mv, 2); 22 | 23 | /* 24 | * Get the voltage level as a percentage of total charge. 25 | * You can optionally specify the voltage level to be considered 26 | * as 100%. The default voltage is 5V if not supplied. 27 | */ 28 | float pct = readPercent(/*5000*/); 29 | Serial.print("Percent: "); 30 | Serial.println(pct, 2); 31 | 32 | /* 33 | * You can also specify both the lower and upper voltage 34 | * ranges to be considered what is 0% and what is 100%. 35 | * This is really useful for battery powered projects! 36 | */ 37 | pct = readPercent(2900, 4700); 38 | Serial.print("Percent: "); 39 | Serial.println(pct, 2); 40 | 41 | /* 42 | * The following code shows how you might use the percent of charge 43 | * to turn on a "needs recharging" LED at the percent you want: 44 | */ 45 | float const low_pct = 70.0; // season to taste :) 46 | bool const needs_charging = pct <= low_pct;// set a "needs charging" flag 47 | int const led_pin = LED_BUILTIN; // Or use any other GPIO pin (besides A6 or A7) 48 | pinMode(led_pin, OUTPUT); // set the pin as an output 49 | digitalWrite(led_pin, needs_charging); // set the LED pin HIGH or LOW as needed 50 | } 51 | 52 | void loop() { } 53 | -------------------------------------------------------------------------------- /src/CPUVolt.cpp: -------------------------------------------------------------------------------- 1 | /*\ ========================================================================= 2 | |*| 3 | |*| CPUVolt.cpp 4 | |*| 5 | |*| Function to use the internal registers in the ATMega cpu to calculate 6 | |*| the processors AVcc. 7 | |*| 8 | |*| Also supports returning the voltage as a percentage with optional 9 | |*| min and max voltage range. This is useful for returning the battery 10 | |*| percent between 3.2V and 4.2V (for example). You can set the voltage 11 | |*| range considered to be 0% and 100%. 12 | |*| 13 | |*| version 1.0: 2022, ++trent m. wyatt 14 | |*| version 1.1: 3, Dec, 2022, ++trent m. wyatt 15 | |*| 16 | |*| ========================================================================= 17 | \*/ 18 | 19 | #include 20 | #include 21 | 22 | #include "CPUVolt.h" 23 | 24 | #ifndef bit_is_set 25 | #define bit_is_set(sfr, bit) (_SFR_BYTE(sfr) & _BV(bit)) 26 | #endif 27 | 28 | long readVcc() { 29 | // Read 1.1V reference against AVcc 30 | // Set the reference to Vcc and the measurement to the internal 1.1V reference 31 | 32 | #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 33 | ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 34 | #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) 35 | ADMUX = _BV(MUX5) | _BV(MUX0); 36 | #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) 37 | ADMUX = _BV(MUX3) | _BV(MUX2); 38 | #else 39 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 40 | #endif 41 | 42 | delay(2); // Wait for Vref to settle 43 | ADCSRA |= _BV(ADSC); // Start conversion 44 | while (bit_is_set(ADCSRA, ADSC)); // measuring 45 | 46 | uint8_t low = ADCL; // must read ADCL first - it then locks ADCH 47 | uint8_t high = ADCH; // unlocks both 48 | 49 | long result = (high << 8) | low; // convert to 32 bit signed value 50 | 51 | result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1 * 1023 * 1000 52 | return result; // Vcc in millivolts 53 | } 54 | 55 | // return the voltage percent between 0% and 100% 56 | float readPercent(float min_volt, float max_volt) { 57 | return (readVcc() - min_volt) * 100.0 / (max_volt - min_volt); 58 | } 59 | 60 | float readPercent(float max_volt /*= 5000*/) { 61 | return float(readVcc()) * 100.0 / max_volt; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Arduino CI](https://github.com/ripred/CPUVolt/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci) 2 | [![Arduino-lint](https://github.com/ripred/CPUVolt/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/ripred/CPUVolt/actions/workflows/arduino-lint.yml) 3 | ![code size:](https://img.shields.io/github/languages/code-size/ripred/CPUVolt) 4 | [![GitHub release](https://img.shields.io/github/release/ripred/CPUVolt.svg?maxAge=3600)](https://github.com/ripred/CPUVolt/releases) 5 | [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ripred/CPUVolt/blob/master/LICENSE) 6 | [![Stars](https://img.shields.io/github/stars/ripred/CPUVolt.svg?style=flat-square&colorB=4183c4)](https://github.com/ripred/CPUVolt) 7 | [![Forks](https://img.shields.io/github/forks/ripred/CPUVolt.svg?style=flat-square&colorB=4183c4)](https://github.com/ripred/CPUVolt) 8 | 9 | # CPU Voltage 10 | 11 | ## Measure the voltage of the processor or retrieve the percent of charge for battery based systems. 12 | 13 | Measure the voltage applied to Vcc on the Microchip (Atmel) ATMega processors using nothing more than the internal registers. 14 | NO external parts or connections necessary! 15 | 16 | [see this Microchip application note to learn more about the internal features used and supported to implement this feature](https://ww1.microchip.com/downloads/en/Appnotes/00002447A.pdf) 17 | 18 | **Update**: Now includes support for reading the voltage as a percentage of total capacity. 19 | You can also optionally supply the voltage level that is considered to be 0% and the voltage level considered to be 100%. 20 | This is really useful for battery-based projects! You can now specify the lower voltage level you would like to use to 21 | indicate when the system needs recharging and the level at which it is fully charged! 22 | ___ 23 | ## Example use: 24 | ```cpp 25 | /* 26 | * CPUVolt.ino 27 | * 28 | * Example Arduino sketch showing the use of the CPUVolt library. 29 | * Updated to show the use of the new readPercent(...) methods. 30 | * 31 | */ 32 | #include 33 | 34 | void setup() { 35 | Serial.begin(115200); 36 | 37 | /* 38 | * Read the current voltage level and convert it 39 | * to an easier to read floating point value 40 | */ 41 | float mv = readVcc() / 1000.0; 42 | 43 | // Show the voltage with 2 decimal places 44 | Serial.print("Voltage: "); 45 | Serial.println(mv, 2); 46 | 47 | /* 48 | * Get the voltage level as a percentage of total charge. 49 | * You can optionally specify the voltage level to be considered 50 | * as 100%. The default voltage is 5V if not supplied. 51 | */ 52 | float pct = readPercent(/*5000*/); 53 | Serial.print("Percent: "); 54 | Serial.println(pct, 2); 55 | 56 | /* 57 | * You can also specify both the lower and upper voltage 58 | * ranges to be considered what is 0% and what is 100%. 59 | * This is really useful for battery powered projects! 60 | */ 61 | pct = readPercent(2900, 4700); 62 | Serial.print("Percent: "); 63 | Serial.println(pct, 2); 64 | 65 | /* 66 | * The following code shows how you might use the percent of charge 67 | * to turn on a "needs recharging" LED at the percent you want: 68 | */ 69 | float const low_pct = 70.0; // season to taste :) 70 | bool const needs_charging = pct <= low_pct;// set a "needs charging" flag 71 | int const led_pin = LED_BUILTIN; // Or use any other GPIO pin (besides A6 or A7) 72 | pinMode(led_pin, OUTPUT); // set the pin as an output 73 | digitalWrite(led_pin, needs_charging); // set the LED pin HIGH or LOW as needed 74 | } 75 | 76 | void loop() { } 77 | ``` 78 | 79 | ## Example Output: 80 | ``` 81 | Voltage: 4.67 82 | Percent: 93.38 83 | Percent: 98.28 84 | ``` 85 | 86 | --------------------------------------------------------------------------------