Close Menu
  • Articles
    • Learn Electronics
    • Product Review
    • Tech Articles
  • Electronics Circuits
    • 555 Timer Projects
    • Op-Amp Circuits
    • Power Electronics
  • Microcontrollers
    • Arduino Projects
    • STM32 Projects
    • AMB82-Mini IoT AI Camera
    • BLE Projects
  • IoT Projects
    • ESP8266 Projects
    • ESP32 Projects
    • ESP32 MicroPython
    • ESP32-CAM Projects
    • LoRa/LoRaWAN Projects
  • Raspberry Pi
    • Raspberry Pi Projects
    • Raspberry Pi Pico Projects
    • Raspberry Pi Pico W Projects
  • Electronics Calculator
Facebook X (Twitter) Instagram
  • About Us
  • Disclaimer
  • Privacy Policy
  • Contact Us
  • Advertise With Us
Facebook X (Twitter) Instagram Pinterest YouTube LinkedIn
How To Electronics
  • Articles
    • Learn Electronics
    • Product Review
    • Tech Articles
  • Electronics Circuits
    • 555 Timer Projects
    • Op-Amp Circuits
    • Power Electronics
  • Microcontrollers
    • Arduino Projects
    • STM32 Projects
    • AMB82-Mini IoT AI Camera
    • BLE Projects
  • IoT Projects
    • ESP8266 Projects
    • ESP32 Projects
    • ESP32 MicroPython
    • ESP32-CAM Projects
    • LoRa/LoRaWAN Projects
  • Raspberry Pi
    • Raspberry Pi Projects
    • Raspberry Pi Pico Projects
    • Raspberry Pi Pico W Projects
  • Electronics Calculator
How To Electronics
Home » Build a DC Energy Meter using Arduino – 32V/5A
Arduino Projects

Build a DC Energy Meter using Arduino – 32V/5A

Mamtaz AlamBy Mamtaz AlamUpdated:August 26, 20258 Mins Read
Share Facebook Twitter LinkedIn Telegram Reddit WhatsApp
DC Energy Meter using Arduino
Share
Facebook Twitter LinkedIn Pinterest Email Reddit Telegram WhatsApp

Overview

In this project, we will build a DC Energy Meter using Arduino that can measure voltage, current, power, and energy consumption.

I recently came across a neat custom-made DC energy meter module from Mutex Embedded. This small but powerful board can measure DC parameters such as voltage (0–32 V range), current (up to 5 A), power, and cumulative energy consumption. It communicates easily over the I²C protocol, making it ideal for direct use with Arduino.

For this guide, I’ll show you how to connect the module to an Arduino and display the live energy meter data on a 16×2 I²C LCD display. The LCD cycles through values of voltage, current, power, and energy, so you can view the parameters in real time without needing a computer.

If you want to take it further, the same module also includes an ESP32 chip option for IoT applications, where the readings can be uploaded to a web server for remote monitoring. But in this guide, we’ll focus only on the Arduino + LCD setup. This project is a simple yet very practical way to track DC energy usage for your electronics, battery projects, or renewable energy experiments. You may use the same DC power module to make an IoT DC Energy meter with ESP32 and view the live data on Webserver.


Bill of Materials

We need following components to build this Arduino DC Energy Meter project.

S.N.Components NameQuantityPurchase Link
1Arduino Nano Board1Amazon | AliExpress
2DC Power Monitor Module1Mutex-Embedded
316x2 LCD Display1Amazon | AliExpress
4Connecting Wires10Amazon | AliExpress
5Breadboard1Amazon | AliExpress




DC Power Monitor Module

The DC Power Monitoring Module is a feature-rich solution for tracking voltage, current, power, and energy consumption across four independent channels. At its core is the ESP32-S2 microcontroller, ensuring high performance and IoT readiness. Current measurement is handled through precision high-wattage shunt resistors, while an onboard SD card slot enables real-time data logging. A CR1220 coin cell holder powers the real-time clock, allowing accurate time-stamping of measurements even when the main supply is off.

On the hardware side, the board includes a tiny rear connector that works with a dedicated power extension board, which provides a USB-to-serial interface, micro-USB port, and reset switch. With support for up to 32 V input voltage and 5 A current per channel, the module is well-suited for monitoring small to medium DC appliances or battery systems.

The module supports both I²C and Modbus RTU (UART/RS485) interfaces, making it compatible with a wide range of microcontrollers, including Arduino and ESP32. Data can also be logged to the SD card for up to a year, with weekly historical summaries available for long-term analysis. To simplify user experience, a free PC application is provided for configuration, live monitoring, and firmware updates.

Features & Specifications

  • Voltage range: 0 – 32V
  • Current range 0 – 5A
  • 4 – Channels with common GND
  • Serial Interface: I2C + UART Modbus
  • RS-485 Bus extension
  • Real-Time Clock
  • Micro SD Card Data Logging
  • PC Application
  • Built for Industrial use

Useful Links

  1. DC Power Monitor Module
  2. DC Power Monitor Extension
  3. Datasheet/User Manual
  4. PC Application Software




Interfacing the DC Energy Meter with Arduino

The DC Power Monitor Module supports both I²C and Modbus RTU communication protocols. In this project, we will be using the I²C interface to connect the module with an Arduino and build our own DC Energy Meter.

Hardware & Circuit

The wiring is very straightforward. Connect the VCC pin of the Power Monitor Module to the 3.3V pin on the Arduino, and connect the GND pin to the Arduino GND. Then, link the communication lines by connecting the module’s SDA pin to the Arduino’s A4 pin and the SCL pin to the Arduino’s A5 pin.

Interfacing the DC Energy Meter with Arduino
Fig: Interfacing the DC Energy Meter with Arduino

With just these four simple connections, the Arduino will be able to read voltage, current, power, and energy data directly from the module over the I²C bus.

Power Supply & Load Connection

To begin, we need to connect a DC supply and a load to the Power Monitor Module. The board provides four input/output channels labeled IN1–IN4 and OUT1–OUT4. In this example, we will be using Channel 1.

  • Connect the Supply
    Take any DC supply, such as a battery or a regulated DC adapter. Connect the positive terminal of the supply to the IN1 terminal. The negative (ground) terminal of the supply should be connected to the GND line provided on the module.
  • Connect the Load
    For the load connection, wire the positive terminal of your load (e.g., a DC motor, lamp, or electronic circuit) to the OUT1 terminal. The negative terminal of the load should also be connected to the common GND of the module.

That’s all that is needed—the module will now measure the supply voltage, the current flowing through the load, and automatically calculate power and energy consumption for Channel 1.



I2C Library (MbI2C_ArduinoPort.h)

The developer of this product has already created a library for the DC Power Monitor Module. Although it was originally written for another microcontroller, I have adapted the same library and used it in this Arduino project to read data via the I²C interface.

Create a folder anywhere in your computer and name it as “mb_energy_meter“. Inside the folder create a text file and save it as “MbI2C_ArduinoPort.h“. Copy the following library code and paste it in the .h file and save it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
#include <Arduino.h>
#include <Wire.h>
#include <stdint.h>
#include <string.h>
 
// -------- Original mb_i2c.h content (with include-guard adapted) --------
typedef bool     (*I2cWriteCallback_t)  (uint8_t slaveAddrs, uint8_t* pDataWr, uint8_t size);
typedef bool     (*I2cReadCallback_t)   (uint8_t slaveAddrs, uint8_t* pDataRd, uint8_t size);
typedef uint32_t (*GetMillisCallback_t) (void);
typedef void     (*DelayCallback_t)     (uint32_t msDelay);
 
typedef struct
{
  uint8_t             i2cAddress;
  I2cWriteCallback_t  cbWrite;
  I2cReadCallback_t   cbRead;
  GetMillisCallback_t cbGetMillis;
  DelayCallback_t     cbDelay;
} MbI2c_Init_t;
 
typedef struct
{
  MbI2c_Init_t init;
  bool         isInitialized;
} MbI2c_Handle_t;
 
typedef enum
{
  MbI2c_RegType_Holding,
  MbI2c_RegType_Input,
} MbI2c_RegType_e;
 
// -------- Constants from mb_i2c.c --------
#ifndef MB_I2C_READ_BUFFER_SIZE
#define MB_I2C_READ_BUFFER_SIZE  128
#endif
 
#ifndef MB_I2C_READ_DELAY
#define MB_I2C_READ_DELAY        5
#endif
 
#ifndef MB_I2C_READ_TIMEOUT
#define MB_I2C_READ_TIMEOUT      100
#endif
 
typedef enum
{
  MbI2c_Cmd_WriteHolding = 1,
  MbI2c_Cmd_ReadHolding  = 2,
  MbI2c_Cmd_ReadInput    = 3
} MbI2c_Cmd_e;
 
// SMBus CRC-8 lookup table
static const uint8_t gLookupTableSmbus[256] =
{
    0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
    0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
    0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
    0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
    0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5,
    0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
    0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85,
    0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
    0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
    0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
    0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2,
    0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
    0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32,
    0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
    0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
    0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
    0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c,
    0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
    0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec,
    0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
    0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
    0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
    0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c,
    0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
    0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b,
    0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63,
    0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
    0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
    0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb,
    0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
    0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb,
    0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3
};
 
static uint8_t gReadBuffer[MB_I2C_READ_BUFFER_SIZE];
 
// -------- Internal functions from mb_i2c.c --------
static uint8_t mbI2c_smbus_calculate (uint8_t* pData, uint16_t size)
{
  uint8_t crcByte = 0;
  for(uint16_t i = 0; i < size; i++)
  {
    crcByte = gLookupTableSmbus[crcByte ^ pData[i]];
  }
  return crcByte;
}
 
static bool mbI2c_smbus_verify (uint8_t* pData, uint16_t size, uint8_t crc)
{
  uint8_t crcByte = mbI2c_smbus_calculate(pData, size);
  return (crcByte == crc);
}
 
static bool mbI2c_readData (MbI2c_Handle_t* pHandle, uint16_t* pData, uint16_t len)
{
  uint8_t lenBytes  = len * 2;
  bool    i2cStatus = false;
 
  uint32_t startTicks = pHandle->init.cbGetMillis();
  do
  {
    if(pHandle->init.cbRead(pHandle->init.i2cAddress, gReadBuffer, lenBytes + 1))
    {
      uint8_t crcValue = gReadBuffer[lenBytes];
      bool crcState = mbI2c_smbus_verify(gReadBuffer, lenBytes, crcValue);
      if(crcState)
      {
        memcpy(pData, gReadBuffer, lenBytes);
        i2cStatus = true;
        break;
      }
      else
      {
        i2cStatus = false;
      }
    }
    else
    {
      i2cStatus = false;
    }
  } while ((pHandle->init.cbGetMillis() - startTicks) < MB_I2C_READ_TIMEOUT);
 
  return i2cStatus;
}
 
// -------- Public API from mb_i2c.c --------
static bool mbI2c_init (MbI2c_Init_t* pInit, MbI2c_Handle_t* pHandle)
{
  if((pInit->cbWrite != NULL) && (pInit->cbRead != NULL) &&
     (pInit->cbGetMillis != NULL) && (pInit->cbDelay != NULL))
  {
    memcpy(&pHandle->init, pInit, sizeof(MbI2c_Init_t));
    pHandle->isInitialized = true;
    return true;
  }
  pHandle->isInitialized = false;
  return false;
}
 
static bool mbI2c_writeHolding (MbI2c_Handle_t* pHandle, uint16_t regAddrs, uint16_t* pWriteBuf, uint16_t len)
{
  if(!pHandle->isInitialized)
  {
    return false;
  }
 
  bool i2cStatus = true;
  uint8_t cmdPacket[5] = {0};
  cmdPacket[0] = MbI2c_Cmd_WriteHolding;
  cmdPacket[1] = (regAddrs & 0xFF);
  cmdPacket[2] = ((regAddrs >> 8) & 0xFF);
  cmdPacket[3] = len;
  cmdPacket[4] = mbI2c_smbus_calculate(cmdPacket, 4);
 
  i2cStatus = pHandle->init.cbWrite(pHandle->init.i2cAddress, cmdPacket, 5);
 
  if(i2cStatus)
  {
    i2cStatus = pHandle->init.cbWrite(pHandle->init.i2cAddress, (uint8_t*)pWriteBuf, len * 2);
  }
 
  if(i2cStatus)
  {
    uint8_t crcValue = mbI2c_smbus_calculate((uint8_t*)pWriteBuf, len * 2);
    i2cStatus = pHandle->init.cbWrite(pHandle->init.i2cAddress, (uint8_t*)&crcValue, 1);
  }
 
  return i2cStatus;
}
 
static bool mbI2c_readHolding (MbI2c_Handle_t* pHandle, uint16_t regAddrs, uint16_t* pReadBuf, uint16_t len)
{
  if(!pHandle->isInitialized)
  {
    return false;
  }
 
  uint8_t cmdPacket[5] = {0};
  cmdPacket[0] = MbI2c_Cmd_ReadHolding;
  cmdPacket[1] = (regAddrs & 0xFF);
  cmdPacket[2] = ((regAddrs >> 8) & 0xFF);
  cmdPacket[3] = len;
  cmdPacket[4] = mbI2c_smbus_calculate(cmdPacket, 4);
 
  bool i2cStatus = pHandle->init.cbWrite(pHandle->init.i2cAddress, cmdPacket, 5);
  if(i2cStatus)
  {
    pHandle->init.cbDelay(MB_I2C_READ_DELAY);
    i2cStatus = mbI2c_readData(pHandle, pReadBuf, len);
  }
  return i2cStatus;
}
 
static bool mbI2c_readInput (MbI2c_Handle_t* pHandle, uint16_t regAddrs, uint16_t* pReadBuf, uint16_t len)
{
  if(!pHandle->isInitialized)
  {
    return false;
  }
 
  uint8_t cmdPacket[5] = {0};
  cmdPacket[0] = MbI2c_Cmd_ReadInput;
  cmdPacket[1] = (regAddrs & 0xFF);
  cmdPacket[2] = ((regAddrs >> 8) & 0xFF);
  cmdPacket[3] = len;
  cmdPacket[4] = mbI2c_smbus_calculate(cmdPacket, 4);
 
  bool i2cStatus = pHandle->init.cbWrite(pHandle->init.i2cAddress, cmdPacket, 5);
  if(i2cStatus)
  {
    pHandle->init.cbDelay(MB_I2C_READ_DELAY);
    i2cStatus = mbI2c_readData(pHandle, pReadBuf, len);
  }
  return i2cStatus;
}
 
static bool mbI2c_writeHoldingUint16 (MbI2c_Handle_t* pHandle, uint16_t regAddrs, uint16_t data)
{
  return mbI2c_writeHolding(pHandle, regAddrs, &data, 1);
}
 
static bool mbI2c_writeHoldingInt16 (MbI2c_Handle_t* pHandle, uint16_t regAddrs, int16_t data)
{
  return mbI2c_writeHolding(pHandle, regAddrs, (uint16_t*)&data, 1);
}
 
static bool mbI2c_writeHoldingUint32 (MbI2c_Handle_t* pHandle, uint16_t regAddrs, uint32_t data)
{
  return mbI2c_writeHolding(pHandle, regAddrs, (uint16_t*)&data, 2);
}
 
static bool mbI2c_writeHoldingInt32 (MbI2c_Handle_t* pHandle, uint16_t regAddrs, int32_t data)
{
  return mbI2c_writeHolding(pHandle, regAddrs, (uint16_t*)&data, 2);
}
 
static bool mbI2c_writeHoldingBool (MbI2c_Handle_t* pHandle, uint16_t regAddrs, bool data)
{
  uint16_t data16 = data;
  return mbI2c_writeHolding(pHandle, regAddrs, &data16, 1);
}
 
static bool mbI2c_writeHoldingFloat (MbI2c_Handle_t* pHandle, uint16_t regAddrs, float data)
{
  return mbI2c_writeHolding(pHandle, regAddrs, (uint16_t*)&data, 2);
}
 
static bool mbI2c_readUint16 (MbI2c_Handle_t* pHandle, uint16_t regAddrs, uint16_t* pReadData, MbI2c_RegType_e regType)
{
  if(regType == MbI2c_RegType_Holding)
  {
    return mbI2c_readHolding(pHandle, regAddrs, pReadData, 1);
  }
  else
  {
    return mbI2c_readInput(pHandle, regAddrs, pReadData, 1);
  }
}
 
static bool mbI2c_readInt16 (MbI2c_Handle_t* pHandle, uint16_t regAddrs, int16_t* pReadData, MbI2c_RegType_e regType)
{
  if(regType == MbI2c_RegType_Holding)
  {
    return mbI2c_readHolding(pHandle, regAddrs, (uint16_t*)pReadData, 1);
  }
  else
  {
    return mbI2c_readInput(pHandle, regAddrs, (uint16_t*)pReadData, 1);
  }
}
 
static bool mbI2c_readUint32 (MbI2c_Handle_t* pHandle, uint16_t regAddrs, uint32_t* pReadData, MbI2c_RegType_e regType)
{
  if(regType == MbI2c_RegType_Holding)
  {
    return mbI2c_readHolding(pHandle, regAddrs, (uint16_t*)pReadData, 2);
  }
  else
  {
    return mbI2c_readInput(pHandle, regAddrs, (uint16_t*)pReadData, 2);
  }
}
 
static bool mbI2c_readInt32 (MbI2c_Handle_t* pHandle, uint16_t regAddrs, int32_t* pReadData, MbI2c_RegType_e regType)
{
  if(regType == MbI2c_RegType_Holding)
  {
    return mbI2c_readHolding(pHandle, regAddrs, (uint16_t*)pReadData, 2);
  }
  else
  {
    return mbI2c_readInput(pHandle, regAddrs, (uint16_t*)pReadData, 2);
  }
}
 
static bool mbI2c_readBool (MbI2c_Handle_t* pHandle, uint16_t regAddrs, bool* pReadData, MbI2c_RegType_e regType)
{
  uint16_t data16 = 0;
  bool status = true;
  if(regType == MbI2c_RegType_Holding)
  {
    status = mbI2c_readHolding(pHandle, regAddrs, &data16, 1);
  }
  else
  {
    status = mbI2c_readInput(pHandle, regAddrs, &data16, 1);
  }
  *pReadData = (bool)data16;
  return status;
}
 
static bool mbI2c_readFloat (MbI2c_Handle_t* pHandle, uint16_t regAddrs, float* pReadData, MbI2c_RegType_e regType)
{
  if(regType == MbI2c_RegType_Holding)
  {
    return mbI2c_readHolding(pHandle, regAddrs, (uint16_t*)pReadData, 2);
  }
  else
  {
    return mbI2c_readInput(pHandle, regAddrs, (uint16_t*)pReadData, 2);
  }
}
 
// -------- Arduino Wire() callbacks (plug into MbI2c_Init_t) --------
static bool ArduinoI2C_Write(uint8_t addr7, uint8_t* pDataWr, uint8_t size)
{
  Wire.beginTransmission(addr7);
  size_t n = Wire.write(pDataWr, size);
  uint8_t err = Wire.endTransmission(true); // send STOP
  return (err == 0) && (n == size);
}
 
static bool ArduinoI2C_Read(uint8_t addr7, uint8_t* pDataRd, uint8_t size)
{
  // One request for 'size' bytes; then pull them out.
  // Note: classic AVR Wire has a 32-byte rx buffer limit.
  uint32_t start = millis();
  uint8_t got = Wire.requestFrom((int)addr7, (int)size, (int)true);
  while ( (Wire.available() < got) && (millis() - start < MB_I2C_READ_TIMEOUT) )
  {
    // wait briefly if somehow not all are queued yet
    delay(1);
  }
  if (got < size) {
    // If the peripheral returned fewer bytes, fill what we have and fail
    for (uint8_t i=0; i<got; ++i) pDataRd[i] = (uint8_t)Wire.read();
    return false;
  }
  for (uint8_t i=0; i<size; ++i)
    pDataRd[i] = (uint8_t)Wire.read();
  return true;
}
 
static uint32_t ArduinoMillis() { return millis(); }
static void     ArduinoDelay(uint32_t ms) { delay(ms); }
 
// Helper to quickly set up a handle for Arduino Wire
static bool MbI2c_BeginArduino(MbI2c_Handle_t* pHandle, uint8_t i2cAddress)
{
  MbI2c_Init_t init;
  init.i2cAddress  = i2cAddress;
  init.cbWrite     = ArduinoI2C_Write;
  init.cbRead      = ArduinoI2C_Read;
  init.cbGetMillis = ArduinoMillis;
  init.cbDelay     = ArduinoDelay;
  return mbI2c_init(&init, pHandle);
}
 
// -------- Portable typed-read helpers (endianness & word-order control) -----
static inline uint16_t bswap16(uint16_t v) { return (uint16_t)((v >> 8) | (v << 8)); }
static inline void swap16(uint16_t& a, uint16_t& b) { uint16_t t=a; a=b; b=t; }
 
/*
* Many metering ICs return:
*  - 16-bit words big-endian (byte order inside each 16-bit is MSB first),
*  - and a 32-bit value as two 16-bit words that may be [HiWord, LoWord] or [LoWord, HiWord].
*
* Use these helpers to normalize into native CPU ordering for float/uint32.
*/
static bool mbRead2Words(MbI2c_Handle_t* h, uint16_t reg, MbI2c_RegType_e type,
                         bool swapBytesEachWord, bool swapWordOrder,
                         uint16_t outWords[2])
{
  uint16_t tmp[2] = {0,0};
  bool ok = (type == MbI2c_RegType_Holding)
            ? mbI2c_readHolding(h, reg, tmp, 2)
            : mbI2c_readInput(h, reg, tmp, 2);
  if (!ok) return false;
 
  // optional byte swap within each 16-bit
  if (swapBytesEachWord) {
    tmp[0] = bswap16(tmp[0]);
    tmp[1] = bswap16(tmp[1]);
  }
  // optional word swap for 32-bit values
  if (swapWordOrder) swap16(tmp[0], tmp[1]);
 
  outWords[0] = tmp[0];
  outWords[1] = tmp[1];
  return true;
}
 
static bool mbReadFloatPortable(MbI2c_Handle_t* h, uint16_t reg, MbI2c_RegType_e type,
                                bool swapBytesEachWord, bool swapWordOrder,
                                float* out)
{
  uint16_t w[2];
  if (!mbRead2Words(h, reg, type, swapBytesEachWord, swapWordOrder, w)) return false;
  memcpy(out, w, sizeof(w)); // now in native layout
  return true;
}
 
static bool mbReadUint32Portable(MbI2c_Handle_t* h, uint16_t reg, MbI2c_RegType_e type,
                                 bool swapBytesEachWord, bool swapWordOrder,
                                 uint32_t* out)
{
  uint16_t w[2];
  if (!mbRead2Words(h, reg, type, swapBytesEachWord, swapWordOrder, w)) return false;
  memcpy(out, w, sizeof(w));
  return true;
}
 
static bool mbReadUint16Portable(MbI2c_Handle_t* h, uint16_t reg, MbI2c_RegType_e type,
                                 bool swapBytesWord,
                                 uint16_t* out)
{
  uint16_t v = 0;
  if (!( (type == MbI2c_RegType_Holding)
        ? mbI2c_readHolding(h, reg, &v, 1)
        : mbI2c_readInput(h, reg, &v, 1))) return false;
 
  if (swapBytesWord) v = bswap16(v);
  *out = v;
  return true;
}



Source Code/Program (DC Energy Meter using Arduino)

This Arduino sketch communicates with the DC Power Monitor Module over the I²C bus and continuously reads voltage, current, power, and total energy from Channel 1. It converts the raw register data into real-world units and prints the measurements to the Serial Monitor every 500 ms. It also performs an optional firmware version check during setup.

Create a new file on the folder that you created earlier and save it with a name “mb_energy_meter.ino“. Paste the following code on the ino file. Then open the Arduino code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
* DCEnergyMeter_CH1_I2C.ino
*
* Reads Channel 1 Voltage / Current / Power / Total Energy from the DPWR meter
* over I2C, and prints to Serial.
*
* REQUIREMENTS:
*  - Put MbI2C_ArduinoPort.h (from our previous message) next to this .ino
*  - Wire I2C to your Arduino (SDA/SCL) and set the correct I2C address
*  - Channel 1 must be wired and powered per the manual
*/
 
#include <Wire.h>
#include "MbI2C_ArduinoPort.h"
 
// ---------------- USER CONFIG ----------------
 
// 7-bit I2C address of the meter (default is 8 decimal -> 0x08)
static const uint8_t I2C_ADDR = 0x08;
 
// Channel 1 Input register addresses (32-bit values in 2x16-bit regs):
// (decimal addresses from the manual)
static const uint16_t REG_VOLTAGE = 80;   // CH1 Voltage   (U32) -> V
static const uint16_t REG_CURRENT = 82;   // CH1 Current   (U32) -> A
static const uint16_t REG_POWER   = 84;   // CH1 Power     (U32) -> W
static const uint16_t REG_ENERGY  = 88;   // CH1 Total Energy (U32) -> Wh
 
// All are "Input" registers
static const MbI2c_RegType_e VOLTAGE_TYPE = MbI2c_RegType_Input;
static const MbI2c_RegType_e CURRENT_TYPE = MbI2c_RegType_Input;
static const MbI2c_RegType_e POWER_TYPE   = MbI2c_RegType_Input;
static const MbI2c_RegType_e ENERGY_TYPE  = MbI2c_RegType_Input;
 
// Endianness from the manual:
//  - each 16-bit word is transmitted MSB-first (big-endian on the wire)
//  - 32-bit values are two words in order [LowWord, HighWord]
static const bool BYTES_BIG_ENDIAN_IN_WORDS = false;
static const bool SWAP_WORDS_32BIT          = false; // order already [Lo, Hi]
 
// Scaling: the device returns scaled integers; apply 0.001 to get engineering units
static const float VOLT_SCALE = 0.001f;  // V per LSB
static const float CURR_SCALE = 0.001f;  // A per LSB
static const float POWR_SCALE = 0.001f;  // W per LSB
static const float ENER_SCALE = 0.001f;  // Wh per LSB
 
// Sample period (ms)
static const uint32_t SAMPLE_MS = 500;
 
// ---------------- END USER CONFIG ----------------
 
MbI2c_Handle_t gMeter;
 
// ---- Typed read helpers for this sketch ----
bool readU32Scaled(uint16_t reg, MbI2c_RegType_e type, float scale, float& outVal)
{
  uint32_t raw = 0;
  if (!mbReadUint32Portable(&gMeter, reg, type,
                            BYTES_BIG_ENDIAN_IN_WORDS, SWAP_WORDS_32BIT, &raw))
    return false;
  outVal = raw * scale;
  return true;
}
 
bool readVoltage(float& v) { return readU32Scaled(REG_VOLTAGE, VOLTAGE_TYPE, VOLT_SCALE, v); }
bool readCurrent(float& a) { return readU32Scaled(REG_CURRENT, CURRENT_TYPE, CURR_SCALE, a); }
bool readPower  (float& w) { return readU32Scaled(REG_POWER,   POWER_TYPE,   POWR_SCALE, w); }
bool readEnergy (float& e) { return readU32Scaled(REG_ENERGY,  ENERGY_TYPE,  ENER_SCALE, e); }
 
// Optional: read 16-bit firmware version fields to confirm non-zero reads
bool readFirmwareVersion(uint16_t& major, uint16_t& minor)
{
  // FW version (example): Input regs 48 = major, 49 = minor
  // Use 16-bit portable read to swap bytes if needed.
  if (!mbReadUint16Portable(&gMeter, 48, MbI2c_RegType_Input, BYTES_BIG_ENDIAN_IN_WORDS, &major)) return false;
  if (!mbReadUint16Portable(&gMeter, 49, MbI2c_RegType_Input, BYTES_BIG_ENDIAN_IN_WORDS, &minor)) return false;
  return true;
}
 
void setup()
{
  Serial.begin(115200);
  while (!Serial) { /* wait for Serial on native USB boards */ }
 
  Wire.begin();          // join I2C bus
  Wire.setClock(400000); // try fast-mode; if bus is long/noisy, use 100000
 
  if (!MbI2c_BeginArduino(&gMeter, I2C_ADDR)) {
    Serial.println(F("ERROR: Meter init failed (callbacks)."));
    for(;;) { delay(1000); }
  }
 
  Serial.println(F("DC Energy Meter (CH1) over I2C"));
  Serial.print(F("I2C address = 0x"));
  Serial.println(I2C_ADDR, HEX);
 
  // Optional sanity check: firmware version
  uint16_t fwMaj=0, fwMin=0;
  if (readFirmwareVersion(fwMaj, fwMin)) {
    Serial.print(F("FW version: "));
    Serial.print(fwMaj);
    Serial.print(F("."));
    Serial.println(fwMin);
  } else {
    Serial.println(F("FW version read failed (optional check)."));
  }
}
 
void loop()
{
  float v=0, a=0, w=0, e=0;
 
  bool okV = readVoltage(v);
  bool okA = readCurrent(a);
  bool okW = readPower(w);
  bool okE = readEnergy(e); // Wh (total)
 
  if (okV && okA && okW && okE) {
    Serial.print(F("V=")); Serial.print(v, 3); Serial.print(F(" V  "));
    Serial.print(F("I=")); Serial.print(a, 3); Serial.print(F(" A  "));
    Serial.print(F("P=")); Serial.print(w, 3); Serial.print(F(" W  "));
    Serial.print(F("E=")); Serial.print(e, 3); Serial.println(F(" Wh"));
  } else {
    Serial.print(F("Read error(s): "));
    if (!okV) Serial.print(F("[V] "));
    if (!okA) Serial.print(F("[I] "));
    if (!okW) Serial.print(F("[P] "));
    if (!okE) Serial.print(F("[E] "));
    Serial.println();
  }
 
  delay(SAMPLE_MS);
}

Testing the Arduino DC Energy Meter

In the Arduino IDE, go to the Board Manager and select Arduino Nano (or the board you are using). Choose the correct COM port, then click on the Upload button to flash the code onto the board.

Once the upload is complete, open the Serial Monitor from the Arduino IDE. Set the baud rate to the value used in your code (e.g., 115200).

Make sure the DC Power Monitor Module is supplied with a suitable DC source such as a battery or a variable DC power supply. Also, connect a load (for example, an LED, a DC motor, or any small DC appliance) to the selected channel.

When everything is connected, you should start seeing real-time readings of voltage, current, power, and energy appear in the Serial Monitor.




Displaying the DC Energy Meter on LCD with Arduino

So far, we have displayed the DC Energy Meter readings on the Serial Monitor. Now, let’s show the same measurements on a 16×2 I²C LCD display.

Hardware & Circuit

Displaying the DC Energy Meter on LCD with Arduino
Fig: DC Energy Meter with LCD & Arduino

The LCD is powered from the Arduino’s 5V supply and communicates using the I²C interface. Simply connect the LCD’s SDA and SCL pins to the corresponding I²C pins of the Arduino (A4 for SDA and A5 for SCL on Arduino Uno/Nano).

Once connected, the real-time values of voltage, current, power, and energy can be displayed directly on the LCD screen for easy monitoring without needing a computer.

Source Code/Program

This code reads voltage, current, power, and energy values from the DC Power Monitor Module via I²C and displays them on a 16×2 LCD. It first shows a splash screen for four seconds, then alternates every three seconds between voltage/current and power/energy readings, while also printing the same data to the Serial Monitor.

Copy the following code and paste it on your main ino file. You need to add LiquidCrystal I2C to the Arduino library folder. You also need the above mentioned energy meter I2C library for reading the energy meter data.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
* DCEnergyMeter_CH1_I2C_LCD.ino
*
* - Reads Channel 1 Voltage / Current / Power / Total Energy from the DPWR meter over I2C
* - Shows a 4s splash screen "DC Energy Meter"
* - Then alternates every 3s:
*      Page A: V on line 1, I on line 2
*      Page B: P on line 1, E on line 2
*
* REQUIREMENTS:
*  - Put MbI2C_ArduinoPort.h (from earlier) next to this .ino
*  - Install LiquidCrystal_I2C library (by Frank de Brabander, or compatible)
*  - Set LCD_ADDR (0x27 is common; sometimes 0x3F)
*  - I2C address of meter = 0x08 (7-bit)
*/
 
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "MbI2C_ArduinoPort.h"
 
// ---------------- USER CONFIG ----------------
 
// LCD config
static const uint8_t LCD_ADDR = 0x27;  // <-- change to 0x3F if your module uses that
static const uint8_t LCD_COLS = 16;
static const uint8_t LCD_ROWS = 2;
 
// Meter I2C address (7-bit)
static const uint8_t I2C_ADDR = 0x08;   // default per manual
 
// Channel 1 Input register addresses (32-bit values in 2x16-bit regs), decimal:
static const uint16_t REG_VOLTAGE = 80;   // CH1 Voltage   (U32) -> V
static const uint16_t REG_CURRENT = 82;   // CH1 Current   (U32) -> A
static const uint16_t REG_POWER   = 84;   // CH1 Power     (U32) -> W
static const uint16_t REG_ENERGY  = 88;   // CH1 Total Energy (U32) -> Wh
 
// All are Input registers
static const MbI2c_RegType_e VOLTAGE_TYPE = MbI2c_RegType_Input;
static const MbI2c_RegType_e CURRENT_TYPE = MbI2c_RegType_Input;
static const MbI2c_RegType_e POWER_TYPE   = MbI2c_RegType_Input;
static const MbI2c_RegType_e ENERGY_TYPE  = MbI2c_RegType_Input;
 
// Endianness discovered (do not swap bytes or words):
static const bool BYTES_BIG_ENDIAN_IN_WORDS = false;  // each 16-bit word already correct
static const bool SWAP_WORDS_32BIT          = false;  // order [Lo, Hi]
 
// Scaling: device returns scaled integers; apply 0.001 to get engineering units
static const float VOLT_SCALE = 0.001f;  // V per LSB
static const float CURR_SCALE = 0.001f;  // A per LSB
static const float POWR_SCALE = 0.001f;  // W per LSB
static const float ENER_SCALE = 0.001f;  // Wh per LSB
 
// Timings
static const uint32_t BOOT_SPLASH_MS = 4000;
static const uint32_t PAGE_HOLD_MS   = 3000;
 
// ---------------- END USER CONFIG ----------------
 
LiquidCrystal_I2C lcd(LCD_ADDR, LCD_COLS, LCD_ROWS);
MbI2c_Handle_t gMeter;
 
// ---- Typed read helpers ----
bool readU32Scaled(uint16_t reg, MbI2c_RegType_e type, float scale, float& outVal)
{
  uint32_t raw = 0;
  if (!mbReadUint32Portable(&gMeter, reg, type,
                            BYTES_BIG_ENDIAN_IN_WORDS, SWAP_WORDS_32BIT, &raw))
    return false;
  outVal = raw * scale;
  return true;
}
 
bool readVoltage(float& v) { return readU32Scaled(REG_VOLTAGE, VOLTAGE_TYPE, VOLT_SCALE, v); }
bool readCurrent(float& a) { return readU32Scaled(REG_CURRENT, CURRENT_TYPE, CURR_SCALE, a); }
bool readPower  (float& w) { return readU32Scaled(REG_POWER,   POWER_TYPE,   POWR_SCALE, w); }
bool readEnergy (float& e) { return readU32Scaled(REG_ENERGY,  ENERGY_TYPE,  ENER_SCALE, e); }
 
// ---- LCD helpers ----
void lcdClear() {
  lcd.clear();
  // small settle delay helps avoid ghosting on some backpacks
  delay(5);
}
 
// prints like "V: 12.345 V" trimmed to 16 chars
void lcdPrintValue(uint8_t row, const char* label, float value, const char* unit, uint8_t decimals)
{
  char val[16];
  dtostrf(value, 0, decimals, val);  // float -> text
 
  char line[32];
  snprintf(line, sizeof(line), "%s %s %s", label, val, unit);
  line[LCD_COLS] = '\0';             // truncate to 16 cols just in case
 
  lcd.setCursor(0, row);
  lcd.print(line);
}
 
// prints like "V: ----" if read failed
void lcdPrintDash(uint8_t row, const char* label, const char* unit)
{
  char line[32];
  snprintf(line, sizeof(line), "%s ---- %s", label, unit);
  line[LCD_COLS] = '\0';
 
  lcd.setCursor(0, row);
  lcd.print(line);
}
 
// (Optional) Serial print for debugging
void serialPrintAll(float v, float a, float w, float e,
                    bool okV, bool okA, bool okW, bool okE)
{
  Serial.print(F("V=")); okV ? Serial.print(v,3) : Serial.print(F("----")); Serial.print(F(" V  "));
  Serial.print(F("I=")); okA ? Serial.print(a,3) : Serial.print(F("----")); Serial.print(F(" A  "));
  Serial.print(F("P=")); okW ? Serial.print(w,3) : Serial.print(F("----")); Serial.print(F(" W  "));
  Serial.print(F("E=")); okE ? Serial.print(e,3) : Serial.print(F("----")); Serial.println(F(" Wh"));
}
 
void setup()
{
  Serial.begin(115200);
  while (!Serial) { /* wait for Serial on native USB boards */ }
 
  Wire.begin();           // join I2C bus
  Wire.setClock(100000);  // 100 kHz (stable with multiple devices); raise to 400k if you like
 
  // Meter init
  if (!MbI2c_BeginArduino(&gMeter, I2C_ADDR)) {
    Serial.println(F("ERROR: Meter init failed (callbacks)."));
    for(;;) { delay(1000); }
  }
 
  // LCD init
  lcd.init();
  lcd.backlight();
  lcdClear();
  lcd.setCursor(0,0);
  lcd.print(F("DC Energy Meter"));
  delay(BOOT_SPLASH_MS);
  lcdClear();
}
 
void loop()
{
  float v=0, a=0, w=0, e=0;
 
  // --- Page A: Voltage & Current ---
  bool okV = readVoltage(v);
  bool okA = readCurrent(a);
 
  lcdClear();
  if (okV) lcdPrintValue(0, "V:", v, "V", 3);
  else     lcdPrintDash (0, "V:", "V");
  if (okA) lcdPrintValue(1, "I:", a, "A", 3);
  else     lcdPrintDash (1, "I:", "A");
 
  serialPrintAll(v, a, w, e, okV, okA, false, false);
  delay(PAGE_HOLD_MS);
 
  // --- Page B: Power & Energy ---
  bool okW = readPower(w);
  bool okE = readEnergy(e);
 
  lcdClear();
  if (okW) lcdPrintValue(0, "P:", w, "W", 3);
  else     lcdPrintDash (0, "P:", "W");
  if (okE) lcdPrintValue(1, "E:", e, "Wh", 2);   // energy usually fine with 2 decimals
  else     lcdPrintDash (1, "E:", "Wh");
 
  serialPrintAll(v, a, w, e, okV, okA, okW, okE);
  delay(PAGE_HOLD_MS);
 
  // loop repeats; LCD is cleared between pages per your request
}



Testing the Arduino DC Energy Meter with LCD

Once you have completed the wiring and uploaded the code to the Arduino, the system is ready for testing.

Make sure that the module is connected to a DC supply and that a load is attached to the selected channel. As soon as the code is running, you will see the measured values of voltage, current, power, and energy displayed directly on the 16×2 I²C LCD screen.

Fig: Displaying Voltage & Current
Build a DC Energy Meter using Arduino - 32V/5A
Fig: Displaying Power & Energy Consumption

The DC Power Meter Module can measure input voltages in the range of 0 to 32 volts and currents from 0 to 5 amperes. For testing, you can connect a variable DC power supply or a battery as the source, along with a suitable load such as an LED, a resistor, or a small DC motor.


Video Tutorial & Guide

IoT DC Energy Meter with ESP32 & Web Dashboard
Watch this video on YouTube.

Share. Facebook Twitter Pinterest LinkedIn Tumblr Email Reddit Telegram WhatsApp
Previous ArticleA Beginner’s Guide to Building Compact Electronic Circuits at Home
Next Article The Future of Video Production: Adding Emotion with AI Voice Generators

Related Posts

Interfacing ADXL375 Accelerometer with Arduino

Interfacing ADXL375 Accelerometer with Arduino (±200g)

Updated:June 28, 2025
PZEM-004T Arduino Energy Meter

DIY AC Energy Meter using PZEM-004T & Arduino

Updated:March 6, 20258K
Interfacing BMI160 Accelerometer & Gyroscope with Arduino

Interfacing BMI160 Accelerometer & Gyroscope with Arduino

Updated:February 2, 20259K
Password Based Door Lock Security System Using Arduino & Keypad

Password Based Door Lock Security System Using Arduino & Keypad

Updated:February 2, 20252436K
Earthquake Detector Alarm with with Accelerometer & Arduino

Earthquake Detector Alarm with Accelerometer & Arduino

Updated:February 2, 2025661K
74HC595 Shift Register with Arduino

Shift Register 74HC595 with Arduino – Examples & Code

Updated:February 2, 202516K
Add A Comment

CommentsCancel reply

Latest Posts
ESP32 Fingerprint Attendance System with Live Web Dashboard

ESP32 Fingerprint Attendance System with Live Web Dashboard

June 16, 2026
IoT Based PM & Air Quality Monitoring System using ESP32

IoT Based PM & Air Quality Monitoring System using ESP32

June 14, 2026
DIY ESP32 MLX90640 IR Thermal Camera with Live Web Display

DIY ESP32 MLX90640 IR Thermal Camera with Live Web Display

May 10, 2026
IoT Activity Tracker with ESP32 & Accelerometer Gyroscope

IoT Activity Tracker with ESP32 & Accelerometer/Gyroscope

May 2, 2026
A Guide to Sourcing Obsolete ICs for Vintage Projects

Beyond AliExpress: A Guide to Sourcing Obsolete ICs for Vintage Projects

April 21, 2026

ESP32 IoT Vehicle Motion Analyzer with MPU6050 & LIS3MDL

April 27, 2026
Building a Smart Sensor Node with a BLE Microcontroller

Building a Smart Sensor Node with a BLE Microcontroller

February 26, 2026
High-Accuracy Pitch, Roll, Yaw with ESP32 & BNO08x IMU

High-Accuracy Pitch, Roll, Yaw with ESP32 & BNO08x IMU

April 27, 2026
Top Posts & Pages
  • ESP32 Fingerprint Attendance System with Live Web Dashboard
    ESP32 Fingerprint Attendance System with Live Web Dashboard
  • IoT AC Energy Meter with PZEM-004T & ESP32 WebServer
    IoT AC Energy Meter with PZEM-004T & ESP32 WebServer
  • 12V DC to 220V AC Inverter Circuit & PCB
    12V DC to 220V AC Inverter Circuit & PCB
  • How to use ADS1115 16-Bit ADC Module with Arduino
    How to use ADS1115 16-Bit ADC Module with Arduino
  • Buck Converter: Basics, Working, Design & Application
    Buck Converter: Basics, Working, Design & Application
  • Interfacing PN532 NFC RFID Module with Arduino
    Interfacing PN532 NFC RFID Module with Arduino
  • ECG Graph Monitoring with AD8232 ECG Sensor & Arduino
    ECG Graph Monitoring with AD8232 ECG Sensor & Arduino
  • DIY AC Energy Meter using PZEM-004T & Arduino
    DIY AC Energy Meter using PZEM-004T & Arduino
Categories
  • Arduino Projects (197)
  • Articles (60)
    • Learn Electronics (19)
    • Product Review (15)
    • Tech Articles (28)
  • Electronics Circuits (46)
    • 555 Timer Projects (21)
    • Op-Amp Circuits (7)
    • Power Electronics (13)
  • IoT Projects (205)
    • ESP32 MicroPython (7)
    • ESP32 Projects (82)
    • ESP32-CAM Projects (15)
    • ESP8266 Projects (76)
    • LoRa/LoRaWAN Projects (22)
  • Microcontrollers (38)
    • AMB82-Mini IoT AI Camera (4)
    • BLE Projects (18)
    • STM32 Projects (19)
  • Raspberry Pi (93)
    • Raspberry Pi Pico Projects (57)
    • Raspberry Pi Pico W Projects (12)
    • Raspberry Pi Projects (24)
Follow Us
  • Facebook
  • Twitter
  • Pinterest
  • Instagram
  • YouTube
About Us

“‘How to Electronics’ is a vibrant community for electronics enthusiasts and professionals. We deliver latest insights in areas such as Embedded Systems, Power Electronics, AI, IoT, and Robotics. Our goal is to stimulate innovation and provide practical solutions for students, organizations, and industries. Join us to transform learning into a joyful journey of discovery and innovation.

Copyright © How To Electronics. All rights reserved.
  • About Us
  • Disclaimer
  • Privacy Policy
  • Contact Us
  • Advertise With Us

Type above and press Enter to search. Press Esc to cancel.

Ad Blocker Enabled!
Ad Blocker Enabled!
Looks like you're using an ad blocker. Please allow ads on our site. We rely on advertising to help fund our site.