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

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

[复制链接]
STMCU小助手 发布时间:2021-12-2 16:03
前言. h+ |( A% Z0 {% T$ w, t5 e
  最近在调试STM32F2XX系列ADC多通道DMA采集时,发现采集的AD值大于4095,有的65000多了,这是什么节奏?adc不是12位吗,最大才0xfff,即4095,怎么会出现这种情况呢?难到是adc数据对齐方式出现问题了,adc的对齐明明设置的是右对齐啊,神马情况?
' V# f, _/ }8 g$ u' `% T0 ]' X) g  J
. E- W1 P" L2 @ADC结构体参数分析
. x1 J- ^) w! ~# t
  百思不得adc之姐,只能keil单步调试,一步一步查看adc结构体的参数。我使用的是adc dma方式采集,共9个通道。初始化程序如下:
5 q; v; @: g4 C; \2 Z8 j# ~
  1. void ADC_DMA_Config(void): x7 M5 G% e, h5 |( U
  2. {2 {0 q) p, \( {/ Z, C
  3.     ADC_InitTypeDef       ADC_InitStructure;
    ( G1 X% L; p0 X+ Q7 D
  4.     ADC_CommonInitTypeDef ADC_CommonInitStructure;3 e( J" M6 x% |0 I% Y# S
  5.     DMA_InitTypeDef       DMA_InitStructure;
    4 T! G- d  q2 g! D! z6 o
  6.     GPIO_InitTypeDef      GPIO_InitStructure;
    0 d+ T1 X' H# W! b) x
  7. ) d4 C% e: @) O1 w, d* u% {/ S( @# c
  8.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);
    3 v9 B) }  a' I( E' I
  9.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);' n( f% b. a! L8 l- t% b
  10. . O6 L" e3 t: Y& I4 x
  11.     DMA_InitStructure.DMA_Channel = DMA_Channel_0;  & @' e8 |% v- ^6 Z0 G
  12.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;& }3 _- A% E( B: c
  13.     DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_ConvertedValue;  
    . t: L% y- `" ]! f6 y
  14.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    8 t( H0 G$ q7 _3 {
  15.     DMA_InitStructure.DMA_BufferSize = Sample_Num*Channel_Num;         % k8 y; h3 k7 S& k6 V
  16.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    0 Z  H' L0 b* Y: E) A
  17.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;/ ]0 X0 ~, e5 L) N- o( B# F% [# `
  18.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    : y2 \2 P+ Y- {/ r; h, }5 Y( k5 H
  19.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;+ o: R  [1 Z- u# \2 h
  20.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    $ b8 W' S! D* J" p4 x
  21.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    ) S9 Y1 O  m6 H( t2 A7 m- a( w
  22.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         , b; _0 m! X' e
  23.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;# E  {( r, [4 b, e2 D
  24.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;- U& w' Q% Q1 t, a1 }3 f4 K# ^
  25.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    ' _9 n' V& P% K% ^, g) a% N* g/ X
  26.     DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    ! ]0 c9 [* W  r' w! M0 X, O9 C# V
  27.     DMA_Cmd(DMA2_Stream0, ENABLE);
    $ i0 s: i8 b- Q* o5 G3 R8 }1 X; i
  28. 0 @* O5 z% ^3 O3 `
  29. $ ?- c' [4 D  U
  30.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 |GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;6 h" V1 J$ u+ n" D7 x  d7 K9 b
  31.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;6 j* O6 s* o. L. e/ K
  32.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;1 G5 o  X+ r4 K( o- P1 y
  33.     GPIO_Init(GPIOA, &GPIO_InitStructure);
    & T  w( \0 V% w0 o5 c

  34. 1 t6 ]' J# @+ `9 m& K9 M
  35.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5;2 K; x" K- m) a
  36.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;) p& u) Q. Q. B
  37.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    " z8 E( A* L; m6 e8 A7 y
  38.     GPIO_Init(GPIOC, &GPIO_InitStructure);& i) S9 t& y. O, Q+ x

  39. & t2 v& a. G9 v4 o( U
  40.     /* ADC Common Init **********************************************************/. b" p7 W6 a7 f
  41.     ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;2 _, [1 b: M8 O; x& y' T2 h
  42.     ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;7 _4 Y* a4 a- |0 }+ }6 G" ?: `1 ?
  43.     ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
    ( S' e# [: m" ^5 i4 o- b4 e
  44.     ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
    - r) G! f: a/ c# |. Y! \
  45.     ADC_CommonInit(&ADC_CommonInitStructure);" r9 q" n' {# F7 k

  46. - `4 e$ T( H8 K6 |- c) Q
  47.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;( k( _  @( [( T! V
  48.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;6 u; f1 K) D* q  F: o
  49.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    - M+ K' e/ F: `5 Z* i' R0 V
  50.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;3 @$ H, @; t  W$ I1 V9 @/ W8 }: S* O' Q, ?
  51.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;1 k  c' `$ }+ a3 _6 m9 H
  52.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    0 A( M2 E! [! \; S# N; }
  53.     ADC_Init(ADC1, &ADC_InitStructure);7 U0 r  r- c0 l- L6 c- h. F: ?1 a
  54. , M: {! q" T$ j
  55. " m7 h' @/ u* l1 W, S% ^3 c3 h
  56.     ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);4 Y' |; s) o- u7 ^
  57.     ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_3Cycles);
    ( C6 |8 ?( u, Q8 `7 X
  58.     ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_3Cycles);
    : P  F* I! E9 J7 j1 L
  59.     ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 4, ADC_SampleTime_3Cycles);
    / g+ z  K) w' O9 D$ `6 f% l( K& k
  60.     ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 5, ADC_SampleTime_3Cycles);! N* V/ j3 K/ }$ D# n: X
  61.     ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 6, ADC_SampleTime_3Cycles);* u5 n0 x- v+ F
  62.     ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 7, ADC_SampleTime_3Cycles);
    ) j' }7 @8 c0 o' U
  63.     ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 8, ADC_SampleTime_3Cycles);
    3 p- ^# h$ `: P1 b* x# a  N# q
  64.     ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 9, ADC_SampleTime_3Cycles);
    8 m+ ~7 I( ^& n! p/ b  l. h1 h

  65. % h( A  r5 ~; @/ W* f
  66.     ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
    ; ?& O( m9 _! x  i: ?7 ]' R
  67.     ADC_DMACmd(ADC1, ENABLE);
    5 W0 b! T' _" B$ u
  68.     ADC_Cmd(ADC1, ENABLE);
    ! ]7 j4 m( ^0 h% Z
  69. & ^5 N3 _$ I; E3 w: ~
  70. }
复制代码
& T, [" O' I* u( ]
  其中涉及adc的初始化结构体代码部分如下:
# N2 J+ F" M3 X! L# M( q
  k' f  h9 s* c    ADC_InitTypeDef       ADC_InitStructure;" X6 g$ Q4 `9 Y1 m. i9 y  G
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    8 Z$ P4 {* n( w, c4 _7 C, \
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    3 G/ a) E) q  Z7 }; K9 b
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    1 m) h. f! K2 o4 j- p7 I( x
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    6 t) K" d% h; i8 S  o+ T0 x
  5.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    : z5 B4 @, A& u  q0 G
  6.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    1 B7 U* W& r5 A7 {
  7.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  一步一步调式发现结构体有一项ADC_ExternalTrigConv是0x08002d54,这一项并没有初始化对其赋值,忘记给结构体的这一项赋值了。最后这个值通过ADC_Init函数赋值给CR2的时候,第11位(也就是数据对其位)是1了,左对齐了!!!!!% ], n! I$ t. c: [; j; z

# ~8 P7 [$ k$ v1 s: U
20180823193630758.png

, x  x& F! P3 x2 b
7 [7 `. B8 ^2 b# a) w6 c  下面来重点分析下adc初始化结构体中的各项参数的意义:
/ G5 Z2 k! S: }3 v1 F% ~' g  对于STM32,在使用ADC的时候需要配置几个参数。0 ~% ~. Y  a- a" V9 ]3 z; q
(1) 第一个参数是ADC_Mode,这里设置为独立模式:
/ s! t( j0 @) \9 f: x6 H( z# J, `' ?" Y
  1. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
复制代码

" p5 Z. g: \! L在这个模式下,双ADC不能同步,每个ADC接口独立工作。所以如果不需要ADC同步或者只是用了一个ADC的时候,就应该设成独立模式了。
9 M9 E" v9 T6 \' Z9 g
. ]* J- x$ W) Q(2) 第二个参数是ADC_ScanConvMode,这里设置为DISABLE。5 Y- H9 L7 }, G
  1. ADC_InitStructure.ADC_ScanConvMode = ENABLE;
复制代码

% b) V' ~" v7 h1 K如果只是用了一个通道的话,DISABLE就可以了,如果使用了多个通道的话,则必须将其设置为ENABLE。
: {# W9 T8 A% L! ]. Z; x
2 \* O3 E; ]$ B1 T2 [: g3 [/ H(3) 第三个参数是ADC_ContinuousConvMode,这里设置为ENABLE,即连续转换。! i) q+ H$ O. l& O$ K; J
如果设置为DISABLE,则是单次转换。两者的区别在于连续转换直到所有的数据转换完成后才停止转换,而单次转换则只转换一次数据就停止,要再次触发转换才可以。所以如果需要一次性采集1024个数据或者更多,则采用连续转换。
- `" n- Y- w. f) Y3 W( b4 v: x
, H& d0 X4 }8 x(4) 第四个参数是ADC_ExternalTrigConv,即选择外部触发模式。这里只讲三种:5 {' M# X  L7 }4 U! j6 C3 H
# A, ?. H9 p+ e5 Y7 F5 y
1、第一种是最简单的软件触发,参数一般为ADC_ExternalTrigConv_None(注意STM32F2XX系列这个有点蹊跷,后面会讲这个)。设置好后还要记得调用库函数:8 F+ C8 n7 f1 x$ E. {
  1. ADC_SoftwareStartConvCmd(ADC1, ENABLE);
复制代码
  1. void ADC_SoftwareStartConv(ADC_TypeDef* ADCx)* `4 e& J$ \4 a* f: i
  2. {
    6 f& E/ l* [! E: ~# W- r- o
  3.   /* Check the parameters */8 ?) [# T" H+ x5 B0 r
  4.   assert_param(IS_ADC_ALL_PERIPH(ADCx));# z) M- U" x* x: R9 @* `1 @

  5. + K( B  d$ ^1 l. z; X& h/ G
  6.   /* Enable the selected ADC conversion for regular group */2 R6 s7 m( l1 M8 K. B1 ?
  7.   ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
    , B( n' M6 X! N. U9 J8 h
  8. }
复制代码
  1. #define  ADC_CR2_SWSTART                     ((uint32_t)0x40000000)      
    7 M& q0 u, E' U' m8 N
  2. /*!<Start Conversion of regular channels */
复制代码

: L) n9 K/ v% j- {ADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位,这样触发就启动了。
# t8 M& N$ o- T6 s0 J
2 ^( I* o4 N: S* w2、第二种是定时器通道输出触发。共有这几种:ADC_ExternalTrigConv_T1_CC1、ADC_ExternalTrigConv_T1_CC2、ADC_ExternalTrigConv_T2_CC2、
9 f9 b  x# n+ `( N% K1 A2 U- {
5 O7 o% ]/ k. F6 [! t) g5 v# jADC_ExternalTrigConv_T3_T以及ADC_ExternalTrigConv_T4_CC4。定时器输出触发比较麻烦,还需要设置相应的定时器。以
' N; _3 ^: j4 i* h/ V, u* A7 z. v; L
ADC_ExternalTrigConv_T2_CC2触发为例设置相应的定时器:
% h$ p6 e% F) D8 `3 O' R9 D: P' @. }% \
  1. void TIM2_Configuration(void)7 G: w6 B+ y! E; |: @( \; P

  2. 6 z; |4 \; g2 ]( w# \6 `3 |
  3. {# G2 l+ ?- a* |  C
  4. 7 t  a7 @$ u) z6 W6 f- Y+ H
  5. TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;
    4 }" Q# E) f! q
  6. . f* J) B# P: g9 Q" ]7 x
  7. TIM_OCInitTypeDef         TIM_OCInitStructure;
      |! ]- J8 b; N8 D, C, z

  8. % p* ]3 S" ^- T8 y
  9. TIM_TimeBaseStructure.TIM_Prescaler = 4;2 }6 Q$ M1 P. I

  10. ) }# \4 p& o7 B" T/ }& |
  11. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    " G4 [: Y/ g* y4 J  U
  12. 0 @6 a6 N4 p( }( h6 V
  13. TIM_TimeBaseStructure.TIM_Period = 0XFF;
    ( r" B- r3 }( h( f) g
  14. $ w6 b" i/ i. g
  15. TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    ' E3 A7 e8 T/ A9 y0 ~  s  z

  16. 4 U* q) m1 X3 L8 V: J. s5 d4 G) [2 u
  17. TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;) Q8 r7 L( l# z2 P
  18. 4 ?* I# @. w( v
  19. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    * S& o$ b# ~3 E$ N1 ^
  20. % u. ]0 Y* I0 Z* X& m3 x3 J) u
  21. 4 H& Q( n; {# k
  22. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    / I- F, X0 N: y7 k0 C0 i  p

  23. , Z) |, Q  |/ B
  24. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    # Q  e7 A  r# o, F9 q( R

  25. ' I' W$ C; {# T, u7 U
  26. TIM_OCInitStructure.TIM_Pulse = 0X7F;
    3 P5 J+ e  [: j6 P( C
  27. 1 R' z% E7 v8 d% z) e5 m) N
  28. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    # d% E; V) P( X: k
  29. 0 l- K( o; W5 a% r5 n" n" {
  30. TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;        . f, v, ?; v) D8 g) ^# N
  31. # }; @9 \/ e5 M5 e- Z
  32. //配置CC2的属性。若CC3作为ADC的触发源,则应改为TIM_OC3Init(TIM2, &TIM_OCInitStructure);
    ' g; C4 [# a, v( [/ P4 g/ I

  33. " j# Y) o1 a6 ^
  34. TIM_OC2Init(TIM2, &TIM_OCInitStructure);! a% v1 \6 v  t7 d1 t

  35. : D- M5 h: g+ K8 H" X
  36. TIM_Cmd(TIM2, ENABLE);
    8 @8 {, Y2 p1 ~. j5 \: ]6 B$ o* m
  37. TIM_CtrlPWMOutputs(TIM2, ENABLE);
    / p2 h% B- q8 D3 ]8 D9 D8 s) P
  38. }
复制代码

+ G- U, x. C$ b# I+ N  l# ]( k5 m
/ N% r6 ]; q4 P/ Z这样设置之后就可以用定时器2的输出触发了,至于触发的周期,设置TIM2的时间即可。这里不再赘述。
) |- m7 s$ C1 ^4 _5 F3 {  y5 l: ]& X/ W0 w$ q- J8 S# {
3、第三种是外部引脚触发,对于规则通道,选择EXTI线11和TIM8_TRGO作为外部触发事件;而注入通道组则选择EXTI线15和TIM8_CC4作为外部触发事件。% I1 @# ?8 `& H* t, o+ |
3 K7 A; j' j  O$ N6 |5 D
(5) 第五个参数是ADC_DataAlign,这里设置为ADC_DataAlign_Right右对齐方式。建议采用右对齐方式,因为这样处理数据会比较方便。当然如果要从高位开始传输数据,那么采用左对齐优势就明显了。
/ K6 w) a' |0 u3 H1 T9 C) q% T+ ]) \: y  e
(6) 第六个参数是ADC_NbrOfChannel,顾名思义:通道的数量。要是到多个通道采集数据的话就得设置一下这个参数。此外在规则通道组的配置函数中也许将各个通道的顺序定义一下,如:
3 L; G" R% T& A4 N, [
  1.       ADC_RegularChannelConfig(ADC1,ADC_Channel_13,1,ADC_SampleTime_13Cycles5);" Z# Q8 s& I6 b# _  G4 {, \0 l

  2. % J8 e1 X- o: T! L- C7 r" `" A
  3.       ADC_RegularChannelConfig(ADC1,ADC_Channel_14,2,ADC_SampleTime_13Cycles5);
复制代码

; H' C* P5 G9 x. `- {% f+ Q
; @+ m' h* C: {7 q& ]4 |9 V  多通道数据传输时有一点还要注意:若一个数组为ADC_ValueTab[4],且设置了两个通道:通道1和通道2,则转换结束后,ADC_ValueTab[0]和ADC_ValueTab[2]存储的是通道1的数据,而ADC_ValueTab[1]和ADC_ValueTab[3]存储的是通道2的数据。如果数组容量大则依次类推。
0 Y+ M% w4 W. g- L8 v5 m7 n$ d! {9 s. ]  K5 e
  补充一点:在使用DMA传输数据的时候,需要设置外设地址和存储器地址,外设地址当然就是ADC的地址了,而存储器的地址如果使用8位数据的话,存储器必须定义为8位缓冲区;如果使用16位数据格式的话,存储器则为16位缓冲器,不可定义为32位或更多,否则,数据将出错。
' Z, L3 g! R+ ~9 O6 t$ h
: L7 y/ z: g& B6 c: U! s( k问题的解决方法

. V$ i8 T/ ~9 v$ D' f; Q  上面分析了adc结构体的参数,下面再来单独看看ADC_ExternalTrigConv这一项。
3 L. ?* \; E7 A% O  在stm32f2xx_adc.h文件中有这个成员的参数定义,发现里面并没有ADC_ExternalTrigConv_None这个常见的定义。+ s  l; ]1 q- y% ?# a$ ~
# C, E0 F% l- C0 [
  1. /** @defgroup ADC_extrenal_trigger_sources_for_regular_channels_conversion
    - S% P  q, ^+ C: h4 \4 D, ]# p% K
  2.   * @{7 y6 x( R9 _! Y
  3.   */
    - y% w' `! e5 Q/ `2 w
  4. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000)$ P1 d+ V1 }! y
  5. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x01000000)
    0 S/ G5 m- Z( {! Q0 k( F  H+ C! U
  6. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x02000000)
    , @5 k! ?  c4 C0 V( g
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x03000000)
    " x0 H( Y) n5 m) t$ C/ C
  8. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x04000000)
    ( E1 c8 [5 W0 o' Q3 M  _
  9. #define ADC_ExternalTrigConv_T2_CC4                ((uint32_t)0x05000000)
    ) G& S8 Q$ I8 T' j( \4 m
  10. #define ADC_ExternalTrigConv_T2_TRGO               ((uint32_t)0x06000000)
    ( g& n* e3 E1 n
  11. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x07000000)
    ' g3 I0 n  i8 j- ?4 h* y
  12. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x08000000)
    * Y8 Q' g( I/ `2 Z6 Y
  13. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x09000000)9 z# f& o! j! a* d* \% b
  14. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x0A000000)
    3 h2 l9 c6 c9 n9 F( W( F& A; [1 L
  15. #define ADC_ExternalTrigConv_T5_CC2                ((uint32_t)0x0B000000)
    " ^1 x3 q4 }% j. n! y
  16. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x0C000000)
    # }* o+ n2 j6 N
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x0D000000)9 A- {$ l9 Q8 i8 ~3 a; G7 Y
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x0E000000)
    + c, z0 {. g8 Q6 q# p% p& u. k
  19. #define ADC_ExternalTrigConv_Ext_IT11              ((uint32_t)0x0F000000)
复制代码

3 t% ~  a5 d4 m7 x5 `  再来看看stm32f10x_adc.h文件中的ADC_ExternalTrigConv的参数定义:
0 E5 j7 G6 T- I8 n
  1. /** @defgroup ADC_external_trigger_sources_for_regular_channels_conversion 8 I+ S' T  E7 |5 w9 L
  2.   * @{
    ! S3 @: D- |# e+ L& D/ P
  3.   */$ q0 ?2 c- O6 i7 e4 b) f
  4. ) s, q( r* K* a& p- S
  5. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */4 G2 |3 t* M* W
  6. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */' j/ M  c' u, F" T
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */1 f! [2 S& b9 q) |4 U- D, |
  8. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x00080000) /*!< For ADC1 and ADC2 */, B2 i$ r$ a9 k% v3 }
  9. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x000A0000) /*!< For ADC1 and ADC2 */
    6 k1 e/ W& K3 S1 k
  10. #define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO    ((uint32_t)0x000C0000) /*!< For ADC1 and ADC2 */" @: ]; L9 f! r- c
  11. 0 [8 J" r, P4 ^
  12. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x00040000) /*!< For ADC1, ADC2 and ADC3 */7 o- K" ^+ K# H9 S8 t' ]
  13. #define ADC_ExternalTrigConv_None                  ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */   //f2xx系列并没有这个定义7 ?' _: A6 }! V$ E5 ?! M

  14. $ t9 w" ^0 ^3 {* z3 E9 b/ U
  15. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x00000000) /*!< For ADC3 only */
    ' V1 D% D) C- a
  16. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x00020000) /*!< For ADC3 only */( M! q+ [- ?8 O5 G+ T$ u! f
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x00060000) /*!< For ADC3 only */
    ( `$ o  Q$ L  Q. S
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x00080000) /*!< For ADC3 only */% }( [- N" H" s* I$ T
  19. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x000A0000) /*!< For ADC3 only */
    # f& I& X) s8 ]* g- r$ S6 P
  20. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x000C0000) /*!< For ADC3 only */
复制代码

6 j) p, b, e1 A4 r- U, D  对比发现stm32f2xx系列并没有ADC_ExternalTrigConv_None这个定义,很是奇怪,现在还不明白ST的工程师为什么做这个变动。- H% o) X2 Z& t  g0 b' s% W
  那么问题怎么解决呢?) f$ _" ?( M4 U: c( T4 y( o; X* u
  一种是进行adc结构体的初始化操作,在配置之前恢复默认值。即调用ADC_StructInit(&ADC_InitStructure);修改如下:
  1.     ADC_StructInit(&ADC_InitStructure);//新增加的! a( R" |+ M2 O
  2.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    * j, ~1 k/ o; A2 n6 n8 ~5 R3 |) W
  3.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    + P" k0 x' a6 d
  4.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;; V% U9 N9 a3 Q0 t* \3 }
  5.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ' n* D6 D. y7 i- h. s
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    * f1 m7 ~4 k, Z6 n( c/ G: a+ |% g0 r
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;% p/ }0 `, h4 q6 U% S9 G
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  调用ADC_StructInit(&ADC_InitStructure)语句,ADC_ExternalTrigConv会恢复默认值0。如下:
6 C- c/ V6 w9 E* S, j5 D5 h2 m% P; T9 B2 q4 P7 E& r# I* v/ ^
20180823201211262.png
) K* J# _% R( R* j% u' m% I# u1 v
/ f" `  m7 }2 u- b
  另一种方法是直接配置该参数为0,如下:
4 {0 T/ }8 a* Q* G
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ' c( z% N+ k0 @& _5 \5 Y3 P
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;% n! j$ X* u7 m5 B1 {
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;; a& a3 o% _( Q( K3 l9 c2 m7 J
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;3 h5 f- G  |2 U# z8 c& G5 B
  5.     ADC_InitStructure.ADC_ExternalTrigConv= 0;//新增加的
    7 H0 x1 }+ p9 Y
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    2 R7 v1 J  T& r& K
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    , Z3 ~( \$ k  Z
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  R  v- v5 ~9 N8 z* v5 i! l/ r* E
  这两种方法都可以解决adc采样对齐方式异常问题。
3 M' I7 {2 k0 l) n  但是ADC_ExternalTrigConv= 0在stm32f2xx_adc.h中其实是对应ADC_ExternalTrigConv_T1_CC1的。
3 U2 p0 D4 b2 x( S% [
- n9 M( E+ }; ^- v
20180823201832969.png
7 ^1 f$ x- {2 h3 G) l  o  u7 D) b

, I1 N& O1 R4 d  也就是说调用软件触发函数ADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位也可以触发定时器触发方式的adc通道。
+ R" Z) }8 N. d
1 r: w6 v1 I% M, D
$ B  B$ s* p; P7 u
6 S" r1 J  H$ \+ J
收藏 评论0 发布时间:2021-12-2 16:03

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版