だめですね。ソフトに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 } } //**********************************************************************
※コメント投稿者のブログIDはブログ作成者のみに通知されます