エントリー

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

電子負荷に表示部を追加中(その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);
}

 

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

機能仕様とプログラムは落ち着いたので完成させるため基本データ値の計測を行う

シャント抵抗値

正確な電流値を出すため必要となるシャント抵抗(0.5Ω,5.0Ω)の正確な抵抗値を計測

先ずはテスターで計測してみる

0.55.0

4つのテスタで計測してみて結果は次のとおり

テスター名 0.5Ω 5.0Ω
sanwa PM3 0.6 5.1
kaise KU-1188 0.8 5.5
MASTECH MS8221C 0.8 5.2
Janisa PM18C 1.0 5.5

想像していたとおりで正確な抵抗値は計測できないようだ

そこで4端子法を使用して測定(4端子法の説明はこちらが判りやすい)

0.5-25.0-2

電流制限抵抗(Ω) 0.5Ω 5.0Ω 算出抵抗値(Ω)
電圧(mV) 電流(mA) 電圧(mV) 電流(mA) 0.5 5.0
330   7.8 14.86 72.5 14.66  0.52 4.95
100 25.0 48.0 231 46.0  0.52 5.02
50 47.6 91.6 423 84.6  0.52 5.00

内部で保持する初期シャント抵抗値を0.52Ω,5.0Ωとする(調整機能は実装済)

消費電力

USB簡易電圧・電流チェッカーで計測できなかった消費電力を計測しようと「USBテスターツール」(こちらを参考)を作製

USB tester

しかし・・・電流は0

電流値

少し悩んだ末,0.15Ωのシャント抵抗を付けてドロップ電圧を測定

ドロップ電圧

2.6mVと出た

ここの計算はシビアで無くても良いので,2.6 ÷ 0.15 ≒ 17mA,5 × 17 = 85mW

効率を無視(100%)して,85 ÷ 3.3 = 25mA となる

電源は50mAも出せれば十分そうなので,「S-812C33AY-B-G」を使用する

バックライトを消灯して計測したところ2.1mVで,とても省電力なバックライトだった(LEDなのか?)

テスターを購入

そこそこ精度の良い電圧計が無いものか検索していたらAmazonでコストパフォーマンスの良いテスターを見つけたので購入

箱

Janisa PM18C」,出店が多いのか価格が変動しているようで,セール品¥2,437(税込)

火曜の夜オーダーで(水曜にクロネコヤマトからは金曜だよってメール来てたのだけど)木曜に着いた(早)

箱の中身は,本体,テストリード,熱電対,単三電池4本,取説(英語)

中身

バッテリーをセットして電源(スイッチを電圧にして)ON

電源ON

ディスプレイが大きいので良く見えそう

精度を期待して購入した訳ではないが,早速リファレンス電圧を測定してみる(はたして精度のほどはいかがなもんか)

2.465V

2.5V

4.096V

4.1V

そこそこかな

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

今回の電子負荷に16文字×2行のLCDディスプレイは(表示文字数が多いので)大きすぎるためコンパクトなFSTN液晶に変更

FSTN液晶

FSTN液晶が3.3VロジックなのでついでにArduinoも3.3VベースにしADCのリファレンス電圧を3.3Vにした

それが良かったのか計測電圧も(若干調整は必要であるが)安定した感じだ

単独動作させるので電源部(3.3V)の3端子レギュレータの容量を見積もるため電源をUSB供給にしてUSB簡易電圧・電流チェッカーで計測

USB

電流値が表示されない・・・壊れているのか?

使い方を間違えているのかと思い調査したが問題なさそう,で,スマホの充電で確認してみたら正常に表示されていたので消費が10mA以下なのか?

これは単独で組んで調べてみるしかなさそうだ(まずは100mAあれば良いか)

尚,この「USB簡易電圧・電流チェッカー」は便利そうなので秋月でパーツ購入時に同時購入して今回初めて使った

USB電圧・電流

ページ移動

ユーティリティ

検索

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

過去ログ

Feed