|
STM32f103的数电采集电路的双ADC的设计与使用 STM32F103C8T6拥有3个ADC,其独立使用已经在本文的3.1.3里面有详细的介绍,这里主要是介绍双ADC的同时使用,即STM32的同步规则模式使用。在此模式在规则通道组上执行时,外部触发来自ADC1的规则组多路开关(由ADC1_CR2寄存器的EXTSEL[2:0]选择),它同时给ADC2提供同步触发。此功能必须使用DMA通道。同时两组数据是公用一个寄存器,ADC1数据在低16位,ADC2数据在高16位。由于保证数据稳定,在双ADC同步规则模式的情况下,还添加了多通道同时采样。
: [( B6 v' C u2 Y
; I2 A" s! E. K0 S6 Z( A/ O
. Z( a* ?- T+ {4 x2 l, qADC1和ADC2,工作方式采用了同步规则模式,使得两个ADC可以同时对不同的AD输入进行采集和数据存储和传输,而且相互不影响,也可以确保采样时间的减少,同时两个ADC都是使用4通路同时采集,确保了数据的稳定性。5 _' j6 j* a e5 J+ p! j
9 `& ~& H' l5 I7 g+ Z9 Y
) h( Z! @3 T ^# j多功能采集显示平台使用的芯片是STM32F103ZET6,片上资源提供了ADC123共3路ADC模块,为了布线方便以及使用的习惯,多功能采集显示平台采用了ADC1的Chanel 4~7,占用IO口PA 4~7,以及ADC2的Chanel 10~13,占用IO口PC 0~3。7 b& k) u$ F: w4 t5 o7 _+ H( M
- b& x$ C1 X) F5 w" ^
: Y+ c* p& T6 a% m( Y3 s. B使用时有几点需要注意的:
$ [7 W [6 L4 f5 q! Q% U( N) O' l5 e6 {; Z! ?" |) _
2 y3 k) J. V/ }; w6 D: Q' U: M
1.选择正确的模式:ADC_Mode_RegSimult,即DUALMOD[3:0] = 0110,ADC2在双模式中,这些位为保留位# ^. C; }) E- j$ T3 G% r% d# l- ?
2 m9 R. Y5 s7 p% K- q
. J4 g% @8 h2 n' e. M2.开启ADC的DMA,在双ADC模式里,为了在主数据寄存器上读取从转换数据,必须使能DMA位,即使不使用DMA传输规则通道数据。只有ADC1和ADC3能产生DMA请求。所以只需设置ADC1的DMA:ADC_DMACmd(ADC1, ENABLE);: v J, q$ j; E; ]9 ?
, l! L7 E0 L4 B* e: K
0 N8 I* @: u- B ^: X
3.ADC2的转换数据存在ADC1_DR的高半字;
2 L9 \+ A! _( l- h. u0 g: j
; K+ `6 w* ~2 H1 X: Q( x' S9 I
* n/ X% {2 e0 _# @2 Y1 k4.不要在2个ADC上转换相同的通道(两个ADC在同一个通道上的采样时间不能重叠)。
1 x1 q$ F; g" n% c6 W
q& K& }! h8 K8 b1 L
/ E$ v/ ]4 s% S4 S5.ADC2的CR2寄存器的第20位——EXTTRIG:规则通道的外部触发转换模式必须开启(软件启动的时候也要),这样才能利用到ADC1的触发信号。不然的话,需要手动再软启动一次ADC2,例如ADC_SoftwareStartConvCmd(ADC2, ENABLE);
4 {) |; F7 O2 r. X4 W1 S
W8 b2 a4 @+ m* U: k7 i' o0 _6 |/ X- S. Q0 x9 X3 s
但是,假如你设置了这个位之后,就不需要手动软启动ADC2了,所以考虑到同步,这样比较好。用ADC_SoftwareStartConvCmd(ADC2, ENABLE);为什么可以,一方面它 也设置了EXTTRIG位,另一方面也设置了SWSTART。但我觉得先用ADC_ExternalTrigConvCmd(ADC2, ENABLE);的话,一会只要ADC1一启动,两者就同 时启动了,这样更正确一点。8 q; ?: i, B& ]3 ?0 j9 T" u
1 ?/ [- {4 _% V. [
- x% |3 M. P: i0 n( k
以下是ADC1配置代码和使能代码:" m; Q$ z3 l# j. F% N; u6 ~
- //初始化ADC1
5 d8 \, E! L& h: |3 Z/ q - //这里采用多通道连续采样,并用DMA1的通道传送 5 h% V" B3 N& A3 L' { ~
- //我们默认将开启通道4~7 8 D" ?' i7 }0 n
- //相应管脚PA4~7
' i1 z2 v9 h- c# e6 `% I - void Adc1_Multi_Init(void) $ x: @, C! b! q6 o& M; t- t
- {
' X! j' h. Z; l - ADC_InitTypeDef ADC_InitStructure;
6 K+ u; |" P2 E - GPIO_InitTypeDef GPIO_InitStructure;
% l, z% I, [5 ?$ c0 `6 q# C - ; p" R- x6 R4 Y6 ~2 \
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1 , ENABLE ); //使能ADC1通道时钟 ( h: B+ r9 m) U: N2 I4 _, O
- 4 j( o4 _; p- ~1 Y+ t9 G8 R
- 8 \* O, n; M G/ o6 f
- RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M ( s8 S" k, L2 v- M% h
-
7 \ B' U9 B5 d! \ - //PA1 作为模拟通道输入引脚 . L9 i% N: q. U+ r. `
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
1 g# s( D7 U0 X - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚 * B' B3 [, d: F- @% Z# ]
- GPIO_Init(GPIOA, &GPIO_InitStructure); ) @/ D$ z: L6 c% _6 o" m5 s) i
- - e- L) E; X6 g
- ADC_DeInit(ADC1); //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
/ Y! w: k5 e4 l+ Y# V6 Y* r - ( ]: ` `) B) S) \9 V
- ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult; //ADC工作模式:ADC1同步规则组模式 % @* \+ m/ x4 G# p% y4 s- X# S! ?
- ADC_InitStructure.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式 6 {# K6 E: H9 }0 x
- ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在连续转换模式 * h( g0 ^% u$ c8 P
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动
' [ ~8 O$ v2 X; p( H - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐 % o% K# B. ^8 M o! k: @( y" W
- ADC_InitStructure.ADC_NbrOfChannel = 4; //顺序进行规则转换的ADC通道的数目 8 i5 C' V6 R( W& w6 k
- ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器 ; X. v% w8 d1 F- M" b4 m
-
9 {) T) l x6 D2 u; C M - ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_239Cycles5 );
9 b5 y8 T" O6 q3 q+ v, j# ?# W - ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_239Cycles5 ); , I( w! z6 q% U: W/ H- z- I
- ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 3, ADC_SampleTime_239Cycles5 );
+ E. `, e& h, T8 c% g+ L - ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 4, ADC_SampleTime_239Cycles5 ); . ^6 d# s; F" b* C/ w/ c1 Q4 W
-
% v: D, q: Z7 { - // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)
( Q( D7 }1 |6 H& H4 U, Y; ] - ADC_DMACmd(ADC1, ENABLE);
3 p/ g! i# l, ^# L - } # U; |8 H( Z; A$ r" _
- //计算多通道ADC值
z1 U. ~* a( b6 T9 L - //AD_Value[]是DMA目标地址的数组空间 / S$ ~ [/ ?: G9 i6 E
- u16 Get_Multi_Adc1(void) " h0 i2 T# } F/ u4 G9 f( ?4 o
- {
% @+ ]! K0 p. x* D - u32 temp_val=0; [, h* M, p* _9 L1 ^
- u8 t;
$ Z0 M2 E8 D# [4 t - for(t=0;t<4;t++)
5 o$ C6 _: C* D9 u& @ - { 7 X- q" O& P7 G1 K0 I* P( W) r2 A
- temp_val+=(AD_Value[t] & 0xffff); / u- B" G' X: ?) C/ E3 z/ \6 }
- }
2 ^0 g) f% d. T7 b - return temp_val/4; 9 V) I! w. n3 g9 Z& u
- }
复制代码 主要需要修改的是这句话,使得ADC处于同步规则组模式。' v9 A1 E# w- S0 b
- <strong>ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult; //ADC工作模式:ADC1同步规则组模式</strong>
复制代码 AD_Value[]是32位的,用于DMA传送的目标的ADC数据数组。其中高16位是ADC2的数据,地16位的是ADC1的数据。$ f6 @8 v1 D2 u/ Z4 V+ ^
$ c! q& L T7 B1 ~1 W. B
) e i2 S. x, [5 j$ }6 O0 K |! E, A
) a4 ^. i' L h" h. k9 j: i
其次是ADC2配置代码和使能代码:: X0 [$ Q! |+ i' P0 i
- //初始化ADC2
: f6 Q7 @0 S$ S0 \# V3 E- Z( R - //这里采用多通道连续采样,并用DMA1的通道传送 ' A$ ?# B: L& f, Z
- //我们默认将开启通道10~13 6 Q j+ l$ [, [( [0 _$ f4 Z; O
- //相应管脚PC0~3
, D/ m# }) x1 O3 q a - void Adc2_Multi_Init(void) ) R; |$ i& V; S k" ^. Q
- {
3 j1 {* S! W8 E( R7 d+ D/ |* d1 U+ V - ADC_InitTypeDef ADC_InitStructure; 3 ]2 w) z" P2 [! M
- GPIO_InitTypeDef GPIO_InitStructure;
/ i3 f: H. o0 ~+ s$ D - $ m3 @7 ]! r& o
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |RCC_APB2Periph_ADC2 , ENABLE ); //使能ADC2通道时钟 0 v2 \4 E; D" F0 N7 @
- 5 v( C3 e: ~* \' @- n- d8 I$ J
- 6 z. ?3 c$ x' [4 h
- RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
# X4 @( P- e7 B: I8 t9 w. W - 5 G5 {! N e" C, _: {
- //PB0,1 作为模拟通道输入引脚
* M( T4 K* q- S% L% T! e' W - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3; 9 Z" @& u6 @: A& v$ \+ N* z
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚 N T5 B+ k" U: ^1 m0 _) Y3 f
- GPIO_Init(GPIOC, &GPIO_InitStructure); ) b9 A# a) }. r/ Z h
-
- [6 H8 ]/ d/ ]; ?" R! ]0 F - ADC_DeInit(ADC2); //复位ADC2,将外设 ADC2 的全部寄存器重设为缺省值
& ]2 ~+ F: r h" Q9 t" H' Y; y) ]" T" p -
4 o0 C& S: h& t2 @1 F5 h& @3 M/ k - ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult; //ADC工作模式:ADC1同步规则组模式
p& T7 a$ C0 P: G1 V, ? - ADC_InitStructure.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式
5 U3 u. B. {1 k - ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在连续转换模式
' `3 X, g5 `2 D) p; B( w - ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动 : G! F# @3 S& ?& h+ C6 R
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐 3 o9 r! k8 y4 U7 n
- ADC_InitStructure.ADC_NbrOfChannel = 4; //顺序进行规则转换的ADC通道的数目 ' n( n Y) m" U4 x" N( n U
- ADC_Init(ADC2, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器 6 h0 }$ _9 r) O; ]; o; ~
- ; x: `4 D1 g9 j0 x- ]
- ADC_RegularChannelConfig(ADC2, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5 ); : X0 `# H q6 i" |2 {$ T# U/ N
- ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 2, ADC_SampleTime_239Cycles5 ); 6 v' y* v1 G6 G7 x: \- Q
- ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 3, ADC_SampleTime_239Cycles5 );
l7 c8 T5 B0 v' E: |+ I - ADC_RegularChannelConfig(ADC2, ADC_Channel_13, 4, ADC_SampleTime_239Cycles5 ); & _8 y5 o1 V" F: {( X R4 I+ h
- 8 z! j C6 d& w8 x: A4 l
- ADC_ExternalTrigConvCmd(ADC2, ENABLE); //使能ADC2的外部触发模式 3 J9 {5 j- f+ l+ B1 x( X% A7 ~: d
- * t: f# I4 c1 N, c2 U
- // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)
: M/ p8 H/ ^+ H - //ADC_DMACmd(ADC2, ENABLE); s) W( {7 a, z* l+ k
- }
复制代码- //计算多通道ADC值 7 ~6 v: T$ z+ @# I$ v
- //AD_Value2[]是DMA目标地址的数组空间
+ o/ Y' s6 ?: s Q/ r - u16 Get_Multi_Adc2(void) / r( N) n! i8 P- [9 p7 B3 j
- {
" f# `$ ` T3 c: J - u32 temp_val=0;
h2 B5 u9 r3 [; s3 Q; G8 g7 @0 \ - u8 t; * I8 X4 W) N4 }
- for(t=0;t<4;t++)
. K+ y) S% o5 H4 U0 v. W" f - { 3 K- x9 ]9 E/ T8 M, P6 s8 y! H& E
- temp_val+=((AD_Value[t]>>16) & 0xffff);
4 i: V. _" ~, {3 W" I* J - }
8 D& r% z' q; O S! L. B - return temp_val/4;
5 a0 B8 |# z2 d* x$ I0 E0 g - }
复制代码 ADC2主要需要添加下面语句,用于ADC1触发ADC2的工作。- S- F; b; {$ n, e8 w4 M. v% ~' e
- ADC_ExternalTrigConvCmd(ADC2, ENABLE);//使能ADC2的外部触发模式
复制代码 AD_Value[]是32位的,用于DMA传送的目标的ADC数据数组。其中高16位是ADC2的数据,地16位的是ADC1的数据。这里使用AD_Value[t]>>16进行移位操作,获取数据。
- p( A* Q% W( ]' z& M& D4 N" V! }
) U6 f4 H- q4 G0 y1 U0 y7 Q) L
, l3 T1 R+ f: U6 C/ s% [ |