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

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

[复制链接]
STMCU小助手 发布时间:2021-12-2 16:03
前言
, M5 T7 q7 _9 ^8 y* j  最近在调试STM32F2XX系列ADC多通道DMA采集时,发现采集的AD值大于4095,有的65000多了,这是什么节奏?adc不是12位吗,最大才0xfff,即4095,怎么会出现这种情况呢?难到是adc数据对齐方式出现问题了,adc的对齐明明设置的是右对齐啊,神马情况?
  c: ]' F  `/ r5 X6 n# }
0 ]) l% I$ i5 o  _5 j* M7 q. cADC结构体参数分析

+ [0 X& k7 E- G. I+ c: O" M# ?  百思不得adc之姐,只能keil单步调试,一步一步查看adc结构体的参数。我使用的是adc dma方式采集,共9个通道。初始化程序如下:
$ [; o: E, [5 [
  1. void ADC_DMA_Config(void), ~4 o- X9 ]' e8 n" e; r( y
  2. {! u" {/ a% `8 W0 |- h( z
  3.     ADC_InitTypeDef       ADC_InitStructure;
    * R) u2 v0 S+ Q7 K
  4.     ADC_CommonInitTypeDef ADC_CommonInitStructure;7 K$ q' J# e- G8 Y  [0 T: U8 `
  5.     DMA_InitTypeDef       DMA_InitStructure;
    0 X0 t- Z) Z1 H0 c: F$ t
  6.     GPIO_InitTypeDef      GPIO_InitStructure;
    3 m1 J' S! T6 s: O7 |

  7. # [0 F2 w4 J( o
  8.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);/ w+ |9 ?3 v' N, r+ S& d
  9.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    4 ]+ m7 \+ G+ }. q, Z) K1 a
  10. + g2 e) U. I: W+ y' H+ F: O( }0 C
  11.     DMA_InitStructure.DMA_Channel = DMA_Channel_0;  , V  X" j: ^1 f) Q% K
  12.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    / w8 j& _' Z' n  a- T# g. n
  13.     DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_ConvertedValue;  4 d) p2 e3 ]& s- A+ a! t
  14.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    + M# ?: Y0 B& n
  15.     DMA_InitStructure.DMA_BufferSize = Sample_Num*Channel_Num;         
    ( i7 Q' D" s6 M! u9 k. e
  16.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    ! ^" _. f1 T/ r+ k+ |% Q$ {% h
  17.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;2 d/ d: L0 U" J
  18.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    7 A8 e" {9 T$ k' v+ y
  19.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;: k- [4 Y7 T) n6 I
  20.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;: X( t. n3 f1 m. ^0 u- q& E4 g
  21.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;0 j) y" b/ Q4 N3 K  P2 q  @
  22.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
    " p; J  h7 D8 {3 E( V
  23.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;0 s/ l: h) R% G% d( Z, `. _
  24.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;& ]6 E. S  M# Z6 w3 P" {0 h
  25.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    & {+ v$ r1 ], s* L8 w" S0 A
  26.     DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    - j/ a4 ?( y0 A# i+ ^
  27.     DMA_Cmd(DMA2_Stream0, ENABLE);
    % ?2 F. `, R: M0 N( y. g

  28. , @- W! K* G3 G9 o2 F9 l& k
  29. - q& X0 t; P0 t0 [
  30.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 |GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
    - y* z3 c* }5 p1 m. v5 k9 S
  31.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;" ~! Z0 H% R; c( m8 I1 O
  32.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;$ @$ ?% ^. N: O4 }- b
  33.     GPIO_Init(GPIOA, &GPIO_InitStructure);7 L. \0 h4 k! l  m9 ?

  34. ! |8 b3 p1 ^$ D# y2 i3 C& T( t; p
  35.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5;
    5 U* n2 G# n1 J! P, s' R+ U
  36.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    ' f& u; ^$ g# f1 i8 S, U/ H
  37.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    * v- ^7 s& V6 X& x
  38.     GPIO_Init(GPIOC, &GPIO_InitStructure);- L  }7 n) i) k' J$ L
  39. 9 I! U  F$ }0 |4 q+ J' k
  40.     /* ADC Common Init **********************************************************/
    - ^2 ~) T: Y# x0 ]/ Q4 a
  41.     ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
    * U" o+ c$ f  |+ T
  42.     ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;9 F9 p8 t0 R8 `+ L4 R- y* z, p
  43.     ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;7 e. m; x8 ^8 U
  44.     ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;8 L9 c3 k5 L/ ~8 p& L- f/ Q
  45.     ADC_CommonInit(&ADC_CommonInitStructure);5 O6 D  i0 O- S* P0 {5 v1 L" L" R

  46. % G% o+ I9 s3 s! I/ j+ Z0 l6 Q
  47.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    0 a8 A7 k4 [# h% S8 y. o
  48.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    $ `5 M/ `8 J6 E% `, f& `
  49.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    * e: x* o. d# u' Q; Z
  50.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;! G- J( G  B% I5 w7 v& M5 P. w
  51.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    & Q6 W& E6 u, Q) A4 N
  52.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    ( \$ e' n/ y) |
  53.     ADC_Init(ADC1, &ADC_InitStructure);
    & {1 ]5 s  {+ t  q7 Z
  54. 9 I1 |- E) r, E8 G4 n

  55. , s) m4 ]3 R. E! j4 k3 ^# s( `
  56.     ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);3 y+ [2 T6 W% E- ^
  57.     ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_3Cycles);
    3 ~+ @. n: Z! C" h
  58.     ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_3Cycles);
    . w8 |9 c8 T$ u4 {) U5 ?
  59.     ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 4, ADC_SampleTime_3Cycles);( n# _+ O2 c& @8 ?/ L( t
  60.     ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 5, ADC_SampleTime_3Cycles);
    8 I5 Z* U! }6 [/ T
  61.     ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 6, ADC_SampleTime_3Cycles);
    + M* J3 s6 `& j0 K* N# P" ~
  62.     ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 7, ADC_SampleTime_3Cycles);( `2 D) t/ b) d0 E% F6 H
  63.     ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 8, ADC_SampleTime_3Cycles);
    # v: |! I2 x( }  w- R/ u( g6 j& O
  64.     ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 9, ADC_SampleTime_3Cycles);) k) l( T! j3 D- a

  65. 7 j6 H: m) z, ~* ^( h3 _4 f2 X
  66.     ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);/ x1 V: y' f7 }' T( X) h: I. q
  67.     ADC_DMACmd(ADC1, ENABLE);6 A% W% Y& Q: y/ h- |
  68.     ADC_Cmd(ADC1, ENABLE);' X- \. c# o: X& t

  69. 3 p+ e+ A/ t! @' ^$ [6 T3 v5 Q
  70. }
复制代码
- X1 e5 A/ s, {, S# i4 R5 N  U2 ^
  其中涉及adc的初始化结构体代码部分如下:
' B( r) X' @; O& |
& d/ V1 \; {2 e& H* n    ADC_InitTypeDef       ADC_InitStructure;
* U# {/ ?( G, c
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;7 U6 P$ k; v/ a$ j4 y% E! r, R
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;( x( Y4 g- I& l8 K: G( p
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    7 _& I" }# F" z& }7 W3 ^
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;6 A# {: b4 V4 q  w8 J/ r
  5.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    1 V# U: f9 H4 q! \3 M7 }
  6.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    6 N& \, K' K1 I1 Q  E- `" j
  7.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  一步一步调式发现结构体有一项ADC_ExternalTrigConv是0x08002d54,这一项并没有初始化对其赋值,忘记给结构体的这一项赋值了。最后这个值通过ADC_Init函数赋值给CR2的时候,第11位(也就是数据对其位)是1了,左对齐了!!!!!9 g$ A2 C, s" D
) {, s" {1 n9 P1 r5 C: R( ?+ X. d4 h
20180823193630758.png

& N- h* }7 U. T( n0 W
9 ?7 U( b0 S6 S$ R  下面来重点分析下adc初始化结构体中的各项参数的意义:0 q' n3 w& N. z
  对于STM32,在使用ADC的时候需要配置几个参数。- B- Q: ?; C2 e2 b& }
(1) 第一个参数是ADC_Mode,这里设置为独立模式:
3 T) F0 n" Y% _$ G+ R. j( B) I% y& _2 d& \: {/ z
  1. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
复制代码
! Q  k& c+ n5 S) z
在这个模式下,双ADC不能同步,每个ADC接口独立工作。所以如果不需要ADC同步或者只是用了一个ADC的时候,就应该设成独立模式了。8 _5 f1 z, [/ B% V$ p' |9 U+ O

# a" T4 J# d4 {* O( j$ g1 k9 w(2) 第二个参数是ADC_ScanConvMode,这里设置为DISABLE。! q3 z% M/ z; H0 s/ C
  1. ADC_InitStructure.ADC_ScanConvMode = ENABLE;
复制代码
( _: M0 k2 t; K  E% c
如果只是用了一个通道的话,DISABLE就可以了,如果使用了多个通道的话,则必须将其设置为ENABLE。4 j* i  D5 }4 Z7 s, a( h% x

8 [) {( }& f3 K; ?) U(3) 第三个参数是ADC_ContinuousConvMode,这里设置为ENABLE,即连续转换。
+ \7 |! {) d8 j7 n7 ]! l2 _: G5 ^如果设置为DISABLE,则是单次转换。两者的区别在于连续转换直到所有的数据转换完成后才停止转换,而单次转换则只转换一次数据就停止,要再次触发转换才可以。所以如果需要一次性采集1024个数据或者更多,则采用连续转换。
) C: q3 P) t! c7 g4 k9 s5 B" `7 s: t& D
(4) 第四个参数是ADC_ExternalTrigConv,即选择外部触发模式。这里只讲三种:
: L8 h9 _8 e1 [0 k  v/ K
7 u2 k. F+ s! A- {9 j7 W  v1、第一种是最简单的软件触发,参数一般为ADC_ExternalTrigConv_None(注意STM32F2XX系列这个有点蹊跷,后面会讲这个)。设置好后还要记得调用库函数:
" O# `2 O- Y3 L
  1. ADC_SoftwareStartConvCmd(ADC1, ENABLE);
复制代码
  1. void ADC_SoftwareStartConv(ADC_TypeDef* ADCx)) E5 _( T) r+ z& @
  2. {
    3 ]/ G) ^  k8 [( o8 L  r) y
  3.   /* Check the parameters */: p  T- ]. S9 H" ^" z1 |6 s! O
  4.   assert_param(IS_ADC_ALL_PERIPH(ADCx));
    3 ]" @0 x2 v4 a3 [1 _. D- x' q

  5. ) c1 ]1 V  T' t  {3 C5 g
  6.   /* Enable the selected ADC conversion for regular group */
    " t% W% B$ O- E1 k
  7.   ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
    8 f5 ^) d1 O# Q* T+ R) i* o
  8. }
复制代码
  1. #define  ADC_CR2_SWSTART                     ((uint32_t)0x40000000)      % S( Q9 z0 q" |4 U+ ~5 e
  2. /*!<Start Conversion of regular channels */
复制代码

, N$ E- t' a: [, HADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位,这样触发就启动了。) m: M) N# p9 z. ?" c8 {

  @. Q+ i, l- P, G3 x2、第二种是定时器通道输出触发。共有这几种:ADC_ExternalTrigConv_T1_CC1、ADC_ExternalTrigConv_T1_CC2、ADC_ExternalTrigConv_T2_CC2、
- o1 X/ L6 e) R- h% f/ t4 b) [2 l" ]6 h0 o
ADC_ExternalTrigConv_T3_T以及ADC_ExternalTrigConv_T4_CC4。定时器输出触发比较麻烦,还需要设置相应的定时器。以/ G, X& q; ]5 `4 a5 c) |

2 O: P2 w* v) l5 `3 g- }ADC_ExternalTrigConv_T2_CC2触发为例设置相应的定时器:/ n# l, \6 Z* F  ?6 k

# R" T) _  @$ Q9 c6 L* ?$ I6 O# ?$ ?
  1. void TIM2_Configuration(void), w; ^: q+ X0 b
  2. $ [+ K: w; }& w
  3. {; |/ q6 z0 N$ A& Y/ ?3 k; I( K$ z
  4. + x) e  P9 m2 U/ W* I& k" _
  5. TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;9 m# Z5 C% {5 o4 A- v- g/ t

  6. 6 x. Q6 T. k& }; k% y4 D! T5 [
  7. TIM_OCInitTypeDef         TIM_OCInitStructure;
    7 ?- l5 B  c$ ?" z
  8. ! w% W: v8 t# Q( f6 l
  9. TIM_TimeBaseStructure.TIM_Prescaler = 4;& }) M  O6 |- |* J, S+ b
  10. " z* t5 [9 }# I, `0 G( H: x1 |
  11. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;; l) S9 {2 L# P: T( D' P
  12. 0 \7 G0 t- c: h( l! X* t, w$ W% y
  13. TIM_TimeBaseStructure.TIM_Period = 0XFF;9 T% F1 f/ _3 D1 p0 D. y
  14. , c8 @& i, i- i, V
  15. TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    , _( c% U# Q* Y( m; N# e

  16. * P! X5 j  v* Z- C; X2 I
  17. TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    2 e* p& J; @4 |" o& e
  18. ; Y% R, @# b% d
  19. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    + w  O; a4 d) l2 _9 v& q3 o
  20. ; ?. U9 Q2 [5 I

  21.   B  a9 _' E+ B- I6 i2 Y6 [
  22. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;/ C5 w0 u1 t, _! f- l% Z, Q! B

  23. 0 R; i" Q( w% B7 m
  24. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;: r4 A) j5 J0 f2 ~% b( @, ]
  25. : a, }1 e& P4 l4 H
  26. TIM_OCInitStructure.TIM_Pulse = 0X7F;
    8 W& C# p3 p1 u* [

  27. ! O0 s9 |/ R) d5 I
  28. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;$ c* ~; W) A9 z0 O& K

  29. / u# |7 Q0 k; r9 m) Z1 v
  30. TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;        , A3 P5 p0 M' v1 I  i4 H& e
  31. ( Y' W% u% {, X9 ?
  32. //配置CC2的属性。若CC3作为ADC的触发源,则应改为TIM_OC3Init(TIM2, &TIM_OCInitStructure);9 G& O# J# R/ R1 G, V1 |' X$ I/ k: K
  33. ) v' K! k' I3 b7 R
  34. TIM_OC2Init(TIM2, &TIM_OCInitStructure);
      Y( t, G0 v1 L0 q

  35. , @, N. _6 p- u6 h1 \4 K
  36. TIM_Cmd(TIM2, ENABLE);
    # V* k: ^$ p5 f8 E: p+ _' L
  37. TIM_CtrlPWMOutputs(TIM2, ENABLE);
    8 m% j* H9 ?% b) U; n% F( s
  38. }
复制代码

2 f8 Z6 z- b+ z+ J
2 {5 E9 l* w- S* ?( F这样设置之后就可以用定时器2的输出触发了,至于触发的周期,设置TIM2的时间即可。这里不再赘述。
/ f9 V4 Z, i1 ?: S" n9 ~5 G
) m" k# Y/ N' D; b) H3、第三种是外部引脚触发,对于规则通道,选择EXTI线11和TIM8_TRGO作为外部触发事件;而注入通道组则选择EXTI线15和TIM8_CC4作为外部触发事件。% J0 w% K# z. C( Z3 p
( ]* y  o0 M) n# }; c
(5) 第五个参数是ADC_DataAlign,这里设置为ADC_DataAlign_Right右对齐方式。建议采用右对齐方式,因为这样处理数据会比较方便。当然如果要从高位开始传输数据,那么采用左对齐优势就明显了。4 P. l" x9 |8 T0 e$ b% K; p0 p0 g

( K* D' Z1 |1 O1 D# U7 f  F' ~/ l: n: w(6) 第六个参数是ADC_NbrOfChannel,顾名思义:通道的数量。要是到多个通道采集数据的话就得设置一下这个参数。此外在规则通道组的配置函数中也许将各个通道的顺序定义一下,如:
- h3 L9 E' }8 @, a; b
  1.       ADC_RegularChannelConfig(ADC1,ADC_Channel_13,1,ADC_SampleTime_13Cycles5);
    5 W  t+ u% \; h
  2. # @5 ^4 O$ C9 b/ Q6 a
  3.       ADC_RegularChannelConfig(ADC1,ADC_Channel_14,2,ADC_SampleTime_13Cycles5);
复制代码
: l3 c" ~( t* V/ C

+ `- [: M! [: ?* A9 m  多通道数据传输时有一点还要注意:若一个数组为ADC_ValueTab[4],且设置了两个通道:通道1和通道2,则转换结束后,ADC_ValueTab[0]和ADC_ValueTab[2]存储的是通道1的数据,而ADC_ValueTab[1]和ADC_ValueTab[3]存储的是通道2的数据。如果数组容量大则依次类推。: Z) M* R" e6 n" u- ?

2 z( u% ^' Y% d  补充一点:在使用DMA传输数据的时候,需要设置外设地址和存储器地址,外设地址当然就是ADC的地址了,而存储器的地址如果使用8位数据的话,存储器必须定义为8位缓冲区;如果使用16位数据格式的话,存储器则为16位缓冲器,不可定义为32位或更多,否则,数据将出错。) u/ b3 _  i8 N" l& X; k7 z
2 C+ h" L" a% X" ]
问题的解决方法

, S. U* o9 c: @' _6 j  上面分析了adc结构体的参数,下面再来单独看看ADC_ExternalTrigConv这一项。
! q$ O; T* j; s2 u  在stm32f2xx_adc.h文件中有这个成员的参数定义,发现里面并没有ADC_ExternalTrigConv_None这个常见的定义。, W, C- |4 f( N- M

) z& m, v. l2 h. Y: ?8 @
  1. /** @defgroup ADC_extrenal_trigger_sources_for_regular_channels_conversion 6 p9 |! a# {3 ^/ x% @
  2.   * @{
    . w: X( k" L+ J1 L1 q5 d/ W
  3.   */
      d$ b! {9 q* F" D  J3 q7 E
  4. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000)
    ; a# R4 B3 p2 o; A  n: p! L
  5. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x01000000)) w, O2 @0 B8 ^2 Q
  6. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x02000000)
    $ w# z# L$ h* E! x8 `
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x03000000)
    9 d4 z! }, V7 R0 e
  8. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x04000000)7 H! A9 _/ e+ F# c
  9. #define ADC_ExternalTrigConv_T2_CC4                ((uint32_t)0x05000000)2 y; E( r$ O5 Z/ }# H: X2 Q
  10. #define ADC_ExternalTrigConv_T2_TRGO               ((uint32_t)0x06000000)* a, b) @7 k# G6 u
  11. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x07000000)
    $ v8 y6 z! ]8 p* _7 U
  12. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x08000000)/ J6 j+ A9 A* h5 j4 o$ s
  13. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x09000000)" T! M# q6 `* G& j7 K4 ?0 X
  14. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x0A000000)$ o# B6 c* P2 y! W0 E
  15. #define ADC_ExternalTrigConv_T5_CC2                ((uint32_t)0x0B000000)0 T$ a" O) C, M& s' V: {+ I: L' ~7 A
  16. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x0C000000)
    # P7 c3 @. v2 `. m9 }
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x0D000000); d# R; w  Y, e3 ^
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x0E000000)
    & x; {- u8 H4 \, \
  19. #define ADC_ExternalTrigConv_Ext_IT11              ((uint32_t)0x0F000000)
复制代码

$ C0 k4 U8 t% P' I; y  再来看看stm32f10x_adc.h文件中的ADC_ExternalTrigConv的参数定义:
3 `7 u- n$ g4 ~% J( T! N
  1. /** @defgroup ADC_external_trigger_sources_for_regular_channels_conversion
    6 Z- i1 S" x( R; _0 @& ]: _
  2.   * @{
    ! g. w% A1 N# @! w
  3.   */6 s6 I& V* l4 c7 w! h

  4. 9 p. b6 K5 W6 G
  5. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */
    1 Y2 Z( ]+ H( Y( }# h
  6. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */+ C6 _! U6 H) O/ H: n3 P6 s
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */
    , t" ?, t+ `, ^3 x8 h% d6 h) c
  8. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x00080000) /*!< For ADC1 and ADC2 */. i/ @4 f% I( j  o! H
  9. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x000A0000) /*!< For ADC1 and ADC2 */* _2 W, }/ P$ l' o# R/ h( P  X
  10. #define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO    ((uint32_t)0x000C0000) /*!< For ADC1 and ADC2 */
    9 D* [9 ?. z5 C9 G$ H: b

  11. 5 c. J: g; F9 ]# C* V
  12. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x00040000) /*!< For ADC1, ADC2 and ADC3 */- B/ h! Z1 K7 b
  13. #define ADC_ExternalTrigConv_None                  ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */   //f2xx系列并没有这个定义
    3 f% N) N. q$ h% |( K

  14. : [2 J+ f% ?& D. {$ Y
  15. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x00000000) /*!< For ADC3 only */
    " [& I6 k; j1 L/ j/ _: L) H& ^
  16. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x00020000) /*!< For ADC3 only */% U* p/ Q( a2 c# `- h: Y5 A$ I7 R
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x00060000) /*!< For ADC3 only */+ ~; z1 y& s9 y, v8 T9 E
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x00080000) /*!< For ADC3 only */0 c* s  C4 _" T7 ^
  19. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x000A0000) /*!< For ADC3 only */
    ! P& U# x) t0 I4 b' P& G
  20. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x000C0000) /*!< For ADC3 only */
复制代码

9 R0 E: H6 H& A: D0 }  对比发现stm32f2xx系列并没有ADC_ExternalTrigConv_None这个定义,很是奇怪,现在还不明白ST的工程师为什么做这个变动。
4 y* r8 M& R9 l7 T3 a% Y, O  那么问题怎么解决呢?
5 N7 n* K) u! r7 x( U. O  一种是进行adc结构体的初始化操作,在配置之前恢复默认值。即调用ADC_StructInit(&ADC_InitStructure);修改如下:
  1.     ADC_StructInit(&ADC_InitStructure);//新增加的
    " O4 n" a6 C# _3 B2 F2 u+ U
  2.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;( ~" y% d2 J; o7 R! H- v- D% l5 i
  3.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;! r7 X. q7 j3 Y5 L. j5 C$ n- W1 M# M$ F- U
  4.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    7 I  V! |! ~7 _5 J# w
  5.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;3 w% n* f: c+ ~( S
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    4 F1 l9 A! n6 K: H
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;* j9 U2 K! m( H2 K" M
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  调用ADC_StructInit(&ADC_InitStructure)语句,ADC_ExternalTrigConv会恢复默认值0。如下:1 k/ h+ x, k! A  k' o

7 a5 k; [, K0 E3 I/ i2 n$ W! w
20180823201211262.png
; v( j8 @" N9 e, ~
1 C' r3 I7 a2 z/ e  G5 q- f
  另一种方法是直接配置该参数为0,如下:/ l7 P2 N7 ?7 {! j  k
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ! c5 @, X$ T  _2 b# M4 D0 ]4 T
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    9 Z, f8 J" c, J7 }2 [% d/ [7 b
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;+ d; e3 j9 A& ^2 y$ X; n6 \# a
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;- A7 |2 Q% O$ D, w$ y  ^. T) ^
  5.     ADC_InitStructure.ADC_ExternalTrigConv= 0;//新增加的
    4 E, ^; O' k. t' M; t
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;* s9 L& x& V4 A+ u: y1 H& Y2 S# x
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;/ J6 L2 }, @& Z
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
( v7 V1 u6 |% M8 ?
  这两种方法都可以解决adc采样对齐方式异常问题。
' n, J( Y( ^+ R6 V0 v# N) _+ Q  但是ADC_ExternalTrigConv= 0在stm32f2xx_adc.h中其实是对应ADC_ExternalTrigConv_T1_CC1的。# @5 l. i( Q0 U) ]9 L1 ]/ X$ I

( J  x# n  \( X  O, V! G. a
20180823201832969.png

* p' ^: Q& u) P7 x$ ^# [- O0 [8 u  O1 Z- [7 T6 S/ `
  也就是说调用软件触发函数ADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位也可以触发定时器触发方式的adc通道。5 A! P: t2 K8 O" b& D

5 B6 i& y& F% A  F# [  h! P4 s, E# \& l  E% g+ u1 b  }4 ^

5 m. X& Q/ C5 J7 M5 j
赞 收藏 评论0 发布时间:2021-12-2 16:03

举报

0个回答

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版