エントリー

カテゴリー「電源」の検索結果は以下のとおりです。

006P(8.4V 7セル)用簡易充電器改造

以前006P(8.4V 7セル)用充電器を作製したが,知識不足だったこともあり時間の掛かる充電器にしてしまっていた

IMG_20180113_161157.jpg

そこでちょっとした訳もあって改造することにした

回路は以下のとおり0.1Cの定電流で充電し満充電の判定など行わない簡易版である

diagram.png

対象がニッケル水素充電池なので停止しなくても0.1Cなら問題は起きないし,周囲の気温により満充電圧が変動するため面倒な判定を行わなくても確実に満充電させることができる

また,006Pに約25mAと以下の3.6Vの組充電池用に約80mA充電を切り替えるられるようにした

IMG_20180114_153320.jpg

大したパーツもないのでサクッと作り直し

IMG_20180114_111223.jpg

先に電子負荷を使って定電流なのを確認した後にバッテリーを繋いで確認

IMG_20180114_111601.jpgIMG_20180114_111645.jpg

30mAと83mA位にしようとしていたし手持ちの抵抗値の事もあり上の様な電流値となる

IMG_20180114_114113.jpg

3.6Vの組充電池も対応したし満足かな

可変電源の作製

昨年ダイソーで購入していた急速充電対応の自動車バッテリー用USB充電器

IMG_20171112_105906.jpg

その時に持っていた急速充電用の太いUSBケーブルが白だったのと500mAオーバーでの充電の仕組みを理解してなかったため白色を購入したが,これはiPad/iPhone用でAndroid端末では無意味であることを知り後に黒色のAndroid版を購入する

今回は余ったUSB充電器をDCDCに使って可変電源を作製することにした(本商品をこばさんがレビューされており参考にさせていただいた)

分解

まずは分解,無理やり開くことになるので元には戻らない

IMG_20171112_111219.jpg

基板の表と裏

IMG_20171112_111829.jpgIMG_20171112_111700.jpg

改造

使用しているチップHX1304Fの基本回路図(仕様書から抜粋)

HX1304F基本回路図.png

電圧を可変にするためには,R4とR5(基本回路図ではR2とR3)を外し以下の赤で記載したパーツを追加する

KR001.png

可変抵抗は500kΩ位が適切のようだが手持ちが100kΩしかなかった(良くできたら後で交換)

可変抵抗のGND側は0Ωで直結にする(電圧可変は基準電圧~入力電圧となるはず)

実態配線では以下のように3本のラインを取り出した

KR002.png

そして付加配線を楽にするためのと追加パーツがあるのでユニバーサル基板をベースに載せた

出力側のコンデンサの耐圧が6.3Vだったので取り外して100μF35Vのケミコンをユニバーサル基板上で追加

IMG_20171114_191526.jpg

注)まだターミナルは結線していない

動作試験

ここで動作確認する

適当なACアダプタを使用,入力電圧は約16V(無負荷)

IMG_20171115_201128.jpg

可変抵抗を操作して最低電圧から最高電圧へ(1.22~14.15V)

IMG_20171115_201201.jpgIMG_20171115_201308.jpg

電圧の可変を確認していると電圧のふらつきがあり試しに5Vに合わせてみるとふらつきが無くなった

IMG_20171115_201400.jpg

5Vにパーツの値が調整されているのかもしれない

DCDC部の消費電流も確認

5V時(21.1mA)

IMG_20171115_201549.jpg

最小電圧時(6.53mA)

IMG_20171115_201624.jpg

最大電圧時(64.3mA)

IMG_20171115_201704.jpg

100kΩでは少し消費が多いようだ

計器

購入してあった中華バルク版の電圧・電流計を使うことにした

無電圧時は0Vで問題なし

IMG_20171115_202547.jpg

とりあえず電圧のみ,ずれがあるので調整する

IMG_20171115_202634.jpg

結線

必要なパーツの結線を行い,後はケース入れ

IMG_20171116_193357.jpg

ケースが完成したら下記に追加予定

電子負荷に表示部を追加中(その5)

調整も終わったので基板化,秋月のユニバーサル基板Cタイプで部品配置を考えた

旨く配置できたかなっと自己満足,赤のジャンパーピンはバックライトの電源OFFできるように付けた

基板1

ロータリーエンコーダを付けた状態,やはり常時だと邪魔になりそうなので取り外し可能にした

基板2

裏は

裏

(2016.12.11 追加)電子負荷初版完成

電子負荷本体に実装,基板配置で隙間の高さ不足だったのでシャント抵抗を移動させた

完成

この電子負荷は「定抵抗」でしか利用できない

また,当初バッテリーの放電器として利用できないかと考えていたが,最低動作電圧が2.0V(2SJ554のVGS,実働確認1.8V)なので充電池には使えない

不足機能は次期バージョンの課題にしよう

電子負荷に表示部を追加中(その4)

Arduinoで確認できたので単独動作させるためブレッドボードで組み立て

BB

LCDの右のボタンが画面表示切替用,その右にあるのがSW付のロータリーエンコーダで電圧の微調整用(ロータリーエンコーダは常に使う訳でないので基板上では取り外し可能にする予定)

機能仕様

画面表示切替で3つの表示を切り替える

①入力電圧と負荷電流表示

②負荷電流のみ表示

③タイマーと負荷電流の表示(タイマーのリセットはタイマー表示時に画面表示切替ボタンを3秒押す)

VAATA → ①へ戻る

ロータリーエンコーダ(SW)を押すと微調整モードに切り替わる(もう1度押すと戻る)

調整画面は「入力電圧」と「負荷電流のシャント抵抗ドロップ電圧」の2つあり画面表示切替で切り替えてロータリーエンコーダを回す

電圧 ←→ 電流

調整

ブレッドボードの状態で電圧の微調整を行ってみると表示電圧が不安定であることが判明

電源の問題だろうと三端子レギュレータのパスコン等の調整を行ったが変わらない

取り付けた「S-812C33AY-B-G」の仕様を観てみると(出力電圧精度:3.3 V±2.0%)でありADCの基準電圧としては安定度が良くないようだ

そこで(出力電圧精度:3.3 V±0.5%)の「LP2950L-3.3V」(100mA)に変更

更に分圧抵抗に0.1μFのパスコンを追加することで安定した

回路図

回路図

プログラム

ロータリーエンコーダの処理はこちらを利用できたので参考にしてライブラリを使用

昔の人間なもので全て整数で処理してる

#include <EEPROM.h>
#include "MsTimer2.h"
#include "U8glib.h"
#include "rotary.h"

/*
#define REFINTERNAL        1               //内蔵基準電圧
 */
#define PIN_VOLTREG        0               //電流計測用電圧DACピン
#define PIN_VOLTM25        3               //電圧計測用DACピン
#define PIN_MAINTSW        4               //調整モードスイッチピン番号
#define PIN_SHUNTSW        7               //シャント抵抗切替スイッチピン番号
#define PIN_MODESW         8               //モード切替スイッチピン番号

#ifndef REFINTERNAL
#define REF_DEFINE        DEFAULT          //電源電圧定義
#define REF_VOLT         33               //3.3V * 10
#else
#define REF_DEFINE        INTERNAL        //内蔵基準電圧(1.1V)
#define REF_VOLT         11               //1.1V * 10
#endif

#define R1_PART            9825            //分圧抵抗1(100KΩ)
#define R2_PART            1965            //分圧抵抗2(20KΩ)
#define MAX_VOLTREG        ((long)REF_VOLT * 100 - 1)
#define MAX_VOLTM25        ((long)REF_VOLT * (R1_PART + R2_PART) / R2_PART * 100 - 1)
                                           //電圧はmV換算

#define DSP_LINE1         28               //上行表示
#define DSP_LINE2         60               //下行表示
#define DSP_LINEC         44               //中央表示

#define OP_NORMAL          0               //通常オペレーション
#define OP_MAINTENANCE     1               //メンテナンスオペレーション

#define NRD_VOLTCRNT       0               //電圧電流表示
#define NRD_CRNTONLY       1               //電流のみ表示
#define NRD_TIMECRNT       2               //タイマー電流表示
#define NRD_VERSION        3               //ソフトウェアバージョン表示

#define MNT_VOLTADJ        0               //電圧調整
#define MNT_CRNTADJ        1               //電流換算電圧調整

#define TM_SEC            20               //秒換算値(50ms)
#define TM_MINUTE        (TM_SEC * 60)     //分換算値

U8GLIB_MINI12864 u8g(10, 9);
Rotary r = Rotary(2, 3);

static boolean running = false;            //動作状態フラグ
static boolean forced;                     //強制表示フラグ

static unsigned long initTimeCount = 0;    //初期時間
static unsigned long pushTimeCount = 0;    //ボタン押下時間
static unsigned long timeCount = 0;        //時間計測

static int opState = OP_NORMAL;            //初期オペレーションモード(通常モード)
static int normalMode = NRD_VOLTCRNT;     //初期通常モード
static int maintMode = MNT_VOLTADJ;        //初期メンテナンスモード

static boolean btnOnA = false;             //ボタンA押下フラグ
static boolean btnWaitA = false;           //ボタンA押下中フラグ
static boolean btnOnB = false;             //ボタンB押下フラグ

static int adjVolt;                        //電圧調整値(EEPROM:0,1)
static int adjCrntVolt;                    //電流換算電圧調整値(EEPROM:2,3)

//調整値表示
//最小値の1は0.1%
static void displayAdjValue(int dl, int vv) {
    char str[8];
    int i = vv / 10;
    int f = vv % 10;
    if(f < 0) f *= (-1);
    if(vv < 0 && i == 0) {
        sprintf(str, "-0.%d\0", f);
    } else {
        sprintf(str, "%2d.%d\0", i, f);
    }
    u8g.setPrintPos(16, dl);
    u8g.print(str);
    u8g.setPrintPos(86, dl);
    u8g.print(" %");
}

//電圧を小数点付出力文字列に調整する
//入力電圧は1000倍された整数で下3桁が小数点以下となる
//小数点以下の表示は2桁とする
//  1000未満  0.XX
// 10000未満  N.XX
// 上記以外  NN.XX
//
static void displayVoltString(int dl, int ee) {
    char str[8];
    if(ee < 0) {
        //最大電圧超
        u8g.setPrintPos(4, dl);
        u8g.print("@OVER@");
    } else {
        int i = ee / 1000;
        int f = (ee % 1000)/10;            //小数点以下2桁にする
        if(ee < 1000) {
            sprintf(str, " 0.%02d\0", f);
        } else if(ee < 10000) {
            sprintf(str, " %d.%02d\0", i, f);
        } else {
            sprintf(str, "%2d.%02d\0", i, f);
        }
        u8g.setPrintPos(4, dl);
        u8g.print(str);
        u8g.setPrintPos(86, dl);
        u8g.print(" V");
    }
}

//電流表示(swで単位をmA/A切換え)
static void displayCrntString(int dl, int ii, int sw) {
    char str[8];
    if(sw == HIGH) {
        sprintf(str, "%4d\0", ii);
        u8g.setPrintPos(4, dl);
        u8g.print(str);
        u8g.setPrintPos(78, dl);
        u8g.print("mA");
    } else {
        int i = ii / 1000;
        int f = (ii % 1000)/10;            //小数点以下2桁にする
        if(ii < 1000) {
            sprintf(str, " 0.%02d\0", f);
        } else {
            sprintf(str, "%2d.%02d\0", i, f);
        }
        u8g.setPrintPos(4, dl);
        u8g.print(str);
        u8g.setPrintPos(86, dl);
        u8g.print(" A");
    }
}

//時間表示(HH:MM:SS)
static void displayTimeString(int dl, unsigned long tm) {
    char str[10];
    int hh = tm / ((unsigned long)60 * TM_MINUTE);
    int mm = (tm / TM_MINUTE) % 60;
    int ss = (tm % TM_MINUTE) / TM_SEC;
    sprintf(str, "%02d:%02d:%02d\0", hh, mm, ss);
    u8g.setPrintPos(2, dl);
    u8g.print(str);   
}

//電圧測定ポートから読込み
static int readVoltPort() {
    int e, val = (-1);
    if((e = analogRead(PIN_VOLTM25)) < 1023) {
        //ここでMAX_VOLTM25を補正する
        int maxvolt = (long)MAX_VOLTM25 * adjVolt / 1000 + MAX_VOLTM25;
        val = map(e, 0, 1023, 0, maxvolt);
    }
    return(val);
}

//電流測定ポートから読込み
static int readCrntPort() {
    //ここでMAX_VOLTREGを補正する
    int maxvolt = (long)MAX_VOLTREG * adjCrntVolt / 1000 + MAX_VOLTREG;
    return(map(analogRead(PIN_VOLTREG), 0, 1023, 0, maxvolt));
}

//電流読込:電流値算出
//抵抗値の電圧降下による電圧から電流値を算出する
//    D7:0.5Ω=H,5Ω=L 切替
//
static int changeCrnt(int ee, int sw) {
    int val;
    if(sw == HIGH) {
        //R = 5.00
        val = ee / 5;                    //I = E / R
    } else {
        //R = 0.5
        //val = ee * 2;                    //0.5 -> 逆数で*2
        //R = 0.52
        val = (long)ee * 192 / 100;            //1.92 = 0.52 の逆数
    }
    return(val);
}

void timeUp() {
    timeCount++;

    //メンテナンスSW処理(優先)
    int maintsw = digitalRead(PIN_MAINTSW);
    if(btnOnB) {
        //メンテナンスボタン押下後
        if(maintsw == HIGH) {
            //メンテナンスボタンが離された
            btnOnB = false;
            if(opState == OP_NORMAL) {
                //メンテナンスモードへ移行
                opState = OP_MAINTENANCE;
                maintMode = MNT_VOLTADJ;
            } else {
                //通常モードへ移行
                opState = OP_NORMAL;
                //電圧調整値書込み(EEPROMへの書き込みには3.3ミリ秒かかる)
                EEPROM.write(0, adjVolt>>8);
                EEPROM.write(1, adjVolt&0xff);
                EEPROM.write(2, adjCrntVolt>>8);
                EEPROM.write(3, adjCrntVolt&0xff);
            }
        }
    } else if(maintsw == LOW) {
        //メンテナンスボタン押下
        btnOnB = true;
    }

    //モードSW処理
    int modesw = digitalRead(PIN_MODESW);
    if(btnWaitA) {
        if(modesw == HIGH) {
            btnWaitA = btnOnA = false;    //ボタン押下終了
        }
    } else {
        if(btnOnA) {
            //ボタン押下後
            if(timeCount - pushTimeCount >= (TM_SEC * 3)) {
                btnWaitA = true;        //ボタンが離されるまで待つ
                //3秒以上の長押で操作モード変更
                //opState = (opState == OP_NORMAL)? OP_MAINTENANCE: OP_NORMAL;
                //メンテナンスモードにしたら通常モードを1にする(止め)
                //normalMode = NRD_VOLTCRNT;
                if(normalMode == NRD_TIMECRNT) {
                    //時間表示モードならリセット
                    initTimeCount = timeCount;
                    forced = true;        //強制再表示
                }
            } else if(modesw == HIGH) {
                //ボタンが離された
                btnOnA = false;            //ボタン押下終了
                //3秒未満のクリックは表示モード変更
                if(opState == OP_NORMAL) {
                    //通常オペレーション
                    switch(normalMode) {
                    case NRD_VOLTCRNT: normalMode = NRD_CRNTONLY; break;
                    case NRD_CRNTONLY: normalMode = NRD_TIMECRNT; break;
                    case NRD_TIMECRNT: normalMode = NRD_VOLTCRNT; break;
                    }
                } else {
                    //メンテナンスオペレーション
                    maintMode = (maintMode == MNT_VOLTADJ)? MNT_CRNTADJ: MNT_VOLTADJ;
                }
            }//else ボタン押下中
        } else if(modesw == LOW) {
            //ボタン押下
            btnOnA = true;
            pushTimeCount = timeCount;
        }
    }
}

ISR(PCINT2_vect) {
    if(opState == OP_MAINTENANCE) {
        unsigned char result = r.process();
        if(result) {
            //Serial.println(result == DIR_CW ? "Right" : "Left");
            int adj = (result == DIR_CW)? 1: (-1);
            if(maintMode == MNT_VOLTADJ) {
                adjVolt += adj;
            } else {
                adjCrntVolt += adj;
            }
        }
    }
}

void setup() {
    analogReference(REF_DEFINE);
    pinMode(PIN_SHUNTSW, INPUT_PULLUP);    //シャント抵抗切替スイッチの入力設定
    pinMode(PIN_MODESW, INPUT_PULLUP);    //モード切替スイッチの入力設定
    pinMode(PIN_MAINTSW, INPUT_PULLUP);    //調整モードスイッチの入力設定
    u8g.setContrast(190);
    u8g.setFont(u8g_font_helvR24);
    MsTimer2::set(1000/TM_SEC, timeUp);    //インターバルタイマー設定
    MsTimer2::start();
    //調整用ロータリーエンコーダ割込み設定
    PCICR |= (1<<PCIE2);
    PCMSK2 |= (1<<PCINT18) | (1<<PCINT19);
    //電圧調整値
    adjVolt = (EEPROM.read(0)<<8) +  EEPROM.read(1);
    adjCrntVolt = (EEPROM.read(2)<<8) +  EEPROM.read(3);
}

void loop() {
    int volt, crnt, crntvolt, shuntsw, modesw;
    int tm, st, md, mm;

    noInterrupts();
    forced = false;
    tm = timeCount / TM_SEC;
    st = opState;
    md = normalMode;
    mm = maintMode;
    interrupts();

    volt = readVoltPort();
    crntvolt = readCrntPort();
    shuntsw = digitalRead(PIN_SHUNTSW);
    crnt = changeCrnt(crntvolt, shuntsw);
    u8g.firstPage();
    do {
        if(st == OP_NORMAL) {
            //通常オペレーション
            switch(md) {
            case NRD_VOLTCRNT:
                displayVoltString(DSP_LINE1, volt);
                displayCrntString(DSP_LINE2, crnt, shuntsw);
                break;
            case NRD_CRNTONLY:
                displayCrntString(DSP_LINEC, crnt, shuntsw);
                break;
            case NRD_TIMECRNT:
                displayTimeString(DSP_LINE1, timeCount - initTimeCount);
                displayCrntString(DSP_LINE2, crnt, shuntsw);
                break;
            }
        } else {
            //メンテナンスオペレーション
            if(mm == MNT_VOLTADJ) {
                displayVoltString(DSP_LINE1, volt);
                displayAdjValue(DSP_LINE2, adjVolt);
            } else {
                displayAdjValue(DSP_LINE1, adjCrntVolt);
                displayVoltString(DSP_LINE2, crntvolt);
            }
        }
    } while(u8g.nextPage());

    while(!forced && tm == (timeCount / TM_SEC)) delay(100);
}

 

ページ移動

  • ページ
  • 1
  • 2
  • 3
  • 4

ユーティリティ

タグクラウド

検索

エントリー検索フォーム
キーワード

Feed