最近はリチウムイオン電池を使用することが多く、
以前はダイソン掃除機のバッテリーを大容量に変更しました。
純正品は18650タイプの2500mAhですが、パナソニックの電動アシスト自転車の
バッテリーを分解して取り出した20700タイプの4000mAhを2並列にして、
約3倍の8000mAhにしました。
充電は純正の充電器(26.1V,780mA)を使用しました。
26.1/6=4.35Vなので、リチウムイオン電池の通常の充電電圧(4.20V)を
超えています。
無負荷電圧を実測したら25.8Vなので4.3Vですが、それでも高いので、
掃除機のBMS(バッテリーマネジメントシステム)で充電制御している
可能性が高いです。
自作した回路は各セルの電圧を測定して、1個でも4.0Vになったら充電停止
するようにして安全に配慮しました。
以前の充電制御回路のブログです。
充電制御回路
ところが、アンバランスのために、充電終了時の平均電圧が約3.9Vになり、
リチウムイオン電池の大容量が活かせていません。
そこで、アンバランスをなくすることにしました。
バランス回路の例です。

5Vの充電器が6個以上あったので、自作向けの(b)複数個の絶縁型コンバータを
用いた方式にしました。
絶縁型コンバータの代わりにAVアダプター(充電器)を使用しました。
充電は定電圧定電流(CVCC)方式で4.05V(温度で少し変動)1.5Aです。
充電器の電圧が5Vなので、降圧回路と定電流回路を追加しました。
各セルの充電電圧をモニターして表示するとともに、
1個でも設定の電圧(4.15V)を超えたら、充電停止するようにしました。
回路図です。

ACアダプターは6個使用していますが、5個は回路図から省略しています。
フォトモスリレーで切り替えながら、1個のAD端子に入力しています。
AC100VはフォトトライアックカプラでON/OFFし、
充電電圧が設定電圧を超えたらOFFするようにしています。
充電器です。

定電圧回路と定電流回路を追加してます。
電圧と電流は半固定抵抗で微調整できます。
電圧モニター回路です。

左の回路がArduino用のACアダプターで、もともとはUSB用で、
5V,1Aですが、Arduinoの電源として使用できるように、
内部の抵抗値を変更して、6.5V出力に変更しました。
ケースに入れて完成です。

充電器の無負荷電圧です。
(シリアルモニターの表示値です)
Voltages: 4.024, 4.024, 4.024, 4.024, 4.024, 4.023
6個の充電器の電圧が0.1%以内で揃っています。
測定中です。

充電完了直前のバッテリー電圧です。

無負荷の電圧よりも数十mV高くなっていますが、
回路構成上充電器に温特があるため高温時に少し高くなり、
最高で約4.1Vになります。
今回のArduinoのスケッチですが、すべてChatGPTに任せました。
依頼内容と結果です。
● 1回目の依頼
6直列のセル個別充電方式の充電回路が完成したので、
電圧をモニターしようと思います。
Arduino NANO のAD入力で測定する方式で、
フォトモスリレーで切り換えながら6個のセルを順番に測定します。
AD入力はA0を使用し、D7~D12でフォトモスリレーを1秒間隔で切り替え
ながら測定し、I2C接続の16x2LCDで表示します。
1ms間隔で100回測定した平均値を測定値とします。
表示は小数点以下2桁で、測定値、空白、測定値、空白、測定値の14桁とし、
上段に1~3、下段に4~6を表示します。
シリアル通信でパソコンにも測定値を表示します。
スケッチを作成してください。
● 追加依頼
充電電圧は4.1Vにしますが、万一4.15Vを超えたらフォトトライアックカプラで
充電用ACアダプターへのAC100Vを停止したいと思います。
フォトトライアックカプラをD2で駆動して、通常はD2をHIGHにし、
6個のセルのどれか1個でも4.15Vを超えたらD2をLOWにするスケッチを
追加してください。
さらに、D3に赤LEDを接続してD2をLOWにしたときはD3をHIGHにして
赤LEDを点灯するようにしてください。
● 修正依頼
Arduino IDE のシリアルモニターだと正常に表示するのですが、
Tera Term 5 だと、添付の画像のようにずれて表示します。
毎回最初の桁から表示するようにできますか。

3回の依頼で完成したのが、以下のスケッチです。
要望通りの動作で完璧な出来のスケッチが10秒程度で完成です。
当然ですが、私が作成するよりはるかに洗練されています。
Arduino言語はC/C++で、私は還暦を過ぎた約10年前から勉強しましたが、
C/C++言語を知らなくてもスケッチが作成できる時代になりました。
ChatGPT恐るべし。
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define NUM_CELLS 6
#define ANALOG_PIN A0
const uint8_t relayPins[NUM_CELLS] = { 7, 8, 9, 10, 11, 12 };
const int CUT_OFF_PIN = 2; // フォトトライアック制御
const int LED_PIN = 3; // 赤色LED制御
const float OVER_VOLTAGE = 4.15; // 過電圧判定電圧
LiquidCrystal_I2C lcd(0x27, 16, 2);
float cellVoltages[NUM_CELLS];
uint8_t currentCell = 0;
unsigned long lastSwitchTime = 0;
void setup() {
Serial.begin(9600);
for (int i = 0; i < NUM_CELLS; i++) {
pinMode(relayPins[i], OUTPUT);
digitalWrite(relayPins[i], LOW);
}
pinMode(CUT_OFF_PIN, OUTPUT);
digitalWrite(CUT_OFF_PIN, HIGH); // 通常はON
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW); // 通常はOFF
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Cell Monitor");
delay(1000);
lcd.clear();
}
void loop() {
unsigned long now = millis();
if (now - lastSwitchTime >= 1000) {
lastSwitchTime = now;
// フォトモス全OFF
for (int i = 0; i < NUM_CELLS; i++) {
digitalWrite(relayPins[i], LOW);
}
// 現在のセルをON
digitalWrite(relayPins[currentCell], HIGH);
delay(10); // 安定化待ち
// 100回平均測定
long sum = 0;
for (int i = 0; i < 100; i++) {
sum += analogRead(ANALOG_PIN);
delay(1);
}
float avg = sum / 100.0;
float voltage = avg * (5.0 / 1023.0); // 分圧なし想定
cellVoltages[currentCell] = 1.0163 * voltage;
currentCell = (currentCell + 1) % NUM_CELLS;
if (currentCell == 0) {
// LCD表示更新
lcd.clear();
lcd.setCursor(0, 0);
for (int i = 0; i < 3; i++) {
lcd.print(String(cellVoltages[i], 2));
lcd.print(" ");
}
lcd.setCursor(0, 1);
for (int i = 3; i < 6; i++) {
lcd.print(String(cellVoltages[i], 2));
lcd.print(" ");
}
// シリアル出力
Serial.print("Voltages: ");
for (int i = 0; i < 6; i++) {
Serial.print(cellVoltages[i], 3);
if (i < 5) Serial.print(", ");
}
Serial.println(); // ← これがポイント
// 過電圧判定(1つでも4.15V超えたら停止)
bool overVoltage = false;
for (int i = 0; i < NUM_CELLS; i++) {
if (cellVoltages[i] > OVER_VOLTAGE) {
overVoltage = true;
break;
}
}
// フォトトライアック制御とLED制御
if (overVoltage) {
digitalWrite(CUT_OFF_PIN, LOW); // ACカット
digitalWrite(LED_PIN, HIGH); // 赤LED点灯
} else {
digitalWrite(CUT_OFF_PIN, HIGH); // 通電
digitalWrite(LED_PIN, LOW); // 赤LED消灯
}
}
}
}