你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F2XX——ADC多通道DMA采集时AD值大于4095的问题解决方法

[复制链接]
STMCU小助手 发布时间:2021-12-2 16:03
前言) F# p8 @% U5 T$ E" [% f( K
  最近在调试STM32F2XX系列ADC多通道DMA采集时,发现采集的AD值大于4095,有的65000多了,这是什么节奏?adc不是12位吗,最大才0xfff,即4095,怎么会出现这种情况呢?难到是adc数据对齐方式出现问题了,adc的对齐明明设置的是右对齐啊,神马情况?
  B$ c1 t. i: M; I  C- {  P. C) ~( a' G' _& ^
ADC结构体参数分析

  |- E: v0 e3 K1 m9 v0 ]$ \  百思不得adc之姐,只能keil单步调试,一步一步查看adc结构体的参数。我使用的是adc dma方式采集,共9个通道。初始化程序如下:
: f7 |% a6 {/ O& z
  1. void ADC_DMA_Config(void); ]! k) _3 V. _
  2. {4 K9 a8 a' r" |. `& K6 p( X
  3.     ADC_InitTypeDef       ADC_InitStructure;4 P% X: G( m! X
  4.     ADC_CommonInitTypeDef ADC_CommonInitStructure;
    3 @/ }+ j3 T3 p0 ~& l
  5.     DMA_InitTypeDef       DMA_InitStructure;( g) p, d/ H4 P( g+ s
  6.     GPIO_InitTypeDef      GPIO_InitStructure;
    5 b9 F$ C2 O' c

  7. ! s2 r& I* y9 t: z
  8.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);
    , k, g, H0 {( w; T
  9.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);0 b- O2 T% S! A. H

  10. . L& l. j! e4 v  E8 _. ?! C7 J
  11.     DMA_InitStructure.DMA_Channel = DMA_Channel_0;  
    0 T# R) x. l# V( N
  12.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;  L, O/ ^& L7 W/ s
  13.     DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_ConvertedValue;  2 i4 i  R7 V- D) V* B. Y, \7 F' W
  14.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    ' F, W: @3 c) j, `
  15.     DMA_InitStructure.DMA_BufferSize = Sample_Num*Channel_Num;         3 g. a( S( R3 _9 K
  16.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    5 g# J8 b% R7 H8 _, o7 X3 k" ?
  17.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;/ G) P) ]3 D- F: f1 A
  18.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
      @# a6 }3 o2 h& E7 C" z9 t) y4 {
  19.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    & r: B( o0 W; f3 h; g4 Y
  20.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    9 f6 M; v: D: \$ K# j- p7 }
  21.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;$ U% O' |9 ?4 h% U! d3 C3 _
  22.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
    - F' C1 x& t  F" E$ x% Y/ d3 Y
  23.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    . J3 ~! X# [, |6 C% E% `
  24.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;' ~6 _0 Q* S. N7 ?) }/ }' O
  25.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;0 C, W. q6 A5 G* o/ `6 _4 x5 n
  26.     DMA_Init(DMA2_Stream0, &DMA_InitStructure);* T1 N" ?7 h- a' C, x' y, T( V
  27.     DMA_Cmd(DMA2_Stream0, ENABLE);: p5 @8 Y/ U6 x2 c
  28. ) R' D# P, I  b
  29. / S' {6 r3 h+ e5 V# X! M1 A3 R
  30.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 |GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;4 g2 u" ^/ x  d
  31.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;  x  `4 H5 t6 F) b7 }, k
  32.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;  ^: K6 c, N* T
  33.     GPIO_Init(GPIOA, &GPIO_InitStructure);+ r$ _0 P/ q- @" O- B( o
  34. . _( M' F" n9 @7 k6 c7 A/ D
  35.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5;
    + k8 x" a7 j+ a3 s, t0 D
  36.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;0 W6 Y" F  ?- n" v; Y; l0 l: Y
  37.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;( \) T* D% o) E  ?# l1 e3 K, g
  38.     GPIO_Init(GPIOC, &GPIO_InitStructure);; T. R3 y0 S- R4 L6 R9 y  i7 L7 t

  39. " v3 O& n# h6 M: X& k
  40.     /* ADC Common Init **********************************************************/
    2 a! W. ?- A9 j4 [' a8 v1 I
  41.     ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;3 v3 {! f. N1 l
  42.     ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
    5 m; n. U9 Z( c* ]" \- R( D; q
  43.     ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
    0 O- I: R9 Q7 N+ f# {7 Q
  44.     ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;6 ~- x0 ?+ c8 {" G% O
  45.     ADC_CommonInit(&ADC_CommonInitStructure);
    0 S0 x# I+ C5 e. ~+ h. \2 E

  46. - y$ p+ d2 o* i* V" x' W* |$ d& l
  47.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    # \8 p2 ~& v7 B$ F: Z7 `& d# R( K
  48.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;
      P1 w, h9 {- V% K% {  A
  49.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;. [" d; q( D# G3 i* U- y  l
  50.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    5 T! o, S7 k$ X  ~- g0 o- X: |4 F
  51.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ' V" X) C$ P/ [# D+ Z6 x9 U
  52.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    " D2 P* Y: s9 B+ w
  53.     ADC_Init(ADC1, &ADC_InitStructure);
    % i0 Q6 U8 Y! ^' _$ |/ ~
  54. 1 t' E3 t7 {5 v& Y9 a9 t" }

  55. $ _$ n! R+ l' V" h/ L' Z) {7 B# B. ~
  56.     ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);
    * Z% e% X4 a; Q
  57.     ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_3Cycles);
    8 o% M8 }% l: a& M0 U; j: f' ], Z
  58.     ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_3Cycles);2 e  V& ~/ t8 ]: ]: E* L$ `
  59.     ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 4, ADC_SampleTime_3Cycles);/ A2 H& T0 [2 s" z- r, ^; y" ]
  60.     ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 5, ADC_SampleTime_3Cycles);0 n  a  w% X. ^* f, s5 I* ?
  61.     ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 6, ADC_SampleTime_3Cycles);
    " O7 z  |0 m; q9 S
  62.     ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 7, ADC_SampleTime_3Cycles);
    7 z& }/ [+ f& v
  63.     ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 8, ADC_SampleTime_3Cycles);! ^9 F7 L* @& O  y8 L
  64.     ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 9, ADC_SampleTime_3Cycles);
    3 ~2 k0 e4 D! p1 ~- R: k/ u2 v
  65. * \5 H( G7 G. z: r0 O' x" F0 i
  66.     ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);" _1 E) Y8 Z5 ~; k$ L. i: C' y
  67.     ADC_DMACmd(ADC1, ENABLE);
    - a- x- B7 D  ]# p
  68.     ADC_Cmd(ADC1, ENABLE);$ y0 R7 v- [6 q, d  z
  69. 1 N4 o& h- T5 Z5 K& Z0 t
  70. }
复制代码
: K4 s: k  y" C, Y
  其中涉及adc的初始化结构体代码部分如下:
4 f: F5 W) F) s- D
5 J2 l- }8 }; ~4 H, T. q4 n9 X    ADC_InitTypeDef       ADC_InitStructure;! Y5 H. w  e$ p
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;2 M$ W$ a' j4 h% k6 A8 @
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;, @: {3 G- |6 X5 Y. n9 k; Y; M
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    9 w; `! X6 V6 P8 X. E
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;6 [6 N- j: H; C8 j( A, w; x
  5.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;& R: H8 n5 q; G. t9 |% g$ D4 N
  6.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    ! ]+ E) U  i5 N# f
  7.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  一步一步调式发现结构体有一项ADC_ExternalTrigConv是0x08002d54,这一项并没有初始化对其赋值,忘记给结构体的这一项赋值了。最后这个值通过ADC_Init函数赋值给CR2的时候,第11位(也就是数据对其位)是1了,左对齐了!!!!!
9 h6 J6 G6 I, R6 S/ w/ S* W4 L; O  P# k, D
20180823193630758.png
' ^& v7 T; h# u

6 X# E3 D$ L0 X' ]9 [- s" o4 B  下面来重点分析下adc初始化结构体中的各项参数的意义:
: F9 t: a% _$ J$ M0 C( L& i5 r  对于STM32,在使用ADC的时候需要配置几个参数。
0 |1 L1 K4 V0 T(1) 第一个参数是ADC_Mode,这里设置为独立模式:8 Q8 O, u$ A- G0 G( h; r
$ i( F% ]% D' K* L( i# Z
  1. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
复制代码
$ M  ~! ?6 d. o7 M% I/ p3 X
在这个模式下,双ADC不能同步,每个ADC接口独立工作。所以如果不需要ADC同步或者只是用了一个ADC的时候,就应该设成独立模式了。
( g( d. N6 ~0 q, n# z  Z  Y/ T! @' t. n( [& I8 G
(2) 第二个参数是ADC_ScanConvMode,这里设置为DISABLE。" F9 k7 i( Z9 `* g4 c
  1. ADC_InitStructure.ADC_ScanConvMode = ENABLE;
复制代码
! b- ^) c( p3 Y# K% v* ^
如果只是用了一个通道的话,DISABLE就可以了,如果使用了多个通道的话,则必须将其设置为ENABLE。1 l# L1 B( h: J1 M6 ~* m  j6 Q
/ {" H7 M( N( d% m, @, W5 X
(3) 第三个参数是ADC_ContinuousConvMode,这里设置为ENABLE,即连续转换。
5 J/ s  Q9 z" L' \) s+ D如果设置为DISABLE,则是单次转换。两者的区别在于连续转换直到所有的数据转换完成后才停止转换,而单次转换则只转换一次数据就停止,要再次触发转换才可以。所以如果需要一次性采集1024个数据或者更多,则采用连续转换。
% ~0 c% U2 o0 {. ^- [9 i& _0 G& A  h4 w8 Z
(4) 第四个参数是ADC_ExternalTrigConv,即选择外部触发模式。这里只讲三种:- V3 e, s3 z. l1 J

6 R, a2 h1 Z0 n* s! @1、第一种是最简单的软件触发,参数一般为ADC_ExternalTrigConv_None(注意STM32F2XX系列这个有点蹊跷,后面会讲这个)。设置好后还要记得调用库函数:4 E1 j: \& g6 `7 g. i0 m
  1. ADC_SoftwareStartConvCmd(ADC1, ENABLE);
复制代码
  1. void ADC_SoftwareStartConv(ADC_TypeDef* ADCx)
    / @$ X2 b, w& q, m" v* t
  2. {
    0 s4 ?/ X5 p1 \; i- p& G/ N" @
  3.   /* Check the parameters */
    / a& q! x5 l8 B6 ?
  4.   assert_param(IS_ADC_ALL_PERIPH(ADCx));
    5 Q" O' g0 b- l$ O0 K7 t! v$ L

  5. # _5 }3 \# D6 {4 T: J# k& o
  6.   /* Enable the selected ADC conversion for regular group */
    ! A, x* l1 S! |. k
  7.   ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
    ; t! M5 b& A, f' I( ]' g
  8. }
复制代码
  1. #define  ADC_CR2_SWSTART                     ((uint32_t)0x40000000)      6 Y  E' V6 V7 ]- U7 j$ g4 e+ B
  2. /*!<Start Conversion of regular channels */
复制代码

- |8 O0 V% X) }0 G1 BADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位,这样触发就启动了。; X" k4 ?5 a+ Q2 o0 b) F, j" [' B- k# h
& G6 x! I0 Q; T( I& R/ K" p
2、第二种是定时器通道输出触发。共有这几种:ADC_ExternalTrigConv_T1_CC1、ADC_ExternalTrigConv_T1_CC2、ADC_ExternalTrigConv_T2_CC2、# m) [; c+ {3 M# ^5 ]  t  G: Z2 ]
* Z  m" D" w7 Z  O8 M
ADC_ExternalTrigConv_T3_T以及ADC_ExternalTrigConv_T4_CC4。定时器输出触发比较麻烦,还需要设置相应的定时器。以. d% f. e. f- r$ r

% a, ~9 p2 `3 d, uADC_ExternalTrigConv_T2_CC2触发为例设置相应的定时器:$ N& ^+ @3 M0 K4 y" _3 B  p+ M& a
' U/ `, z, N) z& N3 b2 G4 F
  1. void TIM2_Configuration(void)6 d/ _2 G0 ]0 x/ d3 R

  2. . @& H4 @- E! q# p9 y4 O$ N) o
  3. {  i9 m' ?/ `& q- Q! |, s

  4. , b6 d8 r9 R9 K2 R2 Q; {
  5. TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;' d0 \. M- R- O6 X
  6. ) f2 D8 Z+ t% `" w8 a7 a3 J7 x
  7. TIM_OCInitTypeDef         TIM_OCInitStructure;( t" i3 [& P7 S8 n
  8. 2 c" V6 {7 Y, C7 ?- S( B9 s
  9. TIM_TimeBaseStructure.TIM_Prescaler = 4;7 w" I* J; w3 k3 q1 C# `3 |! a8 e6 ?

  10. , W' }5 m' ^8 M2 g0 N
  11. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    . \. i0 c5 z6 \9 o$ a

  12. ) \( U  k3 d9 ^
  13. TIM_TimeBaseStructure.TIM_Period = 0XFF;
    * E* Z9 c0 V, ?7 p3 M: \
  14. ' r* ]7 b3 y  Q4 t! \/ t9 Z0 M
  15. TIM_TimeBaseStructure.TIM_ClockDivision = 0;1 B2 ~. a) b1 x4 G% o7 i' f+ }
  16. : M- b8 @* x5 L+ J4 c5 ^
  17. TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    . _  [6 t- H; z: v: Y
  18. ( w# _7 P, u( \% B6 w
  19. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    1 v1 }+ D, p* M& x+ \( c" Z5 {% M

  20. # _7 |3 y  S, J- I1 E
  21. 3 P/ g1 p0 N/ M5 N" M/ p$ j; T
  22. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    9 m4 X0 \9 b9 q$ ]. B

  23. & j) K+ J5 o2 ?8 J/ p
  24. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    , Z/ E" ^. C# L; ]4 H
  25. 5 ]1 f+ g3 d  f! ?2 x& d# a  [
  26. TIM_OCInitStructure.TIM_Pulse = 0X7F;7 c# n) ?4 t8 K, o& q/ n
  27. + E8 h. ?! u" U  s
  28. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;9 _+ U  \. g8 H) X

  29. . ?& r2 t) S# D
  30. TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;        1 A: {/ U1 |6 H+ J' j2 `
  31. 5 |0 `$ o9 Y# W, K$ n
  32. //配置CC2的属性。若CC3作为ADC的触发源,则应改为TIM_OC3Init(TIM2, &TIM_OCInitStructure);
    $ l; g  D$ T, K4 m; ?7 Q" r

  33. + e: o8 L7 Q, b
  34. TIM_OC2Init(TIM2, &TIM_OCInitStructure);
    ( M* L! V' K: x4 H$ T* Q* @

  35. " Q! R7 Q2 V! V) H
  36. TIM_Cmd(TIM2, ENABLE);
    3 w8 [2 W1 ^5 p% F
  37. TIM_CtrlPWMOutputs(TIM2, ENABLE);
    4 ~! G5 l, v* C/ D& \# a
  38. }
复制代码

: ?9 ]. h7 Q& M1 _' o3 p4 E) K3 ]! t9 A1 M5 v
这样设置之后就可以用定时器2的输出触发了,至于触发的周期,设置TIM2的时间即可。这里不再赘述。
. o; p+ m4 g5 M7 d
; f/ {9 v. u3 _2 u3、第三种是外部引脚触发,对于规则通道,选择EXTI线11和TIM8_TRGO作为外部触发事件;而注入通道组则选择EXTI线15和TIM8_CC4作为外部触发事件。" q  {0 ~* [( Z* c
, o7 o1 F% G% O9 ?2 D
(5) 第五个参数是ADC_DataAlign,这里设置为ADC_DataAlign_Right右对齐方式。建议采用右对齐方式,因为这样处理数据会比较方便。当然如果要从高位开始传输数据,那么采用左对齐优势就明显了。- N+ p' A+ ~% {. J* h: ?% I
; `  v3 r0 o$ b
(6) 第六个参数是ADC_NbrOfChannel,顾名思义:通道的数量。要是到多个通道采集数据的话就得设置一下这个参数。此外在规则通道组的配置函数中也许将各个通道的顺序定义一下,如:
4 e8 P- N% w1 n2 f% \- h1 N& d$ ^  j
  1.       ADC_RegularChannelConfig(ADC1,ADC_Channel_13,1,ADC_SampleTime_13Cycles5);
    $ O  G: m6 l$ s( H$ I

  2. 2 o; e% e3 ]& ?4 W  `
  3.       ADC_RegularChannelConfig(ADC1,ADC_Channel_14,2,ADC_SampleTime_13Cycles5);
复制代码

# Y) Y" L: J, ^( f1 i2 W( g% s; r& B. ^
  多通道数据传输时有一点还要注意:若一个数组为ADC_ValueTab[4],且设置了两个通道:通道1和通道2,则转换结束后,ADC_ValueTab[0]和ADC_ValueTab[2]存储的是通道1的数据,而ADC_ValueTab[1]和ADC_ValueTab[3]存储的是通道2的数据。如果数组容量大则依次类推。9 n& n$ \6 g3 p  T, r2 R
0 r7 Y# V  z) E0 ~
  补充一点:在使用DMA传输数据的时候,需要设置外设地址和存储器地址,外设地址当然就是ADC的地址了,而存储器的地址如果使用8位数据的话,存储器必须定义为8位缓冲区;如果使用16位数据格式的话,存储器则为16位缓冲器,不可定义为32位或更多,否则,数据将出错。
0 Q' x. d  u6 K4 [3 I$ g: x
: @" D3 p, P8 A" G问题的解决方法
3 `2 M7 Z% V3 m7 r( A& F( k
  上面分析了adc结构体的参数,下面再来单独看看ADC_ExternalTrigConv这一项。
/ l2 X% J5 z( W* t- e  在stm32f2xx_adc.h文件中有这个成员的参数定义,发现里面并没有ADC_ExternalTrigConv_None这个常见的定义。
8 v3 z' J! ?5 Z0 i# [
8 _- U: T1 B$ h) A. O
  1. /** @defgroup ADC_extrenal_trigger_sources_for_regular_channels_conversion
    8 E% R% C! V$ L0 }5 U' p0 S
  2.   * @{) H3 T+ V2 B; j4 ?+ L, L2 ^2 c8 j
  3.   */ ) I0 i3 D# f  x) c
  4. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000)
    * H: i* A' C5 n9 u: h  y% r
  5. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x01000000)' @& d( y, m% [; N% D( S7 Y0 u2 O
  6. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x02000000)6 h* V7 G8 {* Y& U' @2 R
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x03000000)
    " d( e- }* R+ L5 ?% D" m2 ~: S8 r
  8. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x04000000)' R* v$ m2 D( T/ _6 H, x8 p
  9. #define ADC_ExternalTrigConv_T2_CC4                ((uint32_t)0x05000000)
    . @( G0 ?& s% R, r8 D
  10. #define ADC_ExternalTrigConv_T2_TRGO               ((uint32_t)0x06000000)4 u! L# Z: ]4 G6 _
  11. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x07000000)
    3 V! j+ x+ a+ ]6 e: ]# X. E0 Q
  12. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x08000000)
    , ^% R$ g0 B2 a* L' T" }
  13. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x09000000)
    : u9 k! w0 a* `3 i; |
  14. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x0A000000)4 r+ q6 a# d) `4 S5 l  K  ~
  15. #define ADC_ExternalTrigConv_T5_CC2                ((uint32_t)0x0B000000)
    2 ~( }7 p; _0 P# w6 N
  16. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x0C000000)( y) l: K- |6 O  X7 K& g
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x0D000000)
    ( o/ B3 W# C* O, U
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x0E000000)
    2 D; R# q3 b6 e
  19. #define ADC_ExternalTrigConv_Ext_IT11              ((uint32_t)0x0F000000)
复制代码
; c; `$ ^: O2 Y+ u9 L
  再来看看stm32f10x_adc.h文件中的ADC_ExternalTrigConv的参数定义:
  Y; h8 k. s; m# P* C$ n8 G
  1. /** @defgroup ADC_external_trigger_sources_for_regular_channels_conversion
    2 c( q, f' t: ]
  2.   * @{5 O( l) I& F9 @! q2 _
  3.   */
    " C* r4 ?* g- j  F/ {* h( A% V
  4. . L, M  e$ K7 S8 B7 V/ w/ }
  5. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */2 e4 t* f3 B3 \1 {5 z1 O: H
  6. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */
    9 ^! f9 L) J. j9 P
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */0 p9 B  s  i- z. q+ B# b9 W
  8. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x00080000) /*!< For ADC1 and ADC2 */# A) {& e! N8 O- y$ W3 g+ _3 T4 W4 I
  9. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x000A0000) /*!< For ADC1 and ADC2 */  O' b9 N2 Q: G* C
  10. #define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO    ((uint32_t)0x000C0000) /*!< For ADC1 and ADC2 */
    $ Y+ x- Z5 M# h9 j8 N4 g6 o" c) w
  11. * h+ u  m, p. s
  12. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x00040000) /*!< For ADC1, ADC2 and ADC3 */
    + ~" g+ N+ Z+ S3 ]  k
  13. #define ADC_ExternalTrigConv_None                  ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */   //f2xx系列并没有这个定义; m% V. C/ }# w, }$ `2 ^4 a. F/ P
  14. . j  x. n2 i0 T6 o. n+ C: Y
  15. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x00000000) /*!< For ADC3 only */
    1 _8 g' E, _& i+ [  [
  16. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x00020000) /*!< For ADC3 only */
    3 D4 S+ f+ }7 H& x# o9 r" K
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x00060000) /*!< For ADC3 only */
    " J2 V) I; T2 x' t3 i
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x00080000) /*!< For ADC3 only */
    7 A7 P8 d5 {: |' D% m6 x
  19. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x000A0000) /*!< For ADC3 only */
    : {! d. g3 X+ ]/ y
  20. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x000C0000) /*!< For ADC3 only */
复制代码
5 I0 B2 r, j8 t6 T$ M9 Z1 |/ u- |
  对比发现stm32f2xx系列并没有ADC_ExternalTrigConv_None这个定义,很是奇怪,现在还不明白ST的工程师为什么做这个变动。. C/ Y7 T! n, ?$ j" V) D9 s! k. z
  那么问题怎么解决呢?
" h% h  Q/ W) c  一种是进行adc结构体的初始化操作,在配置之前恢复默认值。即调用ADC_StructInit(&ADC_InitStructure);修改如下:
  1.     ADC_StructInit(&ADC_InitStructure);//新增加的9 `& x5 J4 v4 T/ C
  2.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    / I" a9 R& W, p
  3.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;3 J8 N. V, o) h
  4.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    , Y& S+ ]9 \4 B# Q, S2 i# I9 R
  5.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ! x8 Q) a- m2 u  A3 c( ^: M" N+ ?8 [
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    & b8 K2 o7 O  K" R) x5 d8 {# c. |
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    5 J4 s6 Z) c( u
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  调用ADC_StructInit(&ADC_InitStructure)语句,ADC_ExternalTrigConv会恢复默认值0。如下:
+ H. k/ |8 \$ y) \4 ]
" L' r* |" Z& r/ e# b; d8 [
20180823201211262.png

& O( u$ U' t! n
: \% y7 r! L" D0 e6 h7 q3 J  另一种方法是直接配置该参数为0,如下:
6 X* _7 z/ S7 e$ Z1 h# G
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;1 z. ^2 n  q" z
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;* |+ t0 O4 m2 c3 o. W; I, n+ V
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    / {7 F& U. |8 H2 s( B4 k" P$ R& P% c
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;# P9 d9 }6 ]; S2 o) v- p
  5.     ADC_InitStructure.ADC_ExternalTrigConv= 0;//新增加的
    7 b1 l# o# I( {- x0 x0 I4 D8 v
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;( E$ H6 N& }1 H
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;8 Q$ }% V* V2 f! u
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
7 [( X. w( ^9 X4 x# Q! X7 Z' Q) Y6 ^
  这两种方法都可以解决adc采样对齐方式异常问题。
: l) T" v8 M( H& L: ^6 i  但是ADC_ExternalTrigConv= 0在stm32f2xx_adc.h中其实是对应ADC_ExternalTrigConv_T1_CC1的。
/ i  O6 T8 v# p  M3 e0 q$ y8 {9 y4 K: y* w
20180823201832969.png

0 z3 b) s. J6 r5 \0 U3 }# c) F3 N
  也就是说调用软件触发函数ADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位也可以触发定时器触发方式的adc通道。1 E! e8 J% k; X; d1 `  G* x

1 b7 ?% |( i+ G
& {# ~4 `' v& |$ B2 i# L/ C- }. q5 F3 Y6 c9 S4 ?8 v2 E' X6 x
收藏 评论0 发布时间:2021-12-2 16:03

举报

0个回答

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版