設計緣由

當初設計那台A類怪獸擴大器時,就很渴望有一台電功率測試儀。特別是裝機完成試聽時,若能隨時監測了解溫度上升時,功率的變化是否仍在安全範圍,會令人安心許多。要量測電功率,主要挑戰在取得電流值,只要取得電流值,其他問題就可以輕易解決。但是在完機測試階段,串入電流表,或用電流勾表量測都不是很方便。

其實,市面上已有許多現成的數位電流錶頭可用,要喝牛奶,實在不太需要自家養隻乳牛,但若要理解乳牛如何餵進牧草產出牛乳,養隻母牛就有必要了。因電流錶頭成品通常未提供其他的彈性應用,加上自己對電流的檢知量測充滿好奇;也很久沒有接觸數位電路,蠻懷念享受隨心所欲駕馭元件實現己意的樂趣,因此興起自己打造一台玩玩的念頭。再者,念頭興起正值盛夏,節能省電一直是最熱門的議題,若能實際了解家中電器耗電量,談論節能省電會很有感的。因此,除了實際需求外,加上好奇心的驅使探索,遂決定付諸行動實際設計一台;另一方面,也藉此過程暫時逃避紛擾的世界,遁入「創作--抗老」忘我境地。

 

硬體設計概述

霍爾電流感測元件CSLA1CD

Honeywell CSL Series Open Loop Current Sensor, 0〜57A,Sensed current type ac or dc,價格1000元有找,輸出模式是將感測到的電流轉換成電壓輸出。未找到原廠所提供的詳細電流/電壓轉換比率曲線,這意味著一切必須自己來,這是挑戰點,也是有趣的地方。使用者須根據自己的需求尋求適合自己的轉換比率曲線。

P1.png

P1-Honeywell CSLA1CD

 

我需要量測AC 0〜15A,這個感測器規格有些大,直接使用解析度會打折扣,解決之道是先放大,再選取0〜57A範圍前段的輸出轉換。

 

第一步:知己知彼

直接加上電流試驗,是了解手上霍爾電流感測元件(CSLA1CD)基本特性的好方法。我的作法是,用自耦變壓器調整電壓施加在電阻上,流經電阻的電流就會隨著電壓的改變而變化,試驗時把其中一條電阻引線穿過電流感測元件預留的線孔,然後用直接使用使示波器觀測電流感測元件的輸出波形。

 

P2.png

P2-檢測觀察電流感測元件特性電路示意圖

 

從示波器上初步觀測到的波形含有許多的雜訊,波形也不是很漂亮的正弦波,直接拿來用會有很大的誤差。這個步驟得到的結論是,需要慮波電路把雜訊濾掉,並做適度的放大,讓0〜20A輸出峰值電壓小於5V,以確保Arduino於A/D轉換時不會產生溢位失真。

 

第二步:去蕪存菁

電流感測元件的工作電壓是8V,輸出端在理想狀況無電流時中點電壓是4V,但是由於周遭游離電磁場的干擾,無電流時的輸出會有些許的正或負偏移。要擷

取有意義的60HZ的正弦信號,首先要隔離直流信號。下圖C16、R19組成高通濾波器,用於阻隔直流成份讓感測到的交流信號通過;U1A將拾取的感應信號作100K/5.6K倍緩衝放大以利後續處理;U1B運算放大器與R17、R18、C15、C17組成二階低通濾波器,把60HZ以上不要的高頻雜訊濾除,留下純淨的60HZ正弦信號。
轉折頻率:

P3.1.bmp

 

P3.png

P3-擷取感測到的60HZ正弦信號電路圖

 

P4.jpg

P4-去掉直流成分,但仍包含雜訊的感測信號

 

P5.jpg

P5-U1B輸出:慮波後的純淨60HZ正弦波
 

第三步:取正半週

電流感測器把電流轉換成對應的正弦電壓後,接著就要把正弦信號取出正半週,讓Arduino作A/D轉換,將半週正弦信號轉換成RMS( Root Mean Square)值。下圖是精密半波整流電路,交流信號由左方輸入,完整的正半週將由右方輸出,輸出端的4.7V Zener diode是防止輸出端輸出大於5V時,保護Arduino輸入端不致受損。

P6.png

P6-取出正半週的精密半波整流電路

 

P7.jpg

P7-全波輸入只剩正半週輸出

 

第四步:計時中斷

本製作採用Arduino NANO開發板處理一切轉換顯示事宜。已知交流電壓為110V,加上所得測量電流值就可以推算消耗功率,若只是這樣似乎太糟蹋Arduino NANO的強大功能了;而且LM324有4組OPA,已經用3組,剩下一組也可以利用一下。心理盤算著,若是加上計時電路,累計功率消耗時間,就可以功率轉換成用電量(度),讓物盡其用,不增加硬體成本就能提升功能。

要達到計時的功能,可以取自60HZ的交流信號,以每一週期計數一次的方式,累計計數到60次就得到一秒的計時值,再以秒往上累計分、時、日,達到計時累積的功能。

前面的電路已經取出漂亮的60HZ的正弦波信號,只要用簡單的零交越偵測電路,當正半週輸入電壓跨過零點時,令接成開集的極電晶體Q2導通,集極會汲取Arduino外部中斷觸發腳位(D2)的電流,將該腳位驅至LOW電位;反之,由正半週跨過零點進入負半週時,電晶體Q2截止,Arduino外部中斷觸發腳位會恢復到HIGH電位。這部分外部觸發硬體完成後,後續只要用軟體就可達到計時目的

下圖是 Arduino外部中斷觸發電路圖。

 

P8.png

P8-Arduino外部中斷觸發電路圖

 

P9.jpg

P9-正弦波轉換成60HZ外部中斷觸發信號

 

P10.png

P10-完整電路圖

 

P11.jpg

P11-電路完成實體圖

 

軟體設計概述

第一步:變數宣告

一般而言,為節省記憶體應盡可能使用區域變數,而少用全域變數,因區域變數只存在於stack內,程序結束會消失,但全域變數會一直佔用著記憶體。然而本程式因程序結構簡單,加上有計時中斷程式。若程式可正常執行,個人覺得使用全域變數程式可讀性較高,程式執行時可減少區域變數配置的程序,讓執行時間更穩定,規劃或除錯也比較容易。基於此原則就將整個程式的變數設成全域變數,但仍儘可能撙節使用,例如能用int就不要使用flot。

本程式最「吃」記憶體的地方是,宣告二個陣列用以儲存A/D轉換後的資料,太小,會遺失資料折損轉換值精確,太大,系統記憶體不足程式無法執行。

//-------------------------------------------------

int samples;// sampling pointer

int No_SineData;//save the number of sine data

unsigned long sample_adc;

unsigned long total_adc; //its range from 0 to 4,294,967,295 (2^32 - 1).

double RMS_adc;

double RMS_volt;

double AC_AMP;

double Single_step;

unsigned int adc_temp[300];//  store sampling data (range of 65535)

unsigned int adc_sine[200];//  store extracted sine data

unsigned int Watt;

float V_A_Slop=0;//

˙˙˙

˙˙˙

//---------------------------------------------------

 

第二步:正弦信號轉換成RMS值

要將已感測到並且整理好的正弦信號,透過A/D轉換成為交流RMS(Root-Mean-Squared)值,可以透過對正弦信號逐點取樣來取得各點的電壓值,再經以下數學式轉換成RMS值。

P12.png

  

P13.png

P13-正弦信號逐點取樣示意圖

 

(a)尋找a/d轉換進入點程式

交流信號瞬瞬時值隨著時間一直在變化,要在正弦信號正半週週期內取樣,必須硬體與軟體彼此配合。硬體電路已經將交流信號正半週取出,軟體要如何在適當時機取樣?參照下圖,t1〜t3是一個已經慮除負半週的完整正弦波週期,軟體可能在此週期內的任一點進入取樣。最理想的起始取樣點是在t3,但是要每次精準直接由t3切入有困難,只能運用些技巧來達到此目的。

 

參照圖P14,假設程式是在t1〜t2期間切入取樣,則無法確保取樣能涵蓋整個正半週,要避免在此區間取樣,程式規劃在t1〜t2期間偵測並等待。以下這段程式可以確保在t1〜t2期間切入時,只等待不取樣。

//-----------------------------------------------------------------------------

do

{

  sample_adc=analogRead(volt_in);  // check the sensors input

} while (sample_adc>0); // seeking 0 level for entrance

//------------------------------------------------------------------------------

程式一旦離開上面這個迴圈跨入t2〜t3區間,就可以開始取樣;考慮另一種情況,若程式一開始切入就得到sample_adc=0,表示切入點已經落在t2〜t3區間,因此,不會進入等待迴圈,而直接開始取樣。

以上二種情況取樣都會先得到一些連續冗餘的    ”0 ” 值,然後才進入取樣有效區間,得到所需的V1〜Vn個電壓值。這些冗餘的 ”0” 值後續利用程式控制捨棄即可,不會造成困擾,只是較佔記憶體。

 

(b)A/D取樣轉換與儲存程式

要確保每個轉換週期轉換值穩定精確,取樣過程程式必須簡潔,「心無旁鶩」,全速a/d轉換,才能使所得值穩定精確。

 

P14.png

P14-正弦信號取樣週期示意圖
 

取樣轉換程式只做A/D轉換與將資料儲存於陣列內。為確保陣列不致滿溢影響精確性,經過幾番測試,取樣有效區的取樣資料幾乎一致為75筆。考慮最壞的情況,從t2就開始取樣,取樣資料會有150筆。為使陣列有餘裕,因此宣告一個unsigned int adc_temp[300]的陣列,以確保能完整把取樣有效區的所有取樣資料存入。

//---------------start sampling and save sampling data-------------------------

  for (samples=0;samples< 300 ;samples++)

  {

  sample_adc=analogRead(volt_in);

  adc_temp[samples]=sample_adc;

  }

//-----------------------------------------------------------------------------------------------

 

(c)去蕪存菁,取出正弦信號

這個步驟主要是把冗餘的 “ 0 ” 捨棄,並按照上述RMS轉換數學式,計算感測所得正弦信號的RMS電壓值。
 

//----------------- get and save sine wave data -------

for (samples=0;samples< 200 ;samples++) //

   {

if (adc_temp[samples]>0)

{

 adc_sine[No_SineData] =adc_temp[samples];

 No_SineData++;

 square_temp=(double)adc_temp[samples]*adc_temp[samples];

 total_adc=(double)square_temp+total_adc; //

   if (adc_temp[samples+1]==0) //check if next sine data is over

     {

        break; //done, exit loop

     }

}

 }

RMS_adc=(double)sqrt(total_adc/No_SineData);// get the RMS value of ADC

RMS_volt=RMS_adc*Single_step;// get the RMS value of voltage

//--------------------------------------------------------------------------

 

第四步:電壓/電流轉換程式

轉換程式是用類似查表的方式完成。作法是用一只自耦變壓器當作電壓源,併接上3個100W/10.5歐姆,誤差1%的電阻當作負載,然後改變電壓值,讀取Arduino NANO轉換所得的VRMS值,同時量測輸入電源電壓、數位勾表讀取實際電流值,詳實記錄這些實測資料供轉換。這樣可以由「輸入電壓/負載電阻」,計算得到電流值;另外可由數位勾表直接得到電流值,二種資料可交互比對參考。

 

測試時由於電阻的瓦特數不夠大,自耦變壓器的最大輸出電流是10A,自忖這二者都稍有韌性,只要速度夠快應不致燒毀;還好完成前有些許焦味但沒有燒毀。轉換的精確度就由以上各元件的精準度決定,解析度大約是0.1A,讀值和其他校正過的數位勾表相較也相差在0.1A以內,這個精確度家庭使用已具參考意義。

 

P15.jpg

P15-用麵包板測試取得各轉換點數值

 

P16.jpg

P16-測試時電壓表、電流表與負載電阻實體圖

 

P17.png

P17測試所得資料

 

P18.png

P18-電流/電壓轉換線性度

 

P19.png

P19-電流/電壓轉換轉換比值(0〜15A)圖
數列1(藍色)是經由電壓/電阻計算值(還算平坦)

數列2(紅色)是數位勾表讀值(小電流受環境雜訊影響較不平坦)

 

查表轉換的方式,只要電壓表、電阻愈精確、測試點愈多,所得電流值就愈精確;其實要找到精密的電阻十分不容易,因為電阻加載會發熱,發熱後電阻值會隨溫度改變。衡量手邊資源與需求決定在1A以內,每0.1A取一個測試點,計算電壓與電流的比值,大於1A就每增加1A取一個測試點,直到15A。

程式中V_A_Slop這個全域變數紀錄每個轉換點的電壓/電流比值。

 

//------------get proper V/A transfer slop--------------

if (RMS_volt<=.03)

{

  V_A_Slop=0.131;

}

else if (RMS_volt >.03 && RMS_volt<=.05)//0.3A

{

 V_A_Slop=0.175;

}

else if (RMS_volt >.05 && RMS_volt<=.07)//0.4A

{

 V_A_Slop=0.175;

}

˙˙˙

˙˙˙

else if (RMS_volt >2.85 )// more than 15A

{

 V_A_Slop=0.189;// curve slope goes flat.

}

//--------------查完表直接代入轉換成電流與瓦特值-----

AC_AMP=RMS_volt/V_A_Slop;

Watt=int(110*AC_AMP);

//------------------------------------------------------------------

 

第五步:中斷服務常式

中斷服務常式必須配合硬體協同一致才會正確運作,在前述硬體已經將正弦信號轉換成TTL位準的矩形波。軟體中將void setup() 中斷設定在每個週期的正緣觸發,並在void loop()主程式置入中斷服務程式。程式執行時,每當外部中斷觸發接腳(PIN2)偵測到正緣上升信號,就會暫時中斷正在執行的程式,跳到中斷服務常式執行;中斷程式執行完又再回到原來的程式執行。

 

中斷服務常式內容非常單純,就是每隔1/60秒產生中斷時,程式先偵測是否有電流流動,若有就開始計時,並計算功率;若無電流就什麼事也不作直接返回。計時動作也十分簡單,每中斷60次就是一秒,然後依此計時累進分、時、日。這些儲存時間的變數都是全域變數,中斷常式執行完返回後,顯示程式會從這些時間變數讀取資料並顯示。

 

計算電功率,是用積分的概念,配合計時程式每隔1/60sec執行功率取樣、累加一次。

程式依下列數學式實現。

P20.png

        

 

P21.png

P21-計算電功率示意圖

 

計時與電功率程式

//--------------------------------------------------------------------------------------

void setup() {

pinMode(interruptPin, INPUT_PULLUP);// pin 2 pull to high

attachInterrupt(digitalPinToInterrupt(interruptPin), TimeProcess, RISING);//to trigger when the pin goes from low to high

//--------------------------------------------------------------------------------------

void loop() {

˙˙˙

˙˙˙

//============================================

//--------Interrupt Service Routine----------

//============================================

void TimeProcess() { 

if (AC_AMP!=0){   // have power consuming

W_cycle_sum=(float)W_cycle_sum+Watt; //calculate cycle Energy

Cycle ++;

 

if (Cycle == 60){

W_sec_sum=(float)W_sec_sum+(W_cycle_sum/60);//calculate second Energy

W_cycle_sum=0;

Sec ++;

Cycle=0;

flag_clear=true; // flag for clear the lcd

 }//cycle

 

if (Sec == 60){

W_min_sum=(float)W_min_sum+(W_sec_sum/60); //calculate minute Energy

W_sec_sum=0;

Minu ++;

Sec=0;

}//sec

 

if (Minu == 60){

W_hour_sum=(float)W_hour_sum+(W_min_sum/60); //calculate hour Energy

W_min_sum=0;

Hour ++;

Minu=0; 

}//minu

 

if (Hour == 24){

W_day_sum=(float)W_day_sum+W_hour_sum;

W_hour_sum=0;//reset

Day ++;

Hour=0; 

}//hour

 

E_total=(float)(W_day_sum+W_hour_sum+(W_min_sum/60)+(W_sec_sum/3600)+(W_cycle_sum/216000))/1000;//KWH

 

}// if

return;  

}//------------------------------------------------------------------

 

第六步:不閃爍顯示程式

Arduino驅動LCD顯示資料簡單方便,但是要讓LCD字幕看起來不閃爍,就需要利用一些顯示技巧。

首先,對一直快速變動的資料,規範每次顯示刷新間隔時間,並取得資料刷新的即時性與字幕穩定不閃爍的平衡點。本程式設定每次LCD顯示幕刷新間隔時間為1秒。

其次,顯示字幕格式與位置儘量保持固定,使沒有改變的資料保持在固定位置。例如:時間單位通常以二位數顯示,若計時值只有一位數時就要補城二位數,如計時值為 ”1” 要補成 ”01”,這樣保持二位數就可以減少字幕跳動。

 

//------data of minute--------

minu_temp=String(Minu);

if(Minu<10){

minu_disp='0'+minu_temp;

}

//------------------display minute --------------

lcd.setCursor(6,1); // put on LCD(6~7,1)

lcd.print(String(minu_disp));// update minute

lcd.setCursor(8,1);

lcd.print(":"); //put on LCD(8,1)

 

//----------------------------------------------------
 

P22.jpg

P22- 要讓LCD字幕不閃爍需要一些技巧

 

第七步:校正與測試

為了得到較精確的測試值,完成後,再度驗證。做法是再借一支經校證過的數位電流勾表,並配合負載電阻交互參考調整。因只要調整軟體不需調整硬體,所以過程並不複雜也不困難。因受限於電壓源與負載的精確與穩定,精確度實在難以確保,但經過交互參考比較,已具有一般用途所需的精確度與參考價值。

P23.jpg

P23-整體完成後再度校正

 

P24.jpg

P24-內部安裝配線圖

 

大同電鍋測試

電鍋規格式700W。電鍋加入一杯水,實測電流6.52A〜6.35A間變化,換算成功率為717.2W〜698.5W。變化的原因是因為電鍋的電熱器電阻值,會隨著溫度改變而改變。加熱至電源跳脫時間為12分32秒,累計耗電量為0.15度。若直接以規格值計算:700*12.5/60/1000=0.145度,算是相當接近。

P25.jpg

P-25大同電鍋電器規格

P26.jpg

P26-大同電鍋加熱實測圖

P27.jpg

P27-大同電鍋加熱時電流值

 

國際牌變頻電冰箱測試

變頻冰箱的特性是壓縮機幾乎不停,一開機測試,電流值就一直從0.36A〜1.72A改變,換算成功率約為40W〜190W。連續測試48小時,累積運轉時間為41小時14分43秒,累計耗電量為2.6度。若以此值推算,每月耗電量為2.6*15=39度,每年耗電量為39*12=468度。此值與冰箱貼紙上每年耗電量360度有108度的差異,推測應該是二者測試條件不同,我是在冰箱實際使用狀況下測試,廠商應該是在較理想狀態下測試。

P28.jpg

P28-Panasonic冰箱上貼的能源效率標籤

 

應用與展望

歷時數月終於大功告成,一如預期可以測試小於15A的各式家電耗電量,了解自己使用的家電到底有多耗電。另一方面這些簡單的功率量測的技術可運用於控制系統的功率監測、功率調整、設備保護,計算烘培食物電功率等。

P29.jpg

P29-過載警示設定為150W,進行測試。 

 

文章標籤
創作者介紹
創作者 錫安居 的頭像
錫安居

六家蓋房子

錫安居 發表在 痞客邦 留言(1) 人氣()


留言列表 (1)

發表留言
  • 竹貞
  • 我的動態訂閱跳出您有新文章。

    雖然光看標題就知道是我看不懂的內容,但既然加為好友,當然要進來關心一下囉!

    好長的文章,果然都看不懂,哈哈!

    不過可以確定的是您沉浸在樂齡maker 生活的喜悅。

    恭喜您喔!

  • 感謝您的關心,祝福您 一切平安順利!

    錫安居 於 2017/10/17 02:17 回覆