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

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

[复制链接]
STMCU小助手 发布时间:2021-12-2 16:03
前言
1 D+ n5 K+ J+ k& a1 _  最近在调试STM32F2XX系列ADC多通道DMA采集时,发现采集的AD值大于4095,有的65000多了,这是什么节奏?adc不是12位吗,最大才0xfff,即4095,怎么会出现这种情况呢?难到是adc数据对齐方式出现问题了,adc的对齐明明设置的是右对齐啊,神马情况?
( i7 e7 [7 @! m. X0 F" C3 y/ [0 M: c) r* n
ADC结构体参数分析
' _8 u4 f  m& _% V' \
  百思不得adc之姐,只能keil单步调试,一步一步查看adc结构体的参数。我使用的是adc dma方式采集,共9个通道。初始化程序如下:
1 _  \9 S) {) a" f
  1. void ADC_DMA_Config(void)/ {, ]' s5 V, F. ?/ I* x$ u
  2. {. b0 s& N3 ]& V! ]. v& N! b) O
  3.     ADC_InitTypeDef       ADC_InitStructure;
    ; X& X" E% q8 d& b  S
  4.     ADC_CommonInitTypeDef ADC_CommonInitStructure;
    & k) R, Z& j' [
  5.     DMA_InitTypeDef       DMA_InitStructure;+ b: y5 y/ ^4 t0 K: y
  6.     GPIO_InitTypeDef      GPIO_InitStructure;
    " Q! R- l% E" V2 @" y& \4 W

  7. : ]4 \( p% z" }8 n; M- c
  8.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);
    # I7 A& [2 O' L
  9.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);7 J" P5 q3 [# P6 x
  10. $ Y. A: o: ?6 q$ k' W+ Q
  11.     DMA_InitStructure.DMA_Channel = DMA_Channel_0;  
    2 R5 `2 r% k! G  i( J9 q- K
  12.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    4 m5 i) Z& y- Y) a" Q
  13.     DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_ConvertedValue;  
    # G/ x! Y* C2 c  R9 J- c9 E* ?
  14.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    / m/ t. z% }  g
  15.     DMA_InitStructure.DMA_BufferSize = Sample_Num*Channel_Num;         / T9 ?7 P8 s8 t4 {0 d* K; ]
  16.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;. M0 J& ]7 I, Z7 u: p. h
  17.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    : A5 Q# `) ]# o9 K
  18.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    / C. q2 W) r! R! }) H
  19.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;) Y5 D. u% I5 z- @  z0 X0 o
  20.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    1 b" Y! c  G4 P; `; M  }  m. B. R# Z
  21.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    $ w& y$ [' _( b! Z# g; F7 Z
  22.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         0 J9 u! G/ J8 [2 `1 M
  23.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;/ N3 G+ F! w* g; e* _5 T7 z' I
  24.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;; D9 T& w" k) ?' q. g  G
  25.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    & Q0 \' z/ y1 K: H: z3 O
  26.     DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    # g+ f& F5 r" g
  27.     DMA_Cmd(DMA2_Stream0, ENABLE);
    : l+ B( e: U2 n4 f0 ?* @1 ~0 E
  28. 4 b" h) C" b3 n  f, ^6 ?
  29. 6 r: o/ ]" p* o
  30.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 |GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
      z# ?' |: J! R) D2 F+ ?
  31.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    2 y5 t( k- L% m
  32.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;. B: e/ x1 `" K7 O/ @; }' y% U
  33.     GPIO_Init(GPIOA, &GPIO_InitStructure);: U7 Z1 b7 D8 k  D% s& p
  34. 7 k! o' F* @0 U1 K7 K
  35.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5;  x! m, Z& _( P* N) C5 t/ V
  36.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    9 C7 e. d# L, I  m4 L* A( K
  37.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;: W( O$ D: ], Z7 i8 y5 y2 A
  38.     GPIO_Init(GPIOC, &GPIO_InitStructure);1 d% O) h9 n4 X( a2 Y# i. l
  39. ! F5 f$ k, O4 g
  40.     /* ADC Common Init **********************************************************/
    - t$ U4 ]+ m3 K$ k1 Y: f
  41.     ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;1 S' ?! f. q, k4 `) u( e
  42.     ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;. E) R' e! P) K( W
  43.     ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
    & R# }( ~/ X: {) z( }3 X8 ]
  44.     ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
    / ?# ^5 x# V3 e5 L4 F
  45.     ADC_CommonInit(&ADC_CommonInitStructure);
    $ _$ N" `* X0 l; q4 b6 E

  46. 6 G% ]( g& A& a$ E9 p- S
  47.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;' Z- x# ?7 \& g1 M, Q, c
  48.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;2 d3 C* u/ n% F
  49.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    $ _- i# @7 U' Q
  50.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;4 y- b' P  K! o7 q
  51.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;1 h8 C( Y' }! M" T# O
  52.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    : n# R5 `$ E* @: Y3 i) X
  53.     ADC_Init(ADC1, &ADC_InitStructure);
    7 x1 d2 h/ x, S* a, _7 L0 g4 a

  54. # [% P1 k5 i8 w$ J1 @0 E4 G

  55. 3 Q7 s( y1 D6 n8 J# N( d; @0 e! W. d% ^7 [
  56.     ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);4 A+ ^5 U* d) b7 n, y. A* A
  57.     ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_3Cycles);* u5 r. A8 z( ]6 C6 E2 G
  58.     ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_3Cycles);
    3 q1 a$ k, x, H3 `
  59.     ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 4, ADC_SampleTime_3Cycles);3 y4 v* q& [" m( m. b( |
  60.     ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 5, ADC_SampleTime_3Cycles);
    5 K' O( A/ Q( r
  61.     ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 6, ADC_SampleTime_3Cycles);/ ]$ J  N: _7 ~% G9 R) V) r9 h
  62.     ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 7, ADC_SampleTime_3Cycles);0 m) J, x# u* ?
  63.     ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 8, ADC_SampleTime_3Cycles);
    5 s0 I! b+ F6 b/ T3 p
  64.     ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 9, ADC_SampleTime_3Cycles);: G" c7 i6 k  l8 u1 {! v9 J% U& o
  65. 3 ?* `) Z- ?6 L  Z6 v: c) v2 n
  66.     ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);8 u! X3 l9 a( s
  67.     ADC_DMACmd(ADC1, ENABLE);7 ?- n# V4 x6 g: M3 A- b" ?! }& E  w: O
  68.     ADC_Cmd(ADC1, ENABLE);# m0 i% @2 T0 v- i8 f: s! k( p

  69. ( c! i* G% B  p: K3 X9 [
  70. }
复制代码

5 `: B! ?$ I" i7 b  其中涉及adc的初始化结构体代码部分如下:
7 ~0 D7 J0 p. @* }5 J  c+ X4 W: _2 H8 L* `# X2 E
    ADC_InitTypeDef       ADC_InitStructure;2 n! Q2 g$ @. t  r
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;8 K. A5 t  s: a2 j  u
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;" [0 g/ {8 F  X9 b1 v0 R
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;: l( P: K$ r& C% O! F! N0 T) M3 T
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
      Y# Y. q! X- Z+ o
  5.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ! m/ s1 Q( K# Y/ E
  6.     ADC_InitStructure.ADC_NbrOfConversion = 9;# ?- v$ _! s* v$ f. w: Z2 A
  7.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  一步一步调式发现结构体有一项ADC_ExternalTrigConv是0x08002d54,这一项并没有初始化对其赋值,忘记给结构体的这一项赋值了。最后这个值通过ADC_Init函数赋值给CR2的时候,第11位(也就是数据对其位)是1了,左对齐了!!!!!
$ o: W  V" S  k2 F5 p
" K+ K  ?4 D" U0 k- J. I0 f
20180823193630758.png

7 C, T) O$ d/ _& ^8 |5 S# r) O" t0 Z6 s
  下面来重点分析下adc初始化结构体中的各项参数的意义:
! s8 ]% ?2 F$ `! K( q1 j. ?  对于STM32,在使用ADC的时候需要配置几个参数。. j2 M. h9 x) A( i2 R
(1) 第一个参数是ADC_Mode,这里设置为独立模式:
: c! H. d6 r; n0 z
$ ?$ K, Z2 s1 d- I# ^% H, y
  1. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
复制代码
" [: |: o, C& N* h% h- y# y
在这个模式下,双ADC不能同步,每个ADC接口独立工作。所以如果不需要ADC同步或者只是用了一个ADC的时候,就应该设成独立模式了。
/ h1 Q8 O( j  \1 G: J; Z7 I" J4 g0 g" f- @( V$ K' l
(2) 第二个参数是ADC_ScanConvMode,这里设置为DISABLE。: o( L4 C: C  _8 D- `
  1. ADC_InitStructure.ADC_ScanConvMode = ENABLE;
复制代码

7 D2 C/ E' P/ J, a& h) j如果只是用了一个通道的话,DISABLE就可以了,如果使用了多个通道的话,则必须将其设置为ENABLE。
' B5 X0 j. H! `5 r) @% A0 O
* X' ]+ w: {% f(3) 第三个参数是ADC_ContinuousConvMode,这里设置为ENABLE,即连续转换。: p; J$ w" U  s
如果设置为DISABLE,则是单次转换。两者的区别在于连续转换直到所有的数据转换完成后才停止转换,而单次转换则只转换一次数据就停止,要再次触发转换才可以。所以如果需要一次性采集1024个数据或者更多,则采用连续转换。; P) Y; m" {/ ]: Q0 Q" F( K  l
% Z8 T+ @4 T4 U7 I5 n* B2 b0 ?8 _
(4) 第四个参数是ADC_ExternalTrigConv,即选择外部触发模式。这里只讲三种:4 [! l! `1 d' Z5 j4 {9 i, l2 t

/ I8 D1 R  N2 W# W; B1、第一种是最简单的软件触发,参数一般为ADC_ExternalTrigConv_None(注意STM32F2XX系列这个有点蹊跷,后面会讲这个)。设置好后还要记得调用库函数:
  Q$ r+ f2 ~- |8 n9 D
  1. ADC_SoftwareStartConvCmd(ADC1, ENABLE);
复制代码
  1. void ADC_SoftwareStartConv(ADC_TypeDef* ADCx)
    + V  M% {( V& i, ^) z/ Q& U" t
  2. {1 e) }6 f- d" x  I0 f/ G! Z
  3.   /* Check the parameters */- Z8 M9 [5 u7 S* E
  4.   assert_param(IS_ADC_ALL_PERIPH(ADCx));9 q! \' L* x% x$ `

  5. + b( g. x2 k( l. F  `. J
  6.   /* Enable the selected ADC conversion for regular group */& X0 z; F% J, \' X2 J
  7.   ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
    . Q, v1 D; H; Q6 W' ?; R  r0 \
  8. }
复制代码
  1. #define  ADC_CR2_SWSTART                     ((uint32_t)0x40000000)      
    1 ~$ I2 \% N$ x4 N. z) O
  2. /*!<Start Conversion of regular channels */
复制代码

' f8 G2 V  x0 G9 T' w: ?6 zADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位,这样触发就启动了。( j* l4 }) U! I7 @
7 G, S8 b9 d( R1 ^* a. R: O9 N  N% v
2、第二种是定时器通道输出触发。共有这几种:ADC_ExternalTrigConv_T1_CC1、ADC_ExternalTrigConv_T1_CC2、ADC_ExternalTrigConv_T2_CC2、
" {8 W8 k3 r( M
8 K+ c2 Z! D3 B, d( \ADC_ExternalTrigConv_T3_T以及ADC_ExternalTrigConv_T4_CC4。定时器输出触发比较麻烦,还需要设置相应的定时器。以
# c8 D/ @* c% E4 f- Y+ V! q6 j' z0 C$ ?+ W1 e# C1 d% z- ^
ADC_ExternalTrigConv_T2_CC2触发为例设置相应的定时器:1 e; R" `# z' ~& c3 B
8 f6 i, g8 D! B# |. X' E" F
  1. void TIM2_Configuration(void)
    : ^% D5 ?, g% e- x$ F5 _6 E
  2. 4 a3 g( j2 R5 ?& Z/ Z& _( Y
  3. {
    / A, M$ D. m7 i' Y- n6 Q1 J
  4. 2 g+ c5 P$ O. I1 N
  5. TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;5 S* Q4 m" @# _3 B! M
  6. 9 o! ^' W6 S; Z+ _5 m7 L
  7. TIM_OCInitTypeDef         TIM_OCInitStructure;
    6 t- s+ a/ x& y4 j- Y/ M0 U7 a
  8. # w& ]8 `) y+ T# J2 H9 \
  9. TIM_TimeBaseStructure.TIM_Prescaler = 4;4 u$ E- g0 z2 @+ N

  10. " b  o6 ?  A7 `( H% {0 D3 B
  11. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    8 A( k& s# d  Y+ D  _3 W& o# W

  12. + t% f" l8 J' t3 y) n
  13. TIM_TimeBaseStructure.TIM_Period = 0XFF;7 g4 Q: D, f! o* B1 n5 o& Q
  14. 5 L% t& @1 R1 A5 a3 A3 t. G' p/ K
  15. TIM_TimeBaseStructure.TIM_ClockDivision = 0;* H; Z) r+ v3 Z  H

  16. - D: Z4 x' S' [3 h( Q# H
  17. TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;- E7 `: C- n8 O8 k: {

  18. 6 z1 Z' u0 D" a
  19. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);7 K% l$ ]. Z' ~3 x% D

  20. $ `. v# C+ D& J# y5 o' N

  21. 7 ^  P# S4 H/ @# L- w1 h
  22. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    7 {# N+ a, _0 F
  23. , X# ^2 l( \4 L9 s+ T3 n* h$ H& P
  24. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;0 o- D' U' Q( F! R

  25. ' ]- c! Z# M) f$ O) V7 t( g, P
  26. TIM_OCInitStructure.TIM_Pulse = 0X7F;  V! n% T% {( J
  27. ) e4 ^' g: N& z: _3 K/ f$ V: h
  28. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    + l- t1 t+ V% f

  29. 8 W% p$ U. [$ g/ U" w! ]) Z* X
  30. TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;          O6 \' g. M# }! l, g5 A
  31. 5 ?3 m. c' T( g/ I
  32. //配置CC2的属性。若CC3作为ADC的触发源,则应改为TIM_OC3Init(TIM2, &TIM_OCInitStructure);9 [2 I- H5 y8 ]
  33. % e& s4 p6 ?) d5 h
  34. TIM_OC2Init(TIM2, &TIM_OCInitStructure);2 y. y+ U2 ?; e

  35. 5 s. Q8 ^6 @" e9 k8 P) t. {2 T
  36. TIM_Cmd(TIM2, ENABLE);. {+ V) T! k' ^- g* b
  37. TIM_CtrlPWMOutputs(TIM2, ENABLE);: N1 G: C* D1 x6 M
  38. }
复制代码
; }* ?! |" _# C* [
! V2 |! f0 \/ }# @& h$ T
这样设置之后就可以用定时器2的输出触发了,至于触发的周期,设置TIM2的时间即可。这里不再赘述。. Q: h' }; B$ h5 r) E, g
8 z4 U) Y+ B5 P( ^& l1 f1 `9 a
3、第三种是外部引脚触发,对于规则通道,选择EXTI线11和TIM8_TRGO作为外部触发事件;而注入通道组则选择EXTI线15和TIM8_CC4作为外部触发事件。: v+ i1 m. [, x/ ]" H

5 `0 O! h; p( ?! C3 ?(5) 第五个参数是ADC_DataAlign,这里设置为ADC_DataAlign_Right右对齐方式。建议采用右对齐方式,因为这样处理数据会比较方便。当然如果要从高位开始传输数据,那么采用左对齐优势就明显了。
. N3 N$ r% W- @, ?2 W# y/ w8 i; r9 s4 |
(6) 第六个参数是ADC_NbrOfChannel,顾名思义:通道的数量。要是到多个通道采集数据的话就得设置一下这个参数。此外在规则通道组的配置函数中也许将各个通道的顺序定义一下,如:
, A# `- H5 q  P4 i4 F: m
  1.       ADC_RegularChannelConfig(ADC1,ADC_Channel_13,1,ADC_SampleTime_13Cycles5);  Q* X3 ~$ K# y% K- p$ E
  2. 4 h2 N8 w$ F( N
  3.       ADC_RegularChannelConfig(ADC1,ADC_Channel_14,2,ADC_SampleTime_13Cycles5);
复制代码
8 ~) ]' V3 k) I: M& O9 t

: z( c* a+ w5 T0 i  多通道数据传输时有一点还要注意:若一个数组为ADC_ValueTab[4],且设置了两个通道:通道1和通道2,则转换结束后,ADC_ValueTab[0]和ADC_ValueTab[2]存储的是通道1的数据,而ADC_ValueTab[1]和ADC_ValueTab[3]存储的是通道2的数据。如果数组容量大则依次类推。+ J* O+ S; w& @! y4 t
5 `* d6 p& D0 o
  补充一点:在使用DMA传输数据的时候,需要设置外设地址和存储器地址,外设地址当然就是ADC的地址了,而存储器的地址如果使用8位数据的话,存储器必须定义为8位缓冲区;如果使用16位数据格式的话,存储器则为16位缓冲器,不可定义为32位或更多,否则,数据将出错。
7 _1 C- z; |4 a$ P  F. ]
2 _7 R% \$ n$ R7 q: J: Q问题的解决方法

. Z0 {* f- U# h& w* E: F8 H  上面分析了adc结构体的参数,下面再来单独看看ADC_ExternalTrigConv这一项。- p8 U, J/ D: K6 M  P$ a
  在stm32f2xx_adc.h文件中有这个成员的参数定义,发现里面并没有ADC_ExternalTrigConv_None这个常见的定义。3 Q. [$ Y" d- A; E" q
) `5 m1 f' i$ I) M0 i9 ~
  1. /** @defgroup ADC_extrenal_trigger_sources_for_regular_channels_conversion ( r! z- X% z- c) f9 O
  2.   * @{
    , g9 q3 ^7 [+ {. r  ~
  3.   */
    3 b' y; |- i; @7 T# }
  4. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000)
    5 |3 G0 n! y: b! \3 ]
  5. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x01000000)$ F+ v: B; c! s' m+ x3 E0 H, T' V9 n& Q
  6. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x02000000)
    ( {6 [$ o6 w+ e$ e1 `* M/ D4 I
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x03000000)+ ~" Y2 j4 ~- n- {
  8. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x04000000)
    % C2 M/ p8 R; d% }" i- \, ]2 o
  9. #define ADC_ExternalTrigConv_T2_CC4                ((uint32_t)0x05000000)
    3 |8 c0 q5 Y  W) U4 d
  10. #define ADC_ExternalTrigConv_T2_TRGO               ((uint32_t)0x06000000)0 I2 l% Q2 a4 F4 @
  11. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x07000000)+ @  H3 M1 i' Y! f% B
  12. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x08000000)% z. \3 k* o2 B& z/ D
  13. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x09000000)
    & d" T/ {& s, M' K
  14. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x0A000000)
    " v; [" l$ d) K: F8 S
  15. #define ADC_ExternalTrigConv_T5_CC2                ((uint32_t)0x0B000000)
    6 N2 u, p$ e3 K" o0 }' a
  16. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x0C000000): A3 j3 D% V: G4 @8 Q0 m, g3 @3 I
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x0D000000)! h" H& ^; L7 \' h/ Z% R. |) Q: [$ N6 j6 M
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x0E000000)
    / o, y  U- U3 S$ ^! i( s+ K: b
  19. #define ADC_ExternalTrigConv_Ext_IT11              ((uint32_t)0x0F000000)
复制代码
% f: p, J! K: F. j  U) r) k( L2 M
  再来看看stm32f10x_adc.h文件中的ADC_ExternalTrigConv的参数定义:
+ F% |4 H( Y, |
  1. /** @defgroup ADC_external_trigger_sources_for_regular_channels_conversion
    ) V! m: c( q8 o. |0 f7 Z
  2.   * @{
    9 g" m2 c( p7 b" V
  3.   */
    % W+ r# @) [: K# g7 O3 a

  4. 9 W1 w7 r5 Z, D  r0 N  y7 M4 ]4 L
  5. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */: S: F; J' F: q! t
  6. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */+ S, u8 h( P. D
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */
    & E% n- c% f1 G  B: }+ T- v
  8. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x00080000) /*!< For ADC1 and ADC2 */
    / L. ^6 i5 ]# j
  9. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x000A0000) /*!< For ADC1 and ADC2 */4 R1 V5 F- u& R4 H# ~
  10. #define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO    ((uint32_t)0x000C0000) /*!< For ADC1 and ADC2 */
    9 E) `1 Q% A2 a; G* Y
  11. ' X7 r; _# N% |
  12. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x00040000) /*!< For ADC1, ADC2 and ADC3 */
    5 u2 }$ F- N3 _4 _0 G$ p$ @
  13. #define ADC_ExternalTrigConv_None                  ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */   //f2xx系列并没有这个定义
    ' ~* A, N/ K) p2 o& r

  14. ) E2 i; Z/ z+ ~6 P$ K9 Z
  15. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x00000000) /*!< For ADC3 only */& h+ V9 u6 U' G2 |; |
  16. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x00020000) /*!< For ADC3 only */% I8 o4 C% h1 X" D. l! R) J
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x00060000) /*!< For ADC3 only */8 ^0 D9 j7 v/ a/ ~* c
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x00080000) /*!< For ADC3 only */" ~* W: @. ?: G; l) ^% G
  19. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x000A0000) /*!< For ADC3 only */6 R3 R! j/ G" a
  20. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x000C0000) /*!< For ADC3 only */
复制代码

- t- p) f' ^6 X, J( S/ i8 G4 |  对比发现stm32f2xx系列并没有ADC_ExternalTrigConv_None这个定义,很是奇怪,现在还不明白ST的工程师为什么做这个变动。
  |4 M* q4 b0 [7 Z" S4 ?/ k0 L% j  那么问题怎么解决呢?& Y+ a0 G6 F) n& L5 [4 s
  一种是进行adc结构体的初始化操作,在配置之前恢复默认值。即调用ADC_StructInit(&ADC_InitStructure);修改如下:
  1.     ADC_StructInit(&ADC_InitStructure);//新增加的
    % I. ~" a5 T& @1 s- ~- V' A& V
  2.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;" J" F: G4 O/ ?
  3.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;$ W# y9 }8 B2 H3 R. H; |
  4.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    * J' `% g" I: T$ R/ K. K9 g
  5.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;9 A( [6 j- b7 L3 Q7 M" t3 ?& m* [. l
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;) a4 A' ]! m4 S7 p; d; Q& a1 _, K9 u
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    9 e1 Q% ^( K3 [1 d) N
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  调用ADC_StructInit(&ADC_InitStructure)语句,ADC_ExternalTrigConv会恢复默认值0。如下:8 |1 g  W5 S1 y4 U" d9 F

+ ?: U$ N1 d( K" A$ Z
20180823201211262.png
. T& m/ z. t# ?

1 J2 }1 t9 d  z7 }4 W+ o* ~# B  另一种方法是直接配置该参数为0,如下:  B$ T7 e, t* u. c4 Y* _
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    8 E, A6 N( `( p* f" q
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    5 n0 z' P+ M1 h( Y0 o; Q# m6 `
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    1 \; q  l" V6 \9 P" E
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ! E( o# O  ^- \! |9 \) N
  5.     ADC_InitStructure.ADC_ExternalTrigConv= 0;//新增加的
    ( ~! }+ m5 b- `* \" ~  K
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;$ r6 Q+ l4 C2 v- w: P4 b+ g3 d; G
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;1 V- b. f) ?# m9 k
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
" m  ~) c4 T- g$ M! N* A+ }
  这两种方法都可以解决adc采样对齐方式异常问题。  J) D0 I% h6 f$ c- K( S+ f
  但是ADC_ExternalTrigConv= 0在stm32f2xx_adc.h中其实是对应ADC_ExternalTrigConv_T1_CC1的。2 O+ r5 q, u  E  E- _  z

& O/ i' @8 H2 x) F/ Y9 e
20180823201832969.png

9 V5 S9 h8 @* o" Q0 U6 e* P, T4 z" [
  也就是说调用软件触发函数ADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位也可以触发定时器触发方式的adc通道。1 k3 H9 |; V4 w# k
8 z7 e/ M/ [0 F6 |

( Z( @  D* [3 x2 A( {$ x5 k, k! {+ E% \( d, G! ~7 p3 j9 y
收藏 评论0 发布时间:2021-12-2 16:03

举报

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