本帖最后由 wenyangzeng 于 2017-8-6 21:13 编辑 : ?2 k7 |6 G9 S8 {: a
; [$ d) }# j5 X基于STM32F446的交流真有效值电压表
; M3 H0 N9 J, s1 R9 a3 k, R. Q6 Y# j8 ^, S. G0 w
一般的数字万用表的交流电压的测量是采用将交流电压经过整流后测量其有效值,由于整流二极管的非线性,使得该测量结果误差较大,不是真有效值,特别是对非正弦波的测量更是如此。8 D% D$ P! [% T
本方案基于使用意法半导体的ARM CORTEX内核的STM32F446交流真有效值电压表,克服上述方案的缺点,使得对交流电的测量更加准确。' t! c; B# p- P
交流电的有效值定义为:
2 j& a5 @& J% V; v7 q& L
) q, j; W( L$ d) N" s/ O, e/ `. `# w6 ^
5 r8 A0 H" V6 r5 k
对其一个周期内连续采样后,根据以下公式进行计算得到结果。+ C3 b+ Z, s% ^) i; R
2 U& x4 }( s6 M8 l) e0 Z, j
硬件连接:0 N( s& p' _# Y7 N9 T) Q
1 n! v* {$ e" w
4 {! s7 A }- s3 p( U G( m
& N" g, q4 z/ a220V交流电经过1:1电压互感器后与STM32F446的ADC0连接。4 h7 S2 l# i$ a9 `! ` f5 o$ g! [) O6 u
' O9 i2 g, e8 z/ H( @
' w2 ^1 T& h7 h# @
. F$ x# i* \$ _+ m9 r- _ ADC通道配置) u+ l7 t. F; c5 c% b& I$ _- }* |
7 |& y: u; \4 Q% ]3 j
时钟配置. A3 {: {; j5 a$ R" Y
8 k9 t" K2 y% K7 j( S ADC参数配置" q2 d) b. ]* F: m
1 b8 D9 q6 ?4 D# s9 g, _. ~6 S* m
关键代码:
+ Q9 Q$ g9 H% P! F% R5 |! b- //MAIN.C) J ]# _$ k, B, m7 q' C
% y- [ l3 H' G( L( E- #include "main.h"3 H* r; n0 ?2 ?2 O8 L Z
- #include "stm32f4xx_hal.h"
" P$ d l; y( v5 b% @9 m, ^, I - #include "adc.h"
" g) _+ Z% J. K7 \/ f( q - #include "dma.h"% V6 Z$ n0 m! p; A
- #include "tim.h"
- M2 i" k$ m5 D; E. e# H1 N - #include "gpio.h"
8 _4 Z' z4 P% q5 Q - #include "math.h"3 C8 y" C! T5 ~+ P" @
, X: _9 l) p [/ p4 X5 }# p- #include "oled.h"
$ d" i# \# X; N; ]. `4 K; v- y5 Q - uint16_t aADCxConvertedData[48][10];) D* u: r: ^& o$ V
- uint32_t Resture=0;
+ P, ?8 g) t1 h' m% O+ e5 z - uint8_t Disp_buf[8],Flag;
+ K. o* h5 N' i% ~" B% h' u7 t" r - uint8_t j=0;
$ U. d& Z/ a& K8 S0 F8 M" ?6 ] - void SystemClock_Config(void);
) z# p$ ?3 |/ \ - - ^& B! u$ }0 m1 P3 W2 m/ x
- void Get_ADC(void)* g! ]9 m( q1 f2 T0 L
- {uint8_t i;$ ]0 v/ J* G2 M' I& }4 c8 M
- static uint32_t total;
8 H+ ?& F/ y2 X" y - double temp;2 |6 v7 l8 G8 {. K2 G
- : }" f. S4 X3 y( A) A! ^+ A+ T
# R% ]" h! F2 ~5 C9 k$ H0 H- total=0;- Z9 u8 X* Q; I2 [; x; V9 K1 Y
- for(i=0;i<48;i++)8 M2 I4 W0 `' ]$ @( Z; [
- {2 h( s1 M- a( h
- total +=(aADCxConvertedData[i][0]*aADCxConvertedData[i][0]);/ {7 T3 ]% f0 o
- }/ o/ Q, T( s% k# H! v
- total /=48;
2 l- A0 W; L; V( k! n: I - temp=sqrt(total) ;
V2 D$ h6 F9 p/ m% P - Resture +=(uint16_t)temp;
, t" i* |3 ] [% g2 [( j - j++;
0 b- T$ C9 g3 y. s* {# E - if(j==32)
9 U/ y% `3 }. ^. C3 i2 V5 J - {
& b0 @8 [( \2 T - Resture=Resture/64;0 o2 W b" }2 o' d0 I$ T7 i
- Disp_buf[0]=(Resture%1000/100)+0x30;
$ F1 v1 p: v! Q- H L - Disp_buf[1]=(Resture%100/10)+0x30;
: m' W5 A: d3 ]1 ^* J$ n2 M - Disp_buf[2]=(Resture%10)+0x30;
1 A2 a0 l7 k/ I2 o! I8 _, V - Disp_buf[3]='\0';
' h5 ^$ i: V4 A5 I3 J - LCD_Print(40,46,Disp_buf,TYPE16X16,TYPE8X16); 5 `( ~- u( L& P9 r5 n
- Resture=0; ! T: L/ u6 Q( p7 ]: Q4 x
- j=0;4 {4 Y1 I; H0 ] j
- }( Q. o3 [) p9 }" S+ Z' B
- }2 E+ ^. C' {6 v, A7 L- ~
- ! \" n/ T; ]$ ]2 U
- - F+ a% T( H' B: {- {
4 ~' B* ]. s* v! C+ q- # ^0 `/ P* I7 f z6 } e, E- G
- int main(void)
' Z% ]9 V) O+ D/ w/ y' ~ - {
4 ?; V, I; J* y3 |1 W& T - & ~1 {/ M9 V/ n: c$ v
- HAL_Init();: R, L; q. A: y/ N/ q0 Z2 w
- SystemClock_Config();" V; c2 J5 g' p1 e, u2 S
- MX_GPIO_Init();& v$ |) b, r/ R+ u3 T2 T+ I& c
- MX_DMA_Init();, L- y1 [: X& v! [ e# M# ~# _
- MX_ADC1_Init();3 a/ E9 j* K; O7 D; G# l2 d
- MX_TIM8_Init();' i6 c! Q) W& b
- HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);+ \6 a6 i* v1 m9 u
- 5 H6 Q9 P5 P2 {: q/ m
- LCD_Init();
% }6 _" a3 Q+ U2 \ - LCD_Print(0, 0,"STM32F446 Nucleo",TYPE16X16,TYPE8X16);
! m- D7 X6 e7 L6 J; ^ - LCD_Print(0, 16, "True effective",TYPE16X16,TYPE8X16);1 ]# g, s$ B# P6 i7 L3 {
- LCD_Print(74,46, "V",TYPE16X16,TYPE8X16);
% u* R1 }; H+ U% \3 T b2 N -
- Q5 K M3 b4 }# ^6 m; m - if(HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&aADCxConvertedData,480) != HAL_OK)
0 R9 ?4 ^" w8 D - {
: _, @1 V8 T, A' B! [4 Q1 s - Error_Handler();
1 M5 H' [# l1 S) C9 D - }
; B* S, r. a5 W3 T
- }' c3 ?% s6 c$ W- while (1)
/ {' B" Y) f0 x2 P - {) u: j2 T; t, H- g; g
- if(Flag==1)' F4 `. ^" {: Y) o7 ]: e8 p
- { ) W) l( ^& Q8 k: X6 T4 @, S
- Get_ADC();+ P7 }5 C0 x: a2 G5 T) l8 J: u
- Flag=0;
$ g$ f9 p- C) s! T* R0 W$ R1 R - }+ Y5 P' M/ `/ ]" u1 U
: I3 f: J& B" o: b- }
. [3 f: Z0 C9 k% f
- T! a0 N2 b! e: Z' x# x- }, d! H( T/ _% V* p% O
- ; k/ P$ \4 S% X! \5 o! x
- 2 L& m+ E* b; @& Y. O$ s5 E! n
- //ADC.C
# y9 j! ^: N5 b0 o" f9 X2 w& `$ O - #include "adc.h", i7 U: A% S0 N) w1 k, q
- #include "gpio.h"7 G* Y* M/ a% U. n. g
- #include "dma.h"/ M2 v! x# q+ z6 M
- ADC_HandleTypeDef hadc1;5 ~& M1 s8 }+ l& A+ l f! I# ^% |) R
- DMA_HandleTypeDef hdma_adc1;' E, E# J _+ |: n S( P
- void MX_ADC1_Init(void)
9 a5 t% Z; q6 J3 `% E0 ] - {
6 ?! E% _! L, A - ADC_ChannelConfTypeDef sConfig;
+ ] E; j% @" I5 a) C - hadc1.Instance = ADC1;
5 M: u, y% ~) ^' [) e - hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8;
; \4 X- a, ~- r ~% t - hadc1.Init.Resolution = ADC_RESOLUTION_12B;
) ~2 M) o6 s& n - hadc1.Init.ScanConvMode = ENABLE;
@ ]$ K/ m9 R' B - hadc1.Init.ContinuousConvMode = ENABLE;
- z; m# F: e4 R3 V8 b; ?9 d - hadc1.Init.DiscontinuousConvMode = DISABLE;4 h: i" Y1 G& r! V; z! |
- hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;% B. `, T3 D7 K. @$ F/ o3 W
- hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
( h* j' R$ U" }: A7 ]8 a4 `; w - hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;$ x: r) {: d6 R" ]& T
- hadc1.Init.NbrOfConversion = 10;8 Z5 H3 |, a/ J2 D* g. |+ d9 I6 d6 |
- hadc1.Init.DMAContinuousRequests = ENABLE;, _& u! o' C, n$ g% C
- hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;" S. n3 ?" L9 d( P& m2 z1 @' b
- if (HAL_ADC_Init(&hadc1) != HAL_OK)8 X \/ K4 y( A
- {. [( K$ i9 [; }
- _Error_Handler(__FILE__, __LINE__);
& q4 Y2 C ?0 U - }
& I5 c4 D$ B; U5 G - sConfig.Channel = ADC_CHANNEL_0;5 m! |8 ~, w: Y* l7 G% Q7 w
- sConfig.Rank = 1;
. X% s2 [) }) c9 D - sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;3 h4 |. h# S5 q
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
9 k, e1 A6 ~7 |) c - {* U) Y- }: v( S: c4 B6 }7 ]
- _Error_Handler(__FILE__, __LINE__);
7 v7 a' _4 T" p+ ]6 G: I( ? - }
! R2 A y' t' X2 b! z8 L- t - " `8 A+ C; ~0 M7 q6 b3 {6 Y
- sConfig.Channel = ADC_CHANNEL_1;1 s5 X* i* @( E& j
- sConfig.Rank = 2;
4 }: R T# r9 P' D - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
1 Q m6 |" h; }2 { - {. M4 }) X* s9 G6 [
- _Error_Handler(__FILE__, __LINE__);
" j9 ]! w5 w; F0 V- ]+ U/ z+ `; x1 k - }
7 f, S% }( }, Y. U- A2 Z - 7 s, G# s, a- ~( ]% z3 w# }/ W
- sConfig.Channel = ADC_CHANNEL_2;1 K1 D, s2 ~) }' B/ _, G1 q
- sConfig.Rank = 3;& z6 h2 M Y; }( d6 s \
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
5 s4 ?3 V( K8 V: O, [ A - {4 P |' ?2 P) _ F
- _Error_Handler(__FILE__, __LINE__);
9 o( V9 H+ D) Q" K1 n - }
$ f9 b F4 D# z) ^" Y
) `$ |0 e5 r2 e& p/ D4 v- sConfig.Channel = ADC_CHANNEL_3;
' } [* t8 }) z) \ - sConfig.Rank = 4;
5 e/ |9 z2 I3 ~9 l+ T - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
% c- v+ K P) x7 q1 C; ~/ G - {/ y9 l; w7 @) k
- _Error_Handler(__FILE__, __LINE__);
* m' ?3 q8 B. X( i' @8 ]- T! v - }# |0 E! t" {- B# s& f
- . F( d7 y. A% O! ~1 m* E3 Q
- sConfig.Channel = ADC_CHANNEL_4;: p' l2 V9 Y' Q9 c ?. x. p( r
- sConfig.Rank = 5;
8 x& Z A& U' ]2 l9 u2 U - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
3 Q* _$ t1 u9 L* \5 {+ k. j - {
0 Y; ]( U4 U3 u l3 l M- H - _Error_Handler(__FILE__, __LINE__);$ b: Q2 J+ K- E+ b& g
- }$ p0 ~% Q" G( ?
( p0 {1 g. x7 | e u& Y6 \0 t3 S- sConfig.Channel = ADC_CHANNEL_6;. A( f$ r, m. S: [3 L& n+ Y
- sConfig.Rank = 6;
3 K" o/ B" R3 v5 g: X/ K - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)6 d3 t9 T. d8 y T1 }& s
- {
5 z7 ^; ?( h, S - _Error_Handler(__FILE__, __LINE__);, Y E8 J$ c5 E5 A* y' a1 [
- }+ W7 G$ R7 J% r% B# g% Q( }% k
- + n6 x; c5 ? ~0 O7 p& l6 v" Q
- sConfig.Channel = ADC_CHANNEL_7;- x0 u8 u, Z! k6 a# w6 i- a
- sConfig.Rank = 7;
8 }( n% f5 z/ i+ d5 ]/ n J4 ^ - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
$ Y$ T5 G L# Y: r* I - {
3 Y3 Z0 G3 b0 S7 e - _Error_Handler(__FILE__, __LINE__);. Z- S9 _5 Q( V, T6 g0 {6 f
- }
- y- d3 |$ h- m4 ~4 z" N1 R' X& W
: n9 X$ K/ Y! F3 N5 A2 y2 e* B- u: T6 p- sConfig.Channel = ADC_CHANNEL_8;
2 z; ]& R1 }, b) X6 L% e$ D - sConfig.Rank = 8;0 `# o& n9 R# u
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)1 H" a0 M' K" V5 J
- {+ `. d% v# C9 n# P' d
- _Error_Handler(__FILE__, __LINE__);
' t1 _) N0 j6 R0 Y" g - }
: C+ ?) {2 g+ `- P$ O# \! D - ' @; a' q% U2 g0 d- S( [
- sConfig.Channel = ADC_CHANNEL_9;
+ m. V1 C/ l) X) v: e+ ` - sConfig.Rank = 9; @- |7 N$ q$ Z: Q- L* x/ F$ V% E! R
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)2 [ R! q$ J9 A! X0 A6 R* k
- {; h6 w' F7 e/ l, @# R
- _Error_Handler(__FILE__, __LINE__);9 c9 e; D8 Z8 T) j0 c
- }
& P7 Z5 _7 H ~; z9 v: n0 F+ o - + y- }5 ]: `# H8 M; T
- sConfig.Channel = ADC_CHANNEL_10;, Y0 Z1 o5 p; Q" e9 c. |
- sConfig.Rank = 10;2 y& e# A8 j" u+ r6 Z
- if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
9 J7 T: I! h" U! Y - {# c! i' ?7 n+ L+ e: O
- _Error_Handler(__FILE__, __LINE__);
; P9 Z' y9 ]9 p( S4 o, ?- g% R) F - }' q& ^/ I, ]1 z% r( J
- % r; N: |0 u& e/ a1 J5 t
- }* W- B0 R$ W+ M! u- d& H( d. r
- + `) {. b. N+ O& V, F1 Y
- void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
$ f0 n3 w9 a. J2 ]! o - { S( e2 v& `' G7 `! W
. J8 K3 J, R w0 t* j8 g9 \- GPIO_InitTypeDef GPIO_InitStruct;7 U$ W. s' R8 M p" @' i
- if(adcHandle->Instance==ADC1)
- y9 S0 V1 v. \; d - {
0 c0 Q S/ b7 K+ r6 l. h2 i% L - __HAL_RCC_ADC1_CLK_ENABLE();
& X( L6 O& L3 z+ a; v& |; N& ]0 N' C - * T! U# \" b% z) N& `7 ]
- GPIO_InitStruct.Pin = GPIO_PIN_0;( D) g- n( L0 n0 |2 \
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;& r$ e, g5 p# ?+ X; A8 k
- GPIO_InitStruct.Pull = GPIO_NOPULL;
' _, \4 G% l5 v2 S/ ]1 d% v8 | - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);3 B% |' f: L8 n; h l" E( \
- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 " c: W6 i$ ^! t% C9 d! R
- |GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_7;
- ^! Y" B" F: `8 c+ r - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; v6 f' ^+ v5 e: Q1 ^
- GPIO_InitStruct.Pull = GPIO_NOPULL;6 B: O; K# E7 ^5 a8 ^
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);3 p6 X% C8 J% p3 F2 s3 \$ c
! ^* F0 ?3 ]' |. }- i8 O- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
- @- I3 j0 \- I/ Y: ? u$ ~6 ]+ C - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
- ?; u9 e. b0 O3 ]: @$ w) H - GPIO_InitStruct.Pull = GPIO_NOPULL;
) x( K2 X, e3 f - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
1 ^( n& Y; B/ o3 g9 d* v - hdma_adc1.Instance = DMA2_Stream0;
) |) |0 n- H3 r; L8 y2 e - hdma_adc1.Init.Channel = DMA_CHANNEL_0;9 s9 {+ Q/ U# G S( Q' W7 v2 Q
- hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;1 W3 {8 i+ Y2 R" K
- hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
9 B+ h* d/ V3 m - hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
& I1 A& D, W$ k5 x% S% ]0 j0 g - hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
2 H: J: V4 a* \2 k% O( _+ h8 E# l - hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
( e; l0 w. n3 v - hdma_adc1.Init.Mode = DMA_CIRCULAR;
2 y% c9 e2 U$ s9 E( |0 K- B/ i - hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;4 _* b2 b S* a; M: F
- hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
) Y* k( g( Q& ] - if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
& \! \% H f: `/ z - {& @+ B9 j* P9 w" w- W* _
- _Error_Handler(__FILE__, __LINE__);3 ]: X: f0 Q8 Q( D( J% F* K7 i) Q
- }5 c5 j7 A( n$ z& _# s( c
- & O6 }+ h! m1 D7 w
- __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
1 Q) \9 r( P D$ J
' T8 F1 z8 a8 g) z+ l- P' q- }$ Y2 r9 _! f3 l- t8 T
- }
$ n8 a. i9 w; L( G, `. w - 7 q( M- B+ l8 J
. Q5 k) a0 s. ]9 d- ! [0 \' {. A% f0 t0 W
- ( e( d1 b5 e0 B; Z1 l8 i0 G
- 6 T1 r5 o4 p& a
% F n6 G ?! V; U! c' Y r
复制代码 http://player.youku.com/player.php/sid/XMjk0ODczODg5Ng==/v.swf3 b9 u: A2 W& O5 H5 \; p; q$ ]
9 J+ z5 [* ^& u; j/ ?4 v& i
由于STM32F446的快速处理信号能力,本方案中同时开启10路带DMA的ADC处理10路50HZ交流电压绰绰有余。演示中在OLED屏幕上显示ADC0通道的转换结果。
; x- f) r5 z3 x& b! `/ e, O. E4 z& J% Z6 I3 y' W" h+ `
' H' T6 S$ r! A1 j1 ~ l
|
楼主,你没有用示波器实际量,采样电阻出来的是个交流正弦波,有正负。所以你直接采样ADC等于把负的忽略l了,这样采样玩玩还可以,会对单片机的ADC有影响的,实际工程项目不能这样做的。
输入级的电阻我知道,我选用300K 的,我是说输出级的、后面我查阅相关资料,你选用的互感器没有标明线性取样电阻,我选用的标明了。
相当于取了绝对值,求RMS无影响。。。。。。。。还有疑问你这个互感器DATASHEET上就是写采样电阻那么大?就我所知道的,都是采样都是100R以下的
STM32CubeMX,到ST官方网站下载。# r7 K1 u/ ~& F0 [; p0 y; U6 e# v
https://www.stmcu.org.cn/document/detail/index/id-218002
经过电压互感器后,次级是完整的正弦波。采样48次耗时20mS,就能够覆盖整个交流电的一个周期。
那互感器出来没有负电压么?我看的采样后直接接ADC了
互感器次级把初级的负电压“垫”高到VSS了。
噢,你用的是什么型号的互感器?