前言; N% I& D+ K+ W" h# D
最近在调试STM32F2XX系列ADC多通道DMA采集时,发现采集的AD值大于4095,有的65000多了,这是什么节奏?adc不是12位吗,最大才0xfff,即4095,怎么会出现这种情况呢?难到是adc数据对齐方式出现问题了,adc的对齐明明设置的是右对齐啊,神马情况?
$ ~1 P0 L% a# O, R* N. O* T# n
8 s F% r1 T+ _! }ADC结构体参数分析4 B7 v# C3 U, g' J; P4 W
百思不得adc之姐,只能keil单步调试,一步一步查看adc结构体的参数。我使用的是adc dma方式采集,共9个通道。初始化程序如下:
; h# A6 b) `+ n8 K% g/ W* Q* P- void ADC_DMA_Config(void): h, x ^5 l" O1 C8 ]/ h7 H S
- {
( N% P% |( O' K) k4 |, X: N6 V& J - ADC_InitTypeDef ADC_InitStructure;' p1 O3 z' L5 Z
- ADC_CommonInitTypeDef ADC_CommonInitStructure;! _9 ?9 q8 \# s5 N0 B" d4 V& n) r
- DMA_InitTypeDef DMA_InitStructure;
6 h1 [ V- p. Y# b - GPIO_InitTypeDef GPIO_InitStructure;
- t" ^; }+ h' d; y! Z% Z
8 u& g. Q% e* h$ ]$ G2 t% C- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);$ n/ q2 S2 b- C# ?3 X" V2 c
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);& e5 @4 |6 s+ a0 d/ H
- 9 P/ d3 H& Z$ O5 j
- DMA_InitStructure.DMA_Channel = DMA_Channel_0; . v& S* }+ t' L% P& b
- DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
* y+ w% [5 x) U" N - DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_ConvertedValue; 9 Q/ Z0 T7 Y# y+ ?# V" Q
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
/ h* _4 ]% E$ M+ v9 x- Z* T S+ y! i - DMA_InitStructure.DMA_BufferSize = Sample_Num*Channel_Num;
: [9 T p# v; J- \ - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;) ~6 g2 } B& d8 Y* ?9 Y. N" Z
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;( c" r$ ]/ ]0 i) E9 [+ s2 D
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;" G! O/ a8 U# E5 D6 ~2 W/ d
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
1 R7 N& q" L) q+ P - DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
' h1 ~5 D4 f1 A* q7 r - DMA_InitStructure.DMA_Priority = DMA_Priority_High;
0 y" F( z) @. \! u) S9 O2 b0 S2 c - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; 7 n9 z* T9 [9 n5 P+ }4 T7 R3 k2 @
- DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;' l8 o( D/ Z; D: L) \2 _' N. p/ W6 e
- DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
$ ~3 Q$ p/ R, S4 W - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
- ^# k+ r* Z G$ J2 f1 j9 | - DMA_Init(DMA2_Stream0, &DMA_InitStructure);+ H" |: y4 H# @& d
- DMA_Cmd(DMA2_Stream0, ENABLE);- g6 T% c$ D; x, S2 b) O. E
, d7 Z: J5 w J$ C# h! ~% U- : |* U: [; n; q" g
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 |GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
5 @. |! ]% d& ~/ B6 B3 w - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
9 C9 P. a+ J% q: m3 E0 w6 R - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;1 D' o9 L* S( K: q$ G5 K
- GPIO_Init(GPIOA, &GPIO_InitStructure);
5 @& \6 K# Y2 v- M+ `, I - ( I% b* f6 J! n- D4 |
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5;4 r: Z9 n a9 s" n% V- \2 L
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;2 Q3 Y( u6 M- @6 J) N
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
( Y0 e& Y8 `. \8 U - GPIO_Init(GPIOC, &GPIO_InitStructure);
- l D% F5 Y* U, ?) P* o% a - z5 r: \: n& v) g' Q- _7 Y. W8 R2 E
- /* ADC Common Init **********************************************************/) L! ]% M, C, N
- ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
+ [) Q( Y2 J* u5 f- E, |& I) _ - ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;( M5 Y4 |7 f$ U7 Y& S N% C
- ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;" T5 j2 z+ U" r8 S- M. p9 N
- ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
# H6 K& I) T* u; `4 H+ W - ADC_CommonInit(&ADC_CommonInitStructure);2 ~" T! T `1 z. y) h
2 [; m2 G- l/ V3 [- ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
9 J% F3 p( U3 Q: |% q - ADC_InitStructure.ADC_ScanConvMode = ENABLE;! u( q( M; c" F: d) A% O1 c1 O
- ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;' ^' I' Y% V& h* N8 }
- ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
; M5 Z$ I( k+ \: U; i3 w - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
) j! p5 m( @6 u% l, Y- } - ADC_InitStructure.ADC_NbrOfConversion = 9;
$ g2 t0 p2 Y+ e' z) J+ r - ADC_Init(ADC1, &ADC_InitStructure);$ x! h( Y* y; C% T( L4 _
0 i) Y3 [# |2 l8 O" I- ; B- l+ N* h4 X' y( W3 x
- ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);+ u i; Z) x! S/ _
- ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_3Cycles);
) D' n0 r* t) Y: P) Q - ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_3Cycles);" C9 _! i9 D2 }9 S
- ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 4, ADC_SampleTime_3Cycles);7 O1 m& R2 b& H1 Q0 z. ^7 D8 v
- ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 5, ADC_SampleTime_3Cycles);! I$ \8 o& Y1 {! ^" L: B
- ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 6, ADC_SampleTime_3Cycles);
, `5 ~+ ~4 L! u' o - ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 7, ADC_SampleTime_3Cycles);1 @- W; Y/ T6 W4 l
- ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 8, ADC_SampleTime_3Cycles);
; q( i; H: U' T% A - ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 9, ADC_SampleTime_3Cycles);
( v* R$ c3 B' P1 [( \. a
( G$ Y% } m4 z# R7 x* Y4 S& D- ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
) q/ Q# r; V7 U7 }0 H - ADC_DMACmd(ADC1, ENABLE);$ u- w* d5 A+ o" R. n( B
- ADC_Cmd(ADC1, ENABLE);- b- h( d9 }+ E+ q% n+ N
- ; F# I/ ~: i( w3 s1 @- [
- }
复制代码 * ^: U. l/ X% g* X a9 F
其中涉及adc的初始化结构体代码部分如下:
1 C0 C8 X4 M* H$ m" W. }. c+ K4 D% { F) F& _; z% H4 x9 z+ u
ADC_InitTypeDef ADC_InitStructure;
4 h9 Z# c, d C( W$ R% A" D i- ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
0 P5 h! P7 F: R# ^# e2 f - ADC_InitStructure.ADC_ScanConvMode = ENABLE;
" j9 v0 p" S, r5 b9 x K9 J, Z - ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;# N+ |9 G6 g: c% f
- ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
; N" a8 |. G4 g - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
/ I4 M! [9 u B - ADC_InitStructure.ADC_NbrOfConversion = 9;
3 Y$ u# ~8 g% K( Y5 g' q; [$ Z - ADC_Init(ADC1, &ADC_InitStructure);
复制代码 一步一步调式发现结构体有一项ADC_ExternalTrigConv是0x08002d54,这一项并没有初始化对其赋值,忘记给结构体的这一项赋值了。最后这个值通过ADC_Init函数赋值给CR2的时候,第11位(也就是数据对其位)是1了,左对齐了!!!!!
/ ]7 Z9 m' U6 D) R1 ~: }1 k1 N* r8 R5 Z5 V" Z9 H, {& I
: l: i2 g& z \9 ^
: f# r, @' G# r* L
下面来重点分析下adc初始化结构体中的各项参数的意义:
: ~8 c$ A1 I5 f* _0 U7 _ 对于STM32,在使用ADC的时候需要配置几个参数。
" U0 t. K$ H R6 f6 S(1) 第一个参数是ADC_Mode,这里设置为独立模式:
* ~1 q& w5 {4 f$ q" h
8 O X; J2 z: {- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
复制代码
5 {3 W& d, T' X ~' i# l# i/ d在这个模式下,双ADC不能同步,每个ADC接口独立工作。所以如果不需要ADC同步或者只是用了一个ADC的时候,就应该设成独立模式了。" }) N+ M- @# M9 J
( p0 J2 W6 g9 T" c& ?7 h. }* d(2) 第二个参数是ADC_ScanConvMode,这里设置为DISABLE。
@- W4 F" Z' I+ L( G3 d- ADC_InitStructure.ADC_ScanConvMode = ENABLE;
复制代码
4 j3 }* j: G0 I2 ]8 o \5 T如果只是用了一个通道的话,DISABLE就可以了,如果使用了多个通道的话,则必须将其设置为ENABLE。
7 d- J' k* E& L" l- h9 m; w4 p9 S8 e. y9 G; o
(3) 第三个参数是ADC_ContinuousConvMode,这里设置为ENABLE,即连续转换。 e5 B9 B/ m1 u8 ]! D: W; ]
如果设置为DISABLE,则是单次转换。两者的区别在于连续转换直到所有的数据转换完成后才停止转换,而单次转换则只转换一次数据就停止,要再次触发转换才可以。所以如果需要一次性采集1024个数据或者更多,则采用连续转换。
5 g/ H3 g# T, M8 _, @5 M, m+ B) U2 q7 F
(4) 第四个参数是ADC_ExternalTrigConv,即选择外部触发模式。这里只讲三种:9 n2 `- `9 ?7 k) h# i
4 N- h! b; Z; ^1、第一种是最简单的软件触发,参数一般为ADC_ExternalTrigConv_None(注意STM32F2XX系列这个有点蹊跷,后面会讲这个)。设置好后还要记得调用库函数:# [ m5 T5 i8 n! l
- ADC_SoftwareStartConvCmd(ADC1, ENABLE);
复制代码- void ADC_SoftwareStartConv(ADC_TypeDef* ADCx)
, Z0 t* b$ e# V* Z/ B. S: \ - {! `8 N4 t+ v0 u5 R+ q& [1 `
- /* Check the parameters */
v# F& }" W" F4 a - assert_param(IS_ADC_ALL_PERIPH(ADCx));
$ _2 X0 D0 @9 G/ V
: }- _9 U3 b3 Z5 ] J2 X9 c- /* Enable the selected ADC conversion for regular group */
- Z$ m6 T2 h/ h9 @$ ?/ M, M - ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;$ y6 A" k5 ~; F0 ?
- }
复制代码- #define ADC_CR2_SWSTART ((uint32_t)0x40000000)
* \5 Z0 z6 S* n$ S4 O; u8 g - /*!<Start Conversion of regular channels */
复制代码
m( p ~- C9 K9 K; ~ADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位,这样触发就启动了。; Y3 M) o/ F, w" R {
5 C& h" ~# b. Z" g2、第二种是定时器通道输出触发。共有这几种:ADC_ExternalTrigConv_T1_CC1、ADC_ExternalTrigConv_T1_CC2、ADC_ExternalTrigConv_T2_CC2、; h& a& k5 T' b& N
( K" B4 r: O( g; I/ _ADC_ExternalTrigConv_T3_T以及ADC_ExternalTrigConv_T4_CC4。定时器输出触发比较麻烦,还需要设置相应的定时器。以4 U+ o9 E0 G) j! N# Y( K0 y. {
- B) u' u+ H8 e& M t; [4 N( g
ADC_ExternalTrigConv_T2_CC2触发为例设置相应的定时器:" Q" k2 h* _, J1 T
: H0 ]' k; c, [* ~. T- void TIM2_Configuration(void)
) [9 v1 A0 o* _+ y - $ [" I* t7 q0 F) A1 b
- {
( s. k& T {& w, i
4 v1 F1 w6 h4 l0 P- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;4 y. t: H, ]# Y8 {
& a4 }" A4 M5 m* j) u5 T+ |- TIM_OCInitTypeDef TIM_OCInitStructure;0 _7 ^! H/ p6 E
6 m+ m& h; ?7 Z6 X- TIM_TimeBaseStructure.TIM_Prescaler = 4;1 g+ L" a. N" Y) ^* Q
0 R/ ~/ f- r- u( z' X1 m: e- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;& z A; a6 Q! A# G7 j
3 }* ^: m( i0 D$ u+ R* _# J2 l- TIM_TimeBaseStructure.TIM_Period = 0XFF;2 _/ N7 O% [9 _) P. o+ t2 R
- 1 Y8 ]* {) c# p8 ^
- TIM_TimeBaseStructure.TIM_ClockDivision = 0;! u9 K1 b& n* K2 r& Y0 R& C
- 0 c' \7 m% M6 p7 } `4 F+ ]
- TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
: b" ]4 p. b: p, W, Y- A8 f
1 w- H7 o: j S& v- TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
! t! m7 V7 x% S4 h - 3 Q1 X* d% w8 Q/ z% W# y
9 C0 V# l% P9 i+ T3 i- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
, ]" x! y3 ~6 \$ ?% o. t& C
+ L+ Q. N r# D! i! o- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
+ v; t8 J M R8 M& l
( y% N4 _. }) z* {- TIM_OCInitStructure.TIM_Pulse = 0X7F;
4 X2 w9 L/ j: i% { Q - : A* K' Y# u2 B1 g5 Y$ p
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;2 a9 B- u6 @, y
. E$ `" x ?6 z/ F1 r- TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
+ |; y# o1 m( J- s
; W1 T0 G) y: r% R, c5 B- //配置CC2的属性。若CC3作为ADC的触发源,则应改为TIM_OC3Init(TIM2, &TIM_OCInitStructure);6 b, q" d* R. |3 u- e
- 1 b; W& W+ F ` J8 c
- TIM_OC2Init(TIM2, &TIM_OCInitStructure);
3 r9 x u/ i; N# }
# q& z% V4 h2 {$ Q' |! m- TIM_Cmd(TIM2, ENABLE);
3 y; U' s3 Q& ?0 s; [ - TIM_CtrlPWMOutputs(TIM2, ENABLE); S4 L' i2 }' }' e T* ^
- }
复制代码 ! ^- V" H$ y! X9 u1 k0 M) e1 s
2 H6 E2 ^" B5 u% d7 P' A8 L8 P! R
这样设置之后就可以用定时器2的输出触发了,至于触发的周期,设置TIM2的时间即可。这里不再赘述。
6 g1 B3 i- f6 l T) H, C: O
, S' L: m1 r5 r3 N/ u B7 a3、第三种是外部引脚触发,对于规则通道,选择EXTI线11和TIM8_TRGO作为外部触发事件;而注入通道组则选择EXTI线15和TIM8_CC4作为外部触发事件。' f6 t# R! B" ?/ I; `0 k
% z) @, z+ O% r I1 h6 u, s# E(5) 第五个参数是ADC_DataAlign,这里设置为ADC_DataAlign_Right右对齐方式。建议采用右对齐方式,因为这样处理数据会比较方便。当然如果要从高位开始传输数据,那么采用左对齐优势就明显了。
?- A% }( c& ~# H7 L |; n A% H) p" l" Z1 }7 O& m" g
(6) 第六个参数是ADC_NbrOfChannel,顾名思义:通道的数量。要是到多个通道采集数据的话就得设置一下这个参数。此外在规则通道组的配置函数中也许将各个通道的顺序定义一下,如:
( I/ u1 I6 I/ _- ]+ b o! c- ADC_RegularChannelConfig(ADC1,ADC_Channel_13,1,ADC_SampleTime_13Cycles5);$ l0 S+ I( f; k/ w7 S* R; N
- , @' b2 m& u" S/ G# j3 t; _9 Q
- ADC_RegularChannelConfig(ADC1,ADC_Channel_14,2,ADC_SampleTime_13Cycles5);
复制代码
, e7 i* i0 }7 \; f, H/ f2 R7 e( T/ M: p2 |5 L$ m
多通道数据传输时有一点还要注意:若一个数组为ADC_ValueTab[4],且设置了两个通道:通道1和通道2,则转换结束后,ADC_ValueTab[0]和ADC_ValueTab[2]存储的是通道1的数据,而ADC_ValueTab[1]和ADC_ValueTab[3]存储的是通道2的数据。如果数组容量大则依次类推。
; c( ?' t2 E1 ?6 _8 }8 @' U; i. Y. \* P& X0 @) X2 t/ B' }# Z' W
补充一点:在使用DMA传输数据的时候,需要设置外设地址和存储器地址,外设地址当然就是ADC的地址了,而存储器的地址如果使用8位数据的话,存储器必须定义为8位缓冲区;如果使用16位数据格式的话,存储器则为16位缓冲器,不可定义为32位或更多,否则,数据将出错。9 [/ n6 ~5 e. [( ]8 c
. c3 Z: Q4 f! d( d! Z( z% ^: S问题的解决方法) ]7 W% P* N: H+ k( B B
上面分析了adc结构体的参数,下面再来单独看看ADC_ExternalTrigConv这一项。3 V, F- N4 g3 R- l7 u5 J( D
在stm32f2xx_adc.h文件中有这个成员的参数定义,发现里面并没有ADC_ExternalTrigConv_None这个常见的定义。9 K: l; ~, d1 n; V5 y" \! O
8 c, p: w3 g! Z4 r; i; c4 Q- /** @defgroup ADC_extrenal_trigger_sources_for_regular_channels_conversion
; e/ E- D2 e& Z7 H6 ?1 S - * @{
" R( Z* X o( S( r6 \ - */
8 ^* u$ Q3 i( g7 F% \% j* R - #define ADC_ExternalTrigConv_T1_CC1 ((uint32_t)0x00000000)
4 L2 d+ V, `/ W' @9 E+ B - #define ADC_ExternalTrigConv_T1_CC2 ((uint32_t)0x01000000)/ W3 R2 W+ r9 M2 W, }: ]9 {
- #define ADC_ExternalTrigConv_T1_CC3 ((uint32_t)0x02000000)
' f4 j5 R+ e/ \- _2 z! p/ ^ - #define ADC_ExternalTrigConv_T2_CC2 ((uint32_t)0x03000000)
2 d y* U$ c. W' E - #define ADC_ExternalTrigConv_T2_CC3 ((uint32_t)0x04000000)
: i' s7 q7 D6 P$ Z+ Y - #define ADC_ExternalTrigConv_T2_CC4 ((uint32_t)0x05000000)* B; T* [9 K9 d4 o
- #define ADC_ExternalTrigConv_T2_TRGO ((uint32_t)0x06000000)
7 z1 V) |8 ~4 s& k) b; A$ | - #define ADC_ExternalTrigConv_T3_CC1 ((uint32_t)0x07000000)
8 M0 W! T7 n( L5 x x D' ] - #define ADC_ExternalTrigConv_T3_TRGO ((uint32_t)0x08000000)# h8 j5 L, }8 R) z
- #define ADC_ExternalTrigConv_T4_CC4 ((uint32_t)0x09000000)
2 M% X6 Z: T/ V2 T" h; T6 K - #define ADC_ExternalTrigConv_T5_CC1 ((uint32_t)0x0A000000)8 c* @9 L/ l3 Z8 ^* Q
- #define ADC_ExternalTrigConv_T5_CC2 ((uint32_t)0x0B000000)! U" D6 r, L2 T) p* ^8 C3 b
- #define ADC_ExternalTrigConv_T5_CC3 ((uint32_t)0x0C000000)
6 m& m6 F) W* S+ u6 R/ ?; P) t - #define ADC_ExternalTrigConv_T8_CC1 ((uint32_t)0x0D000000)
) J. y. y5 }, s: n# I9 I2 \8 O4 c - #define ADC_ExternalTrigConv_T8_TRGO ((uint32_t)0x0E000000) ^' F$ @) X P. \* s0 o9 {
- #define ADC_ExternalTrigConv_Ext_IT11 ((uint32_t)0x0F000000)
复制代码 % Y/ Z; Q6 ]/ \5 g1 ]1 A$ |
再来看看stm32f10x_adc.h文件中的ADC_ExternalTrigConv的参数定义:
# K1 E# I( U; T5 ?- K- /** @defgroup ADC_external_trigger_sources_for_regular_channels_conversion
- Y+ x# |9 Y# o, q9 a: H" B5 m - * @{! M B6 `( x4 j- f# H$ D$ p9 h, f
- */
6 p' L: j& {0 L* L% u8 | - 4 O3 W4 n$ a6 B9 L! w$ U
- #define ADC_ExternalTrigConv_T1_CC1 ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */
* o7 ?: }6 ?8 `, X, x8 L - #define ADC_ExternalTrigConv_T1_CC2 ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */: j8 `. ?1 y1 U. v: z/ `
- #define ADC_ExternalTrigConv_T2_CC2 ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */
# C) Y( u' o& Q+ w9 a - #define ADC_ExternalTrigConv_T3_TRGO ((uint32_t)0x00080000) /*!< For ADC1 and ADC2 */. t6 L* h+ `! W" |( m
- #define ADC_ExternalTrigConv_T4_CC4 ((uint32_t)0x000A0000) /*!< For ADC1 and ADC2 */
" j1 W0 x$ n, |7 q* ?0 a% N4 t - #define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO ((uint32_t)0x000C0000) /*!< For ADC1 and ADC2 */
9 r2 Y0 L$ F" N. U5 V: ~
/ U9 k. O3 M( Z& r' z2 P- #define ADC_ExternalTrigConv_T1_CC3 ((uint32_t)0x00040000) /*!< For ADC1, ADC2 and ADC3 */
1 g' H+ _, Y) f7 ^! ^0 t/ ` - #define ADC_ExternalTrigConv_None ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */ //f2xx系列并没有这个定义) E0 L9 V$ h( N0 X6 J! t
6 I& k ? c- m) m$ `* y/ {- #define ADC_ExternalTrigConv_T3_CC1 ((uint32_t)0x00000000) /*!< For ADC3 only */
" R* J; U2 D' d8 t8 G% Y. ^9 J - #define ADC_ExternalTrigConv_T2_CC3 ((uint32_t)0x00020000) /*!< For ADC3 only */: l2 v" }' j: d0 ` J, d
- #define ADC_ExternalTrigConv_T8_CC1 ((uint32_t)0x00060000) /*!< For ADC3 only */- L4 F& {- |$ c# p
- #define ADC_ExternalTrigConv_T8_TRGO ((uint32_t)0x00080000) /*!< For ADC3 only */7 C# W( G8 t: _
- #define ADC_ExternalTrigConv_T5_CC1 ((uint32_t)0x000A0000) /*!< For ADC3 only */
0 T$ X0 D+ i& p+ h; P' X - #define ADC_ExternalTrigConv_T5_CC3 ((uint32_t)0x000C0000) /*!< For ADC3 only */
复制代码
6 Y$ Q+ j! \2 N$ _2 d% O! o6 d* w( h 对比发现stm32f2xx系列并没有ADC_ExternalTrigConv_None这个定义,很是奇怪,现在还不明白ST的工程师为什么做这个变动。
% f% }; R f4 n2 x& c9 q9 ] 那么问题怎么解决呢?
( o* G! S2 c9 @8 t* q( c3 Y! D) ~ 一种是进行adc结构体的初始化操作,在配置之前恢复默认值。即调用ADC_StructInit(&ADC_InitStructure);修改如下:- ADC_StructInit(&ADC_InitStructure);//新增加的
( ^5 R# H, K2 o& F$ E - ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
/ o% {% r/ }3 P, f7 C+ b8 Z - ADC_InitStructure.ADC_ScanConvMode = ENABLE;! i" E# d2 Q7 ]0 f
- ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;. Q1 ]! q: a' A4 q3 R! \& R2 v
- ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;1 f' j: ~) A. T. C1 A2 v" w7 N F
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
* m1 l: R) @/ ~7 e - ADC_InitStructure.ADC_NbrOfConversion = 9;0 \( h) E3 l9 I' g% F" x
- ADC_Init(ADC1, &ADC_InitStructure);
复制代码 调用ADC_StructInit(&ADC_InitStructure)语句,ADC_ExternalTrigConv会恢复默认值0。如下:: s4 v/ ^. c" X4 u
6 p% _& `. R! K( {4 W. `( L. R$ {! D3 w5 x% K& w5 _
7 u4 e5 l( I8 c+ p 另一种方法是直接配置该参数为0,如下:
/ Q4 ^. L, M4 V g* R) {6 h- ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
. M ?/ {* W8 ^1 S/ [3 e, f$ @ - ADC_InitStructure.ADC_ScanConvMode = ENABLE;% ~) F2 k& S) t4 _
- ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
; }$ y6 T8 J$ L8 V: ^0 ~2 i- G - ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;! F+ D, W# H: v! H7 S. E4 E
- ADC_InitStructure.ADC_ExternalTrigConv= 0;//新增加的
, M: w# ~, F: N* R - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
& X- A2 u1 _/ f- r/ l - ADC_InitStructure.ADC_NbrOfConversion = 9;% ^! g6 Q! _. w- u, z: m3 F& ]$ {
- ADC_Init(ADC1, &ADC_InitStructure);
复制代码 2 v3 F* p4 W; x' M+ J( f. x
这两种方法都可以解决adc采样对齐方式异常问题。
' y* X: s! V& E2 x% [* k( X 但是ADC_ExternalTrigConv= 0在stm32f2xx_adc.h中其实是对应ADC_ExternalTrigConv_T1_CC1的。
+ R6 S* @ I! v0 E1 l- e
2 n( T3 L* a* v+ ? m; `' t; Q7 G' Z( w. l
9 \* `) ~" r+ ^5 y! M% o 也就是说调用软件触发函数ADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位也可以触发定时器触发方式的adc通道。
* X, Y5 x! y1 V$ _# p
8 U- I' m7 @" M \' O0 Y' Y/ f L! X( z
2 S6 Q; U l& q8 D- }" {! N/ |" Y" h
|