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

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

[复制链接]
STMCU小助手 发布时间:2021-12-2 16:03
前言' ]8 P5 Y1 x2 G
  最近在调试STM32F2XX系列ADC多通道DMA采集时,发现采集的AD值大于4095,有的65000多了,这是什么节奏?adc不是12位吗,最大才0xfff,即4095,怎么会出现这种情况呢?难到是adc数据对齐方式出现问题了,adc的对齐明明设置的是右对齐啊,神马情况?
1 m- L6 d0 o4 @" C
/ v! E8 b4 c, oADC结构体参数分析
: S) x+ y9 h* j- s% h
  百思不得adc之姐,只能keil单步调试,一步一步查看adc结构体的参数。我使用的是adc dma方式采集,共9个通道。初始化程序如下:- b. {- Y9 z8 a4 J# d4 L% ^! B/ r/ f
  1. void ADC_DMA_Config(void)
    $ T- J5 h" w/ E2 [; _
  2. {# |0 S  V- o* ~2 ]( h5 C# S' S
  3.     ADC_InitTypeDef       ADC_InitStructure;. s" [" }6 t7 K/ e6 M6 n
  4.     ADC_CommonInitTypeDef ADC_CommonInitStructure;
    " p/ Y' g- C/ y6 \$ }( \
  5.     DMA_InitTypeDef       DMA_InitStructure;& |$ Y5 |* n2 T$ C5 g) t* D
  6.     GPIO_InitTypeDef      GPIO_InitStructure;1 U, ^, G3 h/ l6 B

  7. ! E% s* D3 M, S/ ^3 U* H7 l
  8.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);
    " g' c1 ~1 s4 p/ v9 }
  9.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);& O0 t! G6 P: A( A9 T0 p/ ?2 u
  10. ' ]2 u; M; s+ b: c" S" h5 A8 x& p
  11.     DMA_InitStructure.DMA_Channel = DMA_Channel_0;  
    ) j4 G* [9 X% A0 E! m2 s5 p
  12.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    1 {( ~3 y: Z& |0 p0 u
  13.     DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_ConvertedValue;  , n+ b6 g# m4 r- f9 }
  14.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;! a% q6 B  Q' X/ V0 U
  15.     DMA_InitStructure.DMA_BufferSize = Sample_Num*Channel_Num;         
    * Q/ t3 `8 c+ j0 k
  16.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;6 ~+ [5 S% {  A, {0 C- I9 Z4 k0 y
  17.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    * R3 t8 W: W0 N# r2 {1 ]- B
  18.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  w+ J' x! `' C  @: F
  19.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;$ c: S" v8 p% A1 j. [  R, i% V5 r7 V
  20.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    ( G+ V! w. K2 o5 r0 r+ ]: \
  21.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;. \4 a  \) ^# E5 [; b
  22.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         7 `- R8 Q' \9 I9 m
  23.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    0 J; O4 p1 C: L/ G! R* g
  24.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;9 `1 l, `  N* }2 q
  25.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    * O, I- [, [1 e" T
  26.     DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    7 [! W, s4 w% K% I' I* Q
  27.     DMA_Cmd(DMA2_Stream0, ENABLE);
    4 V3 G+ r, X0 ]' r/ A0 w
  28. . v0 Q' V( B( h; T# u5 b% e/ I

  29. 9 y, ^' c7 e0 b- U- z  V
  30.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 |GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
    , {. l" F/ O( \1 E
  31.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;& h/ L' J3 O2 G: r
  32.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    % H$ e, ?# E4 d5 `
  33.     GPIO_Init(GPIOA, &GPIO_InitStructure);2 q4 [# Q. E  l9 x/ ?
  34. 8 `9 V0 Z! o4 O2 V8 i/ S# R
  35.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5;3 T1 |, H- g) J& y
  36.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;7 e# R/ S* D; M% i% l
  37.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;$ H+ Q. {$ V, D4 K* D4 d2 Y
  38.     GPIO_Init(GPIOC, &GPIO_InitStructure);; `9 @: ~) w: K( X  u4 u" g

  39. / B! h/ M9 M1 t/ E  ^, i
  40.     /* ADC Common Init **********************************************************/
    " \; G6 v2 a. L" C  a1 a
  41.     ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
    / \' Q& r4 ^$ o1 u8 ?$ d
  42.     ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;! ?5 n; O3 W( U2 c$ ^- h
  43.     ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;) s* l% z3 W) `" m0 _0 Z7 }+ X
  44.     ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;0 y, u3 U/ `; G! d; C' }; u. y1 N
  45.     ADC_CommonInit(&ADC_CommonInitStructure);' ~/ `& t" \& Y* W( v2 ~2 V
  46.   B- q3 w0 [; r( Z) [# I
  47.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    , {* @, l3 v8 e: e# t
  48.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;$ o$ p. I% R* @, \; z# K* @# `
  49.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ! h8 h2 Z( _- b9 ^& i
  50.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;' O* e" S' n6 r0 L2 _
  51.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;3 b; I5 j6 i9 o% o
  52.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    $ l! O# m+ n- U, i' F$ d
  53.     ADC_Init(ADC1, &ADC_InitStructure);" c% B+ w( }2 I5 m/ b
  54. % U1 U3 o1 j) K5 M

  55. 6 ^4 h; ?3 }; v# |
  56.     ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);3 H, I' U! k' [# j& R1 n1 \! i
  57.     ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_3Cycles);3 c3 T$ y; E: g8 ]
  58.     ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_3Cycles);
    7 O- J5 I5 S" z
  59.     ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 4, ADC_SampleTime_3Cycles);! [# k- V9 J1 K5 _/ d
  60.     ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 5, ADC_SampleTime_3Cycles);: V  M1 I( k, m; P' T. s
  61.     ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 6, ADC_SampleTime_3Cycles);
    8 m! ]! Z3 ]$ n: q  h$ P' F! p4 m
  62.     ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 7, ADC_SampleTime_3Cycles);- S! O$ k! T( @  C
  63.     ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 8, ADC_SampleTime_3Cycles);
    1 H( C$ y8 t6 M1 j  N
  64.     ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 9, ADC_SampleTime_3Cycles);
    : G: _0 K: z! M7 L- }& z, D

  65. ) X1 Y$ a7 `2 }6 ], q4 }
  66.     ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);2 @8 S' ]' P3 I5 r- a$ P
  67.     ADC_DMACmd(ADC1, ENABLE);
    7 q! H$ \$ Y2 C' z* P
  68.     ADC_Cmd(ADC1, ENABLE);" @  G. j- c* e1 j; l0 J) P$ ?
  69. ! W; L, c  q/ E4 P
  70. }
复制代码
  o0 s1 O1 K$ B: s& U' k: k& P
  其中涉及adc的初始化结构体代码部分如下:
' ?  R# l0 O. N2 P( t
' R- V% r" Q6 W& ^9 w/ k    ADC_InitTypeDef       ADC_InitStructure;
% z& Z5 F; [* I! V# ]
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;+ V# x$ l1 j" L+ p* j6 l
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    8 c  ?* j7 l9 m! P% |  G6 ^" k
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;& R' q- T. s" j& K/ h1 |9 Z0 |
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;" d7 [  s' |" ?
  5.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    9 }3 A4 h+ {; |8 D
  6.     ADC_InitStructure.ADC_NbrOfConversion = 9;9 |6 \, N$ Q5 e
  7.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  一步一步调式发现结构体有一项ADC_ExternalTrigConv是0x08002d54,这一项并没有初始化对其赋值,忘记给结构体的这一项赋值了。最后这个值通过ADC_Init函数赋值给CR2的时候,第11位(也就是数据对其位)是1了,左对齐了!!!!!+ E# G; `' g8 x/ t
# v- @" H6 x) _' R* O4 R7 h
20180823193630758.png

" v7 x# n& F; c( b. j
- ?; d% u; k' A% r1 }& q) v  下面来重点分析下adc初始化结构体中的各项参数的意义:, S* a- H2 f  S1 _4 `1 Q  G  S
  对于STM32,在使用ADC的时候需要配置几个参数。; Q; X9 X  V4 d* z9 W9 ]; K; y
(1) 第一个参数是ADC_Mode,这里设置为独立模式:
# c  i$ ]& m2 {+ i7 W, W, S4 _% a# g
  1. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
复制代码

  [3 l( q/ I1 x3 h2 B. G1 V2 o: b0 n在这个模式下,双ADC不能同步,每个ADC接口独立工作。所以如果不需要ADC同步或者只是用了一个ADC的时候,就应该设成独立模式了。- f  P- ]) F4 k  `8 Z- a4 y

' @- x" |4 ]. y(2) 第二个参数是ADC_ScanConvMode,这里设置为DISABLE。
; v% L- n* }1 l6 y
  1. ADC_InitStructure.ADC_ScanConvMode = ENABLE;
复制代码

! F) {, M3 I! v" A* k如果只是用了一个通道的话,DISABLE就可以了,如果使用了多个通道的话,则必须将其设置为ENABLE。; J8 J# T- t3 N+ C
! W- W- _+ _6 q* i
(3) 第三个参数是ADC_ContinuousConvMode,这里设置为ENABLE,即连续转换。8 x3 b% Z  G: }. j  B5 Q; M
如果设置为DISABLE,则是单次转换。两者的区别在于连续转换直到所有的数据转换完成后才停止转换,而单次转换则只转换一次数据就停止,要再次触发转换才可以。所以如果需要一次性采集1024个数据或者更多,则采用连续转换。: N( M$ `0 d4 D; [  _

: l2 [2 r. P, A7 f% h0 u8 ^( m(4) 第四个参数是ADC_ExternalTrigConv,即选择外部触发模式。这里只讲三种:5 q- |) g5 K! S5 U. K

- V) \' ^6 W! I/ S5 i1、第一种是最简单的软件触发,参数一般为ADC_ExternalTrigConv_None(注意STM32F2XX系列这个有点蹊跷,后面会讲这个)。设置好后还要记得调用库函数:
7 ^# ~1 ?" h/ N+ h: S) t
  1. ADC_SoftwareStartConvCmd(ADC1, ENABLE);
复制代码
  1. void ADC_SoftwareStartConv(ADC_TypeDef* ADCx)7 q3 M! Z+ n: b  J# e% U, l- X
  2. {
    3 K! l4 j( [" H- _3 U4 x& E
  3.   /* Check the parameters */$ G# Z7 v4 B( j' O
  4.   assert_param(IS_ADC_ALL_PERIPH(ADCx));. W' C  o4 c9 `6 l+ c+ B- H- }+ R
  5. % e, d( _& C9 G  Y
  6.   /* Enable the selected ADC conversion for regular group */( |6 j% o. [2 o; X# ]2 S" e
  7.   ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
    - j+ C0 q) z- W( b/ H9 q$ e
  8. }
复制代码
  1. #define  ADC_CR2_SWSTART                     ((uint32_t)0x40000000)      - Z$ G. p- d  d
  2. /*!<Start Conversion of regular channels */
复制代码

* E" W# C/ Z- I2 `  l  D# fADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位,这样触发就启动了。
% }3 [. m5 ~% T2 \$ m8 m+ O5 l& r) o- \: K% p) a" U2 _" ]4 j
2、第二种是定时器通道输出触发。共有这几种:ADC_ExternalTrigConv_T1_CC1、ADC_ExternalTrigConv_T1_CC2、ADC_ExternalTrigConv_T2_CC2、+ o8 e7 g+ @. |3 ]% B; j! E3 {" ]0 t

$ J$ A3 \+ l1 N; AADC_ExternalTrigConv_T3_T以及ADC_ExternalTrigConv_T4_CC4。定时器输出触发比较麻烦,还需要设置相应的定时器。以
4 ^/ ?! S+ {  W2 N' K  n7 s' o. x$ n  b% e8 t- ~1 t0 L2 \; V
ADC_ExternalTrigConv_T2_CC2触发为例设置相应的定时器:) Q8 ]* j( S+ }3 Y8 r

- N5 N' \0 k+ n5 ]
  1. void TIM2_Configuration(void)$ `; z7 _1 P6 Z$ ]3 u) T

  2. 5 [* x% W. }. @; B$ D# ]
  3. {- X% T1 I  K' R

  4. , {, M: ~( m% m
  5. TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;* C$ I! R) c' S& c' Z

  6. 2 D% {3 V' B/ F; H" B2 b; V
  7. TIM_OCInitTypeDef         TIM_OCInitStructure;
      i/ P( u6 N& s( k

  8. 0 t" k# f0 l2 z3 a9 F
  9. TIM_TimeBaseStructure.TIM_Prescaler = 4;- k! g  ?& B) |4 K- m6 ?

  10. % L) Y+ f; W$ c, v8 j& s
  11. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;5 H* _0 _+ Q, ?/ W1 |1 u
  12. & W5 h- D  w. r
  13. TIM_TimeBaseStructure.TIM_Period = 0XFF;9 n: Y  X: M, g) }8 w
  14. ! a. _* b  }- ]& O0 A- A  Y3 m
  15. TIM_TimeBaseStructure.TIM_ClockDivision = 0;, `: K! a: H3 f  a

  16. - h8 S6 j% p$ C1 a
  17. TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;+ d/ C7 k- O) A
  18. # R( t3 X5 ^' U
  19. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);6 V% x- J& Y# \- t/ Q" f- }$ ^! y! F

  20. 3 T6 @: j3 C) L* Y% h+ F$ g. C
  21. + ~# F' t: o1 |
  22. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    5 Q3 N* ^% z% g9 [
  23. : B& q) m( K! y4 `2 L8 d
  24. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    ) A& v; I7 G1 C& P: t8 ?) {1 Y8 A/ P

  25. 8 K) C1 j8 j" f
  26. TIM_OCInitStructure.TIM_Pulse = 0X7F;
    * U: ]5 i# z7 b* j

  27. . d5 f/ [& c( w  E
  28. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    - u' [+ f6 c0 w

  29. " ~# [' B: R8 @+ W( a- g7 Y. K$ }2 u
  30. TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;        
    9 H4 N( N, F3 M- k' d- D, B

  31. 2 B% @! H, P$ J
  32. //配置CC2的属性。若CC3作为ADC的触发源,则应改为TIM_OC3Init(TIM2, &TIM_OCInitStructure);
    2 z1 z  `5 P6 h2 t
  33. 7 e& E( l) `) e$ ^8 H  m, i& _
  34. TIM_OC2Init(TIM2, &TIM_OCInitStructure);
    ' m4 J9 d8 A# h. \, e! ?3 v6 _
  35. : M, i8 _3 |! x/ m3 o
  36. TIM_Cmd(TIM2, ENABLE);! e4 t. \! ^/ F. _
  37. TIM_CtrlPWMOutputs(TIM2, ENABLE);: ~  Z5 a/ b1 @+ h
  38. }
复制代码
: E4 F6 L, n$ h4 ?% s
# X2 r  J/ A: K
这样设置之后就可以用定时器2的输出触发了,至于触发的周期,设置TIM2的时间即可。这里不再赘述。( n; G- P$ @" ?% I) r7 u" J

- }! R, R( }& ?1 y: A) l$ X) @3 d3、第三种是外部引脚触发,对于规则通道,选择EXTI线11和TIM8_TRGO作为外部触发事件;而注入通道组则选择EXTI线15和TIM8_CC4作为外部触发事件。" q, ]2 d$ b& m9 \
( g, e, q" I0 D# ^! }+ K
(5) 第五个参数是ADC_DataAlign,这里设置为ADC_DataAlign_Right右对齐方式。建议采用右对齐方式,因为这样处理数据会比较方便。当然如果要从高位开始传输数据,那么采用左对齐优势就明显了。
! P$ T9 F& s0 K5 ?, e$ Z+ b- `8 \9 K! \# H9 L$ q6 \
(6) 第六个参数是ADC_NbrOfChannel,顾名思义:通道的数量。要是到多个通道采集数据的话就得设置一下这个参数。此外在规则通道组的配置函数中也许将各个通道的顺序定义一下,如:
( Z; \0 I. Q1 |& V
  1.       ADC_RegularChannelConfig(ADC1,ADC_Channel_13,1,ADC_SampleTime_13Cycles5);1 q) ~2 j3 {# M  {

  2. ) |6 r0 ^& _' Y9 t( o' H
  3.       ADC_RegularChannelConfig(ADC1,ADC_Channel_14,2,ADC_SampleTime_13Cycles5);
复制代码
* \( Y8 v9 }' P8 O' G; d. ^/ ~
* J6 s% M& u8 D7 B
  多通道数据传输时有一点还要注意:若一个数组为ADC_ValueTab[4],且设置了两个通道:通道1和通道2,则转换结束后,ADC_ValueTab[0]和ADC_ValueTab[2]存储的是通道1的数据,而ADC_ValueTab[1]和ADC_ValueTab[3]存储的是通道2的数据。如果数组容量大则依次类推。
1 F' M, d, K2 [  j7 l4 s% y) G+ [' l  l% V' j( m- b! Q* A
  补充一点:在使用DMA传输数据的时候,需要设置外设地址和存储器地址,外设地址当然就是ADC的地址了,而存储器的地址如果使用8位数据的话,存储器必须定义为8位缓冲区;如果使用16位数据格式的话,存储器则为16位缓冲器,不可定义为32位或更多,否则,数据将出错。3 F/ o! D9 Q2 x# `8 ^1 J

4 Y7 `8 W2 i6 ?1 B1 C. H/ z问题的解决方法

" p* G! v+ H9 V/ a* C; @! ^  上面分析了adc结构体的参数,下面再来单独看看ADC_ExternalTrigConv这一项。
3 S: Q/ V# X. Q  在stm32f2xx_adc.h文件中有这个成员的参数定义,发现里面并没有ADC_ExternalTrigConv_None这个常见的定义。% D4 l$ d8 |! q8 o

  ~: @, R; m- h5 g+ z$ L" ?3 h5 g
  1. /** @defgroup ADC_extrenal_trigger_sources_for_regular_channels_conversion
    ( ~, {' J2 s$ f* Z
  2.   * @{6 \4 d$ x+ k7 \0 g( ~) D7 J7 w+ q
  3.   */ 5 i7 H% R" @; L
  4. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000)
    6 l1 z/ M2 R: Y* L% J
  5. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x01000000)
    . r  o4 _) o4 M- `) y
  6. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x02000000)
    . o% a: D+ j8 }8 I- T& p
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x03000000)
    & C4 F" k% @- ]/ z' v! y
  8. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x04000000), Q: v9 N- J$ o/ s
  9. #define ADC_ExternalTrigConv_T2_CC4                ((uint32_t)0x05000000), u9 [$ V6 \# z/ e. \; u3 y+ A" V) {
  10. #define ADC_ExternalTrigConv_T2_TRGO               ((uint32_t)0x06000000)' W3 ^, p& H# U% |0 P* B8 u  k
  11. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x07000000)# |  P' e% ~6 O# W( Z% d$ z  J
  12. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x08000000). `5 G6 W5 e3 F3 M4 D7 }
  13. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x09000000)
    . s& h( X' a0 Y. L; R- c, t
  14. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x0A000000)
    ! r+ ~! ~8 j7 F) y& M0 j
  15. #define ADC_ExternalTrigConv_T5_CC2                ((uint32_t)0x0B000000)+ ?# ^* Q! a* Y9 J5 O% d4 R; [
  16. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x0C000000)2 p! g# j! z. a& ^
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x0D000000)! I# ?- j; l8 V! x. A
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x0E000000)
    " {! E  j+ v* l
  19. #define ADC_ExternalTrigConv_Ext_IT11              ((uint32_t)0x0F000000)
复制代码

" i6 J+ Y4 v6 E1 B! _5 o& O: K  再来看看stm32f10x_adc.h文件中的ADC_ExternalTrigConv的参数定义:8 ^, y5 I" r" i" H! V! d. d
  1. /** @defgroup ADC_external_trigger_sources_for_regular_channels_conversion
    % }$ Y0 J5 M8 i; [* ]9 m
  2.   * @{- F+ K. Q4 O# B6 @$ ~5 Q* v  I
  3.   */8 q$ K5 s1 T# Z9 ?! V2 |$ y
  4. 7 }$ u+ k3 \2 N9 v: r& @; {
  5. #define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */, P, `- h" }7 a
  6. #define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */
    - d# O9 \- j. F" a
  7. #define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */
    / d9 I3 u9 n' w- Q7 A' k( k  [+ J9 s
  8. #define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x00080000) /*!< For ADC1 and ADC2 */
    ; X; M- R+ W4 `7 E9 r& ^% s4 W
  9. #define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x000A0000) /*!< For ADC1 and ADC2 */
    ! A. w$ M$ m0 R2 l
  10. #define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO    ((uint32_t)0x000C0000) /*!< For ADC1 and ADC2 */
    8 ~9 _) N" F5 _1 {" c& ?  E4 _" ^
  11. 0 D  y/ i9 }. s, \, G  r; V( z! r
  12. #define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x00040000) /*!< For ADC1, ADC2 and ADC3 */
    : |$ \, j3 q; y0 s' O! _
  13. #define ADC_ExternalTrigConv_None                  ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */   //f2xx系列并没有这个定义
    1 w* S' I. O$ P" w- H& w+ e, G

  14. 4 D8 `+ S( A7 M3 M7 ]' y( o
  15. #define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x00000000) /*!< For ADC3 only */
    # C+ E6 B) U2 Q; Q( X* Z
  16. #define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x00020000) /*!< For ADC3 only */$ D" |" Z6 Q4 g; `1 S4 ?
  17. #define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x00060000) /*!< For ADC3 only */
    9 U) Y% @/ _; }/ ?/ F; W' c
  18. #define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x00080000) /*!< For ADC3 only */- x, V: ^$ R' ^9 |6 O: k
  19. #define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x000A0000) /*!< For ADC3 only */6 d, p: |/ X0 E. G: ^$ f" M
  20. #define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x000C0000) /*!< For ADC3 only */
复制代码
0 e  m- J/ `. ^# c7 j9 D
  对比发现stm32f2xx系列并没有ADC_ExternalTrigConv_None这个定义,很是奇怪,现在还不明白ST的工程师为什么做这个变动。' ]% B- _3 L% B& F
  那么问题怎么解决呢?
+ u+ _7 Z, E" F  一种是进行adc结构体的初始化操作,在配置之前恢复默认值。即调用ADC_StructInit(&ADC_InitStructure);修改如下:
  1.     ADC_StructInit(&ADC_InitStructure);//新增加的7 X- ]0 f: ]  S$ Y- Q
  2.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;9 y. y; H6 V3 y' ~% z+ L& m
  3.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    " P. f- @/ B! h0 c, Q
  4.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    & d& j$ L1 v0 r) ]9 X. E, W
  5.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;& S: X& h, v( ?6 p1 [9 w3 U; @
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ( w# t, Z! S) i9 z
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    6 o* L8 B+ L; A
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
  调用ADC_StructInit(&ADC_InitStructure)语句,ADC_ExternalTrigConv会恢复默认值0。如下:! g. k7 g4 T* y4 Y

% G" E7 S$ m% m
20180823201211262.png
; R9 K. X) k  j% U  G

& ~5 I" z8 A* N" P# U9 F' x  另一种方法是直接配置该参数为0,如下:  r  f5 k" Z8 J9 \0 k/ G
  1.     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    , W6 g6 N; b6 x5 R
  2.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;, a0 l$ h' T) d( N# w! ]" e. a
  3.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;: P& C" B, x9 h/ a' U
  4.     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    3 b' G" Q. c  q& ], w: c
  5.     ADC_InitStructure.ADC_ExternalTrigConv= 0;//新增加的5 r7 l! h4 w- G8 W1 t% W
  6.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ) C1 s( ]' a9 R; l1 f2 W8 k8 L
  7.     ADC_InitStructure.ADC_NbrOfConversion = 9;
    / i! B( ^) N' a- X1 `- t4 N
  8.     ADC_Init(ADC1, &ADC_InitStructure);
复制代码
) s2 F$ e7 |% Z3 c
  这两种方法都可以解决adc采样对齐方式异常问题。/ x+ A% l$ p) a3 P8 [: s
  但是ADC_ExternalTrigConv= 0在stm32f2xx_adc.h中其实是对应ADC_ExternalTrigConv_T1_CC1的。* x1 g; N6 S! `5 R  ^, q

, X- r1 A7 ]3 N7 x' q* @
20180823201832969.png
. H. l% D1 x( {9 B3 p+ P- V' m8 y

6 P1 G' |7 F1 I5 `7 k  也就是说调用软件触发函数ADC_SoftwareStartConv函数里直接置位CR2的ADC_CR2_SWSTART位也可以触发定时器触发方式的adc通道。  I3 K9 O: X5 |/ E2 Y. I. y

; t) Y1 A% z( C/ o% O3 b: x: |2 Z
: @, J+ D) P3 T5 K1 @" m
收藏 评论0 发布时间:2021-12-2 16:03

举报

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