前にPICで作った充電器。
【関連】NiMH6セル組電池用の充電回路を作った

電源が9V専用で、6セルの組電池しか充電出来なかったので
複数の組電池に対応した充電器を作る事にしました。

Arudino UNOと作った充電制御回路

スポンサーリンク

充電器のハードウェア

ハードウェアはLM317による定電流回路とMOS-FETによるスイッチ、
充電休止時電圧を計るのに必要な分圧抵抗の3つで構成されています。

LM317による定電流回路は
2Ωのセメント抵抗を使う事で600mAの定電流回路としました。

排熱の為、LM317とセメント抵抗を放熱用シリコン接着剤で
ヒートシンクに接着してます。

MOS-FETによるスイッチは
PチャネルMOS-FET、2SJ334と
バイアス抵抗内臓トランジスタ(デジタルトランジスタ)RN1201
を使いました。

デジタルトランジスタのベースに5Vを印可すると
FETがONになります。

分圧抵抗は手持ちの330KΩと120KΩを使いました。

分圧した電圧をA0に
デジトラのベースをD13に接続します、もちろんGNDもです。

充電制御

充電制御は2つ

3つ目にマイナスデルタVを入れていましたが満充電検知しない
誤動作が多く外しました。

寸止め充電制御

充電時に充電休止時間を作り、充電休止時の電圧により充電が
完了したか識別する方法。

参考にしたのはこちらのサイト
寸止め充電と、充電効率の評価(ニッケル水素電池充放電器)

今回は600mAと定電流回路で、あまり電流を落としたくなかったので
50秒充電と休止時間10秒としました。

休止時間が五分の一なので実質的な充電電流は500mAとなります。

制御は、休止時電圧が1.5V以上なら充電終了とする様にしました。
7セルのエネループでは動作しました。

ただ、エネループではOKでしたはエコルバでは
電池が暖かくなっても充電完了しません。

よって、電池によって閾値は変更する必要がありそうです。

閾値はeneloopは1.5V、
Ecorubaは1.48Vにしました。

閾値の決め方

閾値は基本的には1.5Vですが、1.5Vに達せずに発熱しだす電池があります。
この発熱を参考にしたサイトではおなかいっぱい反応と呼んでいます。

電池を一度、放電したあとに充電します。
電池容量が2000mAHより大きい場合はタイマーが動作して
正常に充電されない可能性があるので、タイマーの時間を変更します。

充電後、寸止め充電制御で充電が完了すればOK。

タイマーで止まっている場合は、閾値を少し上げて再度充電します。
閾値を変更後、寸止め充電制御で充電が止まればその閾値が良いと思います。

ただし、上でも書いたおなかいっぱい反応による発熱がある場合は
閾値を下げます。

発熱している場合は何度も充電していると、
発熱により電池電圧が下がってしまい寸止め充電制御で充電を止める事が出来ません。

タイマーによる充電の強制終了

寸止めで止まられなかった場合に予備的な制御です。
充電から6.4時間以上なら充電を終了します。

6.4時間は、
エネループなど2000mAHのニッケル水素充電池の標準充電は
200mA×16Hとなっています。

これを計算し、500mAの時は6.4Hとなりました。

電池が空な状態から充電した場合が最悪タイマーで防げますが
継ぎ足し充電の場合は過充電となってしまいます。

その他

充電開始時のバッテリー電圧が低すぎた場合
バッテリーの電圧が低いか接続されていないと言う事で
充電を行いません。

充電を終了した場合はトリクル充電などはしません。

スケッチ

ご利用は自己責任でお願いします。

int sensorPin = A0; // select the input pin for the potentiometer
int fet = 13; //充電FET制御ピン
int mode = 0; //0充電中 1充電終了 2充電開始電圧異常 3タイマーアウト 
double max_v = 0; //充電休止時最大電圧
double b_threshold = 1.5 //(V)閾値デフォルト1.5V
double voltage_c = cell * b_threshold; //充電を停止する電圧

int cell = 6; //セル数

void setup() {
Serial.begin(9600); // シリアル通信(960bps)を開始
Serial.println("NiMH - CHG SKTCH V1");
pinMode(fet, OUTPUT); //FET出力を出力に設定
digitalWrite(fet, LOW);//FET出力をLOWに設定

//ここで充電前で電圧を測定し1cellあたり0.9V以下の場合、処理終了
double voltage = analogRead(sensorPin);
voltage *= 5;
voltage /= 1024;
voltage *= 3.374;
double voltage_c = cell * 0.9;
if(voltage_c >= voltage){
mode = 2;
Serial.println("Battery is not connected or Battery Voltage is too low.");
while(true){
delay(1000);
}
}

}

void loop() {
//50秒充電、10秒休止 実充電電流500mA(LM317=600mA)
digitalWrite(fet, HIGH);
delay(50000);
digitalWrite(fet, LOW);
delay(10000);
//電圧測定
double voltage = analogRead(sensorPin);
voltage *= 5;
voltage /= 1024;
voltage *= 3.374;
//voltage *= 330;
/* 充電休止時電圧が閾値を超えていたら充電終了 */
if(voltage_c <=voltage){
mode = 1;
Serial.println("Battery has been Fully charged.");
while(true){
delay(1000);
}
}
/* サイクル数が384(6.4h)以上ならタイマーにより異状終了 */
if(384 <= cycle){
mode = 3;
Serial.println("Termination by a timer.");
while(true){
delay(1000);
}
}

//最大電圧を記憶
if(max_v < voltage){
max_v = voltage;
}
Serial.print(voltage);
Serial.print(",");
Serial.print(voltage_c);
Serial.print(",");
Serial.print(max_v);
Serial.print(",");
Serial.print(cycle);
Serial.print(",");
Serial.println(mode);
cycle++;
}

所々、無駄なコードが有りますが
まだこれからなので今後キレイにしていきます。

今後、シリアルからセル数と閾値を設定出来る様にしようと思っています。

電池電圧の分圧比、voltage *= 3.374;の部分は抵抗により誤差があるので調整が必要です。
できれば金属皮膜抵抗器の方が精度が高いので良いでしょう。

あとがき

LM317だと排熱がすごいです。
LED用の定電流ドライバでも良いのですが出力の制限があるので
このままでも良いかなと思っています。

電源電圧はセル×2V程は必要かと思います。
ただし、あまり電源が高いとシリーズ型のレギュレーターは
電源と電池電圧の差はすべて熱として捨てられるので排熱がより多くなります。

セル数が少ない場合は、電源電圧を小さくした方が
より排熱が少なくなります。