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

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

[复制链接]
STMCU小助手 发布时间:2021-12-2 16:03
前言9 E% S6 V  x4 y3 R1 p7 W0 @( L
  最近在调试STM32F2XX系列ADC多通道DMA采集时,发现采集的AD值大于4095,有的65000多了,这是什么节奏?adc不是12位吗,最大才0xfff,即4095,怎么会出现这种情况呢?难到是adc数据对齐方式出现问题了,adc的对齐明明设置的是右对齐啊,神马情况?
' r4 R0 w- N% m% e; k5 q/ A, \0 q
: P: H0 _. u/ S1 t6 i$ fADC结构体参数分析

, L' e# ?; q/ N/ g2 [1 j* J  百思不得adc之姐,只能keil单步调试,一步一步查看adc结构体的参数。我使用的是adc dma方式采集,共9个通道。初始化程序如下:+ ]/ g, }! X& E! y# V( q
  1. void ADC_DMA_Config(void)6 r% H2 q$ V* E- l
  2. {
    7 w3 j" n' \! w0 I# S! r- Y5 Q
  3.     ADC_InitTypeDef       ADC_InitStructure;
    $ d1 I6 T' L+ y$ m
  4.     ADC_CommonInitTypeDef ADC_CommonInitStructure;
    " C4 R( F( T  Q  J- b! W$ ^
  5.     DMA_InitTypeDef       DMA_InitStructure;  ?5 r9 @8 Y3 }' r8 h/ J
  6.     GPIO_InitTypeDef      GPIO_InitStructure;
    ( F6 G8 p7 O5 I+ y

  7. % C$ x8 u) p* a; @6 o
  8.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);
    ; Y5 I: o* g4 ~! h$ r2 V0 e- z+ Z  A
  9.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    ) D2 N, y1 k2 ^% z$ J3 L. `/ E  B

  10. 1 f/ F' E( g8 T5 G! C  M5 F: ~: Y
  11.     DMA_InitStructure.DMA_Channel = DMA_Channel_0;  
    & f( q, S' r, k9 z0 P9 t# Q/ [8 J" P
  12.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    ! |' C7 P, f+ s- ~0 P  w
  13.     DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_ConvertedValue;  # @3 V6 x# d* h6 I4 N5 u$ h
  14.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    + ], z/ @) ]2 C+ N
  15.     DMA_InitStructure.DMA_BufferSize = Sample_Num*Channel_Num;         
    . ~# d. K  b- }
  16.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;4 s4 e" \# Z( }; P
  17.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    ! L' @5 D  S1 [0 Z
  18.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;- A4 P+ n8 b3 Z5 M, Q' c6 m- @
  19.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    ' m- Y, E, l: ^: T+ ~. x: f/ g$ U
  20.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
      M# k# w4 {. I6 q2 G' ^* R6 ?
  21.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    ; x0 s8 G, ]$ F3 Z  f3 d
  22.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
    ) m$ {$ q4 m2 h# Q  n' ~+ j
  23.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;2 e2 q/ d8 t2 ~! b! i7 p
  24.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    # V: F" {8 t. q' p$ f; s# i/ s" k
  25.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    . r# C" i0 w4 Q6 `9 G
  26.     DMA_Init(DMA2_Stream0, &DMA_InitStructure);& M0 O' b/ K8 E4 `, ]3 u1 h
  27.     DMA_Cmd(DMA2_Stream0, ENABLE);; @8 M( ~+ J0 ^& `5 |  G# K
  28. 2 V0 c5 U% v4 L

  29. 6 y8 ]! _6 w; |' e
  30.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 |GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
    - o  p4 Z3 S# l* s& n: g
  31.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    9 e+ A) K' t. y
  32.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;  `) B- t( D0 b7 B
  33.     GPIO_Init(GPIOA, &GPIO_InitStructure);9 G! v0 a& |7 L, o, t

  34. . c9 [* r9 \, ]/ O
  35.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5;
    : j7 L) g" T  `$ n$ Y: A" ]+ u
  36.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    1 u6 l0 i% G: y( ?
  37.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;6 _+ V' O: S& K8 K* B
  38.     GPIO_Init(GPIOC, &GPIO_InitStructure);
    + z! g8 C2 z3 ?2 h+ ]0 U& a. G- T
  39. - ]5 Q$ _6 R2 V# |& _
  40.     /* ADC Common Init **********************************************************/8 H8 X. o2 d1 z
  41.     ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
    3 v! @/ U& ^# m
  42.     ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
    9 b, U& ?7 k( D: Q9 {
  43.     ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;( L2 M; ?/ h3 ^; Z% Q. v) E
  44.     ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;# W# V' S9 ~5 ~1 V  E! R
  45.     ADC_CommonInit(&ADC_CommonInitStructure);
    3 `) J% D0 h1 d3 ^, d1 m

  46. & G# j, U6 a% Z
  47.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;* j  x+ r+ {- I  N
  48.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;" i  I- o) p9 e
  49.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;$ @! f# ^' ]: b9 V' ?( w
  50.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;" [$ }/ h2 z4 J% ^3 ^" s
  51.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    7 O2 h2 x. ?2 E1 `/ b
  52.     ADC_InitStructure.ADC_NbrOfConversion = 9;% x7 F9 O6 z+ T" T6 C& d: m8 ]
  53.     ADC_Init(ADC1, &ADC_InitStructure);
    1 ~9 j4 T- a) r% e6 c6 A4 p

  54. 0 j  m1 D8 o, D* X4 y* P

  55. $ m" Z9 z6 V: h9 z
  56.     ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);- k5 t% o) M; ~, |
  57.     ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_3Cycles);
    ' R2 Q. B) H% R! B; i# m
  58.     ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_3Cycles);6 T  ^" n: K$ s
  59.     ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 4, ADC_SampleTime_3Cycles);4 l, E2 o# X- i9 D1 m5 d+ i
  60.     ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 5, ADC_SampleTime_3Cycles);/ H& ?: S* x( P8 c9 I: a$ ^8 u
  61.     ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 6, ADC_SampleTime_3Cycles);7 Y7 B- O3 ^: ]
  62.     ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 7, ADC_SampleTime_3Cycles);
    : |1 [! N* _5 H- N6 m; B" X
  63.     ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 8, ADC_SampleTime_3Cycles);
    - G# \7 G" s0 R+ k; f; [
  64.     ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 9, ADC_SampleTime_3Cycles);" u# U0 v- ~  G9 E
  65. : {: C4 i! }+ h  T
  66.     ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);! N, f8 g( l4 r+ Z( G" v* p/ Q9 m
  67.     ADC_DMACmd(ADC1, ENABLE);' Y. z' K& |+ H9 U" k- ^2 A
  68.     ADC_Cmd(ADC1, ENABLE);) f) I+ J6 P- M4 a( z! G$ l' |6 w

  69. 3 D' M0 P* [1 l( w% r1 U, K0 M
  70. }
复制代码
7 H$ c. R- @# @* }2 M# m
  其中涉及adc的初始化结构体代码部分如下:' n$ ]7 g0 \( f) x  v& p
) A" f* ?: K' m* {1 }1 O' P
    ADC_InitTypeDef       ADC_InitStructure;; A/ y9 J: H- A2 Z
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    6 F! \1 D5 ?3 j, X& `, n5 Q/ i# J
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;
      I6 `1 P7 f# ]7 F/ ?
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;& s7 P6 J7 v+ Z, |/ @
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ; q/ l! @. R, f- a' q1 I
  5.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;; E  B. Y6 }$ t- t) v! [4 t$ `$ i, P3 H
  6.     ADC_InitStructure.ADC_NbrOfConversion = 9;5 J- S3 a" K# \! v" g% u4 u) [
  7.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  一步一步调式发现结构体有一项ADC_ExternalTrigConv是0x08002d54,这一项并没有初始化对其赋值,忘记给结构体的这一项赋值了。最后这个值通过ADC_Init函数赋值给CR2的时候,第11位(也就是数据对其位)是1了,左对齐了!!!!!
+ T  P1 H8 j6 y, P% t, ~
* |. Z' W+ S/ \: v
20180823193630758.png
9 q7 a7 _# k1 [% ~" ?2 ?7 _

1 x* p* I% B$ j$ `8 z6 E  下面来重点分析下adc初始化结构体中的各项参数的意义:
  u* B: B8 t1 @8 Z6 P) \  对于STM32,在使用ADC的时候需要配置几个参数。
7 u# @! z7 w* S% y; y9 D3 ~6 }$ {% L; D(1) 第一个参数是ADC_Mode,这里设置为独立模式:
3 {, W2 g) o7 _& i+ @
6 a  u7 E# S, ~; L! T
  1. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
复制代码

/ U: C4 ~! n$ T9 A在这个模式下,双ADC不能同步,每个ADC接口独立工作。所以如果不需要ADC同步或者只是用了一个ADC的时候,就应该设成独立模式了。4 z6 E8 U- s% ~9 L

9 _5 d! v" r+ l& {' O# {(2) 第二个参数是ADC_ScanConvMode,这里设置为DISABLE。' a2 S& x% r  y4 e. i, f! W
  1. ADC_InitStructure.ADC_ScanConvMode = ENABLE;
复制代码
) h3 h8 n! K" Y( q- L$ _3 B
如果只是用了一个通道的话,DISABLE就可以了,如果使用了多个通道的话,则必须将其设置为ENABLE。
. j# T: a' f$ w: f# f( O( ^. q+ r7 @- Y
(3) 第三个参数是ADC_ContinuousConvMode,这里设置为ENABLE,即连续转换。
4 G4 W. s8 y- i' V& t如果设置为DISABLE,则是单次转换。两者的区别在于连续转换直到所有的数据转换完成后才停止转换,而单次转换则只转换一次数据就停止,要再次触发转换才可以。所以如果需要一次性采集1024个数据或者更多,则采用连续转换。. ?1 H8 P% x7 Y' G! f" R# t  t4 d
" d$ Z; R- w3 x8 ?/ H
(4) 第四个参数是ADC_ExternalTrigConv,即选择外部触发模式。这里只讲三种:6 W3 W0 r. F6 U0 F7 `3 _$ o3 y
) {2 ~% c2 C) s5 p
1、第一种是最简单的软件触发,参数一般为ADC_ExternalTrigConv_None(注意STM32F2XX系列这个有点蹊跷,后面会讲这个)。设置好后还要记得调用库函数:
7 f0 Y2 b6 D$ o8 K2 q" J7 w( X) |3 q
  1. ADC_SoftwareStartConvCmd(ADC1, ENABLE);
复制代码
  1. void ADC_SoftwareStartConv(ADC_TypeDef* ADCx)
    + V; F" g1 i) ?4 I' I
  2. {
    / S7 G( s. U& ?! H
  3.   /* Check the parameters */
    - E9 {  w/ L7 f0 I: C" w
  4.   assert_param(IS_ADC_ALL_PERIPH(ADCx));1 s; G& f0 A2 [. y( Y; n

  5. % `* ]" o: @# g5 Z
  6.   /* Enable the selected ADC conversion for regular group */3 O2 [$ c& Y/ a7 J
  7.   ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;( s7 T9 t- K- k. ^3 N8 C: L
  8. }
复制代码
  1. #define  ADC_CR2_SWSTART                     ((uint32_t)0x40000000)      ! Y: q6 a  i! P4 y' O2 X/ }+ }
  2. /*!<Start Conversion of regular channels */
复制代码

- C! ?! ?6 Y4 ^  ?' c* _0 B# hADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位,这样触发就启动了。5 W3 |/ q; d, q
6 Z7 `6 \4 R: w. x4 z
2、第二种是定时器通道输出触发。共有这几种:ADC_ExternalTrigConv_T1_CC1、ADC_ExternalTrigConv_T1_CC2、ADC_ExternalTrigConv_T2_CC2、
8 V# H) y5 y5 a' @
/ ]! U) R+ g- i0 PADC_ExternalTrigConv_T3_T以及ADC_ExternalTrigConv_T4_CC4。定时器输出触发比较麻烦,还需要设置相应的定时器。以' N: c- _/ a0 P) W8 v# A
* x) G% r6 r+ ~: J, d
ADC_ExternalTrigConv_T2_CC2触发为例设置相应的定时器:
) G9 {) b: d! y* i# q) L! A) F+ ]; Q* k8 r) {0 x4 ~
  1. void TIM2_Configuration(void)
    / H' i$ M- o4 u6 w- ]/ i

  2. 1 v; y2 Z& T+ Z9 o
  3. {9 j* q5 B3 z3 X2 @' k' e' v7 N

  4. - @! ]! q* ?5 S+ T) a4 {) Y! h
  5. TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;
    7 |. q; g! q/ r  v: c2 k! j

  6. ; }% C/ w: v0 |+ W9 J  F
  7. TIM_OCInitTypeDef         TIM_OCInitStructure;
    0 ~& e. o( K6 t- D
  8. 2 b  q6 z' t- f0 y* j6 d
  9. TIM_TimeBaseStructure.TIM_Prescaler = 4;2 r- r# S  x! e
  10. # |  B* B9 B* O
  11. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;3 M( S! W$ G4 _0 p; w$ v
  12.   }( g" i. E: f# k; {0 L
  13. TIM_TimeBaseStructure.TIM_Period = 0XFF;: n5 z; s# U* h6 q
  14.   D. s, K9 o: X0 ]! W" `
  15. TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    9 k4 S. b  \2 t. k7 _# P2 W- A' `

  16. $ S: W2 O/ x! G, P: h( Y
  17. TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    " T6 ?$ w$ l) K+ C8 X* g

  18. 8 E+ l+ S* @* V/ r4 x+ _
  19. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);1 g; V, [' D* ~
  20. . R/ |) `; ?, V* M% Q* W
  21. ) e$ @1 M& r, i+ E2 a; W
  22. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;7 d8 C7 {" a# s3 q) ]3 ]

  23. 9 K. a4 ?8 ]! s- O4 J- G
  24. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    , [! I4 @$ {/ ~% A; k  l) Z! q
  25. $ H+ U8 H" l( \; Z
  26. TIM_OCInitStructure.TIM_Pulse = 0X7F;1 e" t6 H0 \! {8 O* N  D' I) M
  27. & A) p; {$ y0 G  ~7 z7 T
  28. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;! T3 D7 w' {& E5 ]

  29. # B( T5 S, h# v1 y  e
  30. TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;        6 c9 R) [4 g2 _& B5 U
  31. . a- N4 w" ~" }; W7 N
  32. //配置CC2的属性。若CC3作为ADC的触发源,则应改为TIM_OC3Init(TIM2, &TIM_OCInitStructure);
    / D( H0 T. a, e

  33. / i/ W# E  K( }2 q9 |
  34. TIM_OC2Init(TIM2, &TIM_OCInitStructure);
    4 j1 T- f+ S8 x7 b( H3 K" _

  35. 4 U+ y0 {+ J/ W6 V
  36. TIM_Cmd(TIM2, ENABLE);
    * d# @- y1 P0 o# M$ |+ j5 d0 s
  37. TIM_CtrlPWMOutputs(TIM2, ENABLE);
    8 d( n9 S% a5 p/ @" h7 M& W3 T
  38. }
复制代码

4 I  B1 i. O% r
4 k8 ?4 f4 h' A3 {1 M/ ]* M这样设置之后就可以用定时器2的输出触发了,至于触发的周期,设置TIM2的时间即可。这里不再赘述。
0 I% Z! X1 ~1 o; A0 F! d2 B* l- g$ `) ~8 ?4 \
3、第三种是外部引脚触发,对于规则通道,选择EXTI线11和TIM8_TRGO作为外部触发事件;而注入通道组则选择EXTI线15和TIM8_CC4作为外部触发事件。
' E6 W3 O3 e+ X9 w* E# q( Y2 R: |
(5) 第五个参数是ADC_DataAlign,这里设置为ADC_DataAlign_Right右对齐方式。建议采用右对齐方式,因为这样处理数据会比较方便。当然如果要从高位开始传输数据,那么采用左对齐优势就明显了。
; p0 F2 M( I& s5 h/ \4 R1 x3 A) o, F
(6) 第六个参数是ADC_NbrOfChannel,顾名思义:通道的数量。要是到多个通道采集数据的话就得设置一下这个参数。此外在规则通道组的配置函数中也许将各个通道的顺序定义一下,如:4 L2 {6 W0 F" g. ^
  1.       ADC_RegularChannelConfig(ADC1,ADC_Channel_13,1,ADC_SampleTime_13Cycles5);+ e) p6 S% ?- W6 A

  2. ! `3 w# Z1 I  k
  3.       ADC_RegularChannelConfig(ADC1,ADC_Channel_14,2,ADC_SampleTime_13Cycles5);
复制代码
( o$ `6 Y4 W8 |0 A# j( }5 C

* i$ B% o3 G$ A# S2 T  多通道数据传输时有一点还要注意:若一个数组为ADC_ValueTab[4],且设置了两个通道:通道1和通道2,则转换结束后,ADC_ValueTab[0]和ADC_ValueTab[2]存储的是通道1的数据,而ADC_ValueTab[1]和ADC_ValueTab[3]存储的是通道2的数据。如果数组容量大则依次类推。+ I  C3 j* y# T( y% ~

3 S; W; L7 z& ~0 f) F  补充一点:在使用DMA传输数据的时候,需要设置外设地址和存储器地址,外设地址当然就是ADC的地址了,而存储器的地址如果使用8位数据的话,存储器必须定义为8位缓冲区;如果使用16位数据格式的话,存储器则为16位缓冲器,不可定义为32位或更多,否则,数据将出错。9 r# F% z' d% ?4 P& Z7 q- a

; \& d& a6 T" x- K( z问题的解决方法
* J" `1 Q+ A6 V- V" m- Z
  上面分析了adc结构体的参数,下面再来单独看看ADC_ExternalTrigConv这一项。
. d" Q* i0 d: x4 Z0 |' C  在stm32f2xx_adc.h文件中有这个成员的参数定义,发现里面并没有ADC_ExternalTrigConv_None这个常见的定义。+ v" b8 h7 a3 W" K- A, |2 X
5 H$ U0 T9 F# a6 [1 r  n
  1. /** @defgroup ADC_extrenal_trigger_sources_for_regular_channels_conversion ) H. r+ Y. m: u# _  B/ `: L. p9 i; }
  2.   * @{
    # d6 j9 ^# V: @; _% c- k
  3.   */ " f- r5 W4 D! f- w# U: B$ y
  4. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000)
      g$ z  ?- x8 z" d+ V0 ~" p
  5. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x01000000)) C, V/ S% ?& C8 c
  6. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x02000000)
    # a0 ^, v- t% N+ D
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x03000000); z8 I! S4 o1 ^5 h. h6 x+ S
  8. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x04000000)
    6 {) d3 Z& h4 w8 m. a8 x$ ~
  9. #define ADC_ExternalTrigConv_T2_CC4                ((uint32_t)0x05000000)
    0 J- M' v' e7 {9 {4 E# ~3 i
  10. #define ADC_ExternalTrigConv_T2_TRGO               ((uint32_t)0x06000000)
    " r7 z" V( }' a  E  c* F9 m  v
  11. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x07000000)# |+ O4 d# Y2 r) ]7 M* n
  12. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x08000000)
    " v& i! X5 Z& r# ^6 X3 ^" o) u
  13. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x09000000)
    $ a2 h$ o2 t  F
  14. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x0A000000)0 h# f/ n0 i, Z  ^& Z3 V8 d8 V
  15. #define ADC_ExternalTrigConv_T5_CC2                ((uint32_t)0x0B000000)
    / ~# J1 K: Z+ q; T) p
  16. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x0C000000)
    8 B% A% M9 u8 V3 v
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x0D000000)4 F2 e& x( J2 M. R
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x0E000000)
    0 |; X' e% J* A" Q
  19. #define ADC_ExternalTrigConv_Ext_IT11              ((uint32_t)0x0F000000)
复制代码
9 x% \- E, Q9 x2 C9 n3 M; x
  再来看看stm32f10x_adc.h文件中的ADC_ExternalTrigConv的参数定义:
  ]2 E) @0 K. B# t/ T
  1. /** @defgroup ADC_external_trigger_sources_for_regular_channels_conversion
    ' R9 `# g! d5 ]6 _# y
  2.   * @{  e7 a) b  \% ]- ?/ p3 [
  3.   */
    ; j- O& p; `3 h9 ?: O4 l- \  }% J" V
  4. , [3 p8 ]* u  @, [; A
  5. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */! A( J$ o; H' W1 V: [2 v
  6. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */) H, A9 t% S2 }& @+ f3 h7 c1 R
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */1 ?0 u2 R. K4 B; [2 O+ p. i) z, B
  8. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x00080000) /*!< For ADC1 and ADC2 */$ O, t2 N3 H' B9 p3 X/ I
  9. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x000A0000) /*!< For ADC1 and ADC2 */
    " d# f) O5 i% U9 t8 N
  10. #define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO    ((uint32_t)0x000C0000) /*!< For ADC1 and ADC2 */
    ' F; {5 j3 P7 P! @4 p6 G
  11. 7 ]9 Z0 @( F# D
  12. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x00040000) /*!< For ADC1, ADC2 and ADC3 */9 P1 n2 x! T' ?( B' y
  13. #define ADC_ExternalTrigConv_None                  ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */   //f2xx系列并没有这个定义
    , B. ?6 p# x: q4 P# o& W
  14. , c- [1 g: l2 w" ]
  15. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x00000000) /*!< For ADC3 only */
    * Q, Y+ |& k: J; l3 O8 k0 Y; n
  16. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x00020000) /*!< For ADC3 only */) D# l* i' u9 _4 X& c+ o
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x00060000) /*!< For ADC3 only */
    * G+ S) K2 Y7 L
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x00080000) /*!< For ADC3 only */' V, J  O" \: O* _0 T9 d# h
  19. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x000A0000) /*!< For ADC3 only */
    0 H4 g1 D; f4 c  `  M- ]" c
  20. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x000C0000) /*!< For ADC3 only */
复制代码

7 q) i$ Z3 B/ L6 G: Q  对比发现stm32f2xx系列并没有ADC_ExternalTrigConv_None这个定义,很是奇怪,现在还不明白ST的工程师为什么做这个变动。! V# r% ~; Y0 L4 r
  那么问题怎么解决呢?: F) N  w/ s! z) k4 z. h
  一种是进行adc结构体的初始化操作,在配置之前恢复默认值。即调用ADC_StructInit(&ADC_InitStructure);修改如下:
  1.     ADC_StructInit(&ADC_InitStructure);//新增加的' @+ I8 m7 D* l1 S2 [5 c
  2.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ; o- t0 n; N- @# [4 x
  3.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;$ P7 j: T) ]! o
  4.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    2 D: D  {/ S# [- N: A
  5.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;) G- l2 J! m# H, {# W8 I
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    6 r; S! u' o5 O& J
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;* ?1 k4 @2 Z4 r# |$ G
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  调用ADC_StructInit(&ADC_InitStructure)语句,ADC_ExternalTrigConv会恢复默认值0。如下:  y& _! B! S; i+ c2 ]4 v/ I: B
2 p9 }3 i* b5 H) |
20180823201211262.png

" {) E) w. v5 t; r( w/ L: y! W+ X$ G# i5 q) u8 ~
  另一种方法是直接配置该参数为0,如下:
2 s$ t( w$ O3 @# b: _# j
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    : i5 D4 `3 M4 S+ b0 a
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    & Q6 I# {  S6 n% w1 R7 Y: B# O
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    , [' j6 ^  A  y/ G2 @
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;; o, r/ S- F1 x2 j- X" t) j
  5.     ADC_InitStructure.ADC_ExternalTrigConv= 0;//新增加的' B4 i8 P# B* T$ L3 l$ U" g% V
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    , K1 Y* v# }& l9 e2 g5 e
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;, C9 ^* D! G, [( _( [$ X5 z
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码

" ^  z& @7 F4 ]  这两种方法都可以解决adc采样对齐方式异常问题。% [& N3 g( Z8 M. D
  但是ADC_ExternalTrigConv= 0在stm32f2xx_adc.h中其实是对应ADC_ExternalTrigConv_T1_CC1的。
/ E& y( m$ o1 v  v* L5 i$ p% d$ S1 }% E, g6 e- h8 T0 n4 O
20180823201832969.png
) b, Q' y  G8 k$ ]% {& h
; T  T$ w% u# ~0 B
  也就是说调用软件触发函数ADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位也可以触发定时器触发方式的adc通道。8 G1 v: j0 F- a' |" b

' T/ J: M( b) s* a6 `' O( L% J
' D: E% e8 c- X. _0 W+ `  c4 a: i8 v+ m8 h8 [+ R/ R4 W1 v  z1 R; f
收藏 评论0 发布时间:2021-12-2 16:03

举报

0个回答

所属标签

相似技术帖

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