QI wireless charger / tester for a Li-Ion battery
LiPo battery "test & charge". A useful COMPONENT to insert in any of your miniaturized projects.
Components and supplies
QI wireless 5W Coil Circuit Board Module
Through Hole Resistor, 680 kohm
OLED I2C SSD1306 0.96 pollici Display 128 x 64 Pixel (AZDelivery)
Li-Ion 3.7V 250mAh battery
Through Hole Resistor, 220 kohm
Microcontroller PRO Mini w/Atmel AVR ATMEGA328P, 3.3V 8MHz
FT232RL USB to serial TTL (3.3V - 5V) (AZDelivery)
TP4056 Micro USB 5V 1A Li - Ion Battery Charger Module (AZDelivery)
Arduino UNO
Tools and machines
Solder Wire, Lead Free
Soldering iron (generic)
Solder Paste, Tack Flux
Apps and platforms
Arduino IDE
Project description
Code
TEST Sketch on Arduino UNO
c_cpp
Breadboard and Arduino UNO test
1// Charger Wireless QI "snippet" by F.Stella 20220314 2 3#include <SPI.h> 4#include <Wire.h> 5#include <Adafruit_GFX.h> 6#include <Adafruit_SSD1306.h> 7#include <Fonts/FreeMono9pt7b.h> 8#include <Fonts/FreeMonoBold9pt7b.h> 9#include <Fonts/FreeMonoBold18pt7b.h> 10// #include <Fonts/FreeMonoBold24pt7b.h> 11 12#define SCREEN_WIDTH 128 // OLED display width, in pixels 13#define SCREEN_HEIGHT 64 // OLED display height, in pixels 14 15#define debug0 //attiva stampa DEBUG base e SERIAL 16#define debug1 //attiva stampa DEBUG sezione1 17 18// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) 19#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) 20Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); 21 22 23// 'BatteryLevels_bitmap_12x22', 22x12px 24const unsigned char BatteryLevelFULL [] PROGMEM = { 25 0x1f, 0xff, 0xfc, 0x1f, 0xff, 0xfc, 0x18, 0x00, 0x0c, 0xfb, 0xff, 0xec, 0xfb, 0xff, 0xec, 0xfb, 26 0xff, 0xec, 0xfb, 0xff, 0xec, 0xfb, 0xff, 0xec, 0xfb, 0xff, 0xec, 0x18, 0x00, 0x0c, 0x1f, 0xff, 27 0xfc, 0x1f, 0xff, 0xfc 28}; 29 30const unsigned char BatteryLevelMID [] PROGMEM = { 31 0x1f, 0xff, 0xfc, 0x1f, 0xff, 0xfc, 0x18, 0x00, 0x0c, 0xf8, 0x3f, 0xec, 0xf8, 0x3f, 0xec, 0xf8, 32 0x3f, 0xec, 0xf8, 0x3f, 0xec, 0xf8, 0x3f, 0xec, 0xf8, 0x3f, 0xec, 0x18, 0x00, 0x0c, 0x1f, 0xff, 33 0xfc, 0x1f, 0xff, 0xfc 34}; 35 36const unsigned char BatteryLevelEMPTY [] PROGMEM = { 37 0x1f, 0xff, 0xfc, 0x1f, 0xff, 0xfc, 0x18, 0x00, 0x0c, 0xf8, 0x00, 0xcc, 0xf8, 0x00, 0xcc, 0xf8, 38 0x00, 0xcc, 0xf8, 0x00, 0xcc, 0xf8, 0x00, 0x0c, 0xf8, 0x00, 0xcc, 0x18, 0x00, 0x0c, 0x1f, 0xff, 39 0xfc, 0x1f, 0xff, 0xfc 40}; 41 42byte pin_A = 2; 43byte button_A = 0; 44 45int offset18_x = -2; 46int offset18_y = 22; 47int offset12_x = -2; 48int offset12_y = 14; 49int offset9_x = -1; 50int offset9_y = 12; 51 52unsigned long button_delay_t = 0; 53 54int analoginput = 0; // Battery CHECK analog pin 55int analogamount = 0; // stores incoming value 56float percAREF = 0; 57float percBatt = 0; // used to store our BATTERY percentage charge value 58float voltBatt = 0; 59float voltage = 0; // used to store voltage value 60float V_out = 0; 61float V_source = 0; 62float referenceVoltage = 0; 63int voltageError = 0; 64// float resist1 = 4604; // 4604 tester value 4.7 kOhm nominal - TEST on ARDUINOuno 5V 65// float resist2 = 1000; // 1 kOhm nominal - TEST on ARDUINOuno 5V 66float resist1 = 982000; // 1 MOhm 680 kOhm nominal 67float resist2 = 306000; // 300 kOhm 220 kOhm nominal 68 69void setup() { 70 71#ifdef debug0 72 Serial.begin(19200); 73 Serial.println(F("")); 74 Serial.print(F("Serial START - press button!")); 75 Serial.println(F("")); 76#endif 77 78 analogReference(INTERNAL); // use INTERNAL (1.1V) for reference voltage 79 80 display.begin(SSD1306_SWITCHCAPVCC, 0x3C); 81 display.clearDisplay(); 82 display.setTextColor(WHITE); 83 display.setFont(&FreeMono9pt7b); // PLAIN font 84 85 display.setCursor(1, 10); 86 display.print("Display on."); 87 display.setCursor(25, 30); 88 display.print("press"); 89 display.setCursor(15, 50); 90 display.print("to test"); 91 display.display(); 92 93 pinMode(pin_A, INPUT_PULLUP); //button 94} 95 96void loop() { 97 do { 98 button_A = digitalRead(pin_A); 99 } while ((button_A == 1) || ((millis()-button_delay_t) < 500)); 100 101 button_delay_t = millis(); 102 103 #ifdef debug1 104 Serial.print(F("Button A (")); 105 Serial.print(pin_A); 106 Serial.print(F(") = ")); 107 Serial.println(button_A); 108 #endif 109 batteryCheck(); 110 showSCREEN(); 111} 112 113void showSCREEN() { 114 display.clearDisplay(); 115 display.setTextColor(WHITE); 116 display.setCursor(10+offset18_x, 20+offset18_y); 117 display.setFont(&FreeMonoBold18pt7b); // PLAIN font 118 display.print(voltBatt,1); 119 display.setCursor(85+offset18_x, 20+offset18_y); 120 display.print("V"); 121 122 // display footer *** 123 display.setCursor(47+offset9_x, 51+offset9_y); 124 display.setFont(&FreeMono9pt7b); // PLAIN font 125 display.print(percBatt,1); 126 display.print("%"); 127 128 if (percBatt > 76 ) { // Battery level graphic display 129 display.drawBitmap(0, 53, BatteryLevelFULL, 22, 12, WHITE); 130 } else if (percBatt > 65 ) { 131 display.drawBitmap(0, 53, BatteryLevelMID, 22, 12, WHITE); 132 } else { 133 display.drawBitmap(0, 53, BatteryLevelEMPTY, 22, 12, WHITE); 134 } 135 display.display(); //Send buffer to display 136 delay(3000); 137 138} 139 140void batteryCheck() { 141 referenceVoltage = 1100; // 1100 internal; 142 V_source = 4.2; // LiPo Vmax 4.2V - UNO R3 5.056 - Vs from the divider calculation 143 // using the REAL resistor values makes it more "precise" - one can also set a fixed value 144 V_out = V_source*(resist2)/((resist1)+(resist2)); // UNO 0.889 - LiPo 1.05 - VOut from the divider calculation 145 voltageError = 0; // to empirically adjust ;-) 146 147 analogamount = analogRead(analoginput); 148 percAREF=(analogamount/1024.00)*100; 149 150 voltage=(analogamount/1024.00)*referenceVoltage+voltageError; // in millivolts 151 voltBatt=(voltage*((resist1)+(resist2))/(resist2))/1000; // V_s = V_out * (R1+R2) / R2 152 percBatt=(voltBatt/V_source)*100; 153 154 #ifdef debug1 155 Serial.print("V_out: "); 156 Serial.println(V_out,3); 157 Serial.print("Lettura analog (0-1023): "); 158 Serial.print(analogamount); 159 Serial.print(" -------- % of AREF: "); 160 Serial.print(percAREF,2); 161 Serial.print(" -------- A0 (mV): "); // compare with result of Voltage Divider calculation Vout 162 // for 5.056 (that I checked on Arduino1) and resistors 1K 4.7K is 0.889 163 Serial.print(voltage,2); 164 165 Serial.print(" -------- % of battery nominal: "); 166 Serial.print(percBatt,2); 167 Serial.print(" -------- Real - no divider (V): "); // if you check Arduino voltage should be 5.0x 168 Serial.println(voltBatt,2); 169 Serial.println(""); 170 #endif 171} 172
TEST Sketch on Arduino UNO
c_cpp
Breadboard and Arduino UNO test
1// Charger Wireless QI "snippet" by F.Stella 20220314 2 3#include 4 <SPI.h> 5#include <Wire.h> 6#include <Adafruit_GFX.h> 7#include <Adafruit_SSD1306.h> 8#include 9 <Fonts/FreeMono9pt7b.h> 10#include <Fonts/FreeMonoBold9pt7b.h> 11#include <Fonts/FreeMonoBold18pt7b.h> 12// 13 #include <Fonts/FreeMonoBold24pt7b.h> 14 15#define SCREEN_WIDTH 128 // OLED 16 display width, in pixels 17#define SCREEN_HEIGHT 64 // OLED display height, in 18 pixels 19 20#define debug0 //attiva stampa DEBUG base e SERIAL 21#define 22 debug1 //attiva stampa DEBUG sezione1 23 24// Declaration for an SSD1306 25 display connected to I2C (SDA, SCL pins) 26#define OLED_RESET 4 // Reset pin 27 # (or -1 if sharing Arduino reset pin) 28Adafruit_SSD1306 display(SCREEN_WIDTH, 29 SCREEN_HEIGHT, &Wire, OLED_RESET); 30 31 32// 'BatteryLevels_bitmap_12x22', 22x12px 33const 34 unsigned char BatteryLevelFULL [] PROGMEM = { 35 0x1f, 0xff, 0xfc, 0x1f, 0xff, 36 0xfc, 0x18, 0x00, 0x0c, 0xfb, 0xff, 0xec, 0xfb, 0xff, 0xec, 0xfb, 37 0xff, 0xec, 38 0xfb, 0xff, 0xec, 0xfb, 0xff, 0xec, 0xfb, 0xff, 0xec, 0x18, 0x00, 0x0c, 0x1f, 0xff, 39 40 0xfc, 0x1f, 0xff, 0xfc 41}; 42 43const unsigned char BatteryLevelMID [] 44 PROGMEM = { 45 0x1f, 0xff, 0xfc, 0x1f, 0xff, 0xfc, 0x18, 0x00, 0x0c, 0xf8, 0x3f, 46 0xec, 0xf8, 0x3f, 0xec, 0xf8, 47 0x3f, 0xec, 0xf8, 0x3f, 0xec, 0xf8, 0x3f, 0xec, 48 0xf8, 0x3f, 0xec, 0x18, 0x00, 0x0c, 0x1f, 0xff, 49 0xfc, 0x1f, 0xff, 0xfc 50}; 51 52const 53 unsigned char BatteryLevelEMPTY [] PROGMEM = { 54 0x1f, 0xff, 0xfc, 0x1f, 0xff, 55 0xfc, 0x18, 0x00, 0x0c, 0xf8, 0x00, 0xcc, 0xf8, 0x00, 0xcc, 0xf8, 56 0x00, 0xcc, 57 0xf8, 0x00, 0xcc, 0xf8, 0x00, 0x0c, 0xf8, 0x00, 0xcc, 0x18, 0x00, 0x0c, 0x1f, 0xff, 58 59 0xfc, 0x1f, 0xff, 0xfc 60}; 61 62byte pin_A = 2; 63byte button_A = 64 0; 65 66int offset18_x = -2; 67int offset18_y = 22; 68int offset12_x = -2; 69int 70 offset12_y = 14; 71int offset9_x = -1; 72int offset9_y = 12; 73 74unsigned 75 long button_delay_t = 0; 76 77int analoginput = 0; // Battery CHECK 78 analog pin 79int analogamount = 0; // stores incoming value 80float 81 percAREF = 0; 82float percBatt = 0; // used to store our BATTERY percentage 83 charge value 84float voltBatt = 0; 85float voltage = 0; // 86 used to store voltage value 87float V_out = 0; 88float V_source = 0; 89float 90 referenceVoltage = 0; 91int voltageError = 0; 92// float resist1 = 4604; // 93 4604 tester value 4.7 kOhm nominal - TEST on ARDUINOuno 5V 94// float resist2 = 95 1000; // 1 kOhm nominal - TEST on ARDUINOuno 5V 96float 97 resist1 = 982000; // 1 MOhm 680 kOhm nominal 98float resist2 = 306000; 99 // 300 kOhm 220 kOhm nominal 100 101void setup() { 102 103#ifdef debug0 104 105 Serial.begin(19200); 106 Serial.println(F("")); 107 Serial.print(F("Serial 108 START - press button!")); 109 Serial.println(F("")); 110#endif 111 112 analogReference(INTERNAL); 113 // use INTERNAL (1.1V) for reference voltage 114 115 display.begin(SSD1306_SWITCHCAPVCC, 116 0x3C); 117 display.clearDisplay(); 118 display.setTextColor(WHITE); 119 display.setFont(&FreeMono9pt7b); 120 // PLAIN font 121 122 display.setCursor(1, 10); 123 display.print("Display 124 on."); 125 display.setCursor(25, 30); 126 display.print("press"); 127 display.setCursor(15, 128 50); 129 display.print("to test"); 130 display.display(); 131 132 pinMode(pin_A, 133 INPUT_PULLUP); //button 134} 135 136void loop() { 137 do { 138 button_A 139 = digitalRead(pin_A); 140 } while ((button_A == 1) || ((millis()-button_delay_t) 141 < 500)); 142 143 button_delay_t = millis(); 144 145 #ifdef debug1 146 Serial.print(F("Button 147 A (")); 148 Serial.print(pin_A); 149 Serial.print(F(") = ")); 150 Serial.println(button_A); 151 152 #endif 153 batteryCheck(); 154 showSCREEN(); 155} 156 157void showSCREEN() 158 { 159 display.clearDisplay(); 160 display.setTextColor(WHITE); 161 display.setCursor(10+offset18_x, 162 20+offset18_y); 163 display.setFont(&FreeMonoBold18pt7b); // 164 PLAIN font 165 display.print(voltBatt,1); 166 display.setCursor(85+offset18_x, 167 20+offset18_y); 168 display.print("V"); 169 170 // display footer *** 171 display.setCursor(47+offset9_x, 172 51+offset9_y); 173 display.setFont(&FreeMono9pt7b); // PLAIN 174 font 175 display.print(percBatt,1); 176 display.print("%"); 177 178 if (percBatt 179 > 76 ) { // Battery level graphic display 180 display.drawBitmap(0, 181 53, BatteryLevelFULL, 22, 12, WHITE); 182 } else if (percBatt > 65 ) { 183 display.drawBitmap(0, 184 53, BatteryLevelMID, 22, 12, WHITE); 185 } else { 186 display.drawBitmap(0, 187 53, BatteryLevelEMPTY, 22, 12, WHITE); 188 } 189 display.display(); //Send 190 buffer to display 191 delay(3000); 192 193} 194 195void batteryCheck() { 196 referenceVoltage 197 = 1100; // 1100 internal; 198 V_source = 4.2; // LiPo Vmax 4.2V - 199 UNO R3 5.056 - Vs from the divider calculation 200 // using the REAL resistor values 201 makes it more "precise" - one can also set a fixed value 202 V_out = V_source*(resist2)/((resist1)+(resist2)); 203 // UNO 0.889 - LiPo 1.05 - VOut from the divider calculation 204 205 voltageError = 0; // to empirically adjust ;-) 206 207 analogamount 208 = analogRead(analoginput); 209 percAREF=(analogamount/1024.00)*100; 210 211 voltage=(analogamount/1024.00)*referenceVoltage+voltageError; 212 // in millivolts 213 voltBatt=(voltage*((resist1)+(resist2))/(resist2))/1000; 214 // V_s = V_out * (R1+R2) / R2 215 percBatt=(voltBatt/V_source)*100; 216 217 218 #ifdef debug1 219 Serial.print("V_out: "); 220 Serial.println(V_out,3); 221 222 Serial.print("Lettura analog (0-1023): "); 223 Serial.print(analogamount); 224 225 Serial.print(" -------- % of AREF: "); 226 Serial.print(percAREF,2); 227 228 Serial.print(" -------- A0 (mV): "); // compare with result of Voltage 229 Divider calculation Vout 230 // for 5.056 (that I checked on Arduino1) and resistors 231 1K 4.7K is 0.889 232 Serial.print(voltage,2); 233 234 Serial.print(" -------- 235 % of battery nominal: "); 236 Serial.print(percBatt,2); 237 Serial.print(" 238 -------- Real - no divider (V): "); // if you check Arduino voltage should 239 be 5.0x 240 Serial.println(voltBatt,2); 241 Serial.println(""); 242 #endif 243} 244
Downloadable files
TEST battery and display charge - breadboard sketch
This is a version of the "voltmeter" that uses an Arduino UNO and a simple bradboard set-up..
TEST battery and display charge - breadboard sketch
TEST battery and display charge - breadboard sketch
This is a version of the "voltmeter" that uses an Arduino UNO and a simple bradboard set-up..
TEST battery and display charge - breadboard sketch
Testing + Charging Li-Ion battery with a QI wireless receiver
This is the circuit as I use it in my projects
Testing + Charging Li-Ion battery with a QI wireless receiver
Comments
Only logged in users can leave comments