おもちゃ、家電、もろもろの修理の足跡と備忘録

色々と忘れるので、趣味のメモ

電圧・電流・電力計にシリアル出力をつける BUG-Fix(V2.2)と5Vレギュレータ追加とシャント抵抗が壊れた話

2021-03-14 17:25:51 | その他工作

だめですね。ソフトにBUGがありました。V2.2版です。
前の記事のV2.1のソフトは消します。

・ソフトのBUG取り
 AD変換器からのデータを繰り返し数だけ加算してゆく変数がOverFlowしていましたので、Longにしました。電源電圧を上げてゆくとゼロに戻る、というとても恥ずかしいBUGです。
・繰り返し回数を1000回に
 あと、データの繰り返し数を1000回にしました。繰り返し数が100回だとチラチラするので、思い切って1000回にしたらちょうどよい感じです。(秒5回位のUpdateになりました。)
・5Vレギュレータの追加とノイズ退治
 PICやOpeAMPの電源をPICkit3から取っていたのですが、これを入力電源から取るように、5Vのレギュレータ(LP2950L-5.0V)を入れました。このレギュレータ、秋月で低損失のレギュレータがあったので購入したのですが、結構Noisyです。あちこちにコンデンサを入れましたが完全には取れませんでした。多少数値が暴れますが、まぁmVくらいなので良しとします。これにより、5V以下は測定できなくなりましたが、必要に応じて別電源で動かすことも可能(例えばPICkit3のICEを接続すれば良い)なので、これも良しとします。
・シャント抵抗が逝った話、、ステンレスの針金シャント
 完成! と思ってオートバイから外したバッテリーに接続して、ダミーの抵抗をつないだりして遊んでいたのですが、何の拍子にShortさせてしまったようで、これまでは安定化電源で、電流の上限値を設定していたのでなんともなかったのですが、バッテリーはだめですね、、、、。ぷちっ、ん?でR050のシャント抵抗が逝かれてしまったようです、、、。どれだけ流れたのでしょうね、、、。(2021/3/22追記:バッテリはバイクから外したもので、6.3Ah、なんとCCAが130Aと書いてありました、、、、だめですね、これでは、、、。)
でも、電流の数値がむちゃくちゃでかい(数A)だけで動いていることは動いてい状態です。破断では無いようです。外して抵抗値を測ってみると、1.010kΩとおっしゃる。なんだコレ状態です。
 シャント抵抗として使っていたR050(50mΩ)は、壊れた電源から外して使っていたので交換部品がありません。
 脱力感の中、どうしようかと一晩考えました。購入するにしても1個2個は売っていないし、、、。どうせだから抵抗のアソートでも買うか、とか。結局、ステンレスの針金を使って、50mΩを作りました。ステンレス針金のなかでも抵抗値が高いそうで、手元にあった0.9mmΦの針金の抵抗を計測して、所望の抵抗値を計測して計算、4cm弱で50mΩになることが判明。既知の抵抗を使って電流値がちょうど合うように多少調整をして、ほぼ?所望の数値になるようにしました。アマチュアが使うので、数%の誤差であれば上出来でしょう。
 求め方は、長いステンレス針金に既知の電流を流して、両端の電圧を計測して抵抗値を求め、その長さに比例した必要抵抗を求める、あとは現地合わせ、です。
 一番上の写真は、逝ってしまったR050と、ステンレスの針金シャント50mΩです。
下の写真は、ステンレス針金シャント抵抗を5Vに5Ωをつないだ時の結果です。5V、5Ω、1Aですね。
回路図: 5VレギュレータをLP2950L-5.0Vにしたのと、あちこちにコンデンサを入れました。
環境: MPLAB-X IDE v5.35 XC8/PICkit3 C99 PIC16F88

以下、V2.2です。


/* 
 * File:   main.c
 * Author: tomoharika
 * 2021/1/16 V1.5
 * 2021/1/23 V1.5a Power表示で32kでOverFlowを修正
 * 2021/2/13 V2.0a Serial Outを追加 @9600bps,8N Fosc=8Mに変更
 *  それに伴い、16F88 pin8をSerial Inのために空けて、ピン15(RA6)をLCD D6へ接続変更
 *  needs "LCDlib2a.c"(pin変更に伴う修正)
 * 2021/2/14 V2.1a sprintf 周りのBUG修正とそれに併せた表示制御の整理(17points/sec)
 * 2021/3/13 V2.2 bug対応 変数adをint->long
 * 
 * 設計目標:16V,5A電源を計測
 * 16x02のLCDに測定電圧(mV)、電流(mA)、消費電力(mW)を表示
 * PIC16F88、TL431、LM358、LCD:SC1602コンパチ?を使用
 * 
 * ・TL431シャントレギュレータを用いて、2.906V(2.495Vから作成)を
 *  標準電圧とし、この2.906をPICでVref+として1024分割したもの用いる
 *  (電源電圧、電流、OpeAmpの増幅率などを勘案して決定した)
 * ・電圧計測: 電圧@16V で、47kohm+10kohmで分圧したものをLM358
 *  VoltageFollowerでPICのAN0に入力
 * ・電流計測: 50mOhmの両端電圧を測定電圧として電流を測定、LM358
 *  で11倍(10kOhm/100kOhm)に増幅してPICのAN1に入力する
 *
 * 環境:
 * MPLAB X IDE/5.35, XC8/2.20, C99, LCDlib, C99
 * 
 * 調整、設定方法:→ソフト側で係数を微調整する
 * 1)電源を入れた際に、電圧、電流ともにゼロになるように、offsetを設定する
 * Line1の右側の4桁x2が、Volt,CurrentのAD変換後の数値:0-1023
 * 2)電圧:例えば、外部から外部計測した12.000Vを加えて、その時のAD変換後の数値XXXXを読む
 * →係数Vcoef=(12.000/XXXX)*1000, if XXXX=734 then 12/734*1000=16.3487=Vcoef
 * 3)電流:同様に、抵抗値のわかっているLoadを接続し、電流を計算、
 * →係数Icoef=(Current/YYYY)*1000, で係数を得、#define に両者を設定する
 */

#include \<stdio.h\>
#include \<xc.h\>
#include "LCDlib2a.h"

//--------------------------------------
// このアプリに必要な設定
//--------------------------------------
#define INITIAL_CREDIT1 "Power Mon v2.2"
#define INITIAL_CREDIT2 "JN1RAC 20210313"

#define offset  0               //印加電圧=0V、電流=0の時に表示がゼロになるように設定
#define repeat_num  1000           //繰り返し計測数。電圧、電流ともに効く
#define Vcoef   16.3043         //例えば、12Vを印加した時には、12.0/adconv()*1000で求めた乗算係数
                                //Over Allでの調整
#define Icoef   5.2215          //電圧と同様、Over Allでの調整係数

//--------------------------------------
// コンフィグレーションビットの指定
//--------------------------------------

// CONFIG1
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
//#pragma config FOSC = HS        // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = ON       // RA5/MCLR/VPP Pin Function Select bit (MCLR enabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB3      // CCP1 Pin Selection bit (CCP1 function on RB3)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

// CONFIG2
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal External Switchover mode disabled)

///////////delay関数を使うために発振周波数を定義 1Mhz////////////
#define _XTAL_FREQ  8000000
#define LED         RA4             //動作確認用のLED。初期ディスプレイ表示、変換動作中に点灯

//********************************************************************** 
/*
    <電圧・電流計>

 ■コンフィグ設定
  LVP_OFF
  MCLR_OFF
  WDT_OFF
  EXTCLK
 ■ピンアサイン (16F88)
  Pin-01 open
  Pin-02 Vref 
  Pin-03 RA4/LED
  Pin-04 /MCLR to VDD(+5V) via 10kohm 
  Pin-05 Vss to GND
  Pin-06 RB0/LCD D4
  Pin-07 RB1/LCD D5
  Pin-08 RB2/ →SerialIN (SPEN=1するとTX/RXともにEnableになる) open
  Pin-09 RB3/LCD D7
  Pin-10 RB4/LCD:E
  Pin-11 RB5/SerialOUT →未搭載、拡張予定
  Pin-12 PGC/LCD:RS
  Pin-13 PGD
  Pin-14 Vdd to +5V 
  Pin-15 RA6/LCD D6 2021/2/13 modified
  Pin-16 open
  Pin-17 AN0/Vvmon 
  Pin-18 AN1/Vimon
*/
//********************************************************************** 

// ADconv function 
unsigned int adconv()
{
    ADON = 1;           //AD変換
    __delay_us(20);
    GO_nDONE = 1;       //AD変換開始
    while(GO_nDONE);    //完了待ち
//    return ((ADRESH<<8)+ADRESL);        //右詰め
    return (ADRESH*256+ADRESL-offset);
}
//********************************************************************** 

void send_char(unsigned char byte)      //for serial transmission test
{
    while(!TXIF){
        continue;
    }
    TXREG = byte;
}

void send_text(char * text)    //for serial transmission test
{
    int i;
    for (i = 0; text[i] != 0; i++)
        send_char( text[i] );
}
//********************************************************************** 

void main()
{
//    static    unsigned    long    // 32bit 0...4294967295
//    static    unsigned    int     // 16bit 0...64k
    static  unsigned    long    Power, ad ; //mV*mAなのでlongが必要
    static  unsigned    int     Vmon, Imon, count, Vad, Iad;
    static  char        fmtbuf[16];
    
    OSCCON = 0b01110000;    //内部周波数8MHz
//    OSCCON = 0b01110000;  //111:内部周波数8MHz,101:2M,110:4M
    // アナログの設定
    ANSEL  = 0b00000011;    //AN0:Vvmon, AN1:Vimon
    // ポートの設定 1=input
    TRISA  = 0b00001011;    //RA0:AN0,RA1:AN1, RA2:opn, RA3:Vref RA4:LED
    TRISB  = 0b00000000;    //RB0-RB4:LCDout RB6+PGC RB7:PGD

//ADCON0
    //bit7:ADCS1
    //bit6:ADCS0
    //bit5:CHS2
    //bit4:CHS1
    //bit3:CHS0
    //bit2:GO_nDONE
    //bit1:not used
    //bit0:ADON
    
    ADCS2 =0;               //ADCON1のbitです
    ADCS1 =0;
    ADCS0 =0;               //000->ACDのclock:1.6usec

    CHS2 = 0;
    CHS1 = 0;
    CHS0 = 0;               //000->AN0,001->AN1

 //ADCON1
    //bit7:ADFM
    //bit6:ADCS2
    //bit5:Vref+
    //bit4:Vref-
    //bit3-0:not used
    ADFM = 1;               //ADC結果の格納方法、右詰め
    //ADCS2はADCON0で設定
    VCFG0 =0;               //ADCを行うポートの基準電圧をVref+に設定
    VCFG1 =1;               //Vref- ->Vss

// serial initial set   2021/2/11 added
    TXSTA = 0x24;           //Set High Baud rate
    RCSTA = 0x80;           //RX do not use
    SPBRG = 51;             //clock:8MHz, 9600bps, ={8000000/(16*9600)}-1

    LED = 0;
    
// LCD初期化
    lcd_init();
    
// LCD画面クリア
    lcd_cls();
    LED = 1;
// LCDにstart-up messageを出力
    lcd_locate( 0, 0 );
//    lcd_puts( fmtbuf );
    lcd_puts( INITIAL_CREDIT1 );
    lcd_locate( 1, 0 );
    lcd_puts( INITIAL_CREDIT2 );

    __delay_ms(2000);
    LED = 0;
    lcd_cls();
    __delay_ms(2000);

//*** start loop ***
    while (1) {
        LED = 1;                        //動作中表示の点灯

// Voltage ...
    // Vmon計測@AN0
        CHS0 = 0;                       //select AN0
    //  TL431シャントレギュレータを使ってVref+に2.906Vを供給
    //  最小分解能:2.906/1024=2.837mV、これ以上にする場合は複数回で平均を取る
    //  入力電圧を分圧してVref+(2.906Vを設定済)以下にしてAN0に入力する
    //  max入力電圧を16Vとして
    //  10k+47kohm(→16*10/(10+47)=2.807V)を設定 max:16.5V
    //    Vmon = (2.906/1024)*adconv()*(47+10)/10;
    //    Vmon = 0.016176*adconv();      //単位は"V"
    // 計算上は上記だが、Over Allでの誤差があるので、表示とadconv()の数値でVcoef,Icoefを算出する

        ad = 0;
        for (count=repeat_num;count>0;count--)
            ad = ad + adconv();
        Vad = ad / repeat_num ;
        Vmon = Vcoef/repeat_num * (float) ad  ;        
        //表示係数をかけたものの整数部分 単位は"mV"
        if (Vmon <= 1) Vmon = 0;

        LED = 0;
        
// Current ...
        CHS0 = 1;                       //select AN1 for Current...
    //  非反転増幅回路による電流計測
    //  TL431シャントレギュレータを使ってVref+に2.906Vを供給
    //  最小分解能:2.906/1024=2.837mV、これ以上にする場合は複数回で平均を取る
    //    Imon = {R1/(R1+R2)}*adconv()*{(2.906/1024)}*{1000/50ohm};
    //    Imon = {R1/(R1+R2)}*adconv()*0.056757812
    //    @ R1=10kohm, R2=47+47+4.7kohm=108.7kohm(100kohmがなかったので、、)
    //    Imon = 5.2215098896*adconv();  //mA maximum:5.2215*1024=5346mA
    // 最終的には実際の数値を求めて、Icoefの割り戻しする。1Aで234とか。
        ad = 0;
        for (count=repeat_num;count>0;count--)
            ad += adconv();
        Iad = ad / repeat_num;
        Imon = Icoef/repeat_num * (float) ad ;    //単位は"mA"
        if (Imon <= 1) Imon = 0;

// send to RS-232C
        sprintf(fmtbuf, "%6d,%6d\r", Vmon, Imon );
        send_text( fmtbuf );
// LCD一行目        
          sprintf(fmtbuf, "%6dmV%4u%4u", Vmon, Vad, Iad );    //電圧とAD値
        lcd_locate( 0, 0 );
        lcd_puts( fmtbuf );
// Power ...
        Power = (float) Vmon * (float) Imon / 1000 ;  //単位は"mW"
// LCD二行目
        sprintf(fmtbuf, "%6dmA%6ldmW", Imon, Power );  //倍精度long "ld"
        lcd_locate( 1, 0 );
        lcd_puts( fmtbuf );

//  LCD:16x02 display map
//        0123456789012345
// Line1: 123456mVXXXXYYYY XXXX:Voltage ADconved, YYYY:Current ADconved.
// Line2: 123456mA123456mW

    }
}
//**********************************************************************