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

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

[复制链接]
STMCU小助手 发布时间:2021-12-2 16:03
前言; 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
  1. void ADC_DMA_Config(void): h, x  ^5 l" O1 C8 ]/ h7 H  S
  2. {
    ( N% P% |( O' K) k4 |, X: N6 V& J
  3.     ADC_InitTypeDef       ADC_InitStructure;' p1 O3 z' L5 Z
  4.     ADC_CommonInitTypeDef ADC_CommonInitStructure;! _9 ?9 q8 \# s5 N0 B" d4 V& n) r
  5.     DMA_InitTypeDef       DMA_InitStructure;
    6 h1 [  V- p. Y# b
  6.     GPIO_InitTypeDef      GPIO_InitStructure;
    - t" ^; }+ h' d; y! Z% Z

  7. 8 u& g. Q% e* h$ ]$ G2 t% C
  8.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);$ n/ q2 S2 b- C# ?3 X" V2 c
  9.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);& e5 @4 |6 s+ a0 d/ H
  10. 9 P/ d3 H& Z$ O5 j
  11.     DMA_InitStructure.DMA_Channel = DMA_Channel_0;  . v& S* }+ t' L% P& b
  12.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    * y+ w% [5 x) U" N
  13.     DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_ConvertedValue;  9 Q/ Z0 T7 Y# y+ ?# V" Q
  14.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    / h* _4 ]% E$ M+ v9 x- Z* T  S+ y! i
  15.     DMA_InitStructure.DMA_BufferSize = Sample_Num*Channel_Num;         
    : [9 T  p# v; J- \
  16.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;) ~6 g2 }  B& d8 Y* ?9 Y. N" Z
  17.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;( c" r$ ]/ ]0 i) E9 [+ s2 D
  18.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;" G! O/ a8 U# E5 D6 ~2 W/ d
  19.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    1 R7 N& q" L) q+ P
  20.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    ' h1 ~5 D4 f1 A* q7 r
  21.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    0 y" F( z) @. \! u) S9 O2 b0 S2 c
  22.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         7 n9 z* T9 [9 n5 P+ }4 T7 R3 k2 @
  23.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;' l8 o( D/ Z; D: L) \2 _' N. p/ W6 e
  24.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    $ ~3 Q$ p/ R, S4 W
  25.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    - ^# k+ r* Z  G$ J2 f1 j9 |
  26.     DMA_Init(DMA2_Stream0, &DMA_InitStructure);+ H" |: y4 H# @& d
  27.     DMA_Cmd(DMA2_Stream0, ENABLE);- g6 T% c$ D; x, S2 b) O. E

  28. , d7 Z: J5 w  J$ C# h! ~% U
  29. : |* U: [; n; q" g
  30.     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
  31.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    9 C9 P. a+ J% q: m3 E0 w6 R
  32.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;1 D' o9 L* S( K: q$ G5 K
  33.     GPIO_Init(GPIOA, &GPIO_InitStructure);
    5 @& \6 K# Y2 v- M+ `, I
  34. ( I% b* f6 J! n- D4 |
  35.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5;4 r: Z9 n  a9 s" n% V- \2 L
  36.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;2 Q3 Y( u6 M- @6 J) N
  37.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    ( Y0 e& Y8 `. \8 U
  38.     GPIO_Init(GPIOC, &GPIO_InitStructure);
    - l  D% F5 Y* U, ?) P* o% a
  39.   z5 r: \: n& v) g' Q- _7 Y. W8 R2 E
  40.     /* ADC Common Init **********************************************************/) L! ]% M, C, N
  41.     ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
    + [) Q( Y2 J* u5 f- E, |& I) _
  42.     ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;( M5 Y4 |7 f$ U7 Y& S  N% C
  43.     ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;" T5 j2 z+ U" r8 S- M. p9 N
  44.     ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
    # H6 K& I) T* u; `4 H+ W
  45.     ADC_CommonInit(&ADC_CommonInitStructure);2 ~" T! T  `1 z. y) h

  46. 2 [; m2 G- l/ V3 [
  47.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    9 J% F3 p( U3 Q: |% q
  48.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;! u( q( M; c" F: d) A% O1 c1 O
  49.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;' ^' I' Y% V& h* N8 }
  50.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ; M5 Z$ I( k+ \: U; i3 w
  51.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ) j! p5 m( @6 u% l, Y- }
  52.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    $ g2 t0 p2 Y+ e' z) J+ r
  53.     ADC_Init(ADC1, &ADC_InitStructure);$ x! h( Y* y; C% T( L4 _

  54. 0 i) Y3 [# |2 l8 O" I
  55. ; B- l+ N* h4 X' y( W3 x
  56.     ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);+ u  i; Z) x! S/ _
  57.     ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_3Cycles);
    ) D' n0 r* t) Y: P) Q
  58.     ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_3Cycles);" C9 _! i9 D2 }9 S
  59.     ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 4, ADC_SampleTime_3Cycles);7 O1 m& R2 b& H1 Q0 z. ^7 D8 v
  60.     ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 5, ADC_SampleTime_3Cycles);! I$ \8 o& Y1 {! ^" L: B
  61.     ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 6, ADC_SampleTime_3Cycles);
    , `5 ~+ ~4 L! u' o
  62.     ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 7, ADC_SampleTime_3Cycles);1 @- W; Y/ T6 W4 l
  63.     ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 8, ADC_SampleTime_3Cycles);
    ; q( i; H: U' T% A
  64.     ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 9, ADC_SampleTime_3Cycles);
    ( v* R$ c3 B' P1 [( \. a

  65. ( G$ Y% }  m4 z# R7 x* Y4 S& D
  66.     ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
    ) q/ Q# r; V7 U7 }0 H
  67.     ADC_DMACmd(ADC1, ENABLE);$ u- w* d5 A+ o" R. n( B
  68.     ADC_Cmd(ADC1, ENABLE);- b- h( d9 }+ E+ q% n+ N
  69. ; F# I/ ~: i( w3 s1 @- [
  70. }
复制代码
* ^: 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
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    0 P5 h! P7 F: R# ^# e2 f
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    " j9 v0 p" S, r5 b9 x  K9 J, Z
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;# N+ |9 G6 g: c% f
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ; N" a8 |. G4 g
  5.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    / I4 M! [9 u  B
  6.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    3 Y$ u# ~8 g% K( Y5 g' q; [$ Z
  7.     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
20180823193630758.png
: 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: {
  1. 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
  1. 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
  1. ADC_SoftwareStartConvCmd(ADC1, ENABLE);
复制代码
  1. void ADC_SoftwareStartConv(ADC_TypeDef* ADCx)
    , Z0 t* b$ e# V* Z/ B. S: \
  2. {! `8 N4 t+ v0 u5 R+ q& [1 `
  3.   /* Check the parameters */
      v# F& }" W" F4 a
  4.   assert_param(IS_ADC_ALL_PERIPH(ADCx));
    $ _2 X0 D0 @9 G/ V

  5. : }- _9 U3 b3 Z5 ]  J2 X9 c
  6.   /* Enable the selected ADC conversion for regular group */
    - Z$ m6 T2 h/ h9 @$ ?/ M, M
  7.   ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;$ y6 A" k5 ~; F0 ?
  8. }
复制代码
  1. #define  ADC_CR2_SWSTART                     ((uint32_t)0x40000000)      
    * \5 Z0 z6 S* n$ S4 O; u8 g
  2. /*!<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
  1. void TIM2_Configuration(void)
    ) [9 v1 A0 o* _+ y
  2. $ [" I* t7 q0 F) A1 b
  3. {
    ( s. k& T  {& w, i

  4. 4 v1 F1 w6 h4 l0 P
  5. TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;4 y. t: H, ]# Y8 {

  6. & a4 }" A4 M5 m* j) u5 T+ |
  7. TIM_OCInitTypeDef         TIM_OCInitStructure;0 _7 ^! H/ p6 E

  8. 6 m+ m& h; ?7 Z6 X
  9. TIM_TimeBaseStructure.TIM_Prescaler = 4;1 g+ L" a. N" Y) ^* Q

  10. 0 R/ ~/ f- r- u( z' X1 m: e
  11. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;& z  A; a6 Q! A# G7 j

  12. 3 }* ^: m( i0 D$ u+ R* _# J2 l
  13. TIM_TimeBaseStructure.TIM_Period = 0XFF;2 _/ N7 O% [9 _) P. o+ t2 R
  14. 1 Y8 ]* {) c# p8 ^
  15. TIM_TimeBaseStructure.TIM_ClockDivision = 0;! u9 K1 b& n* K2 r& Y0 R& C
  16. 0 c' \7 m% M6 p7 }  `4 F+ ]
  17. TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    : b" ]4 p. b: p, W, Y- A8 f

  18. 1 w- H7 o: j  S& v
  19. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    ! t! m7 V7 x% S4 h
  20. 3 Q1 X* d% w8 Q/ z% W# y

  21. 9 C0 V# l% P9 i+ T3 i
  22. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    , ]" x! y3 ~6 \$ ?% o. t& C

  23. + L+ Q. N  r# D! i! o
  24. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    + v; t8 J  M  R8 M& l

  25. ( y% N4 _. }) z* {
  26. TIM_OCInitStructure.TIM_Pulse = 0X7F;
    4 X2 w9 L/ j: i% {  Q
  27. : A* K' Y# u2 B1 g5 Y$ p
  28. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;2 a9 B- u6 @, y

  29. . E$ `" x  ?6 z/ F1 r
  30. TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;        
    + |; y# o1 m( J- s

  31. ; W1 T0 G) y: r% R, c5 B
  32. //配置CC2的属性。若CC3作为ADC的触发源,则应改为TIM_OC3Init(TIM2, &TIM_OCInitStructure);6 b, q" d* R. |3 u- e
  33. 1 b; W& W+ F  `  J8 c
  34. TIM_OC2Init(TIM2, &TIM_OCInitStructure);
    3 r9 x  u/ i; N# }

  35. # q& z% V4 h2 {$ Q' |! m
  36. TIM_Cmd(TIM2, ENABLE);
    3 y; U' s3 Q& ?0 s; [
  37. TIM_CtrlPWMOutputs(TIM2, ENABLE);  S4 L' i2 }' }' e  T* ^
  38. }
复制代码
! ^- 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
  1.       ADC_RegularChannelConfig(ADC1,ADC_Channel_13,1,ADC_SampleTime_13Cycles5);$ l0 S+ I( f; k/ w7 S* R; N
  2. , @' b2 m& u" S/ G# j3 t; _9 Q
  3.       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
  1. /** @defgroup ADC_extrenal_trigger_sources_for_regular_channels_conversion
    ; e/ E- D2 e& Z7 H6 ?1 S
  2.   * @{
    " R( Z* X  o( S( r6 \
  3.   */
    8 ^* u$ Q3 i( g7 F% \% j* R
  4. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000)
    4 L2 d+ V, `/ W' @9 E+ B
  5. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x01000000)/ W3 R2 W+ r9 M2 W, }: ]9 {
  6. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x02000000)
    ' f4 j5 R+ e/ \- _2 z! p/ ^
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x03000000)
    2 d  y* U$ c. W' E
  8. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x04000000)
    : i' s7 q7 D6 P$ Z+ Y
  9. #define ADC_ExternalTrigConv_T2_CC4                ((uint32_t)0x05000000)* B; T* [9 K9 d4 o
  10. #define ADC_ExternalTrigConv_T2_TRGO               ((uint32_t)0x06000000)
    7 z1 V) |8 ~4 s& k) b; A$ |
  11. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x07000000)
    8 M0 W! T7 n( L5 x  x  D' ]
  12. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x08000000)# h8 j5 L, }8 R) z
  13. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x09000000)
    2 M% X6 Z: T/ V2 T" h; T6 K
  14. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x0A000000)8 c* @9 L/ l3 Z8 ^* Q
  15. #define ADC_ExternalTrigConv_T5_CC2                ((uint32_t)0x0B000000)! U" D6 r, L2 T) p* ^8 C3 b
  16. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x0C000000)
    6 m& m6 F) W* S+ u6 R/ ?; P) t
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x0D000000)
    ) J. y. y5 }, s: n# I9 I2 \8 O4 c
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x0E000000)  ^' F$ @) X  P. \* s0 o9 {
  19. #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
  1. /** @defgroup ADC_external_trigger_sources_for_regular_channels_conversion
    - Y+ x# |9 Y# o, q9 a: H" B5 m
  2.   * @{! M  B6 `( x4 j- f# H$ D$ p9 h, f
  3.   */
    6 p' L: j& {0 L* L% u8 |
  4. 4 O3 W4 n$ a6 B9 L! w$ U
  5. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */
    * o7 ?: }6 ?8 `, X, x8 L
  6. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */: j8 `. ?1 y1 U. v: z/ `
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */
    # C) Y( u' o& Q+ w9 a
  8. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x00080000) /*!< For ADC1 and ADC2 */. t6 L* h+ `! W" |( m
  9. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x000A0000) /*!< For ADC1 and ADC2 */
    " j1 W0 x$ n, |7 q* ?0 a% N4 t
  10. #define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO    ((uint32_t)0x000C0000) /*!< For ADC1 and ADC2 */
    9 r2 Y0 L$ F" N. U5 V: ~

  11. / U9 k. O3 M( Z& r' z2 P
  12. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x00040000) /*!< For ADC1, ADC2 and ADC3 */
    1 g' H+ _, Y) f7 ^! ^0 t/ `
  13. #define ADC_ExternalTrigConv_None                  ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */   //f2xx系列并没有这个定义) E0 L9 V$ h( N0 X6 J! t

  14. 6 I& k  ?  c- m) m$ `* y/ {
  15. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x00000000) /*!< For ADC3 only */
    " R* J; U2 D' d8 t8 G% Y. ^9 J
  16. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x00020000) /*!< For ADC3 only */: l2 v" }' j: d0 `  J, d
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x00060000) /*!< For ADC3 only */- L4 F& {- |$ c# p
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x00080000) /*!< For ADC3 only */7 C# W( G8 t: _
  19. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x000A0000) /*!< For ADC3 only */
    0 T$ X0 D+ i& p+ h; P' X
  20. #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);修改如下:
  1.     ADC_StructInit(&ADC_InitStructure);//新增加的
    ( ^5 R# H, K2 o& F$ E
  2.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    / o% {% r/ }3 P, f7 C+ b8 Z
  3.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;! i" E# d2 Q7 ]0 f
  4.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;. Q1 ]! q: a' A4 q3 R! \& R2 v
  5.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;1 f' j: ~) A. T. C1 A2 v" w7 N  F
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    * m1 l: R) @/ ~7 e
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;0 \( h) E3 l9 I' g% F" x
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  调用ADC_StructInit(&ADC_InitStructure)语句,ADC_ExternalTrigConv会恢复默认值0。如下:: s4 v/ ^. c" X4 u

6 p% _& `. R! K( {4 W. `( L
20180823201211262.png
. R$ {! D3 w5 x% K& w5 _

7 u4 e5 l( I8 c+ p  另一种方法是直接配置该参数为0,如下:
/ Q4 ^. L, M4 V  g* R) {6 h
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    . M  ?/ {* W8 ^1 S/ [3 e, f$ @
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;% ~) F2 k& S) t4 _
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ; }$ y6 T8 J$ L8 V: ^0 ~2 i- G
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;! F+ D, W# H: v! H7 S. E4 E
  5.     ADC_InitStructure.ADC_ExternalTrigConv= 0;//新增加的
    , M: w# ~, F: N* R
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    & X- A2 u1 _/ f- r/ l
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;% ^! g6 Q! _. w- u, z: m3 F& ]$ {
  8.     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+ ?
20180823201832969.png
  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
收藏 评论0 发布时间:2021-12-2 16:03

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版