本帖最后由 wenyangzeng 于 2017-8-6 21:13 编辑 / K6 x. c0 c6 g' F
, [, _4 |" H5 L0 n2 g! p+ } @
基于STM32F446的交流真有效值电压表
/ P( Z1 p, ~# o. V. N
, w4 [# r2 C: o9 ?" ]$ G# `- K 一般的数字万用表的交流电压的测量是采用将交流电压经过整流后测量其有效值,由于整流二极管的非线性,使得该测量结果误差较大,不是真有效值,特别是对非正弦波的测量更是如此。% v' y! f2 u1 j9 G( `6 S k
本方案基于使用意法半导体的ARM CORTEX内核的STM32F446交流真有效值电压表,克服上述方案的缺点,使得对交流电的测量更加准确。; Q4 r2 `9 Y. r/ G
交流电的有效值定义为:: q+ {$ F3 F/ q2 k; G6 ]
6 Y. [# ?8 Z8 L6 c6 E3 i. \5 D# r
7 n: i1 B( \- b. s2 R$ {# r
T! w: f% h( q5 t9 [ 对其一个周期内连续采样后,根据以下公式进行计算得到结果。
3 `/ L. G% ^, ]/ B' ]3 F
5 a0 }: z3 w2 Y2 D) o
硬件连接:
! p" u6 ?- w& q& R
6 g1 h) ~$ O2 F5 T4 I
8 G w3 s3 q3 n5 E
) W7 ?; \5 p1 ?! |2 d* n220V交流电经过1:1电压互感器后与STM32F446的ADC0连接。' {$ f" U7 h1 c) V5 d
- ]; r4 q/ D+ c4 ~; }
- d+ e+ M: J5 i$ _ A
& N1 W3 U2 i e8 t" [ ADC通道配置$ v$ z7 |% h' _ U4 b; ^
/ b9 U5 O5 P( }2 n 时钟配置0 e7 m. S/ o4 E3 E& j8 H$ R
3 I+ z) g( x9 m, k0 }5 Z
ADC参数配置- `) ^* V3 D! a& S2 V" _
0 a5 d( v$ t/ c) Z关键代码:% o0 ` \5 f: y- s4 g# z
- //MAIN.C
1 _+ f# z5 E' ^1 ]; J) P7 w - # ~1 v' M. X% i: R
- #include "main.h"! {/ Q* P- r9 }( K
- #include "stm32f4xx_hal.h"
& i& x4 h2 n3 L" B# c5 a2 d5 B - #include "adc.h"
7 i; \$ b# B% ]. `7 W- G g3 ~9 t - #include "dma.h"1 x) M! [# g% u3 k2 H Z
- #include "tim.h"
3 ]2 _/ l8 m3 D2 y+ ` - #include "gpio.h"
7 M) t$ b' E8 n - #include "math.h"' [8 {& [8 [! n1 `, ~& [1 d
- / }9 F5 {4 A- y2 B# u5 A
- #include "oled.h", w1 W. ]! e/ R9 L& y
- uint16_t aADCxConvertedData[48][10];' a6 `: l* E, F+ Q; ^
- uint32_t Resture=0;! ~! Y& _# l6 Q0 X, [7 g
- uint8_t Disp_buf[8],Flag;; N/ Y7 e+ d1 g% Q9 l. b' n8 X% b# G
- uint8_t j=0;
" [; Q2 N: ?5 u5 K - void SystemClock_Config(void);
& l/ I. Y7 m+ Y0 h - : n! `) P& i2 R& W5 v+ F
- void Get_ADC(void)
& F% o4 O' A& Y" C: o1 p - {uint8_t i;) p8 m6 q/ M. |
- static uint32_t total;' h4 [! n0 v6 m9 x
- double temp;2 B2 V1 y3 w. D% C! S
- 2 B3 P6 H* q8 H7 ?, Y
: ~3 H- I; U. M2 C! b' J' B- total=0;
2 Q0 p+ V5 P2 r0 C3 y+ d% \5 u - for(i=0;i<48;i++)
9 d3 ~3 k" o- `1 {- Y - {, O, f1 E! L* s8 U2 d
- total +=(aADCxConvertedData[i][0]*aADCxConvertedData[i][0]);
. _- _1 J: g: q; [ - }3 l. `7 c J4 W" W. ?
- total /=48;
8 p9 H6 @. q Y- p; F4 }/ T - temp=sqrt(total) ;9 ?1 D6 Z6 F! w" S, z
- Resture +=(uint16_t)temp;( o+ p* X3 y5 k9 q5 S: z
- j++;
- Y% K9 J/ T' ~* j3 h - if(j==32)$ t$ S5 P) J& f
- {; y8 N2 R' k+ u7 U F. ~6 e; f2 E
- Resture=Resture/64;) ~5 p! L) J( C0 B$ O1 p! Q2 b# z& S
- Disp_buf[0]=(Resture%1000/100)+0x30; 3 t- d6 o, H) L+ Z
- Disp_buf[1]=(Resture%100/10)+0x30;
7 ]* L. z4 w( R6 q: T - Disp_buf[2]=(Resture%10)+0x30; ; T% U2 y3 |" l5 Q) D
- Disp_buf[3]='\0';! M% f ^' U: s1 Z' \2 O, E
- LCD_Print(40,46,Disp_buf,TYPE16X16,TYPE8X16);
2 Y/ M7 |6 }8 }+ Y% W - Resture=0; 5 x3 q4 j! g3 z# K
- j=0;
1 ~* k, n2 H6 D" F- x: l1 e* p - }! A- l' H7 x0 M( t" j0 ~4 m+ ?
- }" A2 ~/ z: {2 t& @8 G! E: v
- + ^/ r/ o+ f* Y7 ^3 C0 D
- 7 w, T% @/ v6 I( X5 a
- , P; r& }- u. N& S9 b
K5 ~1 r( m4 Z2 p* S$ u- int main(void)# n% e; V% h; F0 L$ L5 W
- {: K9 G; p5 @3 ]$ e
- 9 j2 P' ?6 z4 a3 ~8 R7 r
- HAL_Init();: N, j$ J& F+ F6 I) {& D* o
- SystemClock_Config();. h5 h( I; W3 N) }$ ~7 Q
- MX_GPIO_Init();1 k" e" U5 L8 i8 @' ?
- MX_DMA_Init();
+ z1 n) F* |; V2 ^7 X - MX_ADC1_Init();; ~9 u/ L4 v$ G% |* B! W
- MX_TIM8_Init();8 s% V' I/ \! u
- HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);" z0 s9 l' e) [2 V4 I( o5 o
5 c- j; A* M4 ~! j; l0 W' @- LCD_Init();
. `) d+ t7 J M* o - LCD_Print(0, 0,"STM32F446 Nucleo",TYPE16X16,TYPE8X16);% Z5 i' S1 O9 F+ n
- LCD_Print(0, 16, "True effective",TYPE16X16,TYPE8X16);& ]3 x; A/ y1 W
- LCD_Print(74,46, "V",TYPE16X16,TYPE8X16);
8 ^* H, A, ?( v4 y: W& X - + A! P6 w* \3 Q Z- o! q
- if(HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&aADCxConvertedData,480) != HAL_OK)$ P# |* z/ U- v8 {# |
- {; z( {+ b, _; e' i/ d
- Error_Handler();
* S+ e) e Y( ^/ o" A - }
6 n: p/ c y# i( F5 ^! t$ j1 s - : k: m4 `9 y# p# W4 \( }: p
- while (1)
$ @8 D9 P/ |, u4 d - {
7 Q4 q `1 n0 l- @6 {7 y, t - if(Flag==1)
& M" T+ F- L: c - { ' J5 z( v. K/ T$ W0 }' I4 @% B
- Get_ADC();) S* H( `6 p& E7 S3 ^
- Flag=0;* b; T0 l* _+ `' x* c! k9 Q
- }. I, Y+ S: ~0 ?% q8 o1 U$ h
- 1 q2 R2 i L0 J/ z
- }
0 Y# `3 R3 x3 t' O; n/ _1 w
" a% i% l/ h' n& V3 J' l$ M' Q- }
) {# g3 _" ]2 W. s7 a - * d, N; P+ a( ^# J
% |& [; W/ X. `/ l% q& C ?- //ADC.C
5 d- v$ T" H' k - #include "adc.h"
$ V1 N% E" z9 D# v3 U- n' M - #include "gpio.h"
$ z7 G$ o) T( O$ m( }1 w' U - #include "dma.h"; r Y1 N7 B! I1 s" A( u
- ADC_HandleTypeDef hadc1;% v- H* f+ @5 N# N, {
- DMA_HandleTypeDef hdma_adc1;& z; c8 o( D3 [) o6 ]
- void MX_ADC1_Init(void)
* b. q {6 r! D! `0 d( n# K - {
- I1 ?# t4 L- P: Y& u - ADC_ChannelConfTypeDef sConfig;
6 j1 O s1 @7 m4 C, x: R% e; d* \3 K - hadc1.Instance = ADC1;4 x: f# U, |% d/ K
- hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8;
; R- Z/ i) L7 I4 w - hadc1.Init.Resolution = ADC_RESOLUTION_12B;
: \3 ]3 j" `2 P' y5 q+ i3 q% B/ E - hadc1.Init.ScanConvMode = ENABLE;
; w" t0 \3 r7 Y5 F# x - hadc1.Init.ContinuousConvMode = ENABLE;
# k/ g' b1 p+ }. o5 P - hadc1.Init.DiscontinuousConvMode = DISABLE;/ ?- a; D6 ~* R( ~" a
- hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
- K) U, Q' U5 `4 F7 B - hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;- Y; I2 {& c/ Q+ ~! h/ V
- hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;+ X5 n* Y/ C; [; A$ ~' E6 l3 E0 p
- hadc1.Init.NbrOfConversion = 10;
# E; B( l& |: v' I; g3 ? - hadc1.Init.DMAContinuousRequests = ENABLE;& W* z8 ]- H1 r2 N
- hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
+ i$ {% [0 k1 o" w/ l P; [; ~8 f6 X - if (HAL_ADC_Init(&hadc1) != HAL_OK)
S4 f* z2 @* F8 s; { - {
6 e$ p* ~& ~4 m# x7 L - _Error_Handler(__FILE__, __LINE__);6 A6 h7 y |8 g) ?3 L0 N$ b3 Q
- }
1 J) `( F; A- x: C/ f0 v' w - sConfig.Channel = ADC_CHANNEL_0;1 F3 Q; x" U6 [0 x& s+ h3 U+ d
- sConfig.Rank = 1;
- k, [7 a/ K5 u - sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
& ^/ F' A9 i9 F, X3 S - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
* W9 _: _7 d* q2 I - {
$ r8 f% P$ c c ~ - _Error_Handler(__FILE__, __LINE__);$ W9 K# W* G% |! N
- }/ R5 R e, t: r2 f
3 D2 T8 q1 N6 n3 U- sConfig.Channel = ADC_CHANNEL_1;5 Q$ B/ w0 z8 o' L3 v" L
- sConfig.Rank = 2;' l4 D: B( L% \- S
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
* J4 u1 A, C2 D+ c9 A. @ - {' N. c- |8 @4 _3 D; @
- _Error_Handler(__FILE__, __LINE__);. L4 o% k! b. R) ]- j
- }
3 Q) m3 B8 ?1 G - 9 l N% S3 F8 P( `- b
- sConfig.Channel = ADC_CHANNEL_2;
. P: a1 J$ ^8 M% P; A% k - sConfig.Rank = 3;
/ }9 _2 [" N( e" F - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)0 } I# `5 ~5 M! |
- {
+ U2 d4 u" ^. t" A* @1 V& l - _Error_Handler(__FILE__, __LINE__);3 O6 ^: [/ s* }$ b) ^* ^
- }
3 u7 X ]! f- z0 C5 J! R* D
. E- Z, z% H, f. o- sConfig.Channel = ADC_CHANNEL_3;( A4 g+ ^( [" J
- sConfig.Rank = 4;( d6 T5 P. H: z2 D
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)3 I% c, J1 d x2 A5 D. h3 U+ I. n
- {
4 m: _9 P. S) Q$ C( k0 s - _Error_Handler(__FILE__, __LINE__);
! H" v) d* ^2 o; M! H; n - }
, ~- j# L9 k' a
- d/ A' ?' ]2 Y1 v, ~- sConfig.Channel = ADC_CHANNEL_4;
/ t6 g' k, `8 K% R - sConfig.Rank = 5;8 t' `+ Z2 J) f2 S2 z6 N @% {
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
$ \: q8 P4 i: H3 {" C9 Q f# k! d" |: h - {- b' p" E1 p+ m
- _Error_Handler(__FILE__, __LINE__);
' R8 B; d/ Y6 K3 F - }
# T. d( k# {0 u5 Y+ \ - ! ~, `2 S+ D2 G0 x# i2 H0 r
- sConfig.Channel = ADC_CHANNEL_6;
5 l8 i' V' A. D7 |. c: o - sConfig.Rank = 6;0 i9 B6 N: L3 I! G% D
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)* R% ?1 T& h. R$ j% s* V/ Q
- {
* A# A7 D' a" K+ c - _Error_Handler(__FILE__, __LINE__);9 V; n3 }$ [( f
- }" H& M5 n% I5 u9 W
- I8 W& ?+ E) C* |7 z
- sConfig.Channel = ADC_CHANNEL_7;) w3 t7 U. i f
- sConfig.Rank = 7;
. k& E, a! Z$ S9 T2 W - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)7 r6 B) }% A* a
- {! V. i$ `) P* m# x+ N1 ]5 X* S- Y
- _Error_Handler(__FILE__, __LINE__);
0 b2 S. e- \1 @. {2 N7 L- M7 p$ H1 O - }2 a# ?9 s6 B7 o. m" D
& j# ]* j. u" D* \; Q# T- |- sConfig.Channel = ADC_CHANNEL_8;5 n3 y% P% O: b/ B
- sConfig.Rank = 8;2 o3 ^% q, w( d# L9 T$ o" m
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)- o7 t/ {& `* M* R
- {
% t! {: M2 f, l4 I& z$ c - _Error_Handler(__FILE__, __LINE__);
0 `* u- ^+ E+ v2 ^* e6 n7 S' p0 d - }& x3 ~6 {' x( J! G; ?2 M
3 J4 e/ f* x8 p* g* {- sConfig.Channel = ADC_CHANNEL_9;
4 c* n0 Y# F# u* t; v& s5 Q! h5 P - sConfig.Rank = 9;6 l" V: \" d t) K! E% d! x
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
% G$ p3 k0 c8 v/ Q - {4 x% B( ^9 x; K& X- _- E0 v
- _Error_Handler(__FILE__, __LINE__);
4 t1 ~& C: T$ @; j; C5 X6 L - }
/ \- y @+ N2 D+ _% I - , b! N7 i' ], f. c' B$ K {4 X
- sConfig.Channel = ADC_CHANNEL_10;
/ ^8 l0 W: e, @/ e - sConfig.Rank = 10;9 d# Z" R, z8 W7 x
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)% n; V5 n* q6 y) ~& m
- {, ^5 y5 k$ R. C5 @6 }0 U/ _
- _Error_Handler(__FILE__, __LINE__);" d: x$ b; l# U! g; w) o
- }8 P. i0 B7 a2 w1 T. C, T
- ]2 N0 N) l* j8 R+ J( e/ c- j8 n
- }
; S6 i |5 c; {! i - 1 A3 l* }# W3 J, h5 E6 m5 w) C; _& @
- void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)( ^0 p# |/ D* ~) j8 `* G/ E5 E7 H
- {0 b9 q7 a n. T$ ^* K) q, ?" j
- 2 E. F& L' }3 O$ w7 N% H# c: k# V
- GPIO_InitTypeDef GPIO_InitStruct;5 X+ {5 w9 ~$ [3 a8 t
- if(adcHandle->Instance==ADC1)9 F2 ?4 N& u' U0 X9 u
- {
0 v% x+ a/ n( @ - __HAL_RCC_ADC1_CLK_ENABLE();1 D$ [: d. N8 }+ H* {8 a$ t* r
! u' V& N; m& Z* d8 V5 v: Z- GPIO_InitStruct.Pin = GPIO_PIN_0;+ t! e, `/ \6 T
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;+ E* b; S& d7 I& j
- GPIO_InitStruct.Pull = GPIO_NOPULL;
* _$ x6 K' s9 ^+ E - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);- q$ V6 y: d& ]
- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
/ w8 u3 {! c L* s6 M - |GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_7;4 L: t6 K% }0 C3 t- u+ I& `
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; x* N. E7 |9 v0 G/ F+ p- Q
- GPIO_InitStruct.Pull = GPIO_NOPULL;* ?5 _* U: i" g8 Q0 d. x5 c2 |
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
; a+ G+ m4 o# V% O, Z
1 n7 N0 [4 {' G6 y3 A' h/ r. n2 B5 _- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;$ f; d9 v6 C. M* T, I( |/ |
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;9 a: Z1 y3 Q) I3 ~7 ?, ?
- GPIO_InitStruct.Pull = GPIO_NOPULL;
6 w% G3 m0 I S B - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);) c* y- q* \; K6 J8 }
- hdma_adc1.Instance = DMA2_Stream0;
2 e. M% ]' U- e/ c - hdma_adc1.Init.Channel = DMA_CHANNEL_0;1 C: l U" d, l( e$ N% |* }
- hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;6 e5 v# n& ^! K7 g
- hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;9 w3 w; U4 C+ h. {9 n
- hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
0 G$ I0 z$ H. y. X& q. c- U1 A g - hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
2 N# z8 ]! M) l" f \ - hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;/ T* Q: w1 U% C7 o0 d
- hdma_adc1.Init.Mode = DMA_CIRCULAR;) t, C5 z3 W, O/ y) U
- hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;4 X3 R- L9 ^ ~# G6 E; r8 e- x, {$ w E
- hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;1 a6 h+ g$ z, j0 h4 e) A
- if (HAL_DMA_Init(&hdma_adc1) != HAL_OK): N4 S Q$ V" N0 U
- {
2 o# y. [) g5 ~7 z - _Error_Handler(__FILE__, __LINE__);
6 n k7 q" U, ]- h - }. N, @ ~7 m1 u" o6 z2 j$ u; e. b
9 v% @! I0 [ J. ]; n3 d- __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
3 M l: o I* j. j - 8 `2 X9 O; V/ ]8 D- ? P& H% y
- }3 C# p5 t1 `( i3 _4 S; m
- }# U1 j) g9 s/ I) D; u: @9 Z
" {5 E3 e# F: [# s+ b8 T1 o. p& w% ?- ! D/ }4 E6 H% C. G( s: G7 U! w1 J
- + C& F7 Z3 S, K$ N9 s9 ~) x5 ~
& ?/ ~$ J1 O7 B; G: L- 5 v& C: O4 W9 W- ]1 d# ~7 s
- 3 p% c! U- ?3 n# X- T, |
复制代码 http://player.youku.com/player.php/sid/XMjk0ODczODg5Ng==/v.swf3 k" h: f* g. q3 d8 |! Q* G
1 F0 Q. F. Y, A, P T由于STM32F446的快速处理信号能力,本方案中同时开启10路带DMA的ADC处理10路50HZ交流电压绰绰有余。演示中在OLED屏幕上显示ADC0通道的转换结果。
) I& }( h, s0 y' c9 L/ z& i
^' K. r( ~. Z3 D9 g/ ~' K0 D# ~5 Z5 Q! L* I) _1 N! h
|
楼主,你没有用示波器实际量,采样电阻出来的是个交流正弦波,有正负。所以你直接采样ADC等于把负的忽略l了,这样采样玩玩还可以,会对单片机的ADC有影响的,实际工程项目不能这样做的。
输入级的电阻我知道,我选用300K 的,我是说输出级的、后面我查阅相关资料,你选用的互感器没有标明线性取样电阻,我选用的标明了。
相当于取了绝对值,求RMS无影响。。。。。。。。还有疑问你这个互感器DATASHEET上就是写采样电阻那么大?就我所知道的,都是采样都是100R以下的
STM32CubeMX,到ST官方网站下载。7 q" e& S: x/ Y% d% R) q r
https://www.stmcu.org.cn/document/detail/index/id-218002
; T; R4 Z9 j+ r9 I% z4 `0 a
经过电压互感器后,次级是完整的正弦波。采样48次耗时20mS,就能够覆盖整个交流电的一个周期。
那互感器出来没有负电压么?我看的采样后直接接ADC了
互感器次级把初级的负电压“垫”高到VSS了。
噢,你用的是什么型号的互感器?