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

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

[复制链接]
STMCU小助手 发布时间:2021-12-2 16:03
前言
( v7 z7 P8 j( D$ t4 H8 F1 @  最近在调试STM32F2XX系列ADC多通道DMA采集时,发现采集的AD值大于4095,有的65000多了,这是什么节奏?adc不是12位吗,最大才0xfff,即4095,怎么会出现这种情况呢?难到是adc数据对齐方式出现问题了,adc的对齐明明设置的是右对齐啊,神马情况?4 y9 d/ {7 r* m. d, z! M( c
2 A8 b6 ]9 o3 T4 C! F8 \+ z* N+ [
ADC结构体参数分析
: \9 e7 `+ `. o% |2 ~
  百思不得adc之姐,只能keil单步调试,一步一步查看adc结构体的参数。我使用的是adc dma方式采集,共9个通道。初始化程序如下:
# S& p/ n( S& }! {& {9 [
  1. void ADC_DMA_Config(void)3 Y0 A8 |% p5 y& ~( l
  2. {* O3 l0 ^* Y9 S% d
  3.     ADC_InitTypeDef       ADC_InitStructure;
    0 A. @- ]- N$ ^2 J/ _" M5 s
  4.     ADC_CommonInitTypeDef ADC_CommonInitStructure;
    : s" o0 P* O" F' x
  5.     DMA_InitTypeDef       DMA_InitStructure;
    8 H: o  Y6 |3 c/ t; C6 W* E7 G. _
  6.     GPIO_InitTypeDef      GPIO_InitStructure;
    0 j8 S2 h) M1 N7 `/ q0 }, v. T
  7. % i7 m: J' }( h9 s
  8.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);, a# a& F3 d0 Q
  9.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);1 @$ |2 {" j! b5 J: V. y1 U* b: B
  10. + `" J- ~& [, o0 c1 i: h2 Q' T
  11.     DMA_InitStructure.DMA_Channel = DMA_Channel_0;  & p1 k+ J! p1 L) d( G/ p
  12.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;4 M( p* `5 _; ?+ k8 C
  13.     DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_ConvertedValue;  
    9 f/ y& V# r/ q! m6 P* ?) M
  14.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;& `9 P2 k  r2 a& t" t( ~
  15.     DMA_InitStructure.DMA_BufferSize = Sample_Num*Channel_Num;         ( H  J! c2 g& `: S$ O; r
  16.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;+ q: t, c1 Q. k$ Z: s# V
  17.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;3 @  ~/ }% t9 P+ a/ l
  18.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;, w$ x) |/ U/ Q/ F
  19.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    2 D* Q3 N! y% @& f
  20.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    % ?5 X2 F3 l& ?/ u+ g/ L8 Y
  21.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    $ f, q4 X  [& q, W& h8 I% n
  22.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
    9 R4 l1 @- G+ n7 l
  23.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;9 G% k/ O& @7 a- L9 O) m2 x5 c
  24.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;3 B7 U) f: J& l" W' e7 Y9 e2 k
  25.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;' k; {% ?2 f1 }+ {
  26.     DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    3 ?  n. r7 ^/ j! n# h, w3 o
  27.     DMA_Cmd(DMA2_Stream0, ENABLE);
    / D* O1 J7 I7 I( O( ]4 M" v
  28. + X3 x( |8 ?; o' O8 R: o5 p

  29. ( O( g% `$ O6 `
  30.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 |GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;% V1 ]5 i+ B8 U0 l* p& y, n
  31.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    , c4 s# I& i: D9 N$ n
  32.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;; d9 V! g4 }0 G" Q
  33.     GPIO_Init(GPIOA, &GPIO_InitStructure);
    8 D8 i# n4 |4 C2 S

  34. / m4 J9 T- A3 c% _, D
  35.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5;
    + ^8 _8 u0 k" p  N7 |
  36.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;9 \8 D; g! p. s5 E
  37.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    - V7 n$ M  i# R, T! E! W% p- d
  38.     GPIO_Init(GPIOC, &GPIO_InitStructure);
    ! {( R8 _+ T6 \6 r

  39. $ w* N/ v  n& G) o1 t; i+ p7 Y
  40.     /* ADC Common Init **********************************************************/" u6 R# J: c. e- L' O
  41.     ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;/ J* ?$ {. K$ Q! Y2 b
  42.     ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;4 P* L4 i4 A( Q) h1 e% p) y
  43.     ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;& W" u4 f9 W  b0 ~
  44.     ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;, ?* }4 e& t9 U8 A* D
  45.     ADC_CommonInit(&ADC_CommonInitStructure);! U1 q# c) }/ _. T! H8 _
  46. & {7 N6 A8 O+ b! r/ c
  47.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    8 Y4 Y' {+ `0 b* Q3 _2 }4 H0 W
  48.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    * K5 H- d  R8 l$ _/ I6 H" i
  49.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;; f; [( V, Y/ A; l8 d
  50.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;& y. I, ^- V9 K& w) U3 g9 E
  51.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;! y+ [! s: |: u  \  J: q
  52.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    ; `) P9 e. _  C( d5 R) x
  53.     ADC_Init(ADC1, &ADC_InitStructure);0 d0 K7 e  p! S) E) M# D, q2 O3 h/ D
  54. ) R, {% Z; ]: r" h$ \* ^) o5 c% p
  55. 2 {  J& p, a7 ^7 W4 E0 U
  56.     ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);
    . e# C( F& c% M: Q# {+ {
  57.     ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_3Cycles);/ M! }& v0 {5 X4 I' c$ V
  58.     ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_3Cycles);
    1 R* y6 V2 p4 a/ H3 x# k! T5 F4 o+ n
  59.     ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 4, ADC_SampleTime_3Cycles);
    0 q) x+ x- O# ~; }- b
  60.     ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 5, ADC_SampleTime_3Cycles);
    # K2 W: C. S7 s+ b" p% j
  61.     ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 6, ADC_SampleTime_3Cycles);
    ) f1 b) w4 w* I6 A3 F" o/ D. p
  62.     ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 7, ADC_SampleTime_3Cycles);* ]9 s% w- j$ A: h: Y* r
  63.     ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 8, ADC_SampleTime_3Cycles);% S& z% f$ R  Q( g( [
  64.     ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 9, ADC_SampleTime_3Cycles);
    ) I# F; U5 Q! D5 e: P

  65. 7 t/ j! i7 J; v  v
  66.     ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);8 U+ q; ~5 Y# S7 C" {
  67.     ADC_DMACmd(ADC1, ENABLE);' U  X9 S3 ?) u, M' s: w
  68.     ADC_Cmd(ADC1, ENABLE);
    / R$ }% F9 R) z7 N% C4 ^/ k- u
  69. ; G, U, i( _5 }! y
  70. }
复制代码

5 X6 p4 l- u2 J' J3 }/ ^8 z" |  其中涉及adc的初始化结构体代码部分如下:
: M. a2 ~" e1 X* `, k- V! I) `* Z/ f; h. v1 D
    ADC_InitTypeDef       ADC_InitStructure;0 E5 m4 C7 R+ o  z" ?
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;6 e" K  ]) C1 w0 J/ t2 ?0 P
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;% G9 O/ M' G  z& X% s& A
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ( o8 Q' T/ ~7 ]8 E: ?. [$ y
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    7 P9 R  m8 v4 ?$ f$ t
  5.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    0 r! t8 M; y! A, z
  6.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    : O# ~1 H4 U4 R( G' U) d: q' }
  7.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  一步一步调式发现结构体有一项ADC_ExternalTrigConv是0x08002d54,这一项并没有初始化对其赋值,忘记给结构体的这一项赋值了。最后这个值通过ADC_Init函数赋值给CR2的时候,第11位(也就是数据对其位)是1了,左对齐了!!!!!( a" p5 }- f- N! u' h

! X5 k# c" }1 N% L  P4 S
20180823193630758.png

$ `- f3 m7 O! F. U9 [7 b" r. \
) _  _$ F. ]& q! n  下面来重点分析下adc初始化结构体中的各项参数的意义:% g# ]# Z+ b# @! }' i
  对于STM32,在使用ADC的时候需要配置几个参数。
; h6 g* o1 T, x* |* f7 q(1) 第一个参数是ADC_Mode,这里设置为独立模式:9 r, g9 [/ M0 U0 T2 e+ Q# f3 D
, u2 @) e! S0 h: v8 v* c
  1. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
复制代码
1 v& Z; r  K+ V  t7 U
在这个模式下,双ADC不能同步,每个ADC接口独立工作。所以如果不需要ADC同步或者只是用了一个ADC的时候,就应该设成独立模式了。
3 u3 B+ _, Q$ p/ i# m- r  z/ Z( b8 x
' z: d% ?$ w8 V- U(2) 第二个参数是ADC_ScanConvMode,这里设置为DISABLE。2 P0 f+ t0 {4 L. D; S* e* p8 Z5 ?
  1. ADC_InitStructure.ADC_ScanConvMode = ENABLE;
复制代码

; [; w% T1 U6 d& U  l如果只是用了一个通道的话,DISABLE就可以了,如果使用了多个通道的话,则必须将其设置为ENABLE。
( f& Q0 O( Z  Y
5 T7 v+ P* a* _$ I(3) 第三个参数是ADC_ContinuousConvMode,这里设置为ENABLE,即连续转换。
4 F, i/ a# a6 K1 u' \如果设置为DISABLE,则是单次转换。两者的区别在于连续转换直到所有的数据转换完成后才停止转换,而单次转换则只转换一次数据就停止,要再次触发转换才可以。所以如果需要一次性采集1024个数据或者更多,则采用连续转换。& m% p" c0 V& q* }+ {" C2 a6 ]
* q  s& \- a0 ~9 V  w4 [+ d! Q/ T$ i
(4) 第四个参数是ADC_ExternalTrigConv,即选择外部触发模式。这里只讲三种:1 K, }/ t/ H5 E% G2 X; ]

1 Q0 @$ p( B& J) i! l( z) f1 P- N1、第一种是最简单的软件触发,参数一般为ADC_ExternalTrigConv_None(注意STM32F2XX系列这个有点蹊跷,后面会讲这个)。设置好后还要记得调用库函数:
# Q2 |' W. L5 O, H7 `# E
  1. ADC_SoftwareStartConvCmd(ADC1, ENABLE);
复制代码
  1. void ADC_SoftwareStartConv(ADC_TypeDef* ADCx)$ ]! E1 Y9 M$ z( R& V1 V
  2. {
    6 U& H! E# x0 w/ s  @! N
  3.   /* Check the parameters */1 S/ ]5 U) G  _1 k
  4.   assert_param(IS_ADC_ALL_PERIPH(ADCx));
    3 \  h' X& Y; ~9 u1 m

  5. 8 T- [5 b  s6 I
  6.   /* Enable the selected ADC conversion for regular group */
    9 x1 U/ ~0 N1 u" B7 B2 Y
  7.   ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;# {4 M1 U1 m% A3 g3 E9 F" B
  8. }
复制代码
  1. #define  ADC_CR2_SWSTART                     ((uint32_t)0x40000000)      $ a; U. e1 ^) v0 j! P$ T. W
  2. /*!<Start Conversion of regular channels */
复制代码

( {, f: {' T" z* GADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位,这样触发就启动了。& i$ N5 i" z2 F& p. B
' N' @! I. K3 ?+ }7 w
2、第二种是定时器通道输出触发。共有这几种:ADC_ExternalTrigConv_T1_CC1、ADC_ExternalTrigConv_T1_CC2、ADC_ExternalTrigConv_T2_CC2、
0 U% I1 J2 K+ Y: m5 ?7 Q4 ?8 T6 t
1 t+ d1 r7 ]& Y% D1 Y1 `% QADC_ExternalTrigConv_T3_T以及ADC_ExternalTrigConv_T4_CC4。定时器输出触发比较麻烦,还需要设置相应的定时器。以
+ h; [" g7 W: O9 q1 _
% b0 p& o0 }7 [% F! j" A. d) QADC_ExternalTrigConv_T2_CC2触发为例设置相应的定时器:  Y5 n' ]! |) V% ~

' T, T/ h/ \) \# q
  1. void TIM2_Configuration(void)6 M* L" V% d6 P7 Z
  2. / f$ M  i/ X: W# ?
  3. {+ e2 w/ r! {6 X( n& ]! F' s
  4. $ c1 a! u$ i! x: @. Y4 W( P  g
  5. TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;, H2 n5 v& Y4 g0 N3 }6 o8 Z

  6. 2 v5 q( {. @6 ~* C5 ~
  7. TIM_OCInitTypeDef         TIM_OCInitStructure;
    / a1 r: _  n: u6 w8 ~
  8. 4 {+ n7 Q8 X/ k9 p
  9. TIM_TimeBaseStructure.TIM_Prescaler = 4;
    . W+ D7 `4 s7 P9 p$ t) N0 z" ?

  10. ) `1 B! v$ ?9 B( O3 q3 ]
  11. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    5 h& o6 Q. ?" D2 A1 d; b" u4 H) G

  12. , ~+ M, f! X/ z. W2 N6 M! g; D
  13. TIM_TimeBaseStructure.TIM_Period = 0XFF;5 R8 T& }( ~7 G% M! C  I' q& E- u( J
  14. " a, ~" [# z$ Y$ o8 O1 G
  15. TIM_TimeBaseStructure.TIM_ClockDivision = 0;7 X! h$ }# h( H0 \" p- ?( d
  16. ; H9 v: y+ [7 S! o9 u
  17. TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    ' D7 S% p! |2 z: Q+ y, v0 G
  18. 0 @" z' {% a* Y; A% z
  19. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    1 s, S& ?# K/ L* J

  20. " L& O8 l, b  u) l0 E$ @# q" U
  21. $ G, D. @7 O" L( ~$ K2 S
  22. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;. L7 j) x, d: h( a# Z& X

  23. ) I2 w, {  ?( R3 n4 R/ a2 y( ?
  24. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    ) a; C  k- y# }% Q# R% G

  25. / J2 j' A9 r* e% K, d
  26. TIM_OCInitStructure.TIM_Pulse = 0X7F;0 E$ C* G7 A8 k( n  V
  27. 6 d5 k0 v  S$ N& Y+ p
  28. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    4 r  z/ f2 A3 \
  29. 4 I3 Z" R/ K4 f5 _1 q) H% k2 {
  30. TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;        8 H) Z" e- {3 t
  31. ) Q2 {. {7 I5 A7 T
  32. //配置CC2的属性。若CC3作为ADC的触发源,则应改为TIM_OC3Init(TIM2, &TIM_OCInitStructure);; v& ~0 V; d+ k6 i

  33. " x" D. L$ W6 h
  34. TIM_OC2Init(TIM2, &TIM_OCInitStructure);6 v2 f4 n6 v2 x( {

  35. % B/ B0 u6 u( t3 s+ w
  36. TIM_Cmd(TIM2, ENABLE);
      l% g, O6 m, q! i
  37. TIM_CtrlPWMOutputs(TIM2, ENABLE);1 @7 u2 W: ~0 s9 R$ [- [; \# P
  38. }
复制代码

; n  C# ]  \4 z. n/ K: S
0 c- B% d# u+ x' N这样设置之后就可以用定时器2的输出触发了,至于触发的周期,设置TIM2的时间即可。这里不再赘述。
+ W5 v/ A' q" {! @+ ^) T% c6 f6 G: G0 o" x9 N  Q6 g( w
3、第三种是外部引脚触发,对于规则通道,选择EXTI线11和TIM8_TRGO作为外部触发事件;而注入通道组则选择EXTI线15和TIM8_CC4作为外部触发事件。
3 o5 ?8 x  x; h8 L% R
6 Z3 n+ E. b; Q: Y(5) 第五个参数是ADC_DataAlign,这里设置为ADC_DataAlign_Right右对齐方式。建议采用右对齐方式,因为这样处理数据会比较方便。当然如果要从高位开始传输数据,那么采用左对齐优势就明显了。
2 Y6 W, }* P7 H6 e' J
- w1 O- l6 A3 X" V1 k6 r(6) 第六个参数是ADC_NbrOfChannel,顾名思义:通道的数量。要是到多个通道采集数据的话就得设置一下这个参数。此外在规则通道组的配置函数中也许将各个通道的顺序定义一下,如:
. @9 K" y7 @5 _' k2 Y7 W
  1.       ADC_RegularChannelConfig(ADC1,ADC_Channel_13,1,ADC_SampleTime_13Cycles5);
    / @& a% q7 `  k  U' O4 l' f

  2. - u( j; A+ i6 y2 |
  3.       ADC_RegularChannelConfig(ADC1,ADC_Channel_14,2,ADC_SampleTime_13Cycles5);
复制代码
& W* _9 `+ A% s3 v2 e; |5 w  }
, ^; _" Y' B8 o: g1 v8 A4 {
  多通道数据传输时有一点还要注意:若一个数组为ADC_ValueTab[4],且设置了两个通道:通道1和通道2,则转换结束后,ADC_ValueTab[0]和ADC_ValueTab[2]存储的是通道1的数据,而ADC_ValueTab[1]和ADC_ValueTab[3]存储的是通道2的数据。如果数组容量大则依次类推。
+ H* s7 M+ @& T4 a4 w
1 X% k; p  J6 y. ^, y  补充一点:在使用DMA传输数据的时候,需要设置外设地址和存储器地址,外设地址当然就是ADC的地址了,而存储器的地址如果使用8位数据的话,存储器必须定义为8位缓冲区;如果使用16位数据格式的话,存储器则为16位缓冲器,不可定义为32位或更多,否则,数据将出错。& z7 F! d& n% I, h: i
. d: o& ]" ~8 w' A
问题的解决方法
6 }" ]6 a2 X5 P6 _
  上面分析了adc结构体的参数,下面再来单独看看ADC_ExternalTrigConv这一项。7 C- R! [* |& m
  在stm32f2xx_adc.h文件中有这个成员的参数定义,发现里面并没有ADC_ExternalTrigConv_None这个常见的定义。" M$ v" r% f2 U6 n" w% g3 A6 y

" O9 C6 n& i2 p- a5 T- A
  1. /** @defgroup ADC_extrenal_trigger_sources_for_regular_channels_conversion 0 o# H6 Z6 c* r9 h* j0 n7 K
  2.   * @{0 T) U6 Q" {2 X
  3.   */
    ! {5 y8 w4 P) r1 @: F# Z5 ~! L
  4. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000)
    1 g& ]7 u' u6 X& P2 D
  5. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x01000000)* E8 Z& P0 X0 [( x7 X, @
  6. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x02000000)7 X1 v: j, J2 I+ ]. ~& R
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x03000000)
    6 A  [" ?' F6 x5 R
  8. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x04000000)  ~" i) f( r2 a
  9. #define ADC_ExternalTrigConv_T2_CC4                ((uint32_t)0x05000000)' g6 G. u8 l) L8 D6 {4 V( s
  10. #define ADC_ExternalTrigConv_T2_TRGO               ((uint32_t)0x06000000)1 [0 T( B0 G% P4 K
  11. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x07000000)
    + ]( g2 ?& E# Z% R, l1 t1 b; q
  12. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x08000000)
    9 U3 v- J5 K! y. B. C/ h5 \
  13. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x09000000)  X$ ]* W& \) g+ Q. r) H: E1 R- ^
  14. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x0A000000)
    # x- e8 H6 F' k9 a' Q
  15. #define ADC_ExternalTrigConv_T5_CC2                ((uint32_t)0x0B000000)  i' k6 I5 w8 V2 H
  16. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x0C000000)
    8 V# _* s2 ?  d" q
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x0D000000)) v2 {. A% S$ T' R$ I/ j" `, L
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x0E000000)
    ; X- a; A' E4 E
  19. #define ADC_ExternalTrigConv_Ext_IT11              ((uint32_t)0x0F000000)
复制代码
1 V/ |# K9 N" V+ s4 [
  再来看看stm32f10x_adc.h文件中的ADC_ExternalTrigConv的参数定义:
1 r+ r+ z  u& o" v" i
  1. /** @defgroup ADC_external_trigger_sources_for_regular_channels_conversion
    % b7 C% J. S# a% d, l6 W: a9 b6 ?% |
  2.   * @{& s" r- }) v/ f8 f1 z
  3.   */
    : s* l( D8 U& a
  4. 2 F* ^( v) o) x  p$ W8 O: M
  5. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */
    & Y4 p" w  u- f7 |2 a% x
  6. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */
    0 O9 Q6 N0 U, ?, X) K3 U4 u' f
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */
    & q5 M0 X6 l8 r- t5 w4 ^- ~, S
  8. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x00080000) /*!< For ADC1 and ADC2 */; G: d$ |, t1 K" {/ r0 h0 j
  9. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x000A0000) /*!< For ADC1 and ADC2 */
    ; u8 L# G8 d! A$ i; c+ p8 j
  10. #define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO    ((uint32_t)0x000C0000) /*!< For ADC1 and ADC2 */2 C9 }/ V( u3 R* K. h  P

  11. ' t; L# ^) s, l. u6 e; w, \7 D
  12. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x00040000) /*!< For ADC1, ADC2 and ADC3 */' G; C3 C. \8 {
  13. #define ADC_ExternalTrigConv_None                  ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */   //f2xx系列并没有这个定义2 M" i1 }( O/ `- I8 `/ ^

  14. ' C2 O3 F% P- I0 J
  15. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x00000000) /*!< For ADC3 only */  S1 L. E0 U2 }% M
  16. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x00020000) /*!< For ADC3 only */
    ( C& c+ {) @4 c
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x00060000) /*!< For ADC3 only */
    * l+ x% a" c1 U% O9 f* [. S3 G7 M
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x00080000) /*!< For ADC3 only */
    . E# m5 z# @3 u# |9 P
  19. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x000A0000) /*!< For ADC3 only */
    ; ?5 U& o% C, S4 ^& i0 e, A3 p
  20. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x000C0000) /*!< For ADC3 only */
复制代码
$ Z" j9 [- q7 R4 W2 E7 L, U
  对比发现stm32f2xx系列并没有ADC_ExternalTrigConv_None这个定义,很是奇怪,现在还不明白ST的工程师为什么做这个变动。
- b- w9 J" I+ i/ L  那么问题怎么解决呢?
4 k. s; N4 I& _6 t; G& q- H/ x  一种是进行adc结构体的初始化操作,在配置之前恢复默认值。即调用ADC_StructInit(&ADC_InitStructure);修改如下:
  1.     ADC_StructInit(&ADC_InitStructure);//新增加的- S4 ?7 `3 J! i" |
  2.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ) S4 ~3 j" x5 ]9 |5 F
  3.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;; x" g5 x5 c* J6 z
  4.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;4 V  j  ^. _3 B$ |9 b/ a
  5.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    $ r+ ~9 r& D. `& Q
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    5 E( H( R3 o1 m% y# e+ `* E
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;+ B; Z1 a. V; K, D
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  调用ADC_StructInit(&ADC_InitStructure)语句,ADC_ExternalTrigConv会恢复默认值0。如下:
" T9 d& P7 ]' Q" L
. j1 J) D* u0 g- ]7 g
20180823201211262.png
2 d* j# J* G/ D. b0 t& a" v& h

1 P$ j& ~  {! O% Y. h5 k4 A+ Z) x  另一种方法是直接配置该参数为0,如下:
. q2 p6 B- a# m
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;/ C: a& e4 }8 ~& h+ l
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;: i* t* W$ b# L/ v7 j, t6 F6 X
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    * f: B4 J; {; B, t. T
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;3 l# w7 P: v& A, P( ]0 V: R
  5.     ADC_InitStructure.ADC_ExternalTrigConv= 0;//新增加的
    6 ~, X& ~8 [' b( D0 E& V
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;* w" e% q: @6 {
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;3 [4 w# X/ `( ]
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
. \1 r; n9 ^$ r9 A# s
  这两种方法都可以解决adc采样对齐方式异常问题。% `0 Y, l# h. H
  但是ADC_ExternalTrigConv= 0在stm32f2xx_adc.h中其实是对应ADC_ExternalTrigConv_T1_CC1的。
7 c- |3 ]/ L2 ^
# ^! g2 Y  `9 C3 D1 ]4 C
20180823201832969.png
: h1 n. K. H3 X1 S  K* a; Y; [& M3 [* F
4 o+ j9 p' ~7 D; h8 }
  也就是说调用软件触发函数ADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位也可以触发定时器触发方式的adc通道。' p* L1 \$ e! Z; D( r
1 j) v/ f6 S! l6 N

3 p4 u6 N' w; l; i* V0 e, A) j. B* ?# j0 ^6 h
赞 收藏 评论0 发布时间:2021-12-2 16:03

举报

0个回答

所属标签

相似技术帖

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