前言, F1 z7 W# m: B5 M0 j; F: F
最近在调试STM32F2XX系列ADC多通道DMA采集时,发现采集的AD值大于4095,有的65000多了,这是什么节奏?adc不是12位吗,最大才0xfff,即4095,怎么会出现这种情况呢?难到是adc数据对齐方式出现问题了,adc的对齐明明设置的是右对齐啊,神马情况?
1 X6 M1 X% j$ O) Y- U) ~4 W7 ]
8 n" I6 s; `5 d! jADC结构体参数分析6 z" a2 G+ c/ p6 f2 ^
百思不得adc之姐,只能keil单步调试,一步一步查看adc结构体的参数。我使用的是adc dma方式采集,共9个通道。初始化程序如下:( C( z( p" q( [1 J
- void ADC_DMA_Config(void)
* I$ H. k a6 h9 _, B - {2 i) P6 Q8 y* X
- ADC_InitTypeDef ADC_InitStructure;7 \6 J7 v9 h- B; B& n- M
- ADC_CommonInitTypeDef ADC_CommonInitStructure;3 @; }( {4 R4 K! N
- DMA_InitTypeDef DMA_InitStructure;- U6 h* G6 t4 J
- GPIO_InitTypeDef GPIO_InitStructure;
( ?( q. k% E, O, H# n$ E
( [# Q6 u% T; \- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);4 o9 s: d0 Y6 D! U* }
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
) p# f6 U/ o: S: Z' J5 l
0 W" M2 P l7 \$ V% H- DMA_InitStructure.DMA_Channel = DMA_Channel_0; ' D. o- ?* c$ P3 k, g7 Z
- DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
) }' P* }; t" `1 q, S5 H! P - DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_ConvertedValue; - C" ?/ ?% J$ w* f0 j7 Q
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
7 X, u. Q9 E `# Y( k R - DMA_InitStructure.DMA_BufferSize = Sample_Num*Channel_Num; 3 k% i6 M6 ]2 e* S2 n( A" Y( j6 m1 u4 f
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;! _ ~: q, v& h
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
8 G9 k% o* K, G' i! Z% T$ v - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
' e; }) m" q% N. W9 l( n - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;( @5 r$ E- G8 x
- DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;2 u% ~( c+ f0 K& D- q) \7 ?
- DMA_InitStructure.DMA_Priority = DMA_Priority_High;
$ l. ~2 }4 O- W - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; 1 K+ [# c. @# |. r% P5 ~
- DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;7 A6 [6 D0 a4 P( s3 ^
- DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
7 D2 C, d" t: w2 N0 e - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;1 X+ W9 C" U \. i* G
- DMA_Init(DMA2_Stream0, &DMA_InitStructure);$ y) J7 x: t+ `* Y# V0 M" |# n
- DMA_Cmd(DMA2_Stream0, ENABLE);! C' R& B& X; {
- " B1 |! n8 J* }
3 A+ a. y3 @: `- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 |GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;, ~/ Q+ F' E1 R
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;3 x- a0 V l* ^. F* p$ P* ]1 ?1 V
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;3 Y8 I' R, y7 i! c( ~
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- \$ X; H/ p/ I6 K0 v$ }/ u
( B- r- M; b6 F- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5;4 ~) f0 X# V+ z/ e3 {; d
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;4 Q- I3 p/ u2 g B# ]$ s
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;5 ?6 e7 h3 i: R, t+ m
- GPIO_Init(GPIOC, &GPIO_InitStructure);
. f6 Q3 I0 t1 _ - ( ]5 i' ~& C! J: i( ~6 Q9 }
- /* ADC Common Init **********************************************************/
: l* N& Z% u4 b: c - ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;5 G q, K8 F7 G8 v3 T/ b* D( `0 S
- ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;* U' u, h8 a, D& K
- ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
/ y. h5 i( r' W' d- r- S1 Z - ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
) J! A; j. |6 m - ADC_CommonInit(&ADC_CommonInitStructure);0 B( P) b1 M! g2 J: h& k0 J/ T
) [7 o6 A+ F1 K: b' N6 h, ?- ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;+ H6 C- n1 l( d, A, V
- ADC_InitStructure.ADC_ScanConvMode = ENABLE;
; o7 [7 Y) w( N d) z - ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;! K3 Y! L% V$ f
- ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
0 U, f5 M% }3 Q. t - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
! G, s! q1 n! [0 o _ - ADC_InitStructure.ADC_NbrOfConversion = 9;
4 M+ `8 ~) R6 Z% a: l - ADC_Init(ADC1, &ADC_InitStructure);6 Q! q) z( A+ O8 {/ |; D3 M. h
8 n7 W v& ]( s* G5 r+ D
& X# n$ @5 \% J3 c& g# U7 t$ B- ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);: v( N% t" Y9 w5 t& A2 ^, z
- ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_3Cycles);6 \+ w9 @7 [: t' E; D G6 l
- ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_3Cycles);
) B+ i# H6 A4 Z - ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 4, ADC_SampleTime_3Cycles);
: ]% ?+ a1 p' |9 I+ L* X+ j% a - ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 5, ADC_SampleTime_3Cycles);
/ n9 ~- }6 [" h; @/ ~. V - ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 6, ADC_SampleTime_3Cycles);
3 P% v- o' ] c/ c* x - ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 7, ADC_SampleTime_3Cycles);4 b" H6 @4 N# _& y) x/ a
- ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 8, ADC_SampleTime_3Cycles);
( V% x# |" V" P' k( K# d, z! w0 H - ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 9, ADC_SampleTime_3Cycles);
/ r' _! Y2 a4 x I7 t
' o+ K4 _+ c+ K {+ p- B- ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
/ O" a1 r6 G3 w( [ o% j; k - ADC_DMACmd(ADC1, ENABLE);: T3 a% u; t/ M- {" @
- ADC_Cmd(ADC1, ENABLE);
0 Z' V* k5 c' Y) b! h* x - 0 h! F% U. G! }$ O7 z
- }
复制代码
3 H$ g+ t" T1 c1 w U( q, J- |9 C 其中涉及adc的初始化结构体代码部分如下:% z; i# n$ O2 B6 j! E' M
2 W: `$ o: Q% L u
ADC_InitTypeDef ADC_InitStructure;/ o' p% |6 p+ z; B/ C+ Y
- ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
1 h2 I: C m$ f - ADC_InitStructure.ADC_ScanConvMode = ENABLE;2 C: Y5 f. R2 t1 v/ m1 Z
- ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
9 ]+ ^# c, o% `2 N - ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;6 ?, V( o6 d6 i1 k
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
5 L. P$ y: M1 i- E0 }! T5 a* b - ADC_InitStructure.ADC_NbrOfConversion = 9;
- C+ O2 F6 U# j. \ - ADC_Init(ADC1, &ADC_InitStructure);
复制代码 一步一步调式发现结构体有一项ADC_ExternalTrigConv是0x08002d54,这一项并没有初始化对其赋值,忘记给结构体的这一项赋值了。最后这个值通过ADC_Init函数赋值给CR2的时候,第11位(也就是数据对其位)是1了,左对齐了!!!!!* G j4 F/ R$ N" s5 x# j& `
; `: c" T) {8 v/ [
0 X/ n z! Q+ w: g( u7 H" }. m
4 Z5 e9 n; y% `% h6 j, G4 q" y! D 下面来重点分析下adc初始化结构体中的各项参数的意义:
! X. z9 T; d/ {9 Y9 P 对于STM32,在使用ADC的时候需要配置几个参数。
( p! d2 k$ d3 i(1) 第一个参数是ADC_Mode,这里设置为独立模式: M2 C" Y! |5 s
' q6 r3 ^4 t3 O- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
复制代码
, x1 V7 h1 v/ S: U9 ^: `7 t在这个模式下,双ADC不能同步,每个ADC接口独立工作。所以如果不需要ADC同步或者只是用了一个ADC的时候,就应该设成独立模式了。& l# d2 K4 b8 l, S
( L7 B7 Y& Y/ E: k: |3 j {6 ](2) 第二个参数是ADC_ScanConvMode,这里设置为DISABLE。
! K% q# g; ~/ W6 {- ADC_InitStructure.ADC_ScanConvMode = ENABLE;
复制代码 ; w2 `# T" D" h) e
如果只是用了一个通道的话,DISABLE就可以了,如果使用了多个通道的话,则必须将其设置为ENABLE。& J" U1 w+ f0 G" U/ i# G; t# x1 [
3 Q# K6 m* j* R0 A" H$ A% Y(3) 第三个参数是ADC_ContinuousConvMode,这里设置为ENABLE,即连续转换。
) b4 j9 U4 E8 V4 T如果设置为DISABLE,则是单次转换。两者的区别在于连续转换直到所有的数据转换完成后才停止转换,而单次转换则只转换一次数据就停止,要再次触发转换才可以。所以如果需要一次性采集1024个数据或者更多,则采用连续转换。) a) l4 y: ^" X7 c
: f! X' P1 r" J& B" A* T3 A/ l(4) 第四个参数是ADC_ExternalTrigConv,即选择外部触发模式。这里只讲三种:
( C" Z) I4 Q P S- H% b$ ^9 R& K* r3 ?8 q7 i
1、第一种是最简单的软件触发,参数一般为ADC_ExternalTrigConv_None(注意STM32F2XX系列这个有点蹊跷,后面会讲这个)。设置好后还要记得调用库函数:
/ R1 S% Z# O6 ^+ J, Y8 V- ADC_SoftwareStartConvCmd(ADC1, ENABLE);
复制代码- void ADC_SoftwareStartConv(ADC_TypeDef* ADCx)
$ C p# ^+ g0 X5 |9 L* X- V/ ?( d - {4 C$ L% o. ?. |% J
- /* Check the parameters */
2 `0 ^0 z- J3 T& S; n& l' E - assert_param(IS_ADC_ALL_PERIPH(ADCx));
4 C, X, J' Z& C
! c: ?6 v6 z. a7 d! p- /* Enable the selected ADC conversion for regular group */& i* O7 M1 l" x i% j
- ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
2 O0 j6 ^7 W) \8 _ R( @ - }
复制代码- #define ADC_CR2_SWSTART ((uint32_t)0x40000000) / a; t" X; l; T* o) c
- /*!<Start Conversion of regular channels */
复制代码 $ H" E+ | i1 E; j
ADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位,这样触发就启动了。
6 _2 a1 [2 A% q' v
& X) r% \5 q5 k w; m1 r2、第二种是定时器通道输出触发。共有这几种:ADC_ExternalTrigConv_T1_CC1、ADC_ExternalTrigConv_T1_CC2、ADC_ExternalTrigConv_T2_CC2、
) S. \5 W9 b5 N: i5 l6 ^
0 t7 v$ @8 O' w5 y. oADC_ExternalTrigConv_T3_T以及ADC_ExternalTrigConv_T4_CC4。定时器输出触发比较麻烦,还需要设置相应的定时器。以
$ H' ~: @8 l+ ?$ @# G, h. S& v2 T- U7 X! \- N$ E" M
ADC_ExternalTrigConv_T2_CC2触发为例设置相应的定时器:- X/ D! r5 P* A4 j8 N
9 E& A! h" d0 i
- void TIM2_Configuration(void)0 i0 H$ g3 J- L M
- : U( `/ K9 h, ^) K
- {
" l0 s, Z( Z, L9 A3 P$ x
! m. R3 g/ p# |' F1 p% i- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
& d# H9 I3 s2 H2 |$ @$ W+ l. M- s i
1 C# U" E% F5 |! q9 O; x. z; X# U- TIM_OCInitTypeDef TIM_OCInitStructure;, j( f s4 H! J- [* a
- : V. p. O7 z. c. e# p9 C
- TIM_TimeBaseStructure.TIM_Prescaler = 4;
, [& p: i& K% ?' p! I - 9 C) E# j( }# Q
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;% v* W" Z W& T8 ]' Y
- $ l9 H# `/ ^1 y: x0 H; L
- TIM_TimeBaseStructure.TIM_Period = 0XFF;
& g; l4 A; Q( G% _/ H4 v, H; L& ?8 b
! q# i' X4 @9 y( L: z6 ?( Y- TIM_TimeBaseStructure.TIM_ClockDivision = 0;
3 _( f/ @1 p: D
- ]/ T9 s; g; }# r" g: P. A- TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
' e0 B. P0 L7 k* c; ~ - ( V5 I, w: n1 e
- TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
( g, m- q: P( S8 B! ? w! e, R% s - + [. G# t3 J- I6 w( D6 J
- 0 b5 R9 d; T2 Q* r8 D+ g
- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
! M9 E+ x3 o7 r) N6 P' o- v. e - 8 ]' U( O4 ?) C/ @# Y
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;2 F( @6 ?1 u* l0 [% E
- ; w5 i$ a2 T% K
- TIM_OCInitStructure.TIM_Pulse = 0X7F;
( B( u# f0 n2 H0 N; r
$ z. ~' e4 u8 T: e' z/ t0 _0 z- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;; g+ O0 z& T! W) x* K" a
- * c! I8 x8 s% r, @6 W1 M
- TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; 6 v, B, O* ]% x: `. E" _# s$ Y
- 3 I4 d# k! D6 H, t' b
- //配置CC2的属性。若CC3作为ADC的触发源,则应改为TIM_OC3Init(TIM2, &TIM_OCInitStructure);7 f/ A \5 L" X# g* k& M" ]- f
# }9 X4 v: `" V L- TIM_OC2Init(TIM2, &TIM_OCInitStructure);
! q* N9 l- H4 X2 P( z
$ C# s! S, V0 o5 H, n0 t) G* `. V- TIM_Cmd(TIM2, ENABLE);
- s) q5 p. z9 Z6 P - TIM_CtrlPWMOutputs(TIM2, ENABLE);% y# B8 d! a; e" u1 F4 n) [
- }
复制代码
3 Q8 B! }. y+ z
" N# Y& n6 y6 g. Q- h% r3 [这样设置之后就可以用定时器2的输出触发了,至于触发的周期,设置TIM2的时间即可。这里不再赘述。
5 M$ b! a" ?! j: u# y! t) D
+ l8 u9 Z+ _9 G2 `. j3、第三种是外部引脚触发,对于规则通道,选择EXTI线11和TIM8_TRGO作为外部触发事件;而注入通道组则选择EXTI线15和TIM8_CC4作为外部触发事件。
/ Q, ^& T7 i$ P: B b0 f
1 D3 W3 C/ L1 O( E7 J( H(5) 第五个参数是ADC_DataAlign,这里设置为ADC_DataAlign_Right右对齐方式。建议采用右对齐方式,因为这样处理数据会比较方便。当然如果要从高位开始传输数据,那么采用左对齐优势就明显了。
. G2 p2 h9 {) T- d; I2 S* M" g- w Y' i" t h4 `2 c6 |
(6) 第六个参数是ADC_NbrOfChannel,顾名思义:通道的数量。要是到多个通道采集数据的话就得设置一下这个参数。此外在规则通道组的配置函数中也许将各个通道的顺序定义一下,如:4 O7 @9 h# D- W# z c
- ADC_RegularChannelConfig(ADC1,ADC_Channel_13,1,ADC_SampleTime_13Cycles5);
, m+ n& @* e* \$ a/ c& z, c6 W - 7 w: Y& v, V' s+ l3 b
- ADC_RegularChannelConfig(ADC1,ADC_Channel_14,2,ADC_SampleTime_13Cycles5);
复制代码 : J# K& ?- F- G! @* {4 j+ L
Y* V/ r& C1 w 多通道数据传输时有一点还要注意:若一个数组为ADC_ValueTab[4],且设置了两个通道:通道1和通道2,则转换结束后,ADC_ValueTab[0]和ADC_ValueTab[2]存储的是通道1的数据,而ADC_ValueTab[1]和ADC_ValueTab[3]存储的是通道2的数据。如果数组容量大则依次类推。
7 N+ Z0 B: f+ P$ ]
5 D/ }9 A g- i8 Q! I: k4 C$ p1 x 补充一点:在使用DMA传输数据的时候,需要设置外设地址和存储器地址,外设地址当然就是ADC的地址了,而存储器的地址如果使用8位数据的话,存储器必须定义为8位缓冲区;如果使用16位数据格式的话,存储器则为16位缓冲器,不可定义为32位或更多,否则,数据将出错。" S) m6 F( Z: |0 @# m5 e
% n& L# j4 i# h: W
问题的解决方法7 G$ @+ e& T2 P, g6 w
上面分析了adc结构体的参数,下面再来单独看看ADC_ExternalTrigConv这一项。
, |) P4 T" Z8 ?% J 在stm32f2xx_adc.h文件中有这个成员的参数定义,发现里面并没有ADC_ExternalTrigConv_None这个常见的定义。
* W' O' j8 {& N" N# M+ m. C* X/ I$ w1 |, w0 u( L
- /** @defgroup ADC_extrenal_trigger_sources_for_regular_channels_conversion : W( G, F$ C3 D7 O. k- f% Y
- * @{
' ^- i/ z( V0 o4 _% r& y - */
3 }5 Q) j+ i; B9 O8 C% P+ x% l1 Z( y - #define ADC_ExternalTrigConv_T1_CC1 ((uint32_t)0x00000000)5 e! r2 h' G I3 i
- #define ADC_ExternalTrigConv_T1_CC2 ((uint32_t)0x01000000)0 w, o/ d M& d7 ~5 x
- #define ADC_ExternalTrigConv_T1_CC3 ((uint32_t)0x02000000)/ c. Z. F& X) j
- #define ADC_ExternalTrigConv_T2_CC2 ((uint32_t)0x03000000)& L0 H. z& K) N5 G$ C4 s$ T4 r
- #define ADC_ExternalTrigConv_T2_CC3 ((uint32_t)0x04000000)
_+ \+ E( {: x! m7 ?8 t5 u" j - #define ADC_ExternalTrigConv_T2_CC4 ((uint32_t)0x05000000)! P2 l1 g; Z6 t) ^! C; a# t& C( c
- #define ADC_ExternalTrigConv_T2_TRGO ((uint32_t)0x06000000)/ P k# `* W1 c
- #define ADC_ExternalTrigConv_T3_CC1 ((uint32_t)0x07000000)
( ^0 c* o7 E* h& k' n - #define ADC_ExternalTrigConv_T3_TRGO ((uint32_t)0x08000000)/ l0 v8 G0 m v( x
- #define ADC_ExternalTrigConv_T4_CC4 ((uint32_t)0x09000000)# m+ I; u$ H& ]. p* I
- #define ADC_ExternalTrigConv_T5_CC1 ((uint32_t)0x0A000000)' m/ w+ M% R- H7 a6 m! I+ |
- #define ADC_ExternalTrigConv_T5_CC2 ((uint32_t)0x0B000000)
2 m( d8 V# H. M- L/ o7 y - #define ADC_ExternalTrigConv_T5_CC3 ((uint32_t)0x0C000000)) u: d4 c$ ?7 V' C
- #define ADC_ExternalTrigConv_T8_CC1 ((uint32_t)0x0D000000)/ x: {* x# C/ ^
- #define ADC_ExternalTrigConv_T8_TRGO ((uint32_t)0x0E000000)( q' q# H, D- ?+ Y2 F* l
- #define ADC_ExternalTrigConv_Ext_IT11 ((uint32_t)0x0F000000)
复制代码 ; e; G5 s) M. ~( V: G
再来看看stm32f10x_adc.h文件中的ADC_ExternalTrigConv的参数定义:
, L: H% _. t3 x, x- /** @defgroup ADC_external_trigger_sources_for_regular_channels_conversion & V- Y. l% F4 n( L0 m
- * @{ ]# x! I% ^- S
- */* z! ]& H6 S# Q, o, e
- $ {, k$ F- u, F. R
- #define ADC_ExternalTrigConv_T1_CC1 ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */- Z/ @9 _$ w& ]$ v
- #define ADC_ExternalTrigConv_T1_CC2 ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */; J8 R$ B8 m, c$ |2 v! b" R
- #define ADC_ExternalTrigConv_T2_CC2 ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */5 N- j' f' L; i; Q9 Q/ l- A& N$ a
- #define ADC_ExternalTrigConv_T3_TRGO ((uint32_t)0x00080000) /*!< For ADC1 and ADC2 */
. M& z6 O, Y4 D% [# Q - #define ADC_ExternalTrigConv_T4_CC4 ((uint32_t)0x000A0000) /*!< For ADC1 and ADC2 */4 j' N- ^6 X" n' U4 e
- #define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO ((uint32_t)0x000C0000) /*!< For ADC1 and ADC2 */
4 Z0 A6 N) }4 e! s - / e8 B3 J' j8 d) s& A4 B
- #define ADC_ExternalTrigConv_T1_CC3 ((uint32_t)0x00040000) /*!< For ADC1, ADC2 and ADC3 */' ^1 Q+ u" k; s* N* G
- #define ADC_ExternalTrigConv_None ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */ //f2xx系列并没有这个定义
" Q4 l/ I" O) @' P: Q - ( P$ Z6 r, D1 ~0 T
- #define ADC_ExternalTrigConv_T3_CC1 ((uint32_t)0x00000000) /*!< For ADC3 only */
5 a8 C) }9 M9 }8 \$ ~7 I" c - #define ADC_ExternalTrigConv_T2_CC3 ((uint32_t)0x00020000) /*!< For ADC3 only */8 T/ s6 R0 Y$ ]% A& F
- #define ADC_ExternalTrigConv_T8_CC1 ((uint32_t)0x00060000) /*!< For ADC3 only */( Y+ k! j; `% \ M" `
- #define ADC_ExternalTrigConv_T8_TRGO ((uint32_t)0x00080000) /*!< For ADC3 only */
! z$ ^4 l) a+ l' ?! P4 m - #define ADC_ExternalTrigConv_T5_CC1 ((uint32_t)0x000A0000) /*!< For ADC3 only */
3 e D8 n' a, |! M - #define ADC_ExternalTrigConv_T5_CC3 ((uint32_t)0x000C0000) /*!< For ADC3 only */
复制代码
1 ^1 H' z+ I0 v/ ?8 {; Y 对比发现stm32f2xx系列并没有ADC_ExternalTrigConv_None这个定义,很是奇怪,现在还不明白ST的工程师为什么做这个变动。
/ M8 |5 b# m5 L( L2 v5 G+ T8 V! z 那么问题怎么解决呢?: i Q! [; q5 a- F( }! g" J" E
一种是进行adc结构体的初始化操作,在配置之前恢复默认值。即调用ADC_StructInit(&ADC_InitStructure);修改如下:- ADC_StructInit(&ADC_InitStructure);//新增加的' ~: }; a- n, l9 q
- ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
# t" V: ~* d$ i$ c2 W - ADC_InitStructure.ADC_ScanConvMode = ENABLE;
$ J3 m; A, l9 E3 O2 N6 T+ ]1 l - ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;- F" ?. ]# I0 U8 |# }
- ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
, X2 ?7 N- J6 b9 x9 z - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
1 P1 F5 J% Y% E* r i - ADC_InitStructure.ADC_NbrOfConversion = 9;
' k0 }; ^ n% ^6 F4 _ - ADC_Init(ADC1, &ADC_InitStructure);
复制代码 调用ADC_StructInit(&ADC_InitStructure)语句,ADC_ExternalTrigConv会恢复默认值0。如下:
! V- f* l& J2 \6 @& ~) @5 F# \- Q4 P1 t
9 \$ f) I3 F; R" G+ x& i2 e' ^
2 ?& I- @$ p3 {9 b, [ 另一种方法是直接配置该参数为0,如下:
) o. `# s$ ~: x# ~% v- ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
* U; M8 O* @8 @5 k* g' I K" M8 _ - ADC_InitStructure.ADC_ScanConvMode = ENABLE;! W2 n( E9 N& \+ q# C# E& L
- ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
) A2 e1 Y$ T% U/ [ - ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
( M, B5 C1 G9 V6 E - ADC_InitStructure.ADC_ExternalTrigConv= 0;//新增加的! C/ m5 ^+ x3 ?' j7 D* k0 [
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;- l0 f' v7 z, Q3 t7 l$ }
- ADC_InitStructure.ADC_NbrOfConversion = 9;
) j, p. g* f: S$ ^# o - ADC_Init(ADC1, &ADC_InitStructure);
复制代码
. f3 N! [* z) P k( }1 ~, A0 R; K 这两种方法都可以解决adc采样对齐方式异常问题。
+ }# r1 i# A- y. u: c 但是ADC_ExternalTrigConv= 0在stm32f2xx_adc.h中其实是对应ADC_ExternalTrigConv_T1_CC1的。
* k# U& d4 ]4 Q! W R, L
5 F+ r2 s1 d- c
* e% B- d5 U# D% n6 C5 @
$ x8 N$ e7 ~ E6 w 也就是说调用软件触发函数ADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位也可以触发定时器触发方式的adc通道。
! U a7 [0 |7 q* a% C! k! B, c* t9 x
+ g' e. w- ^3 {6 F: m* p* @3 o
. O" H4 M; T3 j# l1 Y+ n4 F# `6 }% }. m/ v: Q
|