本帖最后由 wenyangzeng 于 2017-8-6 21:13 编辑 2 q& X" I" L0 N& X; z
9 G& ~: X" A' a基于STM32F446的交流真有效值电压表, z$ J5 r0 Y1 I+ }+ p
2 k; [( _' G. u: q' Z6 Y9 L 一般的数字万用表的交流电压的测量是采用将交流电压经过整流后测量其有效值,由于整流二极管的非线性,使得该测量结果误差较大,不是真有效值,特别是对非正弦波的测量更是如此。
; h& X( T/ G5 w# f E- z0 V 本方案基于使用意法半导体的ARM CORTEX内核的STM32F446交流真有效值电压表,克服上述方案的缺点,使得对交流电的测量更加准确。
. u! |3 a5 P! n0 F' L: L) m: p 交流电的有效值定义为:
% [/ ]; p4 J: O6 P
' g. r6 E1 p: a- \) a& _
' d* |9 s5 U: D7 o+ D" u
* T4 R# d6 o: b+ a. E& I
对其一个周期内连续采样后,根据以下公式进行计算得到结果。7 M* w$ }7 I: p6 d# g
& @6 R; u- L5 q" ?1 X; t r" o! O' { o
硬件连接:
" ]% D, y. }! ~- I o3 d( _2 ?
: H0 m/ t& i# k
1 H9 O; B$ N$ n% W
! P$ v' T0 M8 i2 _ N8 [+ h6 {220V交流电经过1:1电压互感器后与STM32F446的ADC0连接。
- n! m4 C( e4 B% ]& I( m, Z( N& {; ]3 J' a2 `8 W) Z/ }- p7 ^ d
3 `2 K3 \! H. C! ]- i7 K
: i3 R2 N" ]& H0 h' r+ b- S ADC通道配置1 |7 a3 W7 Q' U4 k8 e* v' ~
' a# {. U4 }) t' E1 W; e; [" \
时钟配置
1 Q/ Z8 c1 m- I' B2 @- r% y( w
0 j& {; O# h1 S- R ADC参数配置
2 L2 @& R$ Z: c: w$ J( X/ [8 y3 s6 t6 \" S$ b: d
关键代码:
: M; |) i4 q: F2 O- //MAIN.C
; T2 Y! l2 t! x/ y. B* J$ F# R E ] - 7 i) R1 A. r$ k2 y' x
- #include "main.h"
9 T2 x5 c# u, o0 @ - #include "stm32f4xx_hal.h"
: l ]% `( ~1 Y+ D - #include "adc.h"* q% {+ K2 X" S+ p. z
- #include "dma.h"
* U# A5 a8 }9 R0 Z2 h0 p; D7 e - #include "tim.h" Y* L; { t& f0 t3 ^8 ~( n( c- F
- #include "gpio.h"
$ R# N8 x7 b+ l: [9 b# @) d - #include "math.h"% I/ n8 t6 e; O( P. `
- 3 L5 g9 t" J. q: k0 x: e" I
- #include "oled.h"
. v2 I' t$ m% Y0 _- c - uint16_t aADCxConvertedData[48][10];4 |7 Y1 c6 Q5 v. i# H
- uint32_t Resture=0;+ @- v: f+ U. S+ C6 A
- uint8_t Disp_buf[8],Flag;: d; q! w% R3 H1 r4 g1 Y8 Z4 g Z- O/ @
- uint8_t j=0;
" J1 K2 [. x7 P - void SystemClock_Config(void);
; \4 T# v2 U4 |% A( k
; O" s" }( w# V n0 W$ P- void Get_ADC(void)
' v# m& w; ?* b4 V+ N( n - {uint8_t i;7 d3 k# W" H7 i3 d0 A, v( `
- static uint32_t total;" O- b7 Q& T' m1 L+ _( [4 e
- double temp;
6 L. T5 }: p) }) C- `, S1 E - ! \* J5 Y* [% W; u9 |5 @
- 7 i3 ~! f2 ] R( F
- total=0;- G3 s- ]0 o9 N- g/ c
- for(i=0;i<48;i++)
\' I: x( r+ W' b m8 h0 t - {0 u6 z: ]& p9 V
- total +=(aADCxConvertedData[i][0]*aADCxConvertedData[i][0]);
( i% @4 H/ R5 d* j5 g# c - }$ d" L5 P9 n( e, k @
- total /=48;1 ]7 h9 O! R. ?! F! G
- temp=sqrt(total) ;
9 I( G+ I, M- Z - Resture +=(uint16_t)temp;
( G' T9 H8 W* N/ I - j++;8 N1 b! m1 i) V$ s
- if(j==32)
5 X& }; u4 }- w B" J - {
! b% Z7 v- e3 i- H! V/ z - Resture=Resture/64;
0 }, F; B$ T6 L1 l - Disp_buf[0]=(Resture%1000/100)+0x30;
) |7 ~& r% M# J - Disp_buf[1]=(Resture%100/10)+0x30;
) M; Y j- I' V- t" I2 [ - Disp_buf[2]=(Resture%10)+0x30; 6 L9 y* c" k; C# z. o
- Disp_buf[3]='\0';- j6 _, B9 @8 K, ?/ G
- LCD_Print(40,46,Disp_buf,TYPE16X16,TYPE8X16);
8 H3 y7 F7 s( f" A% @ - Resture=0; & u5 C/ V; r- s/ V* l
- j=0;* m9 A# g$ W3 U" E( k7 N% K
- }& y8 a, }5 i/ r0 ?7 ^
- }; U$ u% `; G; V& s- v
- ) u$ ~0 _: Z& s# |; F7 ]& x: `5 `8 z
- 4 W5 y: S/ `4 E7 R% C
/ r% K" n0 s$ @0 Q5 a- 5 C' U" E3 }0 r& C3 s0 R: o4 a. ] ^
- int main(void)
/ |% ^0 ~! u1 [: ~+ f r - {
& L+ C0 H( C' ?7 c$ t; C( |
+ U& t+ l- _$ r2 e- HAL_Init();
1 p4 l" M) O. \2 m - SystemClock_Config();
# i; Z# G; n3 n. N1 u/ c* A6 ~ - MX_GPIO_Init();( I6 G4 A! L7 _! T6 @3 X
- MX_DMA_Init();
4 E6 j1 f# I; d1 P9 a - MX_ADC1_Init();
5 j/ _/ C# q+ g: N+ J- M: j5 ^8 a - MX_TIM8_Init();
0 u/ v! t G n' L - HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);8 U6 |* d7 v/ o7 X
/ s: \% y4 A: A- LCD_Init();
, `; F5 e2 n( q3 v - LCD_Print(0, 0,"STM32F446 Nucleo",TYPE16X16,TYPE8X16);
3 h2 s8 K+ Z# p. T6 |3 H" G. x - LCD_Print(0, 16, "True effective",TYPE16X16,TYPE8X16);
) M: N- @* T1 P6 w9 j! D. ? - LCD_Print(74,46, "V",TYPE16X16,TYPE8X16);
; ]' a* G$ ]8 w' B5 r3 ? -
* s1 O$ F$ D8 Y" S - if(HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&aADCxConvertedData,480) != HAL_OK)
$ ?$ F$ A4 C* U& z1 j# R* u - {' p& R) W/ L- m9 V6 U& j
- Error_Handler();
9 D0 B9 M3 y ~ - } : w$ d) k9 h$ d' d' l' f$ X
- , _- r1 I# ~% F l
- while (1)
7 u( d) `. m* y5 E - {
0 u6 c7 F" @! ^+ F2 D r5 d - if(Flag==1)
+ z: Y$ u0 j5 j; y& C5 O- L/ N% g - {
{& b8 _3 D' b% A' M6 K - Get_ADC();. |0 r' t) K$ i! V6 K" Z/ O+ L# s
- Flag=0;* U( r7 z n5 R3 d! S* ^/ }' u& a
- }0 Z* w* o" T. l& J1 N
% o9 f2 N7 `/ T6 K) t, D$ ^9 d- }! T0 C% g2 B# [4 |/ m/ ]# g6 w3 x
9 H- C8 N7 L# g- }1 i& b# D4 E. h- }) B" T
6 f$ j5 {/ ~& e: _- , R; i& W* r% Y5 b! U
- //ADC.C
! U$ k9 c j& W7 t) w - #include "adc.h"' N/ w) l3 H; _0 F( @9 a
- #include "gpio.h"6 k" l* {/ h$ x; T
- #include "dma.h"
0 f3 W/ W, s2 P' f* `/ L4 q - ADC_HandleTypeDef hadc1;
2 o: E/ H: L \; P - DMA_HandleTypeDef hdma_adc1;
) G0 z; ?4 L3 b& f - void MX_ADC1_Init(void)
* N8 A; [/ ^/ C8 I3 |" X - {$ m( m( ~' D& ^+ H w' B( r: t
- ADC_ChannelConfTypeDef sConfig;
3 B6 [0 m" N. Q3 F4 G0 w2 Y% X: z - hadc1.Instance = ADC1;6 s0 R2 L% D! m( r
- hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8;
1 i" q, ~& A% p4 E - hadc1.Init.Resolution = ADC_RESOLUTION_12B;2 a( X8 w8 x! F" S) ?- `( K
- hadc1.Init.ScanConvMode = ENABLE;( H- F G7 A9 p1 R+ i: C$ Y
- hadc1.Init.ContinuousConvMode = ENABLE;# @0 i Q$ {3 |$ G
- hadc1.Init.DiscontinuousConvMode = DISABLE;
6 Y/ `6 Z; s$ K. h' r" x - hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
; W; i! T! N. O* B9 D - hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;$ n, X% a7 k; @' G, e) v& n7 Q
- hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
+ a6 z5 Q0 e( A - hadc1.Init.NbrOfConversion = 10;
6 f% M. X2 Z8 C - hadc1.Init.DMAContinuousRequests = ENABLE;
. Z4 ?' U# _; Y1 h - hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;6 O+ O/ ]- V/ K$ y+ `$ p& H- s6 U$ l
- if (HAL_ADC_Init(&hadc1) != HAL_OK)
& o. s2 T4 n, O+ w, b5 t! s - {
! t J' T2 O- Z - _Error_Handler(__FILE__, __LINE__); `+ C3 W5 I$ ~, F9 T. l
- }
/ l4 S) |$ S$ H E# \' f, t9 n$ d8 p - sConfig.Channel = ADC_CHANNEL_0;
5 _% t( e4 G+ F7 z - sConfig.Rank = 1;' j: l, n! I4 w0 A9 N- U
- sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;' g3 O9 H1 o$ {$ }0 ^6 l
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)2 o. v* ]9 s4 i ^
- {
6 N! L6 J4 O/ Y5 V. h - _Error_Handler(__FILE__, __LINE__);
* {' b/ L( j6 f7 g t8 A7 s - }0 G, \7 O* t, ^3 O+ ~( d$ z' Z5 e
1 q+ }+ Q) j2 p- sConfig.Channel = ADC_CHANNEL_1;
9 j; _8 L: u. b - sConfig.Rank = 2;
4 |8 u3 Y7 @" s! W# y6 ?: o - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)9 H+ [) C0 m. F4 [' O, I
- {% s% o( O1 @6 t0 h
- _Error_Handler(__FILE__, __LINE__);
. ~/ E( l5 H( ~% P; `7 | - }* D$ R7 \* N0 }6 [1 d$ D
- # O8 s7 i" f; L) ~0 G& I, t4 ?0 U& n0 L
- sConfig.Channel = ADC_CHANNEL_2;
$ j6 O8 d- w# h - sConfig.Rank = 3;/ t2 e7 A+ d+ y
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK). v+ A$ x: v- ^; T, t( ?
- {
3 @9 K/ j( u; ]3 x - _Error_Handler(__FILE__, __LINE__);- \) x" \6 c& |
- }
L" k: D1 u7 X
5 [# C) B E( ?6 h- sConfig.Channel = ADC_CHANNEL_3;2 |; t2 k6 E: `7 J0 Z6 C
- sConfig.Rank = 4;5 n, n/ e" ?3 ~: U+ u& S8 Q# Q
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)1 P& x7 {4 n0 E c3 k; f/ k' T
- {; t& Y; i! P4 e9 G" F, @
- _Error_Handler(__FILE__, __LINE__);
; v& k6 J9 n! q3 R/ H' _8 c- c - } y% c, T A" b2 S8 [6 {
- 8 N2 V5 M2 ]2 ?& f
- sConfig.Channel = ADC_CHANNEL_4;
& c& J4 ~& g5 Y8 f; i - sConfig.Rank = 5;
4 y; ?5 Z( S( [) Y - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)5 z& e) i- _/ f( K
- {2 v1 E1 ~/ a, R- ^; C# W
- _Error_Handler(__FILE__, __LINE__);) i1 P: o2 x0 p v
- }8 P8 e+ W& ]2 o# ~9 g5 p
- . P7 u# l3 x' O# L7 w
- sConfig.Channel = ADC_CHANNEL_6;
! Z( G6 \& n* O - sConfig.Rank = 6;1 T1 z, @5 a( ~" _7 P2 b$ b$ f
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
/ L6 [5 h1 t$ M* v0 \; C) y0 B - {
5 W) u1 z; n- g$ F' r - _Error_Handler(__FILE__, __LINE__);
: P! ^7 W/ d. U* C1 u8 ~' H$ F - }
, Z8 h! c- T9 U8 O6 [
+ c- O+ x, f4 O8 c, N- sConfig.Channel = ADC_CHANNEL_7;& N9 q) A0 z6 V- b+ a
- sConfig.Rank = 7;% Z9 n: j3 Z! \8 ^$ R# O5 V
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK), U, u' U$ i- w; i- k3 M
- {! r7 q4 s n2 @( \4 k5 O
- _Error_Handler(__FILE__, __LINE__);
$ x* k1 v* X8 n% U+ k: C - }' `* J$ w' X! ]+ b
* h9 t5 q4 ]( {- B- sConfig.Channel = ADC_CHANNEL_8; p5 ]1 b5 D" H
- sConfig.Rank = 8;6 c/ o& l0 m2 J7 g- v, ]- e
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)6 N/ W ? b! N% r8 F5 I
- {
4 B0 i# }. p. G& K5 l/ y - _Error_Handler(__FILE__, __LINE__);" [1 H3 e. ~+ b5 q3 m
- }; p5 q a2 ~: a: ]' C& Q
- ' w! |- F. _2 {( e0 \# l0 {. w
- sConfig.Channel = ADC_CHANNEL_9;* y7 F) p/ L6 ^: ~- Z
- sConfig.Rank = 9;) I% N: c5 V ?7 s6 ?8 |5 X
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
0 g! @5 t) g, b$ D! C) |6 L9 J - {
% \. ]9 ~" I+ r5 `- v8 {' O - _Error_Handler(__FILE__, __LINE__);0 @5 c. g9 a) B6 b# s; ~1 z C3 h
- }) R* I! O2 X3 g, ~$ c8 V
' `$ v8 F" n! g! b$ X; M! D& C- sConfig.Channel = ADC_CHANNEL_10;
" Y* {9 W* b- ]0 s - sConfig.Rank = 10;
* c+ V1 ]) t& r! R) p - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK). f) a4 A( V9 }9 v, N% |% y" M
- {
6 N' N& R/ f+ [ K) J - _Error_Handler(__FILE__, __LINE__);
& ^6 d8 W" Z* ^9 l - }. ~0 u# @5 g% M9 B5 n
- ! z7 ?% o `/ _& S0 m e/ \8 w
- }
. b. H5 o; O6 F1 |/ o3 V
0 U4 ^4 k( K8 m' D2 P# _, z. v# |2 M- void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)8 w6 [. q' x$ m8 y
- {
7 `) }6 B! K( E) E6 s
5 E K" C. _; ^* \/ }- G- GPIO_InitTypeDef GPIO_InitStruct;
5 ]. T0 f: x- W; o) u - if(adcHandle->Instance==ADC1)
; ~- c3 ]& o. U# V" W3 B - {+ N9 @. q! D: Z8 e8 l: A9 D
- __HAL_RCC_ADC1_CLK_ENABLE();
" p8 X! G, |9 S, e. V - 5 P% B# |5 [ y6 V' _+ u
- GPIO_InitStruct.Pin = GPIO_PIN_0;
a% @/ Y: v6 d- k7 e! X8 j - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
# N9 v# v! ]) [9 U- i' S - GPIO_InitStruct.Pull = GPIO_NOPULL;* N; [$ p0 _# S) o. @- Z9 S a
- HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);/ k2 m; K% G3 k7 H8 }6 Y
- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
0 K7 Y4 F, b) N k; O; J+ U. Y - |GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_7;2 E2 g2 X0 R. d! B: M2 p/ i, e
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;; ^5 a$ w' Z. N I
- GPIO_InitStruct.Pull = GPIO_NOPULL;8 Q8 c2 v3 D" p8 y0 y3 `( A1 v
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/ }: w, j) O& t; s* v% \& [6 j8 |3 }
- ! f( f% R B+ ]9 j0 {8 o
- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;6 P0 R; r U3 D0 v% Z: n' q. @
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;+ d3 l8 @2 {. a; Y9 y
- GPIO_InitStruct.Pull = GPIO_NOPULL;- G! ~. Y% s! p* B1 Z* ]$ u. z0 ]
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
- H9 \- e+ J' _. Y2 Q! ? - hdma_adc1.Instance = DMA2_Stream0;+ q5 C( H0 V8 ~ X( b! C4 ^
- hdma_adc1.Init.Channel = DMA_CHANNEL_0;
4 q# D5 ], q3 Z) x/ ^0 X - hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;6 s8 w3 l* r3 h8 |# ~+ q7 g2 z
- hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
, I7 x3 D) u$ m$ r# ^ - hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
0 {$ c5 v* H3 k9 P# U: S - hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;8 u7 p8 e$ G( `2 O0 R
- hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;0 r5 Z: C9 ]4 @; X/ B% G0 w# \7 Z
- hdma_adc1.Init.Mode = DMA_CIRCULAR;" A: D9 [- r) c( A
- hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;1 e B3 _' C J
- hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;2 F: z4 U Q8 j3 r7 F+ B
- if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)7 d4 O# d; Z1 I# U/ ]0 p
- {
# x7 `0 T" v- I8 w2 ~/ M- L - _Error_Handler(__FILE__, __LINE__);' g# Z& q( o4 o, C
- }
) z @7 f5 L0 k0 T- W - 8 F; S* F. c9 L3 L3 [7 x. u D T
- __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);; p4 c) o4 e9 M0 H" B6 M
' H5 }# j: l( {5 I- d- }
, [8 L7 Z b( A( ~+ w& ] - }
9 n7 W6 Z* H, Y
# T! E! m; T" J2 k/ v2 @& u- 2 b; Y* ~( r5 C
+ r: D" a6 I8 ^1 |& g: `
. B8 y9 i# Z D# H) F& \, S2 e4 h* N- 6 _8 @8 ~4 r+ v7 N* `; j6 y
( X3 ~& {4 J& M; @# I% W3 z7 L
复制代码 http://player.youku.com/player.php/sid/XMjk0ODczODg5Ng==/v.swf6 f3 Z: u- T* ^% l4 k& `
! y$ g' a' t, [ \8 T) W由于STM32F446的快速处理信号能力,本方案中同时开启10路带DMA的ADC处理10路50HZ交流电压绰绰有余。演示中在OLED屏幕上显示ADC0通道的转换结果。
* n' D5 G. M" M& Z7 q& E& W s2 u7 X5 K% a
% J2 L7 S2 u1 ^ k! @+ M
|
楼主,你没有用示波器实际量,采样电阻出来的是个交流正弦波,有正负。所以你直接采样ADC等于把负的忽略l了,这样采样玩玩还可以,会对单片机的ADC有影响的,实际工程项目不能这样做的。
输入级的电阻我知道,我选用300K 的,我是说输出级的、后面我查阅相关资料,你选用的互感器没有标明线性取样电阻,我选用的标明了。
相当于取了绝对值,求RMS无影响。。。。。。。。还有疑问你这个互感器DATASHEET上就是写采样电阻那么大?就我所知道的,都是采样都是100R以下的
STM32CubeMX,到ST官方网站下载。
https://www.stmcu.org.cn/document/detail/index/id-218002
7 F0 b5 j; b1 V4 Y; C% h7 J
0 X$ i( Z1 s. z1 `, n% @0 b
经过电压互感器后,次级是完整的正弦波。采样48次耗时20mS,就能够覆盖整个交流电的一个周期。
那互感器出来没有负电压么?我看的采样后直接接ADC了
互感器次级把初级的负电压“垫”高到VSS了。
噢,你用的是什么型号的互感器?