下面介紹一種用單片機AD采樣的方式檢測市電電壓的方法
要檢測交流市電的電壓,通常有兩種方法
一、通過頻繁的采樣后再求平均值來獲得實際電壓值
二、通過采樣交流市電的峰值,再通過算法得出實際電壓值
這里我們講述峰值采樣法的步驟:
1、在正半波時,頻繁采樣市電AD值,在每次采樣后進行
從小到大排序並保存幾個最大值的結果,分別放在R_SaveVolAC[0]..R_SaveVolAC[3]
2、在負半波時,把剛才所采樣到的幾個值中,提取R_SaveVolAC[1]的值作為
上個正半波的的最大值。(R_SaveVolAC[2]、R_SaveVolAC[3]當作干擾給濾掉)
3、把N個上述這些正半波的最大值進行累加后除以N得到一個平均值,這個值就是峰值電壓值
電路圖如下:
以下為參考源代碼實例: uint8 R_VolAc = 0 ; //輸入電壓值 uint8 R_SaveVolAC[4] = {0,0,0,0} ;//保存讀AD時的峰值 //************************************** // 函數名稱:ReadZ0 // 函數功能:檢測過零信號 // 入口參數:無 // 出口參數:無 //*************************************** void ReadZ0(void) { uint8 Tcon=0 ; uint8 F_OK=0 ; do{ ReadVol_AC() ; //上半波時讀AC電壓值 Nop(5); if((P_ZER0 == 0)&&(F_PZL)) { Tcon++; } else if((P_ZER0 == 1)&&(!F_PZL)) { Tcon++; } else { Tcon = 0 ; } if(Tcon >= 5)F_OK = 1 ; }while(F_OK == 0); if(F_PZL) F_PZL = 0 ; else F_PZL = 1 ; } //************************************* // 函數名稱:Order_Byte_F2 // 函數功能:選擇法對數組從小到大排序 // 直接對傳遞的地址進行操作 // 入口參數:排序數據的首地址 // 出口參數:無 // 返 回 值:該列數據是的中間值 //*************************************** uint8 Order_Byte_F2(uint8 *a,uint8 DataLong) { uint8 i,j,k; uint8 tmp; for(i=0;i<DataLong-1;i++) { k=i; /*給記號賦值*/ for(j=i+1;j<DataLong;j++) { if(a[k]>a[j]) k=j; /*是k總是指向最小元素*/ } if(i!=k) { /*當k!=i是才交換,否則a[i]即為最小*/ tmp = a[i]; a[i] = a[k]; a[k] = tmp; } } i = DataLong >> 1 ; return a[i] ; } //************************************* // 函數名稱:TestVolage // 函數功能:檢測電源電壓 // 入口參數:無 // 出口參數:無 //***************************************/ void ReadVol_AC(void) { if(F_PZL) //正半波檢測電壓 { Adc_Mode_Scan(DIS) ;//ADC AdcSwitch(ADC_Chanel2) ; R_SaveVolAC[0] = ADC_DRH ; Order_Byte_F2(R_SaveVolAC,4) ;//從小到大排序 } } //======================================= void CalculateVol_AC(void) { uint8 Tmp ; static uint16 R_SaveSum = 0 ; static uint8 Tcon = 0 ; if(!F_PZL) //在負半波時計算AC值 { //AC的在上半波的最大值-已經是最大值的中值 Tmp = R_SaveVolAC[1] ; R_SaveSum += Tmp ; ClrDataBuf_Byte(R_SaveVolAC,4) ; //清除AC緩沖區 Tcon ++ ; if(Tcon >= 32) { Tcon = 0 ; R_VolAc = R_SaveSum >> 5 ; //AC電壓對應的AD值 R_SaveSum = 0 ; //再通過查表或算法得到實際AC電壓值 } } } //******************************************** //********** 主函數 *********** //******************************************** void main(void) { Init_Device() ; while(1) { ReadZ0() ; //讀過零信號 CalculateVol_AC() ; //計算AC電壓 } }