生活随笔
收集整理的這篇文章主要介紹了
MiniSTM32F103实现家庭普通电路中的电流谐波检测
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前言:本人大二小白一個,通過一些小項目來充實下自己,不斷學習,希望能與大家多多交流~
接下來主要分為代碼設計和實際采集操作過程兩部分來講講
111
- 代碼設計
- 程序流程圖
- 配置TIM2、ADC和DMA
- FFT算法
- 處理FFT點
- 尋找直流分量、基波和諧波
- 采集過程
代碼設計
程序流程圖
配置MiniSTM32的TIM2、ADC和DMA,利用TIM2產生矩形波,在上升沿觸發ADC采集,可通過控制矩形波的周期來控制采樣頻率fs,然后由DMA把采集到的數據送入內存,共采集256個點。
配置TIM2、ADC和DMA
個人認為用庫函數配置板子上的外設比較簡單,把是什么、怎么用這兩方面搞清楚就行了,可參考正點原子的教學視頻。
代碼如下:
#include "adc.h"volatile uint16_t ADC_ConvertedValue
[256];
u16 DMA1_MEM_LEN
;
extern complex x
[N
];
#define ADC1_DR_Address ((u32)0x4001244C)
void TIM2_Init(u16 arr
,u16 psc
)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure
;TIM_OCInitTypeDef TIM_OCInitStructure
;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2
|RCC_APB2Periph_GPIOA
, ENABLE
); TIM_TimeBaseStructure
.TIM_Period
= arr
; TIM_TimeBaseStructure
.TIM_Prescaler
=psc
; TIM_TimeBaseStructure
.TIM_ClockDivision
= 0; TIM_TimeBaseStructure
.TIM_CounterMode
= TIM_CounterMode_Up
; TIM_TimeBaseInit(TIM2
, &TIM_TimeBaseStructure
); TIM_OCInitStructure
.TIM_OCMode
= TIM_OCMode_PWM1
; TIM_OCInitStructure
.TIM_OutputState
= TIM_OutputState_Enable
; TIM_OCInitStructure
.TIM_Pulse
= 10;TIM_OCInitStructure
.TIM_OCPolarity
= TIM_OCPolarity_Low
; TIM_OC2Init(TIM2
, & TIM_OCInitStructure
); TIM_Cmd(TIM2
, ENABLE
);
}
void DMA1_Config()
{DMA_InitTypeDef DMA_InitStructure
;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1
,ENABLE
); DMA1_MEM_LEN
= 256;DMA_DeInit(DMA1_Channel1
);DMA_InitStructure
.DMA_PeripheralBaseAddr
= ADC1_DR_Address
; DMA_InitStructure
.DMA_MemoryBaseAddr
= (uint32_t
)&ADC_ConvertedValue
; DMA_InitStructure
.DMA_DIR
= DMA_DIR_PeripheralSRC
; DMA_InitStructure
.DMA_BufferSize
= 256; DMA_InitStructure
.DMA_PeripheralInc
= DMA_PeripheralInc_Disable
; DMA_InitStructure
.DMA_MemoryInc
= DMA_MemoryInc_Enable
; DMA_InitStructure
.DMA_PeripheralDataSize
= DMA_PeripheralDataSize_HalfWord
; DMA_InitStructure
.DMA_MemoryDataSize
= DMA_MemoryDataSize_HalfWord
; DMA_InitStructure
.DMA_Mode
= DMA_Mode_Circular
; DMA_InitStructure
.DMA_Priority
= DMA_Priority_High
; DMA_InitStructure
.DMA_M2M
= DMA_M2M_Disable
; DMA_Init(DMA1_Channel1
, &DMA_InitStructure
);
}void DMA1_Enable()
{DMA_Cmd(DMA1_Channel1
,DISABLE
);DMA_SetCurrDataCounter(DMA1_Channel1
,DMA1_MEM_LEN
); DMA_Cmd(DMA1_Channel1
,ENABLE
);
}void Adc_Init()
{ADC_InitTypeDef ADC_InitStructure
;GPIO_InitTypeDef GPIO_InitStructure
;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA
|RCC_APB2Periph_ADC1
, ENABLE
); GPIO_InitStructure
.GPIO_Pin
= GPIO_Pin_1
;GPIO_InitStructure
.GPIO_Speed
= GPIO_Speed_50MHz
;GPIO_InitStructure
.GPIO_Mode
= GPIO_Mode_AIN
;GPIO_Init(GPIOA
, &GPIO_InitStructure
);ADC_DeInit(ADC1
); ADC_InitStructure
.ADC_Mode
= ADC_Mode_Independent
; ADC_InitStructure
.ADC_ScanConvMode
= DISABLE
; ADC_InitStructure
.ADC_ContinuousConvMode
= DISABLE
; ADC_InitStructure
.ADC_ExternalTrigConv
= ADC_ExternalTrigConv_T2_CC2
; ADC_InitStructure
.ADC_DataAlign
= ADC_DataAlign_Right
; ADC_InitStructure
.ADC_NbrOfChannel
= 1; ADC_Init(ADC1
, &ADC_InitStructure
);RCC_ADCCLKConfig(RCC_PCLK2_Div6
); ADC_Cmd(ADC1
,ENABLE
);ADC_ResetCalibration(ADC1
); while(ADC_GetResetCalibrationStatus(ADC1
)); ADC_StartCalibration(ADC1
); while(ADC_GetCalibrationStatus(ADC1
)); ADC_RegularChannelConfig(ADC1
, ADC_Channel_1
, 1, ADC_SampleTime_239Cycles5
); ADC_ExternalTrigConvCmd(ADC1
, ENABLE
);
}
FFT算法
FFT是最重要,也是最難懂的。由于論述篇幅太長,這里就不說了,請看另一篇文章:對于FFT和DFT的理解
這里給出實現FFT的代碼:
#include "sys.h"
#include "fft.h"complex x
[N
],W
[N
];void RaderReverse()
{u16 i
,j
,k
;for(i
=1,j
=N
/2; i
<N
-1; ++i
) {if(i
<j
){complex temp
= x
[j
];x
[j
] = x
[i
];x
[i
] = temp
;}k
= N
/2; while(k
<= j
){ j
= j
-k
;k
= k
/2;}j
= j
+k
;}
}
void fft()
{int i
=0,j
=0,k
=0,l
=0;complex up
,down
,product
;RaderReverse();for(int i
=0;i
<N
;++i
) {W
[i
].real
= cos((2*M_PI
*i
)/N
);W
[i
].img
= -sin((2*M_PI
*i
)/N
); }for(i
=0; i
<log(N
)/log(2); ++i
) {l
= 1<<i
;for(j
=0;j
<N
;j
+= 2*l
) {for(k
=0;k
<l
;++k
) {mul(x
[j
+k
+l
], W
[N
*k
/2/l
], &product
);
add(x
[j
+k
], product
, &up
);sub(x
[j
+k
], product
, &down
);x
[j
+k
] = up
;x
[j
+k
+l
] = down
;}}}
}
double Amplitude
[6], Phase
[6];
volatile u16 j
, m
, k
;
double I2
,I1
;
void Calculate_Wave()
{volatile double Max_Amplitude
= 0.0;volatile double t
=0.0;
Amplitude
[0] = (sqrt(x
[0].real
*x
[0].real
+x
[0].img
*x
[0].img
))/256;Phase
[0] = 180*atan2(x
[0].img
, x
[0].real
)/M_PI
;for(k
=1; k
<52; k
++){t
= sqrt(x
[k
].real
*x
[k
].real
+x
[k
].img
*x
[k
].img
)/128;if(t
> Max_Amplitude
){Max_Amplitude
= t
;j
= k
;}}if(j
!= 0){for(k
=1; k
<6; k
++){m
= k
*j
;Amplitude
[k
] = (sqrt(x
[m
].real
*x
[m
].real
+x
[m
].img
*x
[m
].img
))/128;Phase
[k
] = 180*atan2(x
[m
].img
, x
[m
].real
)/M_PI
;}} I2
= (Amplitude
[0] + Amplitude
[1]*0.7071)/R
;I1
= I2
* 100;
}void add(complex a
,complex b
,complex
*c
)
{c
->real
=a
.real
+b
.real
;c
->img
=a
.img
+b
.img
;
}void mul(complex a
,complex b
,complex
*c
)
{c
->real
=a
.real
*b
.real
- a
.img
*b
.img
;c
->img
=a
.real
*b
.img
+ a
.img
*b
.real
;
}void sub(complex a
,complex b
,complex
*c
)
{c
->real
=a
.real
-b
.real
;c
->img
=a
.img
-b
.img
;
}
處理FFT點
把時域信號變換到頻域,最重要的三個量是頻率、幅值和相位,如何根據FFT的結果算得這三個量?
例如某點n所表示的頻率為:Fn=(n-1)*Fs/N,n是第n個點,Fs是采樣頻率,N是采集點數,Fs/N又稱為頻率分辨率,如果采樣頻率Fs為256Hz,采樣點數為256點,則可以分辨到1Hz。
FFT后某點n是復數(a+bi的形式)
幅值:每一個點對應一個頻率,幅值指的是在該頻率下信號分量的幅值。假設原始信號的峰值為A,那么FFT?結果的每個點(除了第一個點直流分量之外)的模值就是A的N/2倍。而第一個點就是直流分量,它的模值就是原直流分量幅值的N倍。
相位:Pn=atan2(b,a),也就是arctan,反正切求得相角。
這里需要說明的是: FFT后得到的相位實際上是cos()的相位,因為這個FFT過程,根據慣例設定cos(x)的初始相位為0,sin(x)的初始相位為-90°。
尋找直流分量、基波和諧波
直流分量頻率為0,FFT后對應的是第一個頻率點,直接計算即可。
如何尋找基波?結合頻譜圖特性來看,基波的幅值是最大的,所以在這里采用的方法是尋找幅值最大所對應的頻率點,該頻率點對應的頻率即是基波頻率,由于已知市電的頻率為50Hz,所以這里為了節省計算量只在前52個點里面找幅值最大的點。
已知基波,那么諧波頻率是基波頻率的整數倍,可直接算出相關的頻率點。
采集過程
采集方式
由于測試對象是家庭普通電路,需要用到開口式電流互感器,非接觸式,直接夾在單根火線或者零線上。
互感器二次側電阻越小越好,因為這里ADC+電阻的組合其實相當于一個電流表,互感器處于工作狀態時,二次側接近短路。
ADC所讀取的值就是采集點值,FFT后通過流壓關系(歐姆定律)和變比關系即可推出一次側原電路的電流值。
碰到的問題
1.這里需要注意,一般的家用電器(至少我家的是)火線零線都是合并在一條線里面的,用一根粗電線來包含單獨的火線零線,電流互感器直接測這跟粗電線是測不到數據的,因為互感器(變壓器)的原理是利用電流激發的磁場效應,如果互感器同時測火線零線,電流激發的磁場相互抵消,互感器不工作。
2.電流互感器的電流變比不要過大,比如我用的是1000/5A的,變比200,用來測只有最大只有幾十安的電路不合適,因為二次側的電流太小了,影響ADC采集。為了增大二次側電流,我采用的方法是增加一次側纏繞匝數,從原本的單根火線穿入改成兩根火線穿入(還是同一根火線),匝數比從原來的1:200變成了2:200,電流變比降低到了100,這樣二次側的電流就增大了。
總結
以上是生活随笔為你收集整理的MiniSTM32F103实现家庭普通电路中的电流谐波检测的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。