2013-03-07
この写真と部品表を頼りに組み立てて下さい。裏側に配置されている部品はありません。部品面のベタパターンは5Vです。裏面のベタパターンはGNDです
部品表
半固定抵抗は液晶のコントラスト調整用です。回さないと液晶に何も表示されないことがあります
液晶ディスプレイの裏側には100Ωの抵抗を取り付けます。R9は抵抗のリード線を切った物でショートさせます
100V機器の電力を測定するときはこのような延長コードを作ってコードの片方をクランプで銜えます。もう一方のセンサーが繋がっていないのでノイズを拾ってデタラメな値3Wを表示しています。
分電盤に取り付けるときは赤線と黒線をセンサーでクランプします。2つのセンサーで計測した電力を合算した物が全消費電力になります。クランプする電線を間違えても非接触なので壊れることはありませんが正しい値を表示できません。
回路図。小さいので下に添付してある物を見て下さい
------------------------------
ポート番号解説
------------------------------
センサーCT1用
Digital 3,2
レンジ切り替え 電流計測にR1を使うとき D2=HIGH D3=LOW R3を使うとき D2=LOW D3=HIGH にする
R1,R3の抵抗値を変更すると計測可能な電流値を変更出来る
抵抗値を小さくするとより大きな電流を計測出来るようになるが精度が落ちる。抵抗を大きくするとその逆になる
Analog 4
電流電圧変換回路の出力。
測定対象物に電流が流れていない時は約2.5Vになる。この電圧を軸に出力が振れる。
AC100V機器であれば約2.5Vを軸とした交流信号になる
サンプルプログラムでは1サイクルの平均値から約2.5Vの軸電圧を求めているがセンサーに電流が流れていない時の計測値をEEPROMに記憶する方が望ましい
2つの回路は全く同じ物であるが部品のばらつきなどにより軸電圧は僅かに異なる
センサーCT2用
Analog 0,1
レンジ切り替え 電流計測にR2を使うとき A0=HIGH A1=LOW R4を使うとき A0=LOW A1=HIGH にする
Analog 2
電流電圧変換回路の出力
共通
Analog 5
ブザー用 ON/OFFを繰り返さないと鳴りません HIGHにしたままにしないで下さい
Analog 3
基準電圧 ここは2.495Vになる(若干誤差有り。テスターで実測すると良い)
0001 //----------------------------------------------------------------- 2013-03-29 ------------
0002 // 電力計 サンプルスケッチ
0003 //-------------------------------------------------------- written by iizuka --------------
0004 #include <LiquidCrystal.h>
0005
0006 //---------------- 環境により変更する項目 -------------------------------------------
0007 #define FREQ 50 // 50Hz
0008 // #define FREQ 60 // 60Hz
0009 #define CT_TURN 3000 // CTセンサーのコイル巻き数 CTL-10-CLS は 3000巻き
0010 #define CH1_R_LOW_RESOLUTION 200 // 回路図のR1=200Ω 抵抗は出力が振り切れない範囲で大きい方が計測精度が良い
0011 #define CH1_R_HIGH_RESOLUTION 3000 // 回路図のR3=3kΩ
0012 #define CH2_R_LOW_RESOLUTION 200 // 回路図のR2=200Ω
0013 #define CH2_R_HIGH_RESOLUTION 3000 // 回路図のR4=3kΩ
0014 #define SAMPLES 120 // 1サイクル(1/50秒)に何回サンプリングするか
0015 // 大きいほど精度が高く計測できるが大きすぎるとA/D変換の速度が間に合わない 150あたりが限界
0016
0017 //---------------- 配線を変更したら変更する項目 -------------------------------------------
0018 #define PORT_CH1_RANGE_SELECT_HIGH_RESOLUTION 3 // Port Digital 3
0019 #define PORT_CH1_RANGE_SELECT_LOW_RESOLUTION 2 // Port Digital 2
0020 #define PORT_CH2_RANGE_SELECT_HIGH_RESOLUTION 15 // Port Analog 1
0021 #define PORT_CH2_RANGE_SELECT_LOW_RESOLUTION 14 // Port Analog 0
0022
0023 #define PORT_ZERO_CROSS 4 // Port Digital 4 // このサンプルでは未使用
0024 #define PORT_CH1 18 // Port Analog 4
0025 #define PORT_CH2 16 // Port Analog 2
0026 #define PORT_REF 17 // Port Analog 3
0027 #define PORT_BUZZER 19 // Port Analog 5
0028 #define PORT_LED 13 // Port Digital 13
0029
0030 LiquidCrystal lcd(5,6,7,8,9,10);
0031
0032 //---------------- 回路定数など -----------------------------------------------------------
0033 #define SELECT HIGH
0034 #define NOT_SELECT LOW
0035
0036 #define HIGH_RESOLUTION 0
0037 #define LOW_RESOLUTION 1
0038
0039 #define REF_VOLTS 2.495 // TL431 Typ 2.495V
0040 #define PERIOD (1000000/FREQ/SAMPLES) // microsec
0041 const float pi = 3.141592;
0042
0043 int out_volts[SAMPLES]; // 電流->電圧変換回路の出力の計測値
0044 int ac100_sin_volts[SAMPLES]; // AC100V サインカーブ
0045 int ref_volts_10bit; // TL431リファレンス電圧のA/D RAW値
0046
0047 //------------------------------------------------------------------------------------------
0048 // AC100Vサイン波形の生成
0049 // 1/4サイクルでもよいがメモリー不足ではないので1サイクル分生成している
0050 //------------------------------------------------------------------------------------------
0051 void generate_ac100v_sine_curve()
0052 {
0053 for( int time_index = 0 ; time_index < SAMPLES ; time_index++ ) {
0054 ac100_sin_volts[time_index] = abs(sin( ( 2 * pi ) / SAMPLES * time_index )) * sqrt(2) * 100;
0055 }
0056 }
0057
0058 //------------------------------------------------------------------------------------------
0059 // 10ビットの計測値を電流値[mA]に換算する
0060 //
0061 // INPUUT:
0062 // volt -> 計測対象機器の10ビット計測値
0063 // ref_volt -> TL431のA/D計測値
0064 // R_range -> 計測レンジ
0065 //------------------------------------------------------------------------------------------
0066 float convert_10bit_to_milli_amp( int volt, int ref_volt, int R_range )
0067 {
0068 return ((float)volt * REF_VOLTS * CT_TURN) / ((float)ref_volt * (float)R_range);
0069 }
0070
0071 //------------------------------------------------------------------------------------------
0072 // 電流波形がSIN波になる場合の電流実効値[mA]を求める
0073 // 電圧波形を計測していないので力率100%とする
0074 // 平均値に波形率1.11を掛けても良いが定義通り 計算式 √avg(Σ計測値^2) で計算している
0075 //
0076 // INPUT:
0077 // out_volts[SAMPLES] extern
0078 // port -> arduino analog port
0079 // range -> HIGH_RESOLUSION / LOW_RESOLUTION
0080 //------------------------------------------------------------------------------------------
0081 float calc_rms_milliamp( int port, int range )
0082 {
0083 float total = 0.0;
0084 float temp_volt;
0085 float amp_div;
0086 float offset;
0087
0088 offset = calc_offset();
0089 for( int time_index = 0 ; time_index < SAMPLES ; time_index++ ) {
0090 temp_volt = abs((float)out_volts[time_index] - offset);
0091 total += temp_volt * temp_volt;
0092 }
0093 amp_div = get_amp_div( port, range );
0094
0095 return sqrt( total / SAMPLES ) * amp_div;
0096 }
0097
0098 //------------------------------------------------------------------------------------------
0099 // 1サイクルぶんをサンプリングする
0100 //
0101 // INPUT:
0102 // port -> arduinoアナログポート番号
0103 // range -> HIGH_RESOLUSION / LOW_RESOLUTION
0104 //------------------------------------------------------------------------------------------
0105 void ad_get( int port, int range )
0106 {
0107 long time_next_period;
0108 long period = PERIOD;
0109
0110 if( range == HIGH_RESOLUTION ) {
0111 if( port == PORT_CH1 ) {
0112 digitalWrite( PORT_CH1_RANGE_SELECT_HIGH_RESOLUTION, SELECT );
0113 digitalWrite( PORT_CH1_RANGE_SELECT_LOW_RESOLUTION, NOT_SELECT );
0114 } else { // PORT_CH2
0115 digitalWrite( PORT_CH2_RANGE_SELECT_HIGH_RESOLUTION, SELECT );
0116 digitalWrite( PORT_CH2_RANGE_SELECT_LOW_RESOLUTION, NOT_SELECT );
0117 }
0118 } else { // LOW_RESOLUTION
0119 if( port == PORT_CH1 ) {
0120 digitalWrite( PORT_CH1_RANGE_SELECT_HIGH_RESOLUTION, NOT_SELECT );
0121 digitalWrite( PORT_CH1_RANGE_SELECT_LOW_RESOLUTION, SELECT );
0122 } else { // PORT_CH2
0123 digitalWrite( PORT_CH2_RANGE_SELECT_HIGH_RESOLUTION, NOT_SELECT );
0124 digitalWrite( PORT_CH2_RANGE_SELECT_LOW_RESOLUTION, SELECT );
0125 }
0126 }
0127 delay(1);
0128
0129 time_next_period = micros();
0130 for( int time_index = 0 ; time_index < SAMPLES ; time_index++ ) {
0131 out_volts[time_index] = analogRead( port );
0132 time_next_period += period;
0133 while( micros() < time_next_period ) {
0134 // digitalWrite( PORT_LED, HIGH ); // LEDが点灯しないならA/D変換速度が間に合っていないのでサンプル数を小さくすること
0135 }
0136 }
0137 }
0138
0139 //------------------------------------------------------------------------------------------
0140 // リファレンス電圧のA/D変換10ビット値を得る
0141 // 1回A/D変換すれば済むが、A/Dの揺らぎを考慮し10回取得して平均値を求めている
0142 // INPUT:
0143 // port -> arduinoアナログポート番号 = TL431出力
0144 //------------------------------------------------------------------------------------------
0145 float get_ref_volt( int port )
0146 {
0147 int total = 0;
0148
0149 for( int t = 0 ; t < 10 ; t++ ) {
0150 delay(1);
0151 total += analogRead( port );
0152 }
0153
0154 return (float)total / 10;
0155 }
0156
0157 //------------------------------------------------------------------------------------------
0158 // 計測値のオフセット値を求める
0159 // 機器の電流波形は正負均等に触れると見なし、平均値をオフセットとする 値は 大体 512 になる
0160 //------------------------------------------------------------------------------------------
0161 float calc_offset()
0162 {
0163 long total = 0;
0164
0165 for(int time_index = 0 ; time_index < SAMPLES ; time_index++ ) {
0166 total += (long)out_volts[time_index];
0167 }
0168
0169 return (float)total / SAMPLES;
0170 }
0171
0172 //------------------------------------------------------------------------------------------
0173 // 1ビットあたりの電流値[mA]を求める
0174 //
0175 // INPUT:
0176 // range -> HIGH_RESOLUSION / LOW_RESOLUTION
0177 //------------------------------------------------------------------------------------------
0178 float get_amp_div( int port, int range )
0179 {
0180 if( range == HIGH_RESOLUTION ) {
0181 if( port = PORT_CH1 ) {
0182 return (REF_VOLTS * CT_TURN) / ((float)ref_volts_10bit * CH1_R_HIGH_RESOLUTION) * 1000;
0183 } else { // CH2
0184 return (REF_VOLTS * CT_TURN) / ((float)ref_volts_10bit * CH2_R_HIGH_RESOLUTION) * 1000;
0185 }
0186 } else { // LOW_RESOLUTION
0187 if( port = PORT_CH1 ) {
0188 return (REF_VOLTS * CT_TURN) / ((float)ref_volts_10bit * CH1_R_LOW_RESOLUTION) * 1000;
0189 } else { // CH2
0190 return (REF_VOLTS * CT_TURN) / ((float)ref_volts_10bit * CH2_R_LOW_RESOLUTION) * 1000;
0191 }
0192 }
0193 }
0194
0195 //------------------------------------------------------------------------------------------
0196 // ブザーを0.2秒鳴らす
0197 //------------------------------------------------------------------------------------------
0198 void beep()
0199 {
0200 for( int i = 0 ; i < 100 ; i++ ) {
0201 digitalWrite( PORT_BUZZER, HIGH );
0202 delay(1);
0203 digitalWrite( PORT_BUZZER, LOW );
0204 delay(1);
0205 }
0206 }
0207
0208 //------------------------------------------------------------------------------------------
0209 // 消費電力の計算 電流波形がSIN波の場合の計算式
0210 //------------------------------------------------------------------------------------------
0211 float calc_watt_sin( int port, int range )
0212 {
0213 // 実効値の計算式 √avg(Σ計測値^2) で電流実効値を求めて100[V]を掛ける
0214 return calc_rms_milliamp( port, range ) * 100 / 1000;
0215 }
0216
0217 //------------------------------------------------------------------------------------------
0218 // 消費電力の計算 電流波形が尖ったパルス状の場合の計算式
0219 // このタイプの機器は電流がゼロの期間が長い
0220 // 電圧最高点 = 電流最低点として計算する
0221 //------------------------------------------------------------------------------------------
0222 float calc_watt_maxI_eq_maxV( int port, int range )
0223 {
0224 int max_volt_index = 0;
0225 float max_volt = 0.0;
0226 float offset;
0227 float total;
0228 float temp_volt;
0229 int phase_diff;
0230 int phase_index;
0231 float amp_div;
0232
0233 offset = calc_offset();
0234 for( int time_index = 0 ; time_index < SAMPLES ; time_index++ ) {
0235 temp_volt = abs((float)out_volts[time_index] - offset);
0236 if( max_volt < temp_volt ) {
0237 max_volt = temp_volt;
0238 max_volt_index = time_index;
0239 }
0240 }
0241
0242 phase_diff = (SAMPLES/4) - max_volt_index;
0243 if( phase_diff < 0 ) {
0244 phase_index = SAMPLES + phase_diff;
0245 } else {
0246 phase_index = phase_diff;
0247 }
0248 amp_div = get_amp_div( port, range );
0249 total = 0.0;
0250 for( int time_index ; time_index < SAMPLES ; time_index++ ) { // 1サイクルぶん電力を積算
0251 temp_volt = abs((float)out_volts[time_index] - offset);
0252 total += (temp_volt * amp_div * (float)ac100_sin_volts[ phase_index ] / 1000);
0253 if( phase_index == (SAMPLES - 1) ) {
0254 phase_index = 0;
0255 } else {
0256 phase_index++;
0257 }
0258 }
0259
0260 return total / SAMPLES;
0261 }
0262
0263 //------------------------------------------------------------------------------------------
0264 // 消費電力の計算 電流波形が歪んだSIN波の場合の計算式
0265 // 電圧最低点 = 電流最低点として計算する
0266 //------------------------------------------------------------------------------------------
0267 float calc_watt_minI_eq_minV( int port, int range )
0268 {
0269 int min_volt_index = 0;
0270 float min_volt = 0.0;
0271 float offset;
0272 float total;
0273 float temp_volt;
0274 int phase_diff;
0275 int phase_index;
0276 float amp_div;
0277
0278 offset = calc_offset();
0279 for( int time_index = 0 ; time_index < SAMPLES ; time_index++ ) {
0280 temp_volt = abs((float)out_volts[time_index] - offset);
0281 if( min_volt > temp_volt ) {
0282 min_volt = temp_volt;
0283 min_volt_index = time_index;
0284 }
0285 }
0286
0287 phase_diff = (SAMPLES/4) - min_volt_index;
0288 if( phase_diff < 0 ) {
0289 phase_index = SAMPLES + phase_diff;
0290 } else {
0291 phase_index = phase_diff;
0292 }
0293 amp_div = get_amp_div( port, range );
0294 total = 0.0;
0295 for( int time_index ; time_index < SAMPLES ; time_index++ ) { // 1サイクルぶん電力を積算
0296 temp_volt = abs((float)out_volts[time_index] - offset);
0297 total += (temp_volt * amp_div * (float)ac100_sin_volts[ phase_index ] / 1000);
0298 if( phase_index == (SAMPLES - 1) ) {
0299 phase_index = 0;
0300 } else {
0301 phase_index++;
0302 }
0303 }
0304
0305 return total / SAMPLES;
0306 }
0307
0308 //------------------------------------------------------------------------------------------
0309 // arduino setup
0310 //------------------------------------------------------------------------------------------
0311 void setup()
0312 {
0313 pinMode(PORT_CH1_RANGE_SELECT_HIGH_RESOLUTION, OUTPUT);
0314 pinMode(PORT_CH1_RANGE_SELECT_LOW_RESOLUTION, OUTPUT);
0315 pinMode(PORT_CH2_RANGE_SELECT_HIGH_RESOLUTION, OUTPUT);
0316 pinMode(PORT_CH2_RANGE_SELECT_LOW_RESOLUTION, OUTPUT);
0317
0318 pinMode(PORT_LED, OUTPUT);
0319 pinMode(PORT_BUZZER, OUTPUT);
0320
0321 digitalWrite( PORT_CH1_RANGE_SELECT_HIGH_RESOLUTION, NOT_SELECT );
0322 digitalWrite( PORT_CH1_RANGE_SELECT_LOW_RESOLUTION, SELECT );
0323 digitalWrite( PORT_CH2_RANGE_SELECT_HIGH_RESOLUTION, NOT_SELECT );
0324 digitalWrite( PORT_CH2_RANGE_SELECT_LOW_RESOLUTION, SELECT );
0325
0326 lcd.begin(8, 2);
0327 lcd.println("WatMeter");
0328 lcd.setCursor(0,1);
0329 lcd.println("Sample 1");
0330
0331 generate_ac100v_sine_curve();
0332 ref_volts_10bit = get_ref_volt( PORT_REF );
0333
0334 beep();
0335 delay(500);
0336 }
0337
0338
0339 //------------------------------------------------------------------------------------------
0340 // arduino loop
0341 //------------------------------------------------------------------------------------------
0342 void loop()
0343 {
0344 float watt_ch1;
0345 float watt_ch2;
0346
0347 ad_get( PORT_CH1, LOW_RESOLUTION );
0348 watt_ch1 = calc_watt_sin( PORT_CH1, LOW_RESOLUTION ); // 電力の計算ロジックは3種用意してある ヒーターや白熱球はこれ
0349 // watt_ch1 = calc_watt_maxI_eq_maxV( PORT_CH1, LOW_RESOLUTION ); // 電球型蛍光灯やAC-DCアダプターはこれ
0350 // watt_ch1 = calc_watt_minI_eq_minV( PORT_CH1, LOW_RESOLUTION ); // 分電盤ならこれ
0351 ad_get( PORT_CH2, LOW_RESOLUTION );
0352 watt_ch2 = calc_watt_sin( PORT_CH2, LOW_RESOLUTION );
0353 // watt_ch1 = calc_watt_maxI_eq_maxV( PORT_CH1, LOW_RESOLUTION );
0354 // watt_ch1 = calc_watt_minI_eq_minV( PORT_CH1, LOW_RESOLUTION );
0355
0356 lcd.clear();
0357 lcd.print( "C1 " );
0358 lcd.print( (int)watt_ch1 );
0359 lcd.print( "W" );
0360 lcd.setCursor(0,1);
0361 lcd.print( "C2 " );
0362 lcd.print( (int)watt_ch2 );
0363 lcd.print( "W" );
0364 delay(300);
0365 }
0366
0367 //------------------------------------------------------------------ E N D ------------------
0368
-------------------------------------------
グラフ表示プログラム
-------------------------------------------
-----------------
Watt Loggerの仕様
-----------------
・ハードウェアは現時点の全てのワットメーターシールドV1,2,3に対応
・センサーは1つでも2つでも使用可能
・V1はハードウェアの仕様から皮相電力(ボルトアンペア)のみ計測可能
・V2,V3は有効電力(普通のワット)、皮相電力(ボルトアンペア)、力率が計測可能
AC100Vに接続しないと皮相電力のみ計測される。AC100Vに接続しているときはブザーが3回鳴る
・V1,V2の液晶には計測値が表示されるのでパソコンに繋がなくても使用可能
但しレンジが高精度モードになっているので200W程度が計測限界
・V2の液晶に表示される値はAC100に繋いでいると有効電力、繋がないと皮相電力を表示する
・電流検出抵抗を交換すればレンジを変更出来る
但しソフトの仕様上計測可能な最大電流は65A(厳密には65536mAつまり16ビット)
・V3はメモリーを内蔵しているのでWindowsを休止モードにしても記録は続けられる
最大65536秒間(18時間)休止モードに出来る。
プログラムを終了すれば記録は終了するので記録中にWindowsをシャットダウンすると記録はそこで終了してしまう
-----------------
ソフトの使い方概要
-----------------
・プログラムのインストールはダウンロード解凍して wattmeterM.exe を適当なフォルダーに置くだけ
arduinoスケッチはV1,V2,V3共通になっているので修正が必要。以下の2カ所
1.ハードウェアのバージョン
2.50Hz,60Hzの設定
V3の受信機用スケッチはそのまま無修正で使用する
・●RECボタンで計測値が記録開始される。ボタンの色が赤くなるのでそれとわかる。
再度押すと記録終了。記録中で無くても計測されたデータで常にグラフは更新される
・ファイルはプログラムのあるフォルダーの\dataディレクトリーに作成される
ファイル名は日時から自動生成される
・保存したファイルは「ファイル」メニューから開くことが出来る
ファイル形式はCSVなのでEXCEL等でグラフ化することも可能
Arduinoが繋がっていなくてもファイルの参照だけは出来る
・計測器は自動的にソフトが見つけてくれる
見つからなかったときはソフトを再度起動してみる
それでも見つからないときは接続を再確認
・グラフの範囲をドラッグするとその部分が拡大される
縮小はグラフのスクロールバーの左にあるボタンを押す
・PAUSEにチェックを付けると表示が止まる
プログラム上は「表示を止める」のでは無く「受信した計測データを捨てる」という処理になっている
・グラフをクリックするとその時点の計測値が表示される
このときPAUSEにチェックが付いていないと送られてきたデータで上書きされてしまうので値の確認が出来ない
・最大電流はそのレンジで計測可能な最大電流値。これを超えた場合計測値は正しくない。
・グラフの右下に表示される文字はarduinoのシリアルポートから送られてくるデータをそのままの状態で表示した物