本帖最后由 wenyangzeng 于 2017-8-6 21:13 编辑 4 X/ o1 W) l; {
. Y' N% q4 k& L: n4 z) P' v: E
基于STM32F446的交流真有效值电压表
# X" m: J% r' {6 r0 Y3 v8 {2 h. t+ D& |/ ^
一般的数字万用表的交流电压的测量是采用将交流电压经过整流后测量其有效值,由于整流二极管的非线性,使得该测量结果误差较大,不是真有效值,特别是对非正弦波的测量更是如此。
; G* _. G$ _- Q" U0 U: s 本方案基于使用意法半导体的ARM CORTEX内核的STM32F446交流真有效值电压表,克服上述方案的缺点,使得对交流电的测量更加准确。
3 Y0 a) Z. G9 |! B/ ^( n4 h 交流电的有效值定义为:
3 {! Z- G! v- V
& s0 k7 ]0 S& B. x! q
* l% @- K' D/ {
6 y) e5 `2 f8 _+ N# y1 g. v 对其一个周期内连续采样后,根据以下公式进行计算得到结果。 S8 ~+ D1 B( U+ t
7 a; h0 `( h" `" T! [: y( Y( v
硬件连接:
. y+ o( i; T# k3 F7 F. n$ F
. [% l6 U) C- @3 q8 k o
; X# H' k. ]6 j
, |$ ^4 g; ?! U. s9 K- C
220V交流电经过1:1电压互感器后与STM32F446的ADC0连接。
# ^% j& l s2 x% c# W. h
6 a+ \: M) |& I3 Y5 v! A& B2 e3 |# L1 K7 ]; ?/ \$ X' G
) f7 B3 j: n+ J$ w$ k ADC通道配置
5 v- ?+ F* x) s- ]( f
; Y, m6 d7 w( ]* H8 ?: p 时钟配置
+ z! m( T; a* B4 Z
) |1 o) F) I" x1 Q
ADC参数配置# `, s/ k6 m5 F* E
5 n0 x( E: z' [: r
关键代码:% I* O/ v& e, H# P
- //MAIN.C9 g1 C) @0 w$ J& c
- & ?* p6 L9 m* I# ]' E; X! {
- #include "main.h"5 a! R$ H3 p5 \/ L ]
- #include "stm32f4xx_hal.h"
' S* w( O0 c+ `2 r - #include "adc.h"
/ Q4 _+ O+ ?9 V( O - #include "dma.h"
( t8 a$ Z# `+ z - #include "tim.h"/ ?$ z# x! b3 G$ [ H% ?* \1 U o
- #include "gpio.h"
- k$ v7 a. J" d - #include "math.h"5 ]7 o4 f8 F$ O" `
; Q/ I [: V T9 K6 y5 C+ m- #include "oled.h"3 t+ {$ ] n3 N. ]0 P. ?$ b& U
- uint16_t aADCxConvertedData[48][10];8 s3 e$ v! @) t, u: j. x
- uint32_t Resture=0; K7 r) l' g+ V
- uint8_t Disp_buf[8],Flag;. T# S4 U- n7 Q/ ?6 M1 q; h
- uint8_t j=0;
9 @" s: o7 Q" Y7 @$ \ - void SystemClock_Config(void);
5 z1 o1 b+ F9 E/ f- J
$ L' v" G" k& l- void Get_ADC(void)
) d1 q2 A/ U: K ^8 l- P p8 ^) ? - {uint8_t i;
8 t$ }3 G8 ?6 n. e+ g; G. j& k - static uint32_t total;
! _$ _1 W2 S4 I' m' \) `! [ - double temp;% I- ~1 D6 n$ K
-
! W, x( @9 X$ _6 B& w: y2 e) R2 }
$ p/ p( ?+ z3 |: P- total=0;6 ~6 E; h' [9 v j
- for(i=0;i<48;i++)
& q; X/ G" e" O, F1 _5 P0 D - {
& s0 u. _2 {* O2 U - total +=(aADCxConvertedData[i][0]*aADCxConvertedData[i][0]);
0 h; H; i, `8 K$ M& R3 X3 j9 R - }
2 s+ H! P# j. M1 k1 @ - total /=48;0 ]' d% ]. D4 B- Q7 H" p) {
- temp=sqrt(total) ;
, Z U: f7 J: W0 @2 v7 z - Resture +=(uint16_t)temp;( K5 [$ K2 F! W- {3 J, r
- j++;; I: r. h8 p' F0 l$ J& ]; y
- if(j==32)! p- ?5 J9 Z, ^& s% C4 i" p, l# L: f
- {) F2 o, h) V9 G g
- Resture=Resture/64;
1 W+ ]5 a/ |: t/ V) ` - Disp_buf[0]=(Resture%1000/100)+0x30;
4 _* {+ A2 }8 `( O - Disp_buf[1]=(Resture%100/10)+0x30; @9 v% q2 s0 K1 h
- Disp_buf[2]=(Resture%10)+0x30; : |& O0 i9 G6 d# |* c" w1 x9 o
- Disp_buf[3]='\0';0 x+ {9 Y1 r# H3 i* c( Y$ O- Z" Z- A; S
- LCD_Print(40,46,Disp_buf,TYPE16X16,TYPE8X16); ( a8 C* F( I2 V
- Resture=0; 0 w' v+ |2 k1 t5 \
- j=0;
$ J& r0 E* j% y( \6 n - }
& p! `& [* z8 B8 N: ~ - }) ^* h$ V* V% _* W1 S1 o
- ' ?& C# S7 k5 H0 x
- - W# H" r V1 q6 \3 _; ^2 \7 D
- 8 v" j$ _( c: k5 _' d: g+ d
- 6 o9 @3 ^5 V5 v( A- I/ D V7 l
- int main(void)8 z% s+ h* w3 w7 W: x
- {/ e- ~, V$ q7 a
- . T- r' o# p! j7 O% ` O
- HAL_Init();
2 |: |- t8 `0 z& {# z+ \ - SystemClock_Config();( G! K' n: O5 D
- MX_GPIO_Init();
3 d+ m7 ^- S8 \, b - MX_DMA_Init();8 v; ^; A4 ]; C- D; ~
- MX_ADC1_Init(); k( f [0 S- S- I
- MX_TIM8_Init();! C3 U1 Y1 _1 _9 N2 Z6 o' B
- HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);
: `0 b; L6 d, w" z
B7 n4 e! Z. K0 M- LCD_Init();
$ K3 w2 C0 G! i; |* Z - LCD_Print(0, 0,"STM32F446 Nucleo",TYPE16X16,TYPE8X16);
( Y8 C6 D( e+ r: A% Y" U - LCD_Print(0, 16, "True effective",TYPE16X16,TYPE8X16);9 a ]. O& h9 y4 s1 ]6 R
- LCD_Print(74,46, "V",TYPE16X16,TYPE8X16);% _$ Z5 W2 j: o! a: s
-
( G! r4 ~5 A \( V- v, U( U# R2 E - if(HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&aADCxConvertedData,480) != HAL_OK), t& b- |- K$ ~* U3 u9 o
- {
6 N! W2 `, P9 r* C0 q - Error_Handler();
2 r3 m) S, g' i9 Y) x& H4 } e - } ) s5 \2 I9 ^, h
: e& g0 H l! L6 P$ a- while (1)/ u9 j) [7 D! e/ s& W
- {9 u. d8 E K7 ^( D
- if(Flag==1)+ L0 A q( U" O8 J- [' S4 X! Y. P/ [' g
- {
# {& k2 I6 Y. n" Y - Get_ADC();+ r" f% H" R* m+ y/ r
- Flag=0;9 u! o. x, s9 ? g, Y
- }1 F" f/ r9 m; o+ p( D7 I5 J
# a: L5 Y- [' Y- }1 D; _: T$ |% { w" g2 N% R& P* e
- 7 u$ k; C& {/ `1 N$ Y
- }1 }7 ]- I! O+ I; p
- 9 ^4 I1 {& a$ }8 k9 \0 D
- ) J3 ?7 b$ J" [0 `# |# g
- //ADC.C" [; h7 k( N3 N; b& ]) T) X
- #include "adc.h"4 y$ ~3 o8 K5 ?5 J+ `6 v
- #include "gpio.h"" M/ u3 W- F" q9 p
- #include "dma.h"
( g6 g0 t1 ~5 X7 [ - ADC_HandleTypeDef hadc1;
9 X+ \' _# R# ~5 L6 j2 J - DMA_HandleTypeDef hdma_adc1;
S2 ]' |$ w) s/ J# `3 J - void MX_ADC1_Init(void)
( @& W& @$ |5 Q( c6 y5 w/ l - {9 q6 o0 S8 Q# Y$ }
- ADC_ChannelConfTypeDef sConfig;9 v6 q4 \9 s' g3 d- y, m, _
- hadc1.Instance = ADC1;* W! S [" W3 Z3 h' Q. w
- hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8;6 @- V6 {9 s1 t5 E- |4 \
- hadc1.Init.Resolution = ADC_RESOLUTION_12B;
& F3 \: g2 T3 z' r" Z: y - hadc1.Init.ScanConvMode = ENABLE;
5 m* h, Q- H5 M" X* B9 R% m - hadc1.Init.ContinuousConvMode = ENABLE;
. E& B9 K1 ?: H) N3 n - hadc1.Init.DiscontinuousConvMode = DISABLE;
& e. D' |2 p* P1 b+ ~8 t, a$ a - hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
3 p6 @3 u) N ]) Y4 ~ - hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;+ E% n3 y1 {9 w) i" ]( P% c
- hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;" J3 ]/ d% s, J# U- f% D
- hadc1.Init.NbrOfConversion = 10;5 }9 g; F$ Y P' C- o
- hadc1.Init.DMAContinuousRequests = ENABLE;- \( Y; T( f/ V! N+ U; c
- hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;1 \& S/ w1 P; Q# T
- if (HAL_ADC_Init(&hadc1) != HAL_OK)
& m2 `1 U2 V) ? - {6 {6 i2 I+ `" D7 ?- a+ m4 |; _
- _Error_Handler(__FILE__, __LINE__);: ^1 Z% C: E$ z- B& T
- }
+ A9 U1 }5 A6 f- Q. P0 q - sConfig.Channel = ADC_CHANNEL_0;- N- `0 ^: H/ y$ \. ^
- sConfig.Rank = 1;( Z: W+ X( J: S1 `5 _8 e: N3 F# x
- sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
- i4 K% g7 R S3 n& U! M - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)3 t: e% J0 O8 | m/ D* D R a# A# I
- {
' c, k& D$ h: Z, V% ]5 G/ t - _Error_Handler(__FILE__, __LINE__);1 s( k' |2 _# v# _2 s6 w
- }7 I# a" u& W' y4 B' P- [7 C, q! a' r
- , W" v. X* o+ _/ l2 d4 S
- sConfig.Channel = ADC_CHANNEL_1;+ Y8 t8 s- G9 o5 i: l
- sConfig.Rank = 2;# [: c9 C0 W9 Z* U, T6 w
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
: S! [$ d$ S- O- u9 P& x5 i - {
& o3 P! g* C: M/ o% Z - _Error_Handler(__FILE__, __LINE__);
* D; m' _. n: F - }( X8 [) l. ]$ n5 a0 l: o! W! {
3 e7 [0 G3 _) I( C6 z+ n& T- sConfig.Channel = ADC_CHANNEL_2;* D% P- f( O/ u
- sConfig.Rank = 3;$ F( S3 ?& _% O- v G+ k ^/ ~
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)6 ^- p( v" T( R+ v- T
- {: l$ h: A& d- Y
- _Error_Handler(__FILE__, __LINE__);) r3 k" h# k+ H- ~8 G
- }
# O, Q6 h$ [0 n! K( u5 ]- ]
9 a( O) |/ A* t; w0 m9 b- sConfig.Channel = ADC_CHANNEL_3;) L% w, R( k, O
- sConfig.Rank = 4;
9 v5 S! h+ [* b7 S: O* Z - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
+ x. Y' v& B9 K9 g3 ~9 `7 J - {: S8 I8 @* ~# E; l' c
- _Error_Handler(__FILE__, __LINE__);4 l! n& S* R$ c1 U& _' k
- }6 ]4 `) C" P, u# ~
- 3 ^# I* M1 g4 A/ J5 i7 ]
- sConfig.Channel = ADC_CHANNEL_4;' r- Q, A. A, m* a& {/ W: J0 Y' i
- sConfig.Rank = 5;
( c; ` a' H+ ?& `$ e" m2 l - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
3 c8 Q; C- e8 |; m* R! o2 N. h( | - {
) S" H6 t2 ~# A - _Error_Handler(__FILE__, __LINE__);# E/ u% b+ w8 X+ b
- }
+ p2 S- t" A6 K3 E7 c E - ' P3 S4 H, w1 U, \
- sConfig.Channel = ADC_CHANNEL_6;
' H: F* _$ a L5 D$ y - sConfig.Rank = 6;
2 C6 c/ b/ U0 b) K2 [ - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
: j& n$ {+ c: U' ^, A - {2 L0 N& B9 ?* i, @9 J/ r- t
- _Error_Handler(__FILE__, __LINE__);
8 Y6 j. l) M# \0 [. ] - }7 i4 m/ c" U" I) a6 a9 }# d
- . Z1 M+ z8 U/ P* i; G
- sConfig.Channel = ADC_CHANNEL_7;) @/ F% b6 R& z- S6 t/ Z
- sConfig.Rank = 7;
; ^* z8 H1 U5 r% Q4 w; w& `8 T - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK). K* d$ N1 {* \: b: @
- {
( v6 k4 Z& R; A# T7 T - _Error_Handler(__FILE__, __LINE__);
) P3 D: i" _" \1 K; Z - }
% j: K9 E, W& x+ w! x, c& a - , L5 N7 B+ U0 H T' S" R
- sConfig.Channel = ADC_CHANNEL_8;" j. r/ [( E( E6 ^# T
- sConfig.Rank = 8;5 I! `4 F; J- x, k. J
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
% W i# S1 ?3 \+ a3 P. O/ H5 v - {5 \$ U6 K2 L0 C; K6 D9 A4 p8 b- b
- _Error_Handler(__FILE__, __LINE__);( u" t! [7 _5 d4 E4 X
- }0 @1 f1 V& n! A/ p7 r0 y7 Z: j' l
- & ^$ V* p: I3 X5 t# W
- sConfig.Channel = ADC_CHANNEL_9;8 Z4 |, b/ g3 o
- sConfig.Rank = 9;) W R4 o( O7 v" T2 o5 F' C" V
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)" q& ~. ^2 @/ K3 g/ h- H
- {
7 k. O2 w# X# N+ u* u8 u6 M - _Error_Handler(__FILE__, __LINE__);/ l7 o- {' m( a4 P2 o j, I+ e. U
- }/ K- S [+ Z9 h4 H7 p- g; p8 Q/ t
$ E5 E: l, C1 I G4 C9 v- sConfig.Channel = ADC_CHANNEL_10;
* P' U0 s0 a" E$ K4 G - sConfig.Rank = 10;& Q1 i8 h9 @! Y; _+ | p
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)8 t# {! C5 k' J% m. E7 b/ z
- {3 @, E/ u; L: U# _1 R
- _Error_Handler(__FILE__, __LINE__);. N2 N# d* \/ v
- }3 f: e/ w3 S1 }; t7 Z( L
- 3 x' m+ |! O* f; k' Z! }5 @
- }! L7 a2 {$ H7 n" w8 m0 u9 Z0 @
{2 x7 L$ E- k- void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)" y# h d( Y" |: Y( J5 }
- {" a3 D6 W/ a# s- |
+ L: F& y& | A8 x, U- GPIO_InitTypeDef GPIO_InitStruct;7 ~& u7 I: ~+ ?$ p+ |1 H7 X5 M
- if(adcHandle->Instance==ADC1)3 ^4 ]- ]" U8 o) r
- {
. }( g& i7 I9 @+ @: P0 ~# _ - __HAL_RCC_ADC1_CLK_ENABLE();
; ^1 r Q+ l8 p. u* {5 e. V( `" Y3 j- c
8 G/ [: d3 F+ k. g/ L! d q, b0 G. W- GPIO_InitStruct.Pin = GPIO_PIN_0;2 O4 ~' H7 x9 k& x9 u0 W
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;& r( V2 o. q% ~# n$ ~8 S
- GPIO_InitStruct.Pull = GPIO_NOPULL;' m- p+ y! W: q7 V4 R# e! }
- HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/ s* a$ S, ~9 v( @* a, v* i& N - GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
4 |- |% {7 }2 t( h! d - |GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_7;
, b- d3 v/ p" b; F - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
' x% \8 t a; _3 a5 Q4 Q6 H - GPIO_InitStruct.Pull = GPIO_NOPULL;/ z8 {6 K) X5 [6 Z# p% G
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
0 g/ ^ o, Z1 Z" B3 f - , E1 a$ z8 D) s& \( P" M0 F2 g5 _
- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
2 K! J. A% f5 ~: U" S R$ T/ q - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
1 c2 H$ D+ H: r& v - GPIO_InitStruct.Pull = GPIO_NOPULL;
! f+ c$ ]' q6 u. J8 F - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);6 l8 g$ q7 X5 V$ r( r9 |% J5 x
- hdma_adc1.Instance = DMA2_Stream0;9 K# N$ i; ^5 ` n- R: P0 V) r. f, @
- hdma_adc1.Init.Channel = DMA_CHANNEL_0;
' B, O* v; Z( t7 q0 t t( x - hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
& r1 ?0 k5 v4 U0 A; m& n- b - hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;+ q2 d# R/ m3 v* I# y" }& A
- hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
" L+ q3 i! n) p8 L# q - hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;+ n" x3 D. f! E) n. m7 U! D
- hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;" x+ U3 t# J H. V6 X
- hdma_adc1.Init.Mode = DMA_CIRCULAR;$ A. u. ~! e" w7 m, U( d1 y# b2 w4 b
- hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
4 F% W& \) M- l/ Y - hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
" [" Q5 i* ^) U2 i - if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)- }+ w) m2 p+ G! O3 |
- {
+ l! F4 n7 j, \3 v- r - _Error_Handler(__FILE__, __LINE__);# l$ W4 c0 p; C) J( ]9 C
- }, i' m; ~: q$ e( ^/ D) f
- * T. R/ I9 T' }& H( W# R" F
- __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);1 \9 i2 t: D) e0 K# q
- ; M2 P- x0 u) X# d, l t7 Z
- }" q) o& g7 X( ^6 B
- } _! B. e. @- r
- ' O6 |& d+ L! R; A
- & @8 ]1 e" l* \/ a
- ! J3 t( |# O5 R4 c9 p1 Z
- - i2 v" o" m2 _
1 _" l8 ]9 D) i
9 j! T- o% B) ?' l* t
复制代码 http://player.youku.com/player.php/sid/XMjk0ODczODg5Ng==/v.swf2 F) U0 K3 E+ t
* R' a+ K/ G9 @6 p: r0 D: d
由于STM32F446的快速处理信号能力,本方案中同时开启10路带DMA的ADC处理10路50HZ交流电压绰绰有余。演示中在OLED屏幕上显示ADC0通道的转换结果。
4 c+ C. Q: L* ^4 ]( {* S: D
; P" v. S5 ^" F) L! u. r
# l1 m: F0 s) [1 i) v# [ |
楼主,你没有用示波器实际量,采样电阻出来的是个交流正弦波,有正负。所以你直接采样ADC等于把负的忽略l了,这样采样玩玩还可以,会对单片机的ADC有影响的,实际工程项目不能这样做的。
输入级的电阻我知道,我选用300K 的,我是说输出级的、后面我查阅相关资料,你选用的互感器没有标明线性取样电阻,我选用的标明了。
相当于取了绝对值,求RMS无影响。。。。。。。。还有疑问你这个互感器DATASHEET上就是写采样电阻那么大?就我所知道的,都是采样都是100R以下的
STM32CubeMX,到ST官方网站下载。2 \3 h8 f( W( w0 ?$ e! v
https://www.stmcu.org.cn/document/detail/index/id-2180027 E( K8 `5 S& j# K
9 R" y& p9 h' t9 p9 w
经过电压互感器后,次级是完整的正弦波。采样48次耗时20mS,就能够覆盖整个交流电的一个周期。
那互感器出来没有负电压么?我看的采样后直接接ADC了
互感器次级把初级的负电压“垫”高到VSS了。
噢,你用的是什么型号的互感器?