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

【经验分享】STM32开发项目:片上ADC的使用介绍与扩展库

[复制链接]
STMCU小助手 发布时间:2022-4-13 17:00
片上ADC介绍
, P! ^" J3 P+ _1 zSTM32F103系列与STM32F407系列ADC的功能类似。它们总共有 3 个 ADC,精度为 12 位,每个ADC 有 16 个外部通道。另外还有两个内部 ADC 源和 VBAT通道挂在 ADC1 上。ADC 具有独立模式、双重模式和三重模式,对于不同 AD 转换要求几乎都有合适的模式可选。3 {6 S8 w4 D1 H: _- |/ t

  X1 y- d8 \1 z) o0 F! _, y电压输入范围
0 u: Y) E; @* A" P4 u) N" [" ?ADC 输入范围为:VREF- ≤ VIN ≤ VREF+。由 VREF-、VREF+ 、VDDA 、VSSA、这四个外部引脚决定。在设计原理图的时候一般把 VSSA和 VREF-接地,把 VREF+和 VDDA 接 3V3,得到ADC 的输入电压范围为:0~3.3V。: e- \  ^  T) ^' y1 w
输入通道( N4 P* l* q% |& o3 n6 _3 x
STM32 的 ADC 多达 19 个通道,其中外部的 16 个通道就是框图中的 ADCx_IN0、ADCx_IN1…ADCx_IN5。这 16 个通道对应着不同的 IO 口。" C) }" ~& m$ s" e- {

9 z% ], b( I0 T* T; T4 p1 [& q对STM32F103系列单片机,ADC1的通道16连接到芯片内部的温度传感器,通道17连接到了内部参考电压 Vrefint。ADC2 的模拟通道 16 和 17 连接到了内部的 VSS。ADC3 的模拟通道 9、14、15、16 和 17 连接到了内部的 VSS。
! b. \: H" p; A$ Z( h9 O
8 S9 A3 {: V) w6 z+ J对STM32F407系列单片机,ADC1的通道16连接到芯片内部的温度传感器,通道17连接到了内部参考电压 Vrefint,通道18连接到了备用电源 Vbat。ADC2 和 ADC3 的通道 16、17、18 全部连接到了内部的 VSS。
2 a9 G$ @% G4 S; i/ \
+ x' }" v- K; R* Y 202010231842394.png
* H2 y( i1 r9 K3 W5 y% s2 ~3 F! F2 v
20201023184248351.png
+ Q3 M) n. J" t! o8 g- B
) U* O* n5 Z0 m0 u+ l/ C0 n- _9 ]
8 Q' y, e5 d5 `4 C7 N扩展库特性6 d! ?7 ?$ ~  W5 i+ ~, {4 G9 v
本扩展库针对ADC最常见的操作方式,编写了两种ADC配置模板,其一是不使用DMA传输的单次单通道采样(void ADC_UserConfig1()),其二是使用DMA传输的连续多通道采样(void ADC_UserConfig2())。可根据需要在程序初始化的时候调用对应的配置函数实现ADC的快速配置。同时提供了在两种配置模式下的获取ADC数据与平均值数据的函数,也可在适合的位置直接调用。+ e2 U+ Q! {4 ]+ f6 B

9 p. {8 w1 z  h使用了本扩展库,ADC的配置与读取数据将会变得十分简洁高效。2 B% T, s5 I1 Q
$ U) @; W# a0 M
扩展库源码
/ f7 X, Y  E8 b1 YSTM32F103与STM32F407的ADC在使用的时候还是有一些区别的:/ ^5 G; a: f, g. j7 n0 S" p5 B" E
1.STM32F103的ADC需要校准,而STM32F407的ADC无需校准。
3 C  @$ a) a7 R2 n2.STM32F103与F407的ADC时钟配置、外设配置、DMA配置等不同。+ J& i2 _5 W0 Q# z3 m& a& R
% S  ^: {% z) Q) i1 F' Y9 P
基于STM32F103- {6 q, w- p) a! _. f, `
头文件
* T9 T" i8 X9 \2 T/ Z6 O
  1. #ifndef __ADC_EXT_H__  ?" O* g7 b( T7 {
  2. #define __ADC_EXT_H__        
      g! F3 a' Z! n$ a9 o' c' g1 ?
  3. : n$ d/ |9 V2 J  x0 E9 F
  4. #include "stm32f10x_conf.h"7 K* x8 T" u) F' ^& y
  5. #include "stm32f10x.h", z& Y0 `& k0 e7 ?3 @+ S
  6. & F7 M. b; I6 Y6 V; O
  7. #define ADC_CHANNEL_NUM                                48 J, G: }/ `: a: Q
  8. " f  n8 n+ }3 q
  9. #define ADC_DMA_CHANNEL_DEEPTH                10
    3 b+ {/ I$ h: C/ d0 I6 e
  10. #define ADC_DMA_CHANNEL_NUM                        ADC_CHANNEL_NUM
    6 T7 G0 j. I: O; T9 I0 T$ @
  11. #define ADC_DMA_BUFFER_SIZE                        (ADC_DMA_CHANNEL_NUM * ADC_DMA_CHANNEL_DEEPTH)
    # s; L4 z4 F, @  @  R( i! T

  12. ' j2 h; _( \  A3 D& ^: a
  13. extern volatile uint16_t ADC_Data[ADC_CHANNEL_NUM];! L* K, U6 i! I# g4 u. H" a
  14. extern volatile uint16_t ADC_DMA_Value[ADC_DMA_CHANNEL_DEEPTH][ADC_DMA_CHANNEL_NUM];
    : ^  Y. u+ s  D3 {  e7 R6 J

  15. ' s5 ~, J" A5 [
  16. void ADC_UserConfig1();
    1 Q2 }( D; Y9 j& y0 B5 c! P& ~+ x8 Z/ j
  17. void ADC_UserConfig2();+ ]- s6 p( E$ v9 }) O3 F9 @

  18. $ Q# V$ i+ o) w6 Z( \" r
  19. void ADC_Config_NotUseDMA();) n+ u6 \5 b/ U% [. D4 I2 H
  20. void ADC_Config_UseDMA();' F3 W3 b: `6 S
  21. void ADC_Config_SetDMA();5 R7 V$ x. W& l1 k
  22. ; {5 B) z. s: T6 P/ c) l+ B
  23. uint16_t ADC_GetData_NotUseDMA(uint8_t channel);3 d3 l% c9 k5 y# }$ j
  24. uint16_t ADC_GetAverageData_NotUseDMA(uint8_t channel, uint16_t count);
    4 ]. K* q2 ^8 e
  25. uint16_t ADC_GetData_UseDMA(uint8_t channel);5 R- [4 B4 y" b1 R( S* E
  26. uint16_t ADC_GetAverageData_UseDMA(uint8_t channel);
    ! C4 w* Y) L+ \/ S& w# b

  27. $ p4 x! w, a4 w
  28. #endif   _, E! x( j6 H4 |
复制代码

! b2 k% W" D& |' }- H9 P. G源文件! F$ T" T7 Q6 i! z
  1. #include "adc_ext.h") y) V1 R2 K3 z  V
  2. : P9 q3 U6 L( @  l% N- Z9 r
  3. volatile uint16_t ADC_Data[ADC_CHANNEL_NUM];
    ) F; h7 `7 ?7 Z* T3 C% E, ~3 z% t
  4. volatile uint16_t ADC_DMA_Value[ADC_DMA_CHANNEL_DEEPTH][ADC_DMA_CHANNEL_NUM];
    / n6 K) y& K0 o2 o: M

  5. . B6 Z5 I! [6 f8 f
  6. /**
    ( z0 g% X! a$ R9 ^
  7. * @brief 预置的ADC配置1,不使用DMA传输
    ! h$ P3 y8 U9 n1 }
  8. */
    " F$ e! B$ C6 i; u. |
  9. void ADC_UserConfig1(). p1 y; W( I# n; m
  10. {
    4 }6 A  S+ k6 q( y, ~8 |
  11.         GPIO_ConfigPort('A', 0, GPIO_Mode_AIN, 0);8 I$ d$ h  K* U9 P1 P4 S1 q! _+ I% a' Z1 c

  12. ! \1 S0 }" P; h$ O
  13.         ADC_Config_NotUseDMA();, [$ U, ?* c* M% ~, w$ @2 h, b
  14. }3 Q) I: ?/ }5 o/ Z" v9 B9 e
  15. 1 H, P+ [5 ?* u/ S: s" U9 }7 Z, a

  16. 8 H9 \" p: \# b: e" f8 m
  17. /**; K, f. F2 p( z' B- w
  18. * @brief 预置的ADC配置2,使用DMA传输7 q& q: w* ?- ?" ^
  19. */
    + ^1 n- t* i* j) H
  20. void ADC_UserConfig2()% _/ {4 g$ s. J9 a5 J  @
  21. {
    & D- N# j. |1 x4 q5 c# \
  22.         GPIO_ConfigPort('A', 0, GPIO_Mode_AIN, 0);
    , i- |3 c) h/ c7 ?% m( c7 O: E6 P% e
  23.         GPIO_ConfigPort('A', 1, GPIO_Mode_AIN, 0);7 d7 l$ r/ Q1 P- j4 R( f
  24.         GPIO_ConfigPort('A', 2, GPIO_Mode_AIN, 0);
    ' X, M3 a1 V3 z) B
  25.         GPIO_ConfigPort('A', 3, GPIO_Mode_AIN, 0);7 t& M& u! h2 F2 `( i7 B
  26.         
    - A+ A: x/ M  y+ ~$ D; z5 X
  27.         ADC_Config_SetDMA();5 Q  s( _4 P6 |
  28.         ADC_Config_UseDMA();8 K* O) Z' G* ?- o9 ~# V* d  d5 l. L
  29. }% L3 j; ~' l0 x

  30. % A% _& c! W  u4 t
  31. ( v* Y; m" Q7 E1 ^) e6 ?
  32. /**% X5 I  Q: {" F5 k2 f
  33. * @brief 不使用DMA进行数据传输时的ADC配置
    : s% F$ j: m, J4 k+ j4 N8 U% M
  34. *                 由于ADC 规则组数据寄存器 ADC_DR 只有一个,是一个 32 位的寄存器,
    0 Y" r9 ~$ R% n
  35. *                 只有低 16 位有效并且只是用于独立模式存放转换完成数据。& C* t4 P4 k" f
  36. *                 如果使用多通道转换,那转换的数据就全部都挤在了 DR 里面,前一个时间点转换的通道数据,
    # h: N# W& Y0 e
  37. *                 就会被下一个时间点的另外一个通道转换的数据覆盖掉,所以当通道转换完成后就应该把数据取走。
    ' x) t) F- }! q, i0 d
  38. *8 e, I+ O# u: K5 w7 D5 B$ \& _
  39. *                 因此不使用DMA模式的时候,每次只能读取一个通道的数据+ L. B- b' t! f  j/ w
  40. */
    , q' f9 W6 G* F8 o* b
  41. void ADC_Config_NotUseDMA()
    4 V" V! o/ f7 E' s3 g
  42. {7 `. _* c+ G' b
  43.         /**6 I9 e# M8 m' o$ z; u/ r
  44.          * Configuration of ADC1
    7 X5 k9 |9 L0 S: j9 M
  45.          */
    5 X+ I4 W8 Q/ g0 O  X4 ^) J) `5 ~5 ]
  46.         ADC_InitTypeDef ADC_InitStructure;
    % \- \% z; z' X6 g+ b/ I9 F

  47. + N* s3 U8 R3 J8 L, T6 ^( I
  48.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);                                                                        //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
    / A9 J! U3 b2 i9 G$ ]. C
  49.         ADC_DeInit(ADC1);                                                                                                        //复位ADC1# u: N% j. o7 V! J
  50. 1 T' {" ?# r1 o' R2 p1 ^
  51.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                                        //ADC工作模式:ADC1和ADC2工作在独立模式, X$ t- X/ `5 F3 \! e3 m& f
  52.         ADC_InitStructure.ADC_ScanConvMode = DISABLE;                                                //模数转换工作在单通道模式3 J, C2 o; g* {
  53.         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                                        //模数转换工作在单次转换模式
    . {: W" \8 ]. Q3 B( A  W( S' d
  54.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
    : {- ?" {: |1 S$ U4 [" a
  55.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                                //ADC数据右对齐- {1 F, M5 C* A  B: h; ?
  56.         ADC_InitStructure.ADC_NbrOfChannel = ADC_CHANNEL_NUM;                                //顺序进行规则转换的ADC通道的数目  k: H2 C- u8 T- N9 g
  57.         ADC_Init(ADC1, &ADC_InitStructure);                                                                        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
    . K: w7 U( H  G0 c

  58. * g+ S- B! w7 W8 z
  59.         //        ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_71Cycles5);        //ADC1,ADC通道,采样时间为239.5周期; l0 u' j: ?+ f% d$ W( u6 E; N# ?

  60. , j% N# R; l. R- o/ B# }, |7 _( m
  61.         ADC_Cmd(ADC1, ENABLE);                                                                                                //使能指定的ADC1- ?9 m. U! u9 K2 \1 J* A

  62. * X8 q9 g" z/ o" ~. i
  63.         ADC_ResetCalibration(ADC1);        //使能复位校准- s$ _5 J; Y7 o' N1 h
  64. $ f0 n( I: b$ S0 T$ @
  65.         while (ADC_GetResetCalibrationStatus(ADC1))
    . O- r% P) y  I) A/ f2 B: B9 P
  66.                 ;        //等待复位校准结束
    & ]. G7 d& m: Y

  67. 1 ?0 O  U) l0 V& H
  68.         ADC_StartCalibration(ADC1);         //开启AD校准& S1 ~3 N. N+ x1 e( {- H
  69. 0 V2 y' b. \. G2 i) i
  70.         while (ADC_GetCalibrationStatus(ADC1))
    # m- m$ v1 ?+ @
  71.                 ;         //等待校准结束
    5 H8 j; F% h: c

  72. ' M- N+ S- ]! o5 u# T1 D, z
  73.         //        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能- I7 A! s0 Q8 f! E7 z+ {$ ^
  74. }
    ; ~7 \2 c# L1 }8 ]

  75. - U4 `* S- ~% _
  76. & `8 O$ |7 V4 M
  77. /**9 F6 B3 Y- \6 D6 T( o: _' a1 R
  78. * @brief 使用DMA进行数据传输时的ADC配置/ C& W! W! V. i3 o  J9 F* m
  79. *                 注意规则通道的数量需要根据实际项目进行调整
    8 E- L: |. k, p
  80. */: b3 y- V! y3 c
  81. void ADC_Config_UseDMA()
    ) W" z0 S) w9 L" @" k. W
  82. {
    : {+ C. O9 P# Y2 b& E/ ~$ J: \
  83.         /**7 A8 j2 q! t7 b0 z. g
  84.          * Configuration of ADC
    2 f$ b) K/ p% m3 Q8 o1 C
  85.          */2 h- Y- c  E  i0 v
  86.         ADC_InitTypeDef ADC_InitStructure;2 m% f- j1 s1 V$ C. S. I( @* W5 {
  87. 3 ^& x: p, D. p' f. T
  88.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);                                                        //使能ADC1通道时钟
    . z# b  n1 q4 B2 P) d6 u8 k
  89.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);                                                                                                //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M8 J( |6 B% A  T7 R
  90.         ADC_DeInit(ADC1);                                                                                                                                //复位ADC1: e! g& E4 k+ M. P( e' E
  91. . t7 `5 G) U% {2 R
  92.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    + `/ [6 }6 i" r
  93.         ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                                                        //通道扫描0 @0 Q  g9 \4 A
  94.         ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                                                                //连续转换' E9 Q; A8 G; \+ W1 z- F6 B
  95.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    - I4 Q. g6 G3 ]8 B* u* H- C
  96.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;) _1 m% h; Z6 ^* H' y) b. c. J
  97.         ADC_InitStructure.ADC_NbrOfChannel = ADC_CHANNEL_NUM;
    7 z+ ^, X& y' @9 N- c& D# b
  98.         ADC_Init(ADC1, &ADC_InitStructure);; q; R5 ^5 [$ U4 z$ `. ]

  99. $ c. @8 o" j0 p  S( r
  100.         ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);        //通道1转换结果保存到ADCConvertedValue[0~10][0]+ y+ o. y2 G) ?' m- L' W
  101.         ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5);         //通道2转换结果保存到ADCConvertedValue[0~10][1]. h, J4 w% A0 Q0 H+ g# ~9 k  z
  102.         ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5);         //通道3转换结果保存到ADCConvertedValue[0~10][2]2 M! J# U/ a, x8 u) F& ^/ }8 @. f. |9 m
  103.         ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5);         //通道4转换结果保存到ADCConvertedValue[0~10][3]) ~- Y* K6 L9 g  |3 Q4 Z" G
  104.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5, ADC_SampleTime_239Cycles5);         //通道5转换结果保存到ADCConvertedValue[0~10][4]# b$ c6 L9 F" E
  105.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_239Cycles5);         //通道6转换结果保存到ADCConvertedValue[0~10][5]
    , j( d- I" W) G; H: A
  106.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 7, ADC_SampleTime_239Cycles5);         //通道7转换结果保存到ADCConvertedValue[0~10][6]
    2 [! H% Q* ~0 g4 x) F8 h
  107.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 8, ADC_SampleTime_239Cycles5);         //通道8转换结果保存到ADCConvertedValue[0~10][7]
    # s% ]1 O; T, \5 U) @
  108.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 9, ADC_SampleTime_239Cycles5);         //通道9转换结果保存到ADCConvertedValue[0~10][8]# l3 Z; ]9 P/ }0 k
  109.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 10, ADC_SampleTime_239Cycles5);         //通道10转换结果保存到ADCConvertedValue[0~10][9]' O& L4 U' C% J
  110.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 11, ADC_SampleTime_239Cycles5);         //通道11转换结果保存到ADCConvertedValue[0~10][10]
    ; w8 m" Z5 R& ^6 C* _
  111.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 12, ADC_SampleTime_239Cycles5);         //通道12转换结果保存到ADCConvertedValue[0~10][11]5 a+ B% H: U; ~* Q0 ?: \% q
  112.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 13, ADC_SampleTime_239Cycles5);         //通道13转换结果保存到ADCConvertedValue[0~10][12]
    . I7 N( k: l" b* z& s0 g# j) g
  113.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 14, ADC_SampleTime_239Cycles5);         //通道14转换结果保存到ADCConvertedValue[0~10][13]
    * G  {# V3 [% \7 D9 K! q8 D
  114.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 15, ADC_SampleTime_239Cycles5);         //通道15转换结果保存到ADCConvertedValue[0~10][14]
    * K" D) ?; A/ c% P0 V9 Q  Q
  115.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 16, ADC_SampleTime_239Cycles5);         //通道16转换结果保存到ADCConvertedValue[0~10][15]
    ) G4 v$ ?. Z% r) ?! c" @$ H( O- X

  116. ( P3 B1 d9 b/ Q- ?  x: V$ E
  117.         ADC_DMACmd(ADC1, ENABLE); //开启ADC的DMA支持
    : L% @+ H% H/ U  A
  118.         ADC_Cmd(ADC1, ENABLE);# A3 [6 v  Z, l6 a& K; N
  119.         ADC_ResetCalibration(ADC1);9 T& H' r1 g6 V3 f; i
  120.         while (ADC_GetResetCalibrationStatus(ADC1))
    $ u7 \7 o0 i2 r3 p. o9 S1 p8 C7 `
  121.                 ;
    1 b& A  ?+ F8 v/ c% M
  122.         ADC_StartCalibration(ADC1);# @* h1 o% `( n; f1 X1 Y
  123.         while (ADC_GetCalibrationStatus(ADC1))/ x4 V8 ?: \+ K* E/ g8 E
  124.                 ;
      L$ f6 ?6 g4 S0 ~% T- W
  125.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能
    7 E* M" ?% c6 N9 H
  126. }( o) x& K, j6 j3 Z; G

  127. 9 Y; \  X, [. j- z, @' K" L

  128. 3 n6 {& `' m' e1 U
  129. /**
    ' l( u$ A! ~5 T4 d
  130. * @brief 使用DMA进行数据传输时的DMA配置$ L5 |0 g7 J0 A! P
  131. */
    / K# {; _' ]8 o  H7 b4 u7 T' B
  132. void ADC_Config_SetDMA()9 W0 I" o# x8 o0 \* w
  133. {" l( S, U# Z6 c
  134.         /**
      V- d+ x  N( h/ {1 M0 v) T
  135.          * Configuration of DMA
    * c, g+ I# b4 B  _$ Z# s
  136.          */$ ~) V  l) M& q3 w, E: g  v1 A
  137.         DMA_InitTypeDef DMA_InitStructure;
    * N6 H. D7 n+ P) ?4 A7 S* o
  138.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                                                                //使能时钟6 s4 J/ X! v/ V& i/ P" j3 Y
  139.         DMA_DeInit(DMA1_Channel1);                                                                                                                //将通道一寄存器设为默认值
    ) Z0 t/ v( a) r% S

  140. 8 g9 W; `% c+ m/ D
  141.         DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(ADC1->DR);                                //该参数用以定义DMA外设基地址& {. P* {. r: p4 f
  142.         DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) &ADC_DMA_Value;                                //该参数用以定义DMA内存基地址(转换结果保存的地址)6 K3 |; m& f+ _7 a- O% B) j
  143.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                                                //该参数规定了外设是作为数据传输的目的地还是来源,此处是作为来源
    ! `2 ]4 _, i8 @% ^
  144.         DMA_InitStructure.DMA_BufferSize = ADC_DMA_BUFFER_SIZE;                                                        //定义指定DMA通道的DMA缓存的大小,单位为数据单位。这里也就是ADC_DMA_Value的大小
    + ]: E8 K- _$ \, {% x  x
  145.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                                //设定外设地址寄存器递增与否,此处设为不变 Disable! T2 O' Y( w3 Z6 z  o/ S: x; F6 y
  146.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                                        //用来设定内存地址寄存器递增与否,此处设为递增,Enable
    6 D9 K" `, s7 Z, m# D
  147.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;                //数据宽度为16位3 e0 n4 y% T4 \
  148.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                                //数据宽度为16位
      S! C8 O; r: M/ s1 s: m9 q; u
  149.         DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                                                 //工作在循环缓存模式* S% i9 a  F/ Y, E) P1 Q! K% s
  150.         DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                                         //DMA通道拥有高优先级 分别4个等级 低、中、高、非常高7 h3 {0 l( Z6 [
  151.         DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                                                         //使能DMA通道的内存到内存传输
    8 t& r/ U+ i" W- s; S2 \  N/ ]
  152. . P: w$ e8 A# G6 S% T1 y
  153.         DMA_Init(DMA1_Channel1, &DMA_InitStructure);                                                                         //根据DMA_InitStruct中指定的参数初始化DMA的通道
    2 Y1 W$ T1 Z( L. `/ m
  154.         //        DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE);% v, W8 `+ D* W1 [- a* A! e
  155.         DMA_Cmd(DMA1_Channel1, ENABLE);                                                                                                        //启动DMA通道一
    , y6 c7 s. z3 P4 f. r
  156. }
    9 G) E+ s3 Y! m$ _' b) q
  157. % W/ L/ n6 d+ f  V  ]" M2 x+ h) g
  158. 5 z  t% \) V! V) n- R6 J
  159. /**
    ; c9 B+ h8 G! z+ f/ S( M6 ^
  160. * @brief 不使用DMA传输时,获取ADC的采样数据
    9 d7 X, @: c: f: _& O
  161. * @param channel: ADC的采样通道
    ; F% K; Z, S+ l  T) V6 ?
  162. * @return ADC的单次采样结果, z+ C" Q( D& }5 A
  163. */" W' H( }& V8 x9 W* d
  164. uint16_t ADC_GetData_NotUseDMA(uint8_t channel)
    1 o4 [8 O3 e. @3 p/ g
  165. {
    8 S6 d4 B* f1 q+ g9 P
  166.         //设置指定ADC的规则组通道,一个序列,采样时间
    / j4 C4 j0 X( B3 c( b
  167.         ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_71Cycles5);        //ADC1,ADC通道,采样时间为239.5周期
    ' ]2 B7 M, t: ?% e* Z
  168. : y3 r: j$ n  C9 s
  169.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能9 x4 \! ]" K/ d9 r

  170. * m! ?9 ?3 G+ |8 B0 k: `
  171.         /**
    0 l6 e( U( V# J) H
  172.          * 通过查询的方式获取了ADC的转化结果,
    * w. n: i. P4 Z- x1 x  B
  173.          * 也可以通过中断的方式获取ADC的转换结果
    ) {( c( d3 M# B5 V
  174.          */
    ) |8 {6 D  M5 C+ S
  175.         while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))# p" T; g4 @# q9 l
  176.                 ;                //等待转换结束: U" M: c3 d5 a" ?
  177.         return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果
      a6 i5 Q9 x; H6 {  m+ w$ e
  178. }
    ; U' `% c3 `: Z1 v: a
  179. ) F! D- F2 N5 v; S- d% g) ^; y2 ^

  180. , _) L& n& g) h7 U' f; q, c
  181. /**
    0 d' ]7 b( i/ w2 v( f8 b0 W
  182. * @brief 不使用DMA传输时,获取ADC采样数据的平均值
    9 i6 f1 g& s. S; v4 |; c- o  v; s1 i
  183. * @param channel: ADC的采样通道0 j- w/ `' k  a; K
  184. * @param count: 计算平均值的采样数量1 Y! N: Z" ?" R2 Q  _- |: a7 X
  185. * @return ADC的单次采样结果的平均值/ l# M# o' b5 t
  186. */2 a1 p- B) T6 x+ ?: _% c, p' Z
  187. uint16_t ADC_GetAverageData_NotUseDMA(uint8_t channel, uint16_t count)
    # |" O# l3 x. V, `/ I& i0 P9 W
  188. {) [$ O1 U& e3 m; `$ D0 I( R
  189.         uint32_t temp_val = 0;
    6 h2 A. J% m& u3 P. q) |
  190. + ]1 K8 M# C: l% N( k" z. _
  191.         for (uint8_t t = 0; t < count; t++)
    7 L1 m4 e, a% ]4 T$ ]  g( J5 k
  192.         {
    9 c2 l7 ~4 ?' [7 H
  193.                 temp_val += ADC_GetData_NotUseDMA(channel);
    ' M' G5 b) j+ U' O- S7 Q1 F8 U8 ], v
  194.         }1 F: {% S) m: ]8 }* x# `0 h

  195. ) g6 V* j9 i4 I3 B; a8 U
  196.         ADC_Data[channel] = temp_val / count;+ F. d/ |+ v4 j: ?. Z
  197. * v* |! |9 C$ G/ A# }6 k) C
  198.         return ADC_Data[channel];
    $ ^9 L# m" s% H' |) R
  199. }& K- e7 D2 K9 P) x$ p# e

  200. : |) V2 H# B9 F# Q
  201. 0 `& e2 K$ H; ]0 j$ e, r- T
  202. /**6 o# m) e, ~) ?
  203. * @brief 获取通过DMA传输的采样数据6 t. K2 z: I' T8 b5 U" Q5 w: X8 {& [
  204. * @param channel: ADC的采样通道
    7 l& w5 r9 p3 R: n
  205. * @return ADC的采样数据5 {+ m* q7 M' C# [5 m
  206. */
    9 j* T7 S2 J% @7 C
  207. uint16_t ADC_GetData_UseDMA(uint8_t channel)
    ( F# C- h6 q1 m; i8 {6 W, }
  208. {" c- N5 E, j: J% B6 F2 ?: K
  209.         return ADC_DMA_Value[0][channel];
    1 B$ B' ^1 }6 H! j  [3 V4 P3 D  ?
  210. }0 P$ H/ k, e7 i% G3 y  l

  211. 6 u, K  v9 l; N
  212. . |7 j  @+ L' H6 H8 |
  213. /**
    ; Z5 m' J$ ^/ p  N2 Z5 `# V% m
  214. * @brief 获取通过DMA传输的采样数据(求平均值,过采样)# ^) M( |3 e/ Y  E' ]6 K
  215. * @param channel: ADC的采样通道
    . ^1 q  c0 U9 z1 K) D' x4 Z/ P6 V6 @  r
  216. * @return ADC的采样数据
    " {3 q/ _- W- x/ c+ M5 K+ V8 [' v
  217. */7 l/ G' B' L: \! b/ ~& l- W& r' }
  218. uint16_t ADC_GetAverageData_UseDMA(uint8_t channel)
    2 l0 u3 Y; J, a7 x& Z
  219. {
    , d. \  q% y9 s8 \/ R" _9 G
  220.         uint32_t sum = 0;
    * v: {- g, {5 i- c

  221. . \1 K3 P* `( i' z
  222.         for (uint8_t j = 0; j < ADC_DMA_CHANNEL_DEEPTH; j++)
    # s) A  X2 B& |/ b! c3 H
  223.         {
    7 S% X3 H( R4 w+ h' E3 i. h
  224.                 sum += ADC_DMA_Value[j][channel];
    $ d" }' X  u6 @( [/ i
  225.         }( {- {+ p4 @, W6 N9 q0 c
  226. % N3 `# j* h- D/ L1 r
  227.         return sum / ADC_DMA_CHANNEL_DEEPTH;                                                //求平均值并转换成电压值( P' `7 I  R$ \9 T. K
  228. }
复制代码
7 ~, m5 q9 D. {/ n! d8 Q' u4 d
基于STM32F407
$ _9 z- {* x/ s, P* a9 G头文件

% }( x$ q% \1 F2 M9 y( i: n5 M4 }
  1. #ifndef __ADC_EXT_H__8 {( K- ~% g0 }
  2. #define __ADC_EXT_H__        . I( W3 ^* p7 D1 j& T6 {

  3. & I' y4 u+ ~  g/ y. C' m+ ^
  4. #include "stm32f4xx_conf.h"# q, D9 B6 o9 V* Q1 s% L% w
  5. #include "stm32f4xx.h"* J4 A3 h5 k: V
  6. 3 _7 V7 O- i' M+ p7 e3 S) X8 K
  7. #define ADC_CHANNEL_NUM                                        4
    1 L: ]7 E4 y2 q" M+ ?

  8. + T5 B" k( ~% w" a
  9. #define ADC_DMA_CHANNEL_DEEPTH                        10" g* Y7 Q5 l5 S& F+ \+ j3 B: w
  10. #define ADC_DMA_CHANNEL_NUM                                ADC_CHANNEL_NUM
    5 L9 G7 O! W! n+ V
  11. #define ADC_DMA_BUFFER_SIZE                                (ADC_DMA_CHANNEL_NUM * ADC_DMA_CHANNEL_DEEPTH)
    ; O- t# w/ ^# ^
  12. ; Z# U9 `& [. m
  13. extern volatile uint16_t ADC_Data[ADC_CHANNEL_NUM];( K! C2 P" W7 `4 N- ?$ @" }
  14. extern volatile uint16_t ADC_DMA_Value[ADC_DMA_CHANNEL_DEEPTH][ADC_DMA_CHANNEL_NUM];9 j' X5 U8 j' b& A

  15. 1 U. p8 }* A9 y6 ~0 n
  16. void ADC_UserConfig1();
    7 U  S+ ~/ [  T8 j. l
  17. void ADC_UserConfig2();* g# h1 {: @& W1 ^! P/ k% t
  18. * c$ O, _% L$ k/ J  {( G' r+ `' @6 @0 G
  19. void ADC_Config_NotUseDMA();( W; G; Z$ g4 M! X/ A8 s
  20. void ADC_Config_UseDMA();
    $ K. x* K- T' j1 g; M' J
  21. void ADC_Config_SetDMA();3 M9 Z! x* Y9 o8 _

  22. ! E8 `4 y! i/ k* J1 x; u
  23. uint16_t ADC_GetData_NotUseDMA(uint8_t channel);6 r2 ]) v: U6 D0 k% a( n  M8 z2 K
  24. uint16_t ADC_GetAverageData_NotUseDMA(uint8_t channel, uint16_t count);
    0 C) ^6 N2 O/ r( w+ m2 k
  25. uint16_t ADC_GetData_UseDMA(uint8_t channel);  P# w1 J" Y4 j; r' }5 G
  26. uint16_t ADC_GetAverageData_UseDMA(uint8_t channel);. P* S. P; v  a" n: q! @7 H
  27. & R' [) r" c4 U: v/ N
  28. #endif
复制代码
+ f- c: D& a0 A" f' N
源文件
$ P  c- m9 s8 t" Z/ q
  1. #include "adc_ext.h"5 Q8 J0 ~* h0 h7 B9 a# _* }9 f" z
  2. / U: p7 d. Q$ W- s- z" `
  3. /**
    ( ]+ W! {( e& F: M2 g1 Z
  4. * ADC时钟
    / F7 c7 A# D, R  \- u1 [
  5. *
    6 Z8 b3 R9 O0 q) ?7 s# x  ?7 Z
  6. * ADC输入时钟 ADC_CLK 由 PCLK2 经过分频产生,最大值是 36MHz,典型值为30MHz8 L% x* v: \- D9 _
  7. * 分频因子由 ADC 通用控制寄存器 ADC_CCR 的 ADCPRE[1:0]设置,可设置的分频系数有 2、4、6 和 80 m8 k+ n0 }" e' Y- b4 A1 e& g+ k
  8. * 对于STM32F407的PCLK2=HCLK/2=84MHz,所以程序一般使用 4 分频或者 6 分频
    * R3 D- M! j9 V
  9. */: x, M% W. H2 m2 ?( k. z# U0 D2 o9 F3 Z! C
  10. 2 `7 j4 u2 p: _- R) b& y& Q8 U
  11. /**
    9 x- b  r7 S! X; d/ o" v- L3 C7 `
  12. * 采样时间( B) D% r$ v9 `  a1 y- R! E
  13. *
    - S7 J/ g4 y5 R
  14. * ADC 需要若干个 ADC_CLK 周期完成对输入的电压进行采样,  N: n4 a; D, h) h
  15. * 采样的周期数可通过ADC 采样时间寄存器 ADC_SMPR1 和 ADC_SMPR2 中的 SMP[2:0]位设置。% G8 V7 ?! C. ^% p5 F  X7 r
  16. * 每个通道可以分别用不同的时间采样。9 L2 x4 {+ t5 X$ `. }7 F' C
  17. * 其中采样周期最小是 3 个,即如果我们要达到最快的采样,那么应该设置采样周期为 3 个周期。: [: Z- u( U" F4 r6 y
  18. * 这里说的周期就是 1/ADC_CLK。  Q9 T- q: X& ^# Q
  19. */
    1 U9 }  e: Z) Z

  20. 5 V: S/ J; [* B  a4 T' b
  21. /**
    / g% K9 K" W1 x2 F4 l: o- E
  22. * 注意本库函数只实现了ADC1的配置与采样,ADC2与ADC3的配置与使用方法与此类似# l; n  t0 |; C, R% s
  23. */
    ! y( |% n0 I2 T9 H, \1 F% P; O: x- v6 |

  24. $ ]: M4 \& ]  `! s
  25. volatile uint16_t ADC_Data[ADC_CHANNEL_NUM];7 j. [! o" F4 j3 J8 V
  26. volatile uint16_t ADC_DMA_Value[ADC_DMA_CHANNEL_DEEPTH][ADC_DMA_CHANNEL_NUM];
    & I1 H2 p5 F; G7 Z+ l& @1 K" w

  27. 6 Q5 R1 {" `! _+ @+ z; g' t
  28. /**) V: x) Y6 D8 V/ \
  29. * @brief 预置的ADC配置1,不使用DMA传输
    + Q& ?0 ]' b1 r1 V
  30. */+ w& k- w' y# z% ?$ r0 }
  31. void ADC_UserConfig1()' D; r7 ?3 ?0 s* h
  32. {; c8 T9 {4 b: L( N, {/ e- {
  33.         GPIO_ConfigPort('A', 0, GPIO_Mode_AN, GPIO_OType_OD, GPIO_PuPd_NOPULL, 0);
    ( z7 M8 k& [2 u" X" Z# Y
  34.           r2 C1 a8 _5 d$ Z$ Y" Y2 c
  35.         ADC_Config_NotUseDMA();
    / s# p# ?& u2 M' c/ T, J* v
  36. }; \# G( f8 `1 F* u

  37. ' S( `, n* F& O

  38. 2 ?$ `' |" S- B8 {$ ~
  39. /**
    0 }1 t: {' ^3 R8 {  Y" V4 D
  40. * @brief 预置的ADC配置2,使用DMA传输
    + i( P! ^$ d) S% K# i% V$ n5 S3 I: k
  41. */
    # J. g: k- X- O
  42. void ADC_UserConfig2()$ x' m# I' V( `( a
  43. {* S/ y) p7 ]8 j* q8 ~+ i) m
  44.         GPIO_ConfigPort('A', 0, GPIO_Mode_AN, GPIO_OType_OD, GPIO_PuPd_NOPULL, 0);
    4 s! j1 D1 c" {& w, X
  45.         GPIO_ConfigPort('A', 1, GPIO_Mode_AN, GPIO_OType_OD, GPIO_PuPd_NOPULL, 0);! b. _3 F9 B+ x/ N" K
  46.         GPIO_ConfigPort('A', 2, GPIO_Mode_AN, GPIO_OType_OD, GPIO_PuPd_NOPULL, 0);  j0 E6 p; Y' `6 [/ F
  47.         GPIO_ConfigPort('A', 3, GPIO_Mode_AN, GPIO_OType_OD, GPIO_PuPd_NOPULL, 0);
    4 f; Q5 q* N0 f+ h+ B; z9 U
  48.         9 K! J2 @/ Z& E: \- }
  49.         ADC_Config_SetDMA();" s/ Q, O/ O; q$ I$ [+ ^
  50.         ADC_Config_UseDMA();: |8 y% h* `, |
  51. }! u. b) }3 S7 c- s

  52. . |4 R3 T. `5 }  L4 w5 R$ S

  53. 1 m8 U% [* Q: p, E, {
  54. /**# n/ y5 W7 D4 b8 J4 x5 t
  55. * @brief 不使用DMA进行数据传输时的ADC配置% I" Q: h3 |/ Q  \
  56. *                 由于ADC 规则组数据寄存器 ADC_DR 只有一个,是一个 32 位的寄存器,
    4 j: p! [- `; M2 i6 x+ F& A1 V
  57. *                 只有低 16 位有效并且只是用于独立模式存放转换完成数据。& ?) ?2 k' D2 P8 @
  58. *                 如果使用多通道转换,那转换的数据就全部都挤在了 DR 里面,前一个时间点转换的通道数据,
    5 _; c. X3 J2 O/ q
  59. *                 就会被下一个时间点的另外一个通道转换的数据覆盖掉,所以当通道转换完成后就应该把数据取走。1 q/ ]' Y- a5 S8 E% Q- ~8 }
  60. *2 J+ }, s$ Z3 e/ ?
  61. *                 因此不使用DMA模式的时候,每次只能读取一个通道的数据
    / d& v9 ]+ ~/ [3 e
  62. */
    / t; [1 \  o2 S: Y2 u
  63. void ADC_Config_NotUseDMA()/ b* ]; a1 B- {) V% K
  64. {
    % o: ^( ~0 P" B
  65.         /**
    9 H" Q( ?, ^. B7 [8 v! q6 F( S
  66.          * Configuration of ADC# w2 }  [& d- w8 ^/ j1 o0 {& h
  67.          */8 ^) O- F% ]5 ~% q! S) f, d1 \4 O2 z

  68. # M& e& g1 P) A4 [. x( w9 i( ?
  69.         ADC_CommonInitTypeDef ADC_CommonInitStructure;
    7 d' v$ A8 b* u

  70. & }9 p: r* D; P1 {$ E) u
  71.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);                                                                                                //使能ADC1时钟: }3 Y: N3 ]- i
  72.         ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;                                                                                //独立ADC模式
    & F5 N( {: n" I, V! W+ s
  73.         ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;                                                                                //ADC时钟为fpclock/分频8 x5 e' l5 S" e" D7 O1 G2 D- e
  74.         ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;                //禁止DMA直接访问模式
    1 ^- P$ z7 l* W/ ], _6 a
  75.         ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;        //采样时间间隔, g" k! `/ J' t) U9 x
  76. - ^( B  R6 u1 `& V
  77.         ADC_CommonInit(&ADC_CommonInitStructure);
    2 H2 O8 J% I& }; X! W* w
  78. . Z: O7 d+ l0 r9 P: [+ W
  79.         ADC_InitTypeDef ADC_InitStructure;+ |# s& V) z9 v" ?/ [

  80. " m! Q/ l0 O  E, A+ G/ p
  81.         ADC_StructInit(&ADC_InitStructure);, @% R* P3 U$ G; b/ q
  82.         ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;                                                                //设置ADC的分辨率12位8 i- r" N. M; F: R
  83.         ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                                                                        //通道扫描模式
    + Q* f3 Z4 k1 f+ k' r
  84.         ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                                                                //连续转换模式
    ( D8 K5 E8 e0 r) ]3 }; U( q/ C( S* E

  85. ' X- D( s  o6 @7 E( z, O* h1 z. j
  86.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None;        //禁止外部边沿触发6 U7 O4 }6 Z* w% m0 h/ B! M
  87.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;                //外部触发通道
    : S+ q' z; X9 V1 R
  88.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                                                                //设置数据右对齐2 ?1 \9 R9 @3 v+ o
  89.         ADC_InitStructure.ADC_NbrOfConversion = 1;                                                                                                        //设置转换通道,固定为1
    & k/ c) n) B  x' w
  90.         ADC_Init(ADC1, &ADC_InitStructure);
    7 e1 x" X: N- l+ f7 O

  91. 7 I) h! Z! {+ r) L6 v! V
  92.         ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_56Cycles);                        //配置 ADC 通道转换顺序和采样周期
    / ]  z* a( g) m9 Y' z% Y

  93. ! d1 t) I8 @. F8 N9 ^
  94.         //        ADC_ITConfig(RHEOSTAT_ADC, ADC_IT_EOC, ENABLE);                                                                                                //ADC 转换结束产生中断,可以在中断服务程序中读取转换值
    & M7 I1 N+ U' A" }! Z# W

  95. - f0 x7 Y; W/ r: v5 x3 C
  96.         ADC_Cmd(ADC1, ENABLE);                                                                                                                                                                                                //使能ADC
    7 p. C5 G4 l" A3 j  f2 e# u
  97. }
    ! L& F$ L+ H- k
  98. ; q, i( y4 W2 T

  99. # [2 C5 ^$ z" g5 q% g
  100. /**
    6 o- c, O2 x8 F2 u$ ^' S# O
  101. * @brief 使用DMA进行数据传输时的ADC配置
    2 r2 P5 }: v! s
  102. *          注意规则通道的数量需要根据实际项目进行调整
    0 {3 X* ?. U6 F
  103. */
    & \# o4 E2 {" `/ m$ I
  104. void ADC_Config_UseDMA()) S8 S6 J! \/ ]+ n8 v& c& C
  105. {
    2 P, z  p* L- ]
  106.         /**
    7 K6 `4 U. f: V) e8 _
  107.          * Configuration of ADC# v& B$ M7 v% W5 c7 g
  108.          */
    8 E) v$ x# E) V  f
  109.         ADC_CommonInitTypeDef ADC_CommonInitStructure;/ ^. G* i/ [. [* ~/ b" {
  110. ( [$ [0 w  r0 C2 S1 }7 h. s: y6 c
  111.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);                                                        //使能ADC1时钟5 P3 E1 Z. L% O" `, ^
  112.         ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;                                        //独立ADC模式  H0 F' B6 _3 {) f' [7 k. _" `, O
  113.         ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;                                        //ADC时钟为Fpclock/分频8 c1 b: I' O1 q- }
  114.         ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;                //禁止DMA直接访问模式
    " y; S  k0 }( F4 G( N
  115.         ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;        //采样时间间隔# h+ F6 S; X. r9 ]
  116. ) K# f6 W1 Y2 ~# g
  117.         ADC_CommonInit(&ADC_CommonInitStructure);) [' o6 {9 p4 \: \. ?+ O

  118. 5 Y/ |  u' y% o, Z: D3 _; j/ b
  119.         ADC_InitTypeDef ADC_InitStructure;0 M1 [. _1 q" @
  120. ; Q5 s* H: b9 |' T( ^- T0 i* Z5 Z) v2 Q
  121.         ADC_StructInit(&ADC_InitStructure);2 t* \" M3 o# T/ W2 L7 h0 |  `
  122.         ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;                                                                //设置ADC的分辨率12位
    ' I% s. v2 V; _
  123.         ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                                                                        //通道扫描模式
    , V! ?) }9 e( {! C
  124.         ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                                                                //连续转换模式# D* l2 ?5 H+ n
  125. $ `; x$ P  o: k2 o! s) M% b
  126.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None;        //禁止外部边沿触发
    $ x/ m$ n. A) u: P6 X0 P  R
  127.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;                //外部触发通道; C* {( j5 T9 P( W8 X+ C2 x
  128.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                                                                //设置数据右对齐
    ( z5 R/ U- K  ]$ s. w' k2 L6 W
  129.         ADC_InitStructure.ADC_NbrOfConversion = ADC_CHANNEL_NUM;                                        //设置转换通道, H  R+ C6 ]! C' d8 O) v
  130.         ADC_Init(ADC1, &ADC_InitStructure);* E7 s7 y+ j& X0 w* c% H* U' A

  131. * s- A6 A# n7 H' m: `3 @
  132.         ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);                //通道1转换结果保存到ADCConvertedValue[0~10][0]5 s7 G# W# G6 Q" i6 G9 v
  133.         ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_3Cycles);                 //通道2转换结果保存到ADCConvertedValue[0~10][1]
    " X; I# V, C# Z. c- v# n
  134.         ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_3Cycles);                 //通道3转换结果保存到ADCConvertedValue[0~10][2]7 H3 {- s4 p5 ~) H1 B% F3 `4 T
  135.         ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_3Cycles);                 //通道4转换结果保存到ADCConvertedValue[0~10][3]! n( M" I8 D% X; D9 n
  136.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5, ADC_SampleTime_3Cycles);                 //通道5转换结果保存到ADCConvertedValue[0~10][4]
    0 B! l3 F3 y# _! p
  137.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_3Cycles);                 //通道6转换结果保存到ADCConvertedValue[0~10][5]
    # V6 K8 N% X/ d1 T
  138.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 7, ADC_SampleTime_3Cycles);                 //通道7转换结果保存到ADCConvertedValue[0~10][6]
    ) @: c3 R$ k* e4 \$ M( G% O
  139.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 8, ADC_SampleTime_3Cycles);                 //通道8转换结果保存到ADCConvertedValue[0~10][7]+ W! C; K  _! L& Q$ o: C2 S2 `! u
  140.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 9, ADC_SampleTime_3Cycles);                 //通道9转换结果保存到ADCConvertedValue[0~10][8]
    9 Y+ [" G* r6 o+ @1 J+ S  `" Y
  141.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 10, ADC_SampleTime_3Cycles);         //通道10转换结果保存到ADCConvertedValue[0~10][9]
    # ^8 M# f% ^/ {, }2 T
  142.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 11, ADC_SampleTime_3Cycles);         //通道11转换结果保存到ADCConvertedValue[0~10][10]& H7 j" E) D1 [$ \( R
  143.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 12, ADC_SampleTime_3Cycles);         //通道12转换结果保存到ADCConvertedValue[0~10][11]
    # l* Y% y  v7 O: M8 [
  144.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 13, ADC_SampleTime_3Cycles);         //通道13转换结果保存到ADCConvertedValue[0~10][12]
    $ A: y/ I1 f* q2 @# f- `1 N! F4 x$ h
  145.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 14, ADC_SampleTime_3Cycles);         //通道14转换结果保存到ADCConvertedValue[0~10][13]% i- W9 M, {7 r$ H$ {2 {0 C2 @6 p
  146.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 15, ADC_SampleTime_3Cycles);         //通道15转换结果保存到ADCConvertedValue[0~10][14]
    ( c2 X: B9 O* k% _% q& H6 O% _' N. z
  147.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 16, ADC_SampleTime_3Cycles);         //通道16转换结果保存到ADCConvertedValue[0~10][15]
    : P, {1 P# l; Z2 G) f

  148. + b& a% x* g) A7 ~8 m# V
  149.         ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);                                                                                                        // 使能 DMA 请求 after last transfer (Single-ADC mode); V1 {7 S$ G1 h5 t
  150.         ADC_DMACmd(ADC1, ENABLE);                                                                                                                                                                                 //开启ADC的DMA支持
    . i  s. N& b" k/ W% p, d
  151.         ADC_Cmd(ADC1, ENABLE);                                                                                                                                                                                                //使能ADC/ @3 g  D+ Y- \4 T
  152.         ADC_SoftwareStartConv(ADC1);                                                                                                                                                                                //开始ADC转换,软件触发
    % ^. P1 R& u" r
  153. }
    4 Y3 J0 A+ G: Q' x- ]9 K
  154. 4 E7 O1 m5 b5 a  I5 n% k
  155. ; T! K0 N7 {( X2 v
  156. /**
    ' t4 k$ ], r% X$ D* G1 @
  157. * @brief 使用DMA进行数据传输时的DMA配置# ~. v$ l. A. p) n5 k! |
  158. */
    $ [: d# e" E5 h2 P( W! S& h% o
  159. void ADC_Config_SetDMA()
    # l* n" t! Y2 [
  160. {/ J0 w! }) U$ D6 L
  161.         /**  ]8 Y1 }- J1 q( M2 L  w+ q9 [' Z3 L
  162.          * Configuration of DMA- {. k( i1 C! {7 @  {  Z
  163.          */
    % p2 r. n2 Y! [$ F/ p- N1 G
  164.         DMA_InitTypeDef DMA_InitStructure;0 H; V9 I+ d; V5 y! }1 T. b
  165.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);                                                                //使能时钟
    ' }" x+ z* c6 @: ~( C& ~/ i) N
  166.         DMA_DeInit(DMA2_Stream0);                                                                                                                                                                //将通道一寄存器设为默认值
    6 S7 C' a" z5 X1 x0 z/ v
  167. 9 y" R0 k4 x6 Y! W/ A
  168.         DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(ADC1->DR);                                //该参数用以定义DMA外设基地址
    ' H, `6 A- J" j: v
  169.         DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &ADC_DMA_Value;                        //该参数用以定义DMA内存基地址(转换结果保存的地址)6 G' P' E+ t: |; ]/ q
  170.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                                                        //该参数规定了外设是作为数据传输的目的地还是来源,此处是作为来源
    5 U, l% J$ ^+ U
  171.         DMA_InitStructure.DMA_BufferSize = ADC_DMA_BUFFER_SIZE;                                                                //定义指定DMA通道的DMA缓存的大小,单位为数据单位。这里也就是ADC_DMA_Value的大小
    ) y1 ?/ P1 v* t4 i
  172.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                                        //设定外设地址寄存器递增与否,此处设为不变 Disable  x4 ?1 l1 J, x# Y% S! ^( \
  173.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                                        //用来设定内存地址寄存器递增与否,此处设为递增,Enable( B( f; F! f' |% z
  174.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;                //数据宽度为16位
    ) T8 `  C. J& j8 u. Q+ N$ _* f/ \% T
  175.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                                //数据宽度为16位& P" H0 U5 N+ E# b" Z3 B
  176.         DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                                                                 //工作在循环缓存模式. H4 m' @0 ]! G+ r2 V/ F/ c
  177.         DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                                                                 //DMA通道拥有高优先级 分别4个等级 低、中、高、非常高
    6 X/ B5 ]9 c9 f" H4 H) O
  178.         DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                                                        //禁用DMA的FIFO模式,使用直连模式
    ; p* Q" y" h. g; u6 a8 i6 p* |
  179.         DMA_InitStructure.DMA_FIFOThreshold  = DMA_FIFOThreshold_HalfFull;
    # j3 X: P# G3 J- V/ b  g  `  J
  180.         DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;! A* Z- l$ q0 u" I. T/ N
  181.         DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    - O5 p1 m+ C3 G; L- U7 P6 E2 @5 o4 _
  182.         DMA_InitStructure.DMA_Channel = DMA_Channel_0;                                                                                        //选择DMA通道
    ; W, f* p) d! z4 z: B; C
  183. & v; ?3 s3 `& j+ G3 {9 n8 A# Y- r
  184.         DMA_Init(DMA2_Stream0, &DMA_InitStructure);                                                                                                         //初始化DMA流& U3 p; {7 E  b- N. h4 ^* p; {  @
  185.         DMA_Cmd(DMA2_Stream0, ENABLE);                                                                                                                                        //使能DMA流
    ! R6 n, u# k* e* g9 Y; F1 Z! @+ q
  186. }6 k( T1 l( n* b% Y$ f

  187. ; G2 p4 g. Y( t

  188. ' S5 H  C; y1 Z$ \, z
  189. /**
    , ?1 D( z) H8 O/ w, G* q
  190. * @brief 不使用DMA传输时,获取ADC的采样数据# m7 M7 h0 A7 N5 w
  191. * @param channel: ADC的采样通道+ @; j8 e( ^- w& C; N1 B7 y  W
  192. * @return ADC的单次采样结果% |+ a5 Z0 o) J: l% g9 c
  193. */1 p  F: o. I! X0 L6 C
  194. uint16_t ADC_GetData_NotUseDMA(uint8_t channel)
    . N" O' C+ G% b' R* I
  195. {3 S4 N  {2 K- q& a! k
  196.         ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_56Cycles);                        //配置 ADC 通道转换顺序和采样周期" ]6 ?* s+ E' f  H7 t2 a
  197.         ADC_SoftwareStartConv(ADC1);                                                                                                                                                        //使能指定的ADC1的软件转换启动功能$ T1 A. d& J' a( i- e# T9 Q

  198. * ^# H2 M8 H9 V3 u% k
  199.         /**2 p. |2 g" P. w& J4 B% n
  200.          * 通过查询的方式获取了ADC的转化结果,0 s3 ~' \5 G  o: G/ b/ O1 P! P7 r
  201.          * 也可以通过中断的方式获取ADC的转换结果
    $ @$ w! l; F1 H
  202.          */
    # _2 r  w3 \+ l+ N1 c3 d
  203.         while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));                                                                                        //等待转换结束* T! G0 a3 R$ x8 O

  204. : m, c( B$ Y$ Y5 {
  205.         return ADC_GetConversionValue(ADC1);                                                                                                                        //返回最近一次ADC1规则组的转换结果. V; v( n6 `3 A- d0 s
  206. }9 T7 K& q$ @$ y; W5 B
  207. ) l9 h9 E3 m- @1 j
  208. ( D: U6 v  X4 l* \3 \+ m5 t1 }2 g
  209. /**
    " _: N+ c; }' Y3 [
  210. * @brief 不使用DMA传输时,获取ADC采样数据的平均值
    $ _6 r: d2 K  B& b( A3 W
  211. * @param channel: ADC的采样通道
    4 Q) V5 l. P, O$ K% L, _) D# T
  212. * @param count: 计算平均值的采样数量
    * Z+ L& Y9 u! j3 ?  i. u) R
  213. * @return ADC的单次采样结果的平均值
    7 m' D: X+ ?, E. i0 R/ y5 c/ c0 R* G% d
  214. */
    1 H  b# n% o4 T
  215. uint16_t ADC_GetAverageData_NotUseDMA(uint8_t channel, uint16_t count)
    . a$ }( d% m; T, l; G- K( c
  216. {3 _# F( W8 U, ^) B0 K% `0 ]. T
  217.         uint32_t temp_val = 0;
    9 ~6 F6 X( x/ F7 [( C

  218. ' q$ @* e' W2 k1 b; y0 b
  219.         for (uint16_t t = 0; t < count; t++)
    9 Z# Z# F/ I8 a! T( b
  220.         {
    - Y; q( h( j7 F3 ~& [
  221.                 temp_val += ADC_GetData_NotUseDMA(channel);
    ( x8 p" N* S: n
  222.         }: q" t/ ~: S, ?, R: c& ]

  223. 9 N/ U2 `7 {5 Y# z
  224.         ADC_Data[channel] = temp_val / count;
    ( ?! G# }. K- e& f

  225. 8 C2 o, R$ r$ H; d. q
  226.         return ADC_Data[channel];
    : B; d8 Y2 r  A. Q2 d1 P0 g+ [
  227. }+ U" M+ q6 {) B5 D( \6 s
  228. ' d# O+ T+ K! Q4 L  g" c9 k
  229. /**: f, i8 C; n6 g7 u$ n4 I9 l
  230. * @brief 获取通过DMA传输的采样数据
    $ s' r2 o- R2 F- d
  231. * @param channel: ADC的采样通道
    5 r( c- L$ c! a3 @
  232. * @return ADC的采样数据: B' ~" `9 ^: {% k6 X4 Z# c
  233. */8 Z- l, r. M$ v8 b/ p9 V
  234. uint16_t ADC_GetData_UseDMA(uint8_t channel)6 X3 u; f& H! o1 J* P% u# f2 F
  235. {$ c5 X. h+ u" H  k* ]
  236.         return ADC_DMA_Value[0][channel];( I2 X( }7 [5 ]7 H
  237. }& n* J& ^6 N. t  j/ X) g0 s9 \3 \
  238. 2 Q7 ?0 v. [6 S5 K
  239. 3 _0 N0 L; K/ ^1 z3 k6 Q- R1 w
  240. /**& A% V. B1 b- h, s1 `& V# I& A6 f' @
  241. * @brief 获取通过DMA传输的采样数据(求平均值,过采样)9 Y: g, L; S" S# L0 J/ {
  242. * @param channel: ADC的采样通道
    ) f& T0 \- K: k6 u" q
  243. * @return ADC的采样数据9 ^3 I6 ]) Q  ?2 k2 Y$ O
  244. */7 ?9 ?' U" M0 b' M2 @4 z5 I
  245. uint16_t ADC_GetAverageData_UseDMA(uint8_t channel)
    ) ]& ?- q- ]0 m; Q3 z  X3 A' @
  246. {) }% N8 Q% T" u
  247.         uint32_t sum = 0;
    # i6 v, B8 {* p/ U# |

  248. % |1 \' M+ m& \. @/ ]
  249.         for (uint16_t j = 0; j < ADC_DMA_CHANNEL_DEEPTH; j++)
    / B) a6 b0 |8 {3 N. l2 q6 A
  250.         {2 m5 _5 x/ h6 d1 N# Q& F  w
  251.                 sum += ADC_DMA_Value[j][channel];8 j- J0 U, B* Y# c5 L
  252.         }
    6 e, t) s9 f3 o  k5 h
  253. : k, x5 N% Z4 \9 B
  254.         return sum / ADC_DMA_CHANNEL_DEEPTH;                                                //求平均值并转换成电压值
    % E- ~5 @' d0 W4 b5 _
  255. }
复制代码

2 {1 [7 e1 W  E5 B使用指南9 J; [6 r; n& j5 _6 s+ a6 F. ^9 x
由于使用了相同的功能逻辑与函数名(即头文件相同),STM32F103与STM32F407的ADC扩展函数库在使用方法上是相同的。由于在ADC扩展库中提供的模板配置函数中已经完成了GPIO外设与ADC外设的配置,因此可以直接调用一步完成ADC使用前的初始化工作。
1 S& U9 O; |1 A3 P! E
1 ^2 e) E  b$ D/ f+ w  q单次单通道采样(不使用DMA)( N6 f8 O  L( J# g# t
配置ADC
3 C  w$ F+ Y- _# d, \/ G
  1. void Periphl_ConfigAll()
    * h- u' B. I, `- \+ k- E; z* X
  2. {
    . Y6 ?% V) Y- _. M
  3.         /*省略无关代码*/: I3 w* l  |! g0 X; o
  4.         ADC_UserConfig1();
    % T* b$ z+ Y5 _
  5.         /*省略无关代码*/
    + W* {. P% q' o; C( J' c
  6. }
复制代码
. T$ s( u5 ~/ v7 |  _' p
启动采样并获取数据
/ E3 c7 l- R0 h: \5 k* O采集的数据保存在全局数组ADC_Data[ADC_CHANNEL_NUM]中,同时也可以调用相应的函数返回对应的结果。
/ y, R4 J, g9 T调用uint16_t ADC_GetData_NotUseDMA(uint8_t channel)完成一次数据采集。. B0 H2 v0 T" e& ~6 @# E* Z/ m
调用uint16_t ADC_GetAverageData_NotUseDMA(uint8_t channel, uint16_t count)连续采集count个数据后,返回数据采集的平均值。
% L' B* X% r  h3 T4 N8 w9 H  o; p% T0 {) e  U; H4 o* @2 R$ M
5 a7 l) q* |- w* p( O1 K5 a3 S
连续多通道采样(使用DMA)$ V; s9 b* q! _1 f" ~: g
配置ADC5 ~6 V: c: ~* Q
  1. void Periphl_ConfigAll()" E1 F3 v/ B2 ?
  2. {
    / n1 K1 F7 N* \/ Q* g7 F" O
  3.         /*省略无关代码*/
    ( V0 O. K% K- ]& {: Q& M
  4.         ADC_UserConfig2();& W9 {& U8 |1 a  P# g9 ]! C" @3 G; @
  5.         /*省略无关代码*/
    9 q  c7 B. v8 a1 [
  6. }
复制代码
3 J2 g, @/ T) V+ L
获取数据2 ?9 `  q- N! w. @
在配置完ADC的DMA传输后就已经自动打开了ADC采样,采样的数据保存在全局二维数组ADC_DMA_Value[ADC_DMA_CHANNEL_DEEPTH][ADC_DMA_CHANNEL_NUM]中,同时也可以调用相应的函数返回对应的结果。2 q& v' d( v' G- g; \
    调用uint16_t ADC_GetData_UseDMA(uint8_t channel)返回一次数据采集结果。
8 a: |0 n& Z$ A+ H3 ]* n    调用uint16_t ADC_GetAverageData_UseDMA(uint8_t channel)返回数组中保存的最近的ADC_DMA_CHANNEL_DEEPTH个数据的平均值。
, |( K7 V0 }- x* w4 E" l
6 i6 f( G, f) U; ~* R) _2 Q一般情况下,由于DMA的采样速度很快,调用uint16_t ADC_GetAverageData_UseDMA(uint8_t channel)返回一个平均值作为采样的结果是比较推荐的。这也是利用了过采样技术提高了数据的稳定性与分辨率。; a: S; a& ~; h* Z
* z+ J, d( J4 b7 ~
在FreeRTOS任务中

$ j# Y4 d! }2 x: `- Y" b可以创建一个任务完成ADC初始化与数据轮询的工作,但需要注意的是片上ADC的快速配置函数(ADC_UserConfig2())只能调用一次,否则可能会出错。也就是说要么在程序启动的地方配置ADC,要么在任务开始的地方配置ADC,但不能两处同时配置ADC。
7 q$ C* n# k8 c. q3 j# S! Z# D( x; k0 S& }
  1. void McuAdcDaq_task(void *pvParameters)9 A& O& o- l7 |2 |+ W
  2. {! j) Z( {! r& ?1 C, r6 G* M/ ~
  3.         ADC_UserConfig2();- y" J- o7 r" M7 `/ b8 }
  4. ! B; D' h" R3 o4 |! A
  5.         TickType_t ticks = xTaskGetTickCount();; n4 N2 x% @( @3 l. ^
  6.         while (1)
    ; ^3 P/ j8 ^- E1 T# y8 v
  7.         {
    ! g' g, C' ?9 I4 O: N, @8 l( U. C
  8.                 User_RefreshSensor();: f: A5 H. M  z0 P2 m% p
  9.                 User_MB_RefreshInputRegister();
    ! Q+ ^) z  _8 W2 p1 }9 M
  10.   _" M% d1 K; c9 |
  11.                 //100ms 一个处理周期
    / }% b; {0 U4 ^
  12.                 vTaskDelayUntil( &ticks, 100);
    & I9 M! ]$ G7 N7 z5 `  W3 V4 j2 M
  13.         }
    , d. y- R+ U8 |8 u6 [7 D1 M* A: Y
  14. }
复制代码
6 o; D- f* m5 C- i) c

2 L# o& D/ q: R, F( |7 P; w
" B. G9 R  q$ @2 ?! B7 \7 b- o% a
赞 收藏 评论0 发布时间:2022-4-13 17:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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