本帖最后由 wenyangzeng 于 2017-8-6 21:13 编辑
3 L) y) \1 A+ N4 d8 I3 n# u* m9 |4 ?7 z# B* Z
基于STM32F446的交流真有效值电压表
$ I2 G. ]: {) f; ]7 u
+ @8 a; m1 S. I 一般的数字万用表的交流电压的测量是采用将交流电压经过整流后测量其有效值,由于整流二极管的非线性,使得该测量结果误差较大,不是真有效值,特别是对非正弦波的测量更是如此。
1 j, `3 s; j/ M7 B A$ d9 B 本方案基于使用意法半导体的ARM CORTEX内核的STM32F446交流真有效值电压表,克服上述方案的缺点,使得对交流电的测量更加准确。
8 N( t+ p O$ ~# i 交流电的有效值定义为:4 x, @- s8 n; w$ X+ u5 p
$ N2 q, Y: ?3 e/ x; n3 U
: S5 s0 O4 t1 r- Z' B" w* d& _2 }4 h* ^: }, c$ C+ f# i$ a
对其一个周期内连续采样后,根据以下公式进行计算得到结果。
6 a3 |, W9 }" {# _1 q; x
; ] }0 K! J( r/ ~9 H+ I3 H
硬件连接:
1 ~, U) ~+ e% y% f( s
5 Q. X9 W0 ?$ }! Q
! Y7 b6 |- J a4 X1 v8 d7 [) n! l6 L$ L. E
220V交流电经过1:1电压互感器后与STM32F446的ADC0连接。
6 u) L! v: |, _- S7 |( M* O5 r, [: G9 L; C+ B3 w* x: L
& `: q$ K$ k6 N
* _6 K3 j, E: X3 x2 T0 R& ]
ADC通道配置
$ ^6 a1 M" K; ^4 K) D$ P
/ \$ |3 p2 L3 B- r3 k
时钟配置
9 T# [0 w5 K7 r4 [1 E/ _
$ D2 U, v& L& m2 S$ c1 a7 J ADC参数配置4 H% n- Z- A/ X) F
( l3 X# }4 T. ^6 S- Z4 j- E
关键代码:/ X6 k; Z P. ^& G6 G3 _' D
- //MAIN.C
0 E9 y: q& a! s8 Y
~& U- o; O& G8 T; ]- #include "main.h"
6 N- B D2 s' P5 L+ \ - #include "stm32f4xx_hal.h"4 o6 S1 n/ u8 p! a+ H3 r
- #include "adc.h"
& E0 I. ^- ^1 j - #include "dma.h"
! I. r5 a* a; I5 j* U& Z- D - #include "tim.h"/ q$ V5 Y/ h- P) ^3 m/ o* ]3 [* j
- #include "gpio.h"
/ G- G% {8 b t. q" C( b - #include "math.h"
G, C7 f5 ~% @ E8 N7 l! L
% x0 o" {* |" X1 z5 p# S9 E) C- #include "oled.h"
# l: c# d3 k6 x7 x - uint16_t aADCxConvertedData[48][10];$ q9 [9 F, s0 \2 I
- uint32_t Resture=0;* E+ j4 E0 M9 h D
- uint8_t Disp_buf[8],Flag;
9 }& {: s1 H* p# o1 ^ - uint8_t j=0;6 ^7 C* \; R8 O8 o8 v9 F- @0 x
- void SystemClock_Config(void);+ e) \* Y* c Z/ Y) e
- / l$ ]% X; B" y! z
- void Get_ADC(void)
4 g8 _1 g$ W, ?, m' o - {uint8_t i;
+ ~# H; z( G0 T4 f- ?6 R& q - static uint32_t total;
$ R; H& t5 }. q. `/ F1 P {" q( f - double temp;
. q9 l1 }; S/ K0 j4 d1 o% T -
$ [: N' l& k% y) m7 ^ - # {* ~$ x$ W) V. p/ V7 x" e
- total=0;$ d+ B) u* S% K& M3 Y" g) \2 }! L
- for(i=0;i<48;i++)4 z! Z0 _2 q# k0 i* H5 g( `
- {6 z% }; }& d7 h* V3 B. i3 O
- total +=(aADCxConvertedData[i][0]*aADCxConvertedData[i][0]);& t8 Z8 g. N* h6 g% y9 b3 \
- }* @3 o4 B9 i* @8 z
- total /=48;, T+ G, f! c- d
- temp=sqrt(total) ;2 k% m" q" H$ N) P! s) q9 \. k7 o! c
- Resture +=(uint16_t)temp;/ x* ~- f4 ^+ }' p3 M: l/ q# x
- j++;, b O9 L+ n4 m- r" k
- if(j==32)
( {5 `3 D- x1 q7 n& i X) B - {& J3 w+ A' [3 [% ^1 V! r7 [" {1 M
- Resture=Resture/64;3 N, Y) B6 X- i1 M; L# j
- Disp_buf[0]=(Resture%1000/100)+0x30;
0 d3 P5 ~4 E% x$ @ - Disp_buf[1]=(Resture%100/10)+0x30; * R2 F8 ?: ~% s3 p3 V
- Disp_buf[2]=(Resture%10)+0x30; + S9 q; ^) ?: B
- Disp_buf[3]='\0';: \8 }, W) S% \. v
- LCD_Print(40,46,Disp_buf,TYPE16X16,TYPE8X16); * q0 Y2 T2 F/ l) c M, T' s) \
- Resture=0; , m S; x) V/ A1 R
- j=0;
! I+ L% Q" |3 U5 y# L3 J - }9 e+ k, G* F6 `- k7 T$ v" w) D) [
- }
; Q0 S: r, @& T8 r) K1 P, I
5 w A) h/ W8 f- 4 z! B3 n5 D" U; V; y0 J
) Q* [% X3 V$ N) u8 {- + _3 Z2 S, n( `
- int main(void)
1 ?- U. N2 _% O. O# [9 w - {
. @& l* U" v% e+ x9 J
8 X2 v! u- r( m$ @4 ~. z- E- HAL_Init();# `$ U. Y/ m( _& m, s
- SystemClock_Config();7 A1 k) k+ I5 n5 y) w
- MX_GPIO_Init();
# k& I4 \$ @, P3 f7 ~( q. K- u - MX_DMA_Init();- x1 k9 j% W* l2 T# u
- MX_ADC1_Init();6 Z# |6 j/ r1 W5 b3 w9 a+ m
- MX_TIM8_Init();
* K0 I; g/ r; d( O# u1 w; ?# y0 m - HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);
% \# q- M* i9 E+ w0 h q
: @. ~4 v ^+ L" O/ w5 i- LCD_Init();
, ?+ d" @( e! v. }& N9 X' A - LCD_Print(0, 0,"STM32F446 Nucleo",TYPE16X16,TYPE8X16);
7 j1 Q$ r/ c3 k& d7 R. S - LCD_Print(0, 16, "True effective",TYPE16X16,TYPE8X16);; Q: o7 b! Y5 w9 \ R" e
- LCD_Print(74,46, "V",TYPE16X16,TYPE8X16);
+ k1 w' n) G p) A. H -
) G. R$ Q" o& s& k! Z9 K - if(HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&aADCxConvertedData,480) != HAL_OK)
( _/ G3 x3 i+ W. [) S# W' z - {
8 R! z. F }6 W4 F7 ~- y. E - Error_Handler();
& O1 j% K0 ]1 ?) f5 X - } + L1 i, J, i! Q7 N$ y! N
- + Y" L8 n& e; M/ L
- while (1)
1 Y a% m3 C& o, r - {
" g4 ~) k/ U! y- `4 K+ X - if(Flag==1)
$ K- P* c# v% ^4 l3 G9 i! n - { & \8 M/ G5 B W
- Get_ADC();
8 p, |! F! h& ^8 C - Flag=0;' l7 c# \, n$ f, I
- }0 m% b! D/ `0 z! O2 P
+ G( A& D- U# ~ j( X% }/ x. l- }2 O: r. K" x4 m* M+ V3 e
! I4 O1 P1 O1 V, |! W G5 Q" v- }6 V E. L8 z0 Q4 }: q
- 3 K. a- K6 K5 i' t: j7 R. v( N
- * ?) ^& |, i& p
- //ADC.C
4 F& N a c* C3 g/ F* D - #include "adc.h"
9 z+ v* z, ?! w$ g5 d - #include "gpio.h"* @- a; F( c' M4 O x; e
- #include "dma.h"
* O: l: c( Y1 n - ADC_HandleTypeDef hadc1;4 a) d- v& h1 y! s3 Q0 O% T) x
- DMA_HandleTypeDef hdma_adc1;9 k" |2 [! I; }+ h4 u: H1 I8 ?- n
- void MX_ADC1_Init(void)0 Z# I- k( z4 m- `, K
- {% Y5 ^8 X; q! J, O
- ADC_ChannelConfTypeDef sConfig;
4 \+ A2 q( C5 N/ ^! K! ^ - hadc1.Instance = ADC1;9 i" A$ U2 o8 c" H3 x/ H( r
- hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8;
* i$ J6 w8 x! Z, @$ `. Z* N - hadc1.Init.Resolution = ADC_RESOLUTION_12B;
* n5 i( x1 y( T; t3 G - hadc1.Init.ScanConvMode = ENABLE;
! n) R& Z; \! i3 e$ T - hadc1.Init.ContinuousConvMode = ENABLE;
! T$ [/ _( L2 s: n& b5 v( m - hadc1.Init.DiscontinuousConvMode = DISABLE;7 }" ]$ p. ^ ?8 I" x) N6 Q
- hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
/ L8 ^* q7 J4 s' S4 L2 T- v - hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
2 Z' t' n3 n! }( b# c8 f - hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;, q! W- f9 w+ y, k7 j1 `8 k0 T
- hadc1.Init.NbrOfConversion = 10;5 v/ p. r' W0 E6 W
- hadc1.Init.DMAContinuousRequests = ENABLE;- S: n0 h& I1 z
- hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;4 o ?) F- G* d: T; c. d" s
- if (HAL_ADC_Init(&hadc1) != HAL_OK)7 m, K6 n+ v5 |2 S; R7 U
- {3 F Q& d3 R, L
- _Error_Handler(__FILE__, __LINE__);8 e; L% s$ I; |
- }! ^" L0 ], G! R0 z. M& @" o
- sConfig.Channel = ADC_CHANNEL_0;& _! H* L K, K$ W9 E4 ?! }" h' X
- sConfig.Rank = 1;+ [/ z p5 C; R# i* U: Z/ N8 q" O
- sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
+ m0 ]2 G3 D9 C - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
' `3 Q( ^. q3 s! A d1 t - {2 a1 ^( ~; l3 x2 a) R
- _Error_Handler(__FILE__, __LINE__);
3 q9 t6 K2 Q3 J; U' k2 ?5 u( M8 e - }6 u) I8 L" d) e1 _5 e. R6 F
3 a) K$ k0 l" c) `6 F- sConfig.Channel = ADC_CHANNEL_1;8 f. [. L5 h# G$ _1 F$ U
- sConfig.Rank = 2;
5 M: B) S2 D" _& h - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)* I: ~0 u% \: ]7 F; t; T
- {
: E/ l8 D4 X2 M+ a: p# @ - _Error_Handler(__FILE__, __LINE__);
c" H) e' K, u+ J/ k - }
* b1 i3 a: Q" d5 M, ?, t* V0 u
* U, C" I7 h ~5 a6 v T! ^9 @; V1 o- sConfig.Channel = ADC_CHANNEL_2;
( _* ]8 v; N+ o( ]0 _ - sConfig.Rank = 3;/ J! v( o5 B$ R" ]/ x
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)+ ^" W- N. Q! a: M
- {
' k W- J% h2 n; U4 E0 y - _Error_Handler(__FILE__, __LINE__);0 B8 j, @6 ]$ x6 p! L" @
- }( q7 q3 l/ i2 W( r1 z3 s* a
- % p6 L' T% f; ~/ u9 O3 h4 a
- sConfig.Channel = ADC_CHANNEL_3;0 H2 P: l7 z+ r% Y
- sConfig.Rank = 4;1 {' |, H2 a) `# }# r( ^
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)% Z5 a1 ?( T% X; ~/ f( l% B. Q
- {
: A# }# z/ A- h6 o - _Error_Handler(__FILE__, __LINE__);
# r4 V2 h% L; Z5 N' { - }: f1 O4 [/ T' A) r- F
- & I, x0 U/ T- z" c" u5 R+ ~' |! M6 J1 s
- sConfig.Channel = ADC_CHANNEL_4;8 f7 R# r% J2 J R* g4 e
- sConfig.Rank = 5;
0 U* Z( y7 K. C# m8 | - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
- R% J1 A9 J+ M) { - {
1 K, r/ w8 l, M7 O2 J - _Error_Handler(__FILE__, __LINE__);
! ~, l. k& u9 w# |% m - }' G7 T- P+ b. e! x+ N, O
& p; N/ C) }' D6 s5 V- sConfig.Channel = ADC_CHANNEL_6;
/ \! s8 U, N( m - sConfig.Rank = 6;& o! _# p+ f/ r6 v. p
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
/ i5 G) x6 e. }8 M) e9 k - {2 \7 ]5 f( [* T3 v; H
- _Error_Handler(__FILE__, __LINE__); V# s/ U! j6 K5 j. X
- }
+ i Z& s* w! s G+ a - , k9 F! ~, {! V q: r
- sConfig.Channel = ADC_CHANNEL_7;
2 S' f4 J) d# K# N - sConfig.Rank = 7;
R% u5 A6 A1 a+ X8 ` - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
. Q, S& Q& b. T - {2 P! M3 g1 e1 G5 d* S3 c
- _Error_Handler(__FILE__, __LINE__);4 |. q9 ^0 }' H: L% Q
- }
$ }- p3 z7 s8 I, }0 _* W( K! g
: E7 H0 h. W) }+ C9 E- sConfig.Channel = ADC_CHANNEL_8;
- p7 b- t1 H9 p k1 m' n$ v1 l- n - sConfig.Rank = 8;
/ f$ n- Z3 v* a* L! h" l; u - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
9 y* i! Z, {* z3 l* s Y- v - {
) L" z6 @+ l- }9 }, q* Y - _Error_Handler(__FILE__, __LINE__);
' }# i+ O$ L5 n" r - }: n' O- m4 j" z+ L; N: E7 m' b
1 U' i6 d5 i% p/ @0 U8 E) t- sConfig.Channel = ADC_CHANNEL_9; h% Y+ `$ \. b% J5 A) S
- sConfig.Rank = 9;
. j9 B" e( E& F - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
' _7 \/ ?. O" N+ O - {
5 p3 \+ X$ S0 R5 L - _Error_Handler(__FILE__, __LINE__);! |- W9 N7 p# B) l+ F
- }
* ^! \9 \" E8 a% d. u/ {
1 [1 N% \5 b: \2 h( b- sConfig.Channel = ADC_CHANNEL_10;. J- B; l4 X( F/ s; Y$ l. ^
- sConfig.Rank = 10;1 y5 F5 W+ @* r# f; y* m; p; z% ]
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)3 p! ?: M# I( J/ A
- {
* `4 L ?2 |5 _, ?+ P - _Error_Handler(__FILE__, __LINE__);
1 @, | P. {( n. O9 U* z - }* K' N+ ~5 ]- r; F# V% O3 e
- 8 v/ ?3 c/ K0 F I& ?& w
- }) `/ o, o/ X8 I2 h
- 9 Y7 z( I1 C: t- h. @$ }
- void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)' U# y+ n: I( Q6 t. K3 v
- {$ l% i# D; [% ?" z1 G+ s) L
- $ r6 {+ B+ Z; O1 u- e7 ?5 d
- GPIO_InitTypeDef GPIO_InitStruct;
8 }3 f9 A( s* ~8 a - if(adcHandle->Instance==ADC1): l/ X- U' m+ w u& {# C8 d& O t
- {
9 `% {# o3 R5 X& M, v; A - __HAL_RCC_ADC1_CLK_ENABLE();3 j- D0 L2 G' j6 W
" w/ d" P+ ~( L' ~8 v) a- GPIO_InitStruct.Pin = GPIO_PIN_0;
K$ J8 U1 O2 r0 i' C4 j - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;7 _7 }" J# o6 ]# n
- GPIO_InitStruct.Pull = GPIO_NOPULL;
3 A8 P8 P9 f/ B - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
' G2 |$ t9 t9 w+ K w - GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
- s( Q, X6 u, B- X - |GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_7;
$ m8 I3 z% }, W5 q7 ]4 \0 {. d - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;2 ]9 N+ v8 W* j$ z
- GPIO_InitStruct.Pull = GPIO_NOPULL;
* E" z5 n8 _ J* w# ?8 H6 K- q/ L - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/ \- \+ O" B: q5 g) k* t7 M - - m- U6 t! t i( \$ d
- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;0 Z! E. a; A+ |6 h$ m$ [
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
) L1 W: p' O4 r+ k8 Q. e - GPIO_InitStruct.Pull = GPIO_NOPULL;! ?3 R8 t7 |1 t& l+ M, W3 k
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
' [' ?6 ^8 b$ O) C. H- L - hdma_adc1.Instance = DMA2_Stream0;
! }: a$ E$ P8 ?6 F, w$ {- } - hdma_adc1.Init.Channel = DMA_CHANNEL_0;
+ M/ m! N- b6 N( p$ } - hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
0 x7 x6 ]" L4 Z; D m6 f - hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;) {, w3 C8 s2 [8 X( K+ o2 Z, C
- hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;& t6 o4 H7 v& R8 j( I
- hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
! V& i. X! _" b* ?0 m4 { - hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
$ |1 E3 w: h* c) y - hdma_adc1.Init.Mode = DMA_CIRCULAR;& U$ Q) |5 T8 P
- hdma_adc1.Init.Priority = DMA_PRIORITY_LOW; S: k6 \9 R8 n. e3 l$ s, |( i" X1 Q
- hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;. R: ?+ s' E( e3 a' l$ A6 w
- if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)2 \$ Y7 W3 L! a: `8 _( x
- {# U- W) E- \/ i
- _Error_Handler(__FILE__, __LINE__);4 F; ^6 ?8 ]8 {1 t+ L' |" U; ?) n. [
- }/ }- \' `% |6 I E
- ; M. E. C/ v7 Y
- __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
; [7 n1 J- C% y# e; ^8 N - ( o: s* ^$ ?) a0 Y, p, Z& c: [
- }
' A+ S. u- Q, ~- r - }
/ k$ Q- [% r' C. Q p- g" [ - ( q! ?8 t* f/ a# q3 Y$ F- O
- * \% C. \+ A0 w* Z, ? _& p
" ?( ]7 e( u D w' v% b+ t
/ M, O. L8 N+ \5 L4 k5 Q) m
8 `3 M$ x( M5 J: V+ K
; D' x( O; f8 y) c0 E
复制代码 http://player.youku.com/player.php/sid/XMjk0ODczODg5Ng==/v.swf
. C+ J# A0 `& R( j) R' S8 F
/ {) N% D* J8 o由于STM32F446的快速处理信号能力,本方案中同时开启10路带DMA的ADC处理10路50HZ交流电压绰绰有余。演示中在OLED屏幕上显示ADC0通道的转换结果。
, p2 g# J5 I7 ~, y& |0 P. B- x8 ~9 \. q
2 Z* g- z! p: n' w3 n
|
楼主,你没有用示波器实际量,采样电阻出来的是个交流正弦波,有正负。所以你直接采样ADC等于把负的忽略l了,这样采样玩玩还可以,会对单片机的ADC有影响的,实际工程项目不能这样做的。
输入级的电阻我知道,我选用300K 的,我是说输出级的、后面我查阅相关资料,你选用的互感器没有标明线性取样电阻,我选用的标明了。
相当于取了绝对值,求RMS无影响。。。。。。。。还有疑问你这个互感器DATASHEET上就是写采样电阻那么大?就我所知道的,都是采样都是100R以下的
STM32CubeMX,到ST官方网站下载。
https://www.stmcu.org.cn/document/detail/index/id-218002" v$ M8 F7 _& r9 E5 P& q- v$ t
. X3 R5 F# v P% o5 ~( K
经过电压互感器后,次级是完整的正弦波。采样48次耗时20mS,就能够覆盖整个交流电的一个周期。
那互感器出来没有负电压么?我看的采样后直接接ADC了
互感器次级把初级的负电压“垫”高到VSS了。
噢,你用的是什么型号的互感器?