STM32f103的数电采集电路的双ADC的设计与使用 STM32F103C8T6拥有3个ADC,其独立使用已经在本文的3.1.3里面有详细的介绍,这里主要是介绍双ADC的同时使用,即STM32的同步规则模式使用。在此模式在规则通道组上执行时,外部触发来自ADC1的规则组多路开关(由ADC1_CR2寄存器的EXTSEL[2:0]选择),它同时给ADC2提供同步触发。此功能必须使用DMA通道。同时两组数据是公用一个寄存器,ADC1数据在低16位,ADC2数据在高16位。由于保证数据稳定,在双ADC同步规则模式的情况下,还添加了多通道同时采样。$ C0 S5 Q( x. ]3 |1 ~/ [3 x
1 D+ f/ _$ V7 L
4 H. Y& {9 j2 M6 @* x* f# JADC1和ADC2,工作方式采用了同步规则模式,使得两个ADC可以同时对不同的AD输入进行采集和数据存储和传输,而且相互不影响,也可以确保采样时间的减少,同时两个ADC都是使用4通路同时采集,确保了数据的稳定性。
+ M; S5 f# v# [- l. V$ Y1 B
0 b n+ O2 s1 @1 {; x) _; ?8 l5 k+ x: \+ J4 m1 X
多功能采集显示平台使用的芯片是STM32F103ZET6,片上资源提供了ADC123共3路ADC模块,为了布线方便以及使用的习惯,多功能采集显示平台采用了ADC1的Chanel 4~7,占用IO口PA 4~7,以及ADC2的Chanel 10~13,占用IO口PC 0~3。
. W& f; c, L! E! x6 t0 Z; R& }+ \4 Y( |3 x0 ]
3 h+ s" {& I+ k9 w使用时有几点需要注意的:
$ ~6 s+ g2 ^" |* f! [2 r! z! r* K6 ^) d5 x
4 W8 U0 F4 H+ y+ x- {
1.选择正确的模式:ADC_Mode_RegSimult,即DUALMOD[3:0] = 0110,ADC2在双模式中,这些位为保留位; y0 g; g% b: U! i& n2 D8 s
) t1 _3 L) t, w$ I1 [% o8 n0 k
9 X5 o) D! c" h# {$ Q0 ?; d2.开启ADC的DMA,在双ADC模式里,为了在主数据寄存器上读取从转换数据,必须使能DMA位,即使不使用DMA传输规则通道数据。只有ADC1和ADC3能产生DMA请求。所以只需设置ADC1的DMA:ADC_DMACmd(ADC1, ENABLE);
. K% _8 R9 `- ?1 _1 E9 D
$ Q% C* |' P5 W% e/ c8 C# f/ h; ?0 y4 i/ R; f( a c
3.ADC2的转换数据存在ADC1_DR的高半字;( i" z: C3 S8 ?9 y M
! |1 q8 P7 X( [2 p
' D k$ X! H1 b; ]+ U7 W v4.不要在2个ADC上转换相同的通道(两个ADC在同一个通道上的采样时间不能重叠)。
0 b9 E4 n O% l) J4 B! s% v
/ [' D9 d" P& E* n7 [) k( O+ h) |4 |6 G4 c* m. D# n
5.ADC2的CR2寄存器的第20位——EXTTRIG:规则通道的外部触发转换模式必须开启(软件启动的时候也要),这样才能利用到ADC1的触发信号。不然的话,需要手动再软启动一次ADC2,例如ADC_SoftwareStartConvCmd(ADC2, ENABLE);
1 [& S, v: ^/ n. A. X2 O
: w$ ~4 l$ R# s7 l- T) E7 o1 G8 g. H
但是,假如你设置了这个位之后,就不需要手动软启动ADC2了,所以考虑到同步,这样比较好。用ADC_SoftwareStartConvCmd(ADC2, ENABLE);为什么可以,一方面它 也设置了EXTTRIG位,另一方面也设置了SWSTART。但我觉得先用ADC_ExternalTrigConvCmd(ADC2, ENABLE);的话,一会只要ADC1一启动,两者就同 时启动了,这样更正确一点。* }, k* r& V# i% t/ y
. f ` Z5 ]. b6 y. a* S2 d
/ `2 Z1 B! E3 W8 }9 {0 V; f以下是ADC1配置代码和使能代码:) \( n2 d9 r1 N0 j
- //初始化ADC1
; z v. ~- F& t- J - //这里采用多通道连续采样,并用DMA1的通道传送 5 x# _; k7 g! P. r3 `" y
- //我们默认将开启通道4~7
8 R; N7 O' P1 f( N - //相应管脚PA4~7
4 [! y2 k# N0 Z/ _, w/ x - void Adc1_Multi_Init(void) % F% q4 o7 R' Q Q
- { , K2 d" N/ ~1 K7 o6 {
- ADC_InitTypeDef ADC_InitStructure;
& ]% x$ V y9 a" w+ t* ^& l& z - GPIO_InitTypeDef GPIO_InitStructure; 3 O8 S }& @2 |) [
-
+ F* R Z {8 O; p" h& l7 D - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1 , ENABLE ); //使能ADC1通道时钟 & j$ o1 F5 W$ [, a" X" R
- : L& q& h4 @3 X
-
" ?$ \- }6 J) g: e( `) d - RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M 2 i' b- i- l1 h9 _* e- U2 C+ c
- $ M# F+ u! t! d* ]" c
- //PA1 作为模拟通道输入引脚
& p3 W" u) V, A5 V) e/ S9 a) w - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
/ Z! x& w& Z s3 p5 t - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚 1 ], t# G+ r4 g4 p
- GPIO_Init(GPIOA, &GPIO_InitStructure);
3 ?3 u3 Q& S U4 P8 Z4 l6 W -
; O }" {4 g. t - ADC_DeInit(ADC1); //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值 7 Q% K) v; z) `* s; U- ~" Y
-
5 k l6 T- ^" d. l6 t8 e - ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult; //ADC工作模式:ADC1同步规则组模式
0 X6 Z# l/ S8 b4 i! e& C0 f; ~6 K; l6 } - ADC_InitStructure.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式 5 t+ ^+ K3 q0 @" j" x
- ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在连续转换模式 5 j, v7 T) r4 w2 n
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动
+ p3 I4 ^& D9 { - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐 $ b) J2 U: g3 `# L
- ADC_InitStructure.ADC_NbrOfChannel = 4; //顺序进行规则转换的ADC通道的数目 / A' F1 H# {" g; L8 Z( [3 ~
- ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器 # r* I& t y8 m' o
- # f8 }( i# T. K' d0 l! ]
- ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_239Cycles5 );
& o* ]$ C) }0 ~# L# E ^ - ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_239Cycles5 );
/ ]( N% M, }. Y/ p/ w - ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 3, ADC_SampleTime_239Cycles5 );
& x" H ^# { X - ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 4, ADC_SampleTime_239Cycles5 );
+ D$ t8 z- q2 z" ? - : A$ R; T2 l2 G% k8 d0 t, V9 j; x
- // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数) ) U! N/ m5 z% g; W
- ADC_DMACmd(ADC1, ENABLE);
2 F' U* y1 v. `' ?8 P5 a1 @ - } ' ^! t2 W6 {' ~7 u$ d3 H; ]
- //计算多通道ADC值 # p. f3 w8 l- H3 f
- //AD_Value[]是DMA目标地址的数组空间
" J$ \$ \8 |- F+ w! S - u16 Get_Multi_Adc1(void)
- A! c4 W, Z1 H$ J) G% E+ s - {
+ X$ J# r8 _' Q& q P8 l - u32 temp_val=0;
6 ~& N; F7 f& b3 j - u8 t; 2 V* q* ~/ ~4 E4 B4 K# h5 B7 j
- for(t=0;t<4;t++) ; n, e6 v$ s) Y2 j
- { ! l2 L7 ~: o( N0 s1 o
- temp_val+=(AD_Value[t] & 0xffff); 7 A* }9 G( `" y) L2 B
- } 2 ~3 i) s- {; x( K; W0 O8 ]- d5 ], F
- return temp_val/4; ( t& c2 M0 s( h W5 J( V
- }
复制代码 主要需要修改的是这句话,使得ADC处于同步规则组模式。2 U3 w. @, P3 Q8 l' F# Y! d
- <strong>ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult; //ADC工作模式:ADC1同步规则组模式</strong>
复制代码 AD_Value[]是32位的,用于DMA传送的目标的ADC数据数组。其中高16位是ADC2的数据,地16位的是ADC1的数据。+ d, ]$ |4 {: R
/ S, `+ ]5 d* T) K3 [5 @8 n2 F! _" _
! m- H( |7 |0 F2 F
7 W) o% Y- y: }9 \+ B$ E# v其次是ADC2配置代码和使能代码:" n; g. {3 s* D, A2 O
- //初始化ADC2 9 y6 @' T( U, Z$ w( K _' E5 H: D
- //这里采用多通道连续采样,并用DMA1的通道传送 0 H0 U, d( b! E2 i; e7 \9 h
- //我们默认将开启通道10~13
- U2 z/ E4 Y9 W7 g0 e9 [9 L - //相应管脚PC0~3 ( i7 _/ S$ H" R( l
- void Adc2_Multi_Init(void) 9 N( Q% Y/ y$ L- v# ~$ j) H
- { 4 u) q7 ], ^/ C* s c
- ADC_InitTypeDef ADC_InitStructure;
2 S" K( z8 [2 P g3 a, v0 x" }1 n - GPIO_InitTypeDef GPIO_InitStructure;
" ]. W# {5 d* j9 y4 V* I -
3 B3 ^3 |% V& e; R - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |RCC_APB2Periph_ADC2 , ENABLE ); //使能ADC2通道时钟
$ H/ m0 `8 I+ p0 j - : d( I1 P Q4 E* Q8 I5 q4 s
- 7 c- ^' l* L8 R( _
- RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M 8 C8 q/ W+ C% j+ S- g$ I2 Y
-
W& V, L( V6 O! A' e1 c: P% w - //PB0,1 作为模拟通道输入引脚
, H0 \( I8 Z/ I) e6 x1 b$ j - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
C! x' f6 V2 L2 T, d z - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
8 D3 X- @- V7 }6 x5 S# y4 Z* I - GPIO_Init(GPIOC, &GPIO_InitStructure);
- w+ g: [, S2 r: D4 ~" g* b$ T% u -
3 s' H, i" o/ g - ADC_DeInit(ADC2); //复位ADC2,将外设 ADC2 的全部寄存器重设为缺省值
2 W* `0 {% [; P I -
Z0 _* e: u3 z, z/ g - ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult; //ADC工作模式:ADC1同步规则组模式 % Y, v# P% }% K: n: W2 p" @5 w6 j# x
- ADC_InitStructure.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式
+ ~+ B+ `7 w K& H9 t, H& S0 T% l1 F - ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在连续转换模式 1 y: g& f! }6 H/ C# g8 Z: n& W
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动
. Q1 t1 W: i! B/ B - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐
" U4 O6 [" [; D/ e' F% k - ADC_InitStructure.ADC_NbrOfChannel = 4; //顺序进行规则转换的ADC通道的数目
% F7 @" `* K9 o" P- [! B - ADC_Init(ADC2, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器 ' k1 G0 s- r% G" }: J' ~; V( g
-
9 u- N/ B ^8 \5 } - ADC_RegularChannelConfig(ADC2, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5 );
8 Z9 u( j; v5 ] - ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 2, ADC_SampleTime_239Cycles5 ); ) y% H& g R" J# O
- ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 3, ADC_SampleTime_239Cycles5 ); ) I9 ]$ u% q1 `
- ADC_RegularChannelConfig(ADC2, ADC_Channel_13, 4, ADC_SampleTime_239Cycles5 );
# q5 f1 B# s* w+ x0 l d0 j. T -
$ _: b$ i, J; X7 q - ADC_ExternalTrigConvCmd(ADC2, ENABLE); //使能ADC2的外部触发模式 ; h( C8 Q w' ~% Y
-
! C! J0 B3 X) c6 s - // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数) ' w# Q" i2 {7 Z9 O4 C
- //ADC_DMACmd(ADC2, ENABLE); 4 r' v- ?* g+ C* e1 x! q- b
- }
复制代码- //计算多通道ADC值 3 W; k5 L) ~& U- w- i. d
- //AD_Value2[]是DMA目标地址的数组空间 ( k9 \, E' W2 {
- u16 Get_Multi_Adc2(void) , Z2 |" h, e2 P6 q
- {
; P! T& q- c( N1 \: B - u32 temp_val=0;
& v; f/ a4 z$ O$ w, C - u8 t;
+ E5 C/ g8 V9 U) N- X! A( N - for(t=0;t<4;t++) " [; a& i3 [! [' v" R1 B) g
- {
6 K3 S: A0 f+ K+ o* k% W - temp_val+=((AD_Value[t]>>16) & 0xffff); y/ S0 f+ l: A" N; ?1 ]2 }
- }
: W0 y8 l- u' a0 s - return temp_val/4;
2 p ]; E7 n) n/ G9 e1 i8 {" i - }
复制代码 ADC2主要需要添加下面语句,用于ADC1触发ADC2的工作。9 u' [* L' J5 n( b6 _9 N+ C8 J7 H
- ADC_ExternalTrigConvCmd(ADC2, ENABLE);//使能ADC2的外部触发模式
复制代码 AD_Value[]是32位的,用于DMA传送的目标的ADC数据数组。其中高16位是ADC2的数据,地16位的是ADC1的数据。这里使用AD_Value[t]>>16进行移位操作,获取数据。
) E9 M% X m: D9 [- e& l: }
! f- j4 X6 l, q/ ?$ k+ C7 S+ T6 E& ^$ a" k
}. c4 d4 e" A$ o
|