本帖最后由 wenyangzeng 于 2017-8-6 21:13 编辑
1 |, }5 E' A0 o' [/ e' A; E- p! l5 N) e" q
基于STM32F446的交流真有效值电压表 w+ O7 A$ B4 x' w8 u
, s, W+ Q& b1 y& M- {( B( U
一般的数字万用表的交流电压的测量是采用将交流电压经过整流后测量其有效值,由于整流二极管的非线性,使得该测量结果误差较大,不是真有效值,特别是对非正弦波的测量更是如此。
4 e: o4 l( s3 |( N0 q# G K8 C 本方案基于使用意法半导体的ARM CORTEX内核的STM32F446交流真有效值电压表,克服上述方案的缺点,使得对交流电的测量更加准确。9 X& f9 a; Y* s/ p: P
交流电的有效值定义为:
) E- `6 l" `0 B9 v0 J, M. @
5 K* s7 _. K' h" ^; C' O u9 s! N7 l; D: O3 W/ m4 w
" A- J* M' M( v: J8 l% r
对其一个周期内连续采样后,根据以下公式进行计算得到结果。
5 Z$ W4 c/ U. X' Z
: d% z; ]4 } A6 U
硬件连接:: Q: b9 L7 A3 S5 ?. C
# g. b- }6 `$ @: h: |! {
; H' ^0 U( P# h1 q
* a. R0 N) t: n7 O. G2 S* {220V交流电经过1:1电压互感器后与STM32F446的ADC0连接。
! R& v) E/ x9 Y2 s: t) K: b5 d; s1 m8 J
. P' U- M# b8 C) n0 p3 Q
5 s! Q7 @! m+ E6 t) R4 D3 z& P
ADC通道配置
& M1 @. {) K' x( T1 l
# Z- T+ w0 N4 g2 x+ c8 v9 l9 R
时钟配置- k2 B+ L- Y+ b& P
6 j$ W, L! b( X& X ADC参数配置
' L2 T/ l2 l4 N8 _' W4 Y
+ } g8 A" S7 a9 X, g关键代码:
" f+ @/ L! K7 ~ S: e- //MAIN.C
M, A0 e, U# q- y
% _' ^; V/ L) H! t! ]( _* Z7 i! _6 A; \- #include "main.h"
5 N4 ^ ^8 \5 T( } P( w/ O - #include "stm32f4xx_hal.h"
% R1 `- {5 V' f9 u. Z* t, o - #include "adc.h"
% d% L U( A$ b+ P' m* n' O - #include "dma.h"2 y2 H# y7 e- f' H& Q
- #include "tim.h"- r: W8 [2 O& T
- #include "gpio.h"
! m1 W' t) x4 f9 ~" |* ^8 G - #include "math.h"! x3 @) z b! N+ k/ p3 t Z7 t
9 }$ C3 e3 m2 ?7 x- #include "oled.h"
1 e; {: Z6 t2 I, Y$ E - uint16_t aADCxConvertedData[48][10];
+ A& ~; C' b% l$ p - uint32_t Resture=0;
; h$ R5 W `4 u6 s* g- ]# F - uint8_t Disp_buf[8],Flag;
6 h! r% j: @8 z8 M3 t) W0 C - uint8_t j=0;! a/ F7 Y" A- m7 S
- void SystemClock_Config(void);
0 a$ _3 ^. w) d% ~
6 U! Y- ]% w4 Y5 l- void Get_ADC(void)5 p9 N- O; _9 j) _, w
- {uint8_t i;
( G* b s* ~, ~; _: B" M- }0 L - static uint32_t total;
) X( m; M5 y9 n& X! y5 B - double temp;% M' Q/ {2 y* E# y! S. `
- . |0 F' D; u' F% A. ~
- 8 f' }% M/ L/ T6 ^9 i: L
- total=0;: v) k' f" @. F9 q+ g7 C
- for(i=0;i<48;i++)' {4 k6 f) G* z4 s% \
- {
& B, N# {0 ~5 x# y! n! ^+ D - total +=(aADCxConvertedData[i][0]*aADCxConvertedData[i][0]);
5 i$ s6 y( U+ s% N - }" A1 Z1 h+ a. ?( s
- total /=48;
# u+ Q% W! B8 V& U" y - temp=sqrt(total) ;4 c6 j/ k, D. `( z
- Resture +=(uint16_t)temp;
: ], a1 @5 p. A: s, ~ - j++;
$ e! N* B1 E9 C* B0 R* \ - if(j==32)
7 J2 a0 X6 S# Q* u$ s" c! s - {
# y2 x& s ~& ]8 b7 g ] - Resture=Resture/64;
$ V" u) _6 A7 c8 n4 r1 g - Disp_buf[0]=(Resture%1000/100)+0x30; " x& c" m* x' L$ z- E1 w4 @* `
- Disp_buf[1]=(Resture%100/10)+0x30;
" ]9 z* I( R' y- U4 h1 ~ - Disp_buf[2]=(Resture%10)+0x30;
- x) J9 J; ^0 Z5 O - Disp_buf[3]='\0';
8 G$ E) D+ ], U' F9 p! G- T - LCD_Print(40,46,Disp_buf,TYPE16X16,TYPE8X16); ' A" V7 C8 |% v* B8 h
- Resture=0;
, C% w) c' Y5 U3 X6 p( t; \0 `3 \ - j=0;# Z! w" [6 h, x5 n. O
- }1 t5 X8 `' | V. f& ^2 e$ r* m; a4 ?
- }
2 ^1 g2 } h" X- }: s
! M$ ?& {* s0 @1 x+ F. b# O" f- 0 T% C4 F' L5 C) J$ b1 U2 N
- # w4 u7 u3 l7 g5 W. h$ V
% y g( t' ?" ^% ~2 r- int main(void)9 b0 E' z. }0 e
- {8 u2 c" j8 L) C4 P# f9 B
- 2 I0 l% W1 j: M, W7 N
- HAL_Init();: l; g) f3 \* I8 w5 m# a
- SystemClock_Config();8 m! |: \: s6 m0 F8 l
- MX_GPIO_Init();/ W" a+ u Z g0 M8 @/ d" ~1 h
- MX_DMA_Init();
9 U6 P. F% C! Q D* s - MX_ADC1_Init();9 m$ b% ~# j- o4 G/ E$ O0 v9 X" M
- MX_TIM8_Init();1 @1 f# P b9 J
- HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);6 n& R1 r& C0 t% ], C6 k
- ! _+ N- ?6 ]& L0 ]$ x
- LCD_Init();
$ u7 T% k# X) y1 }6 T - LCD_Print(0, 0,"STM32F446 Nucleo",TYPE16X16,TYPE8X16);8 R9 |% A* s) Y$ n6 i6 }$ M
- LCD_Print(0, 16, "True effective",TYPE16X16,TYPE8X16);
# P: y6 o. Z8 P+ o - LCD_Print(74,46, "V",TYPE16X16,TYPE8X16);
# F. w- u; f2 w! `4 O -
- g9 d3 g: Z5 e% m - if(HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&aADCxConvertedData,480) != HAL_OK)
7 Q- @+ ~ u2 E& p - { h3 d- t$ M0 ^
- Error_Handler();
- w. E1 L8 E7 }7 X; X+ z+ N. j - } ' d. X& n. ?- K
5 ?0 F/ g- k3 T% F, C( J- while (1): D" l/ u+ x" H& ^- |
- {! A( z2 F) M$ J0 m$ ~ I
- if(Flag==1)
) t9 H9 H0 v& l: }8 {9 [ - {
# R9 |) u' b/ z6 f1 `. k - Get_ADC();
* l4 A Q* E ]9 ]) v2 h7 J - Flag=0;
4 m+ u4 \, J0 W* s# j1 s$ z - }
# z; X) u- Q, H0 W5 G: C q - 6 j. f; G/ i7 d
- }
* X) Z! K0 b, W! p - 2 T' p; ^7 Y m7 I- t# @
- }
( u# }2 _/ y/ R6 T6 W - 1 [/ q! Y! L, d* ~8 M0 M) E) U* ^+ ~
5 a" x# a* W0 p/ @+ ?0 @/ E- //ADC.C7 C! b3 C/ _# Z0 p& g6 T
- #include "adc.h"
6 Y* ?9 J8 s1 x$ X; i$ P - #include "gpio.h"
0 K* T: I6 G& ]+ { Y$ A" Q& C - #include "dma.h"2 ]) t0 [: _; E. `8 v# @! B' {! [1 i
- ADC_HandleTypeDef hadc1;! ^. g( e- S' o4 @/ ~" U. u% a0 w
- DMA_HandleTypeDef hdma_adc1;
* Z5 N; @+ @$ w5 S% X - void MX_ADC1_Init(void): S/ K4 j# S8 b ^
- {
0 w# h8 r$ w, l+ S8 E+ N - ADC_ChannelConfTypeDef sConfig;2 c! G$ H. k8 l. I E: I. w
- hadc1.Instance = ADC1;9 l' c4 X$ r. q, `4 o9 ^- Q8 ~
- hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8;
+ [$ ^. f( C) d0 p3 S8 f - hadc1.Init.Resolution = ADC_RESOLUTION_12B;
- Z+ \2 w( Z" b4 u- p5 Y5 } - hadc1.Init.ScanConvMode = ENABLE;
3 t( R* x4 y: q - hadc1.Init.ContinuousConvMode = ENABLE;. D: V, Y# H( E+ d9 o
- hadc1.Init.DiscontinuousConvMode = DISABLE;
$ \. `. C7 n' e) F" ?! ` - hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;4 v2 L+ y7 c; N5 {, y
- hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;# l5 I9 P C; d/ ]
- hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;* {: Y h" F7 i6 I& m0 z
- hadc1.Init.NbrOfConversion = 10;; A: L2 Z" G) P! B/ g ~. C
- hadc1.Init.DMAContinuousRequests = ENABLE;0 T5 B4 u3 L$ Y6 w6 f
- hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;5 _" j( I" v5 T8 t% f
- if (HAL_ADC_Init(&hadc1) != HAL_OK)8 W& a1 M8 ~; f
- {0 |' y& X: D' G$ p2 v! T
- _Error_Handler(__FILE__, __LINE__);+ E* i: b; G' F S. z
- }1 K, }- |. O) X, O" U
- sConfig.Channel = ADC_CHANNEL_0;9 c( v3 t$ e- u7 ^
- sConfig.Rank = 1;
1 u2 z" C7 C1 h/ j& A4 n - sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;# ^1 W, U) [% c: C
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)+ o' _& ?) E6 C# V/ l( U
- {2 K1 \$ V: E$ e& [
- _Error_Handler(__FILE__, __LINE__);3 ]- F/ h' J! i5 {# \
- }
5 N' w8 s- G( u/ a0 S8 A5 V$ G/ F
7 G: C2 m9 Y+ x4 b. W- sConfig.Channel = ADC_CHANNEL_1;- e( g |1 H7 L3 K0 x! P9 u
- sConfig.Rank = 2;
: k. w( U& V7 [; h8 [/ _ - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)3 [" |8 Q+ L9 J2 m
- {
5 l, p: h6 c- ~+ m - _Error_Handler(__FILE__, __LINE__);
( U" j( A4 A- \5 ]( m- ] - }0 v5 B. b, t5 }" ~' D1 h
- ! n/ O5 d) k& q
- sConfig.Channel = ADC_CHANNEL_2;; z/ q, b2 g! g; F/ [
- sConfig.Rank = 3;9 S5 m) z/ A h
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)3 F! s) E/ p1 o* i" T" D
- {9 q2 Q9 V: E9 K# v* G
- _Error_Handler(__FILE__, __LINE__);
' `) o2 o9 O! G - }
* w2 ?, F; x7 q: t5 @. x1 l
; H7 G; E$ J+ U0 M) K/ h- sConfig.Channel = ADC_CHANNEL_3;
$ k( q! s& O, Y% H- S) D1 v - sConfig.Rank = 4;
8 }2 N' @' w& ]0 W t - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
' c2 m% _; N2 h- G0 P - {
8 J# y9 A5 F! o, G8 T! }9 \/ |2 S - _Error_Handler(__FILE__, __LINE__);
6 d$ T/ B0 {9 T- ]$ p9 | - }
( f2 }4 |8 Y$ k! s R- I% y - 9 O' k, W: u! x' n
- sConfig.Channel = ADC_CHANNEL_4;
5 t* E0 ~' l* o - sConfig.Rank = 5;3 \) u+ e. ?' @! x- m4 G
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
: A, C/ H4 G8 G* M& |) B) D+ ? - {
: o: v8 Q3 d3 z* e* g0 M' V - _Error_Handler(__FILE__, __LINE__);
" j1 h/ G- t t1 D' x& V) _2 M - }
4 S0 b8 B, C" k( X: T4 l
" K6 O- V8 ^4 T- @, F6 M+ I9 \- sConfig.Channel = ADC_CHANNEL_6;
! n6 [ C0 O) D& N9 t/ z: Q - sConfig.Rank = 6;
- j* M3 w% C6 ` - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)9 m3 C1 \5 h y d& m4 ?
- {
( Q: H; }( q$ }2 B! Q8 H - _Error_Handler(__FILE__, __LINE__); Y% G" _) r& K- d7 \
- }
% O$ p/ f' S. K+ n0 O
& }# H, z$ D: `- sConfig.Channel = ADC_CHANNEL_7;
3 k' O3 h6 {7 u" T( y+ ?% w - sConfig.Rank = 7;
, `. {' x4 g5 e( {) ^6 x. n - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
1 Y( a& r( }: l. `* Q6 Q9 Q$ w - {
) c s0 a7 k; z - _Error_Handler(__FILE__, __LINE__);
$ [& F6 z$ s9 G3 R - }7 V8 s a1 B9 [6 e- [
' N: A9 I+ h: B+ `# b! V- sConfig.Channel = ADC_CHANNEL_8;
( ~- E5 Q! N) y" c - sConfig.Rank = 8;; h, L+ M: s# o; K5 o
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
" y% @5 J! l4 u% ` - {
5 ?( w: B4 z1 r3 k& Y - _Error_Handler(__FILE__, __LINE__);
# s9 k) M7 s6 v. v- g% f) F8 W - }! O, x7 x. y4 |1 f, R. \8 C, v l
8 g3 ?0 G- t8 \5 S- sConfig.Channel = ADC_CHANNEL_9;: {9 A+ V" R6 U6 ~5 Y, ~
- sConfig.Rank = 9;
( d: U. Y6 o+ `; K2 I e. R9 M - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
& }, i# P, V5 A5 O# O6 V" m& ]8 O - {5 k/ v" y- s, @/ Y* ^
- _Error_Handler(__FILE__, __LINE__);. d1 ~- t' E3 ?5 ~
- }
7 ~+ n- c0 l9 @1 p1 d# f& ?
9 L6 O: _7 x" _( q' T# S- sConfig.Channel = ADC_CHANNEL_10;- g( `2 G9 P4 f8 w$ Q" E& Y
- sConfig.Rank = 10;
% t/ z2 @ r' A. D- ^/ @ - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
3 Y1 i9 D7 p; v$ r) R/ i$ q" z - {
/ J) p9 Y7 `% Z* r' I - _Error_Handler(__FILE__, __LINE__);6 H3 R, V" t& U' A+ J
- }- K5 N: k$ Q% \ A m# k
- # m6 ?. E2 {9 v5 {; m% H
- }, j9 Y5 ]! z( ^+ j P0 M4 M# e
7 `* [# A w# a* p- void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)6 I) W( l: V I- A/ p! s
- {
7 K6 W# E1 |. c9 T& Q4 C5 E# r
% j6 E' K7 r- g) e- a2 A& h6 b9 `3 ] D$ o- GPIO_InitTypeDef GPIO_InitStruct;
7 }1 g% f% K; ]+ N* ]4 W - if(adcHandle->Instance==ADC1)
: L# Z. @. j: V! n - {% n$ {$ X( M3 i
- __HAL_RCC_ADC1_CLK_ENABLE();
# ?0 C; x3 t+ h - 9 m- x# n; Y; c# x* ~; P
- GPIO_InitStruct.Pin = GPIO_PIN_0;
" u$ x9 @: ?' u - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;4 t( {" Z h: x5 V0 T
- GPIO_InitStruct.Pull = GPIO_NOPULL;
4 ~0 s2 S N4 r/ n. O+ [ - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);! R% Q" a' p- c" B! m# `: d
- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 ' ^* W2 u6 |5 U/ @% w/ d' O" s
- |GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_7;
% L) J4 h6 j( C: J7 c- d0 [ - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;# a; O: ^ s- R& T0 h; [
- GPIO_InitStruct.Pull = GPIO_NOPULL;3 d5 D/ c s8 n4 o( d
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);% R N2 D# b" g, P
- & g( l/ Z/ R" E0 ~. m/ G# s
- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
) P) C/ k, b6 s8 [) ] - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
( l7 W, ]' g- n e2 ? - GPIO_InitStruct.Pull = GPIO_NOPULL;' F0 p! i- T/ B, X5 }7 q9 c
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);! P/ P! T7 @3 U& r8 e0 P
- hdma_adc1.Instance = DMA2_Stream0;9 i1 D/ O7 c. N0 s; i- g6 t) J I& r
- hdma_adc1.Init.Channel = DMA_CHANNEL_0;
' s/ ?3 @8 f7 Z! H, o! D - hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;7 B$ D& J( N( a
- hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
/ l1 t7 d' n2 i7 i) z8 g$ \! ` - hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
1 z: B) U% k6 E- o - hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
( x4 W. S" X+ _ k# T( b: k - hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
% v& E9 N$ J2 g - hdma_adc1.Init.Mode = DMA_CIRCULAR;4 ^: R3 L( e" X# {
- hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;' H8 Y' E& T5 f
- hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
$ i9 T' q# n/ r& A) I6 | - if (HAL_DMA_Init(&hdma_adc1) != HAL_OK) _3 S* I8 e! I3 z8 ?3 z% f3 @0 o# B
- {) G' l2 A/ g- ~
- _Error_Handler(__FILE__, __LINE__);9 `0 m! U8 c+ t& D5 ~
- }
# I* N: ]" e3 a - . ]$ D) q& y4 E, ^8 Y
- __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
n) p! @0 C: D0 E3 q; M - ) g. m2 W5 m, G; G, X0 h- u
- }
: I! E: @. O8 ~, n6 o - }% @# t- T* c8 Q$ F7 T1 M- z$ j7 R
- # O5 l# |8 e9 B% @
- 1 M2 f9 @' X! w. u8 T) O- Z
- * w9 w! f- R0 G! v
- U/ `* M5 U- R
: W8 H% F: ]& `
- o5 l1 q2 R8 t
复制代码 http://player.youku.com/player.php/sid/XMjk0ODczODg5Ng==/v.swf
" j3 _8 A9 F* K1 Y8 B! q# `8 d; V! K7 @* |5 ^ B2 h
由于STM32F446的快速处理信号能力,本方案中同时开启10路带DMA的ADC处理10路50HZ交流电压绰绰有余。演示中在OLED屏幕上显示ADC0通道的转换结果。
! {% X f4 z T: e# {8 ], o: H/ M- K9 r" N& l
: E( ^ B' e" b. ]
|
楼主,你没有用示波器实际量,采样电阻出来的是个交流正弦波,有正负。所以你直接采样ADC等于把负的忽略l了,这样采样玩玩还可以,会对单片机的ADC有影响的,实际工程项目不能这样做的。
输入级的电阻我知道,我选用300K 的,我是说输出级的、后面我查阅相关资料,你选用的互感器没有标明线性取样电阻,我选用的标明了。
相当于取了绝对值,求RMS无影响。。。。。。。。还有疑问你这个互感器DATASHEET上就是写采样电阻那么大?就我所知道的,都是采样都是100R以下的
STM32CubeMX,到ST官方网站下载。- h& b! _, ]6 d& x/ `0 w. S
https://www.stmcu.org.cn/document/detail/index/id-218002
: N9 R' T# Q7 r `
- P7 O9 h9 h: P" p( r1 |& u
经过电压互感器后,次级是完整的正弦波。采样48次耗时20mS,就能够覆盖整个交流电的一个周期。
那互感器出来没有负电压么?我看的采样后直接接ADC了
互感器次级把初级的负电压“垫”高到VSS了。
噢,你用的是什么型号的互感器?