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

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

[复制链接]
STMCU小助手 发布时间:2022-4-13 17:00
片上ADC介绍* L8 f" L4 j3 B, U) W, d
STM32F103系列与STM32F407系列ADC的功能类似。它们总共有 3 个 ADC,精度为 12 位,每个ADC 有 16 个外部通道。另外还有两个内部 ADC 源和 VBAT通道挂在 ADC1 上。ADC 具有独立模式、双重模式和三重模式,对于不同 AD 转换要求几乎都有合适的模式可选。6 ^  Y3 d" ^, ?( A, ]

4 u# H" Y. P( ~! j$ v电压输入范围
5 u+ `! @6 u/ W% ^ADC 输入范围为:VREF- ≤ VIN ≤ VREF+。由 VREF-、VREF+ 、VDDA 、VSSA、这四个外部引脚决定。在设计原理图的时候一般把 VSSA和 VREF-接地,把 VREF+和 VDDA 接 3V3,得到ADC 的输入电压范围为:0~3.3V。; [7 a3 a7 n( ?
输入通道
; c. y. c$ l6 l7 J1 c% kSTM32 的 ADC 多达 19 个通道,其中外部的 16 个通道就是框图中的 ADCx_IN0、ADCx_IN1…ADCx_IN5。这 16 个通道对应着不同的 IO 口。
& B7 x( x- f3 d" U' d7 u, P; x4 q+ I1 h; g1 n( c! r2 W! O! S" n* F
对STM32F103系列单片机,ADC1的通道16连接到芯片内部的温度传感器,通道17连接到了内部参考电压 Vrefint。ADC2 的模拟通道 16 和 17 连接到了内部的 VSS。ADC3 的模拟通道 9、14、15、16 和 17 连接到了内部的 VSS。
! I% z: W4 u! P7 F4 `0 q; L
! N) i5 _' j7 h- p/ U& H0 |8 P! T对STM32F407系列单片机,ADC1的通道16连接到芯片内部的温度传感器,通道17连接到了内部参考电压 Vrefint,通道18连接到了备用电源 Vbat。ADC2 和 ADC3 的通道 16、17、18 全部连接到了内部的 VSS。4 r. v+ Y( Q5 X7 T- x; X

/ E  q$ F# d, y# J( H 202010231842394.png - i# N. _* r* V+ K8 j

& B7 a6 j$ t; |2 E: q3 g 20201023184248351.png
, ?( L; K+ e. T! B% i+ L! e+ {0 x% _) ~7 k) c. H; G9 q
& V9 r5 |7 ^: N  s5 p- U3 F0 O
扩展库特性
& D& x8 ~2 c+ n6 x. h. k! W& \本扩展库针对ADC最常见的操作方式,编写了两种ADC配置模板,其一是不使用DMA传输的单次单通道采样(void ADC_UserConfig1()),其二是使用DMA传输的连续多通道采样(void ADC_UserConfig2())。可根据需要在程序初始化的时候调用对应的配置函数实现ADC的快速配置。同时提供了在两种配置模式下的获取ADC数据与平均值数据的函数,也可在适合的位置直接调用。
# v# L0 w8 N& h( e+ ?0 H( Z- G9 \5 L+ x7 n
使用了本扩展库,ADC的配置与读取数据将会变得十分简洁高效。
2 _; J) v; ?0 M5 c) M) [
+ B9 G# t) G7 T扩展库源码1 {. s0 e+ A4 t; {! A) T
STM32F103与STM32F407的ADC在使用的时候还是有一些区别的:# W2 b% w8 Y4 h$ B% s
1.STM32F103的ADC需要校准,而STM32F407的ADC无需校准。9 n, `: \$ F' ?- G/ S
2.STM32F103与F407的ADC时钟配置、外设配置、DMA配置等不同。& u, [. R% P. e& a8 R+ D+ a

5 e: _# d1 }$ `" T7 }4 g5 A+ E5 A8 {基于STM32F103
/ k. _$ h- r8 b头文件

, ~, R" v* A; Q" Q: i3 I2 t
  1. #ifndef __ADC_EXT_H__
    7 L( ~2 ~- z1 _
  2. #define __ADC_EXT_H__        
    7 ^+ H0 o7 K5 O  n( _: k( Y
  3. . H8 ?& ]* I1 Z( G& v! e+ j
  4. #include "stm32f10x_conf.h"
    " T! H- g- M. }. b
  5. #include "stm32f10x.h"
    . M6 j9 C' t# m& h" H& J2 G

  6. # z( L- Z' a7 w& B' X- k
  7. #define ADC_CHANNEL_NUM                                4
    & W$ J: O4 \; L% ^" Q

  8. 1 D: o* ?0 ^1 E7 |4 r1 q* x
  9. #define ADC_DMA_CHANNEL_DEEPTH                10( U4 ?% P( h7 Q' y9 H+ o/ [% w8 Y
  10. #define ADC_DMA_CHANNEL_NUM                        ADC_CHANNEL_NUM
    7 X, u7 u4 m: O% r3 H+ u# C
  11. #define ADC_DMA_BUFFER_SIZE                        (ADC_DMA_CHANNEL_NUM * ADC_DMA_CHANNEL_DEEPTH)
    ( ^) ]% r; M+ @7 [

  12. 4 i6 q) y6 ~: U& N2 C  q
  13. extern volatile uint16_t ADC_Data[ADC_CHANNEL_NUM];
    . l0 T2 ]$ d& c$ M1 x
  14. extern volatile uint16_t ADC_DMA_Value[ADC_DMA_CHANNEL_DEEPTH][ADC_DMA_CHANNEL_NUM];
    ! c) y  r+ @3 o/ i3 x/ d' y4 }

  15. 4 {0 b7 b3 t& Q  c. Y! O
  16. void ADC_UserConfig1();& h, z4 [& S# c; M! l# E$ U
  17. void ADC_UserConfig2();0 d% B9 ~8 E7 }# P7 D: N3 S
  18. $ M+ V" i- |1 A( K; i3 B; E& @" h3 j$ J
  19. void ADC_Config_NotUseDMA();) R$ y( I5 w/ H8 h
  20. void ADC_Config_UseDMA();( ]7 i, d; _4 ?$ x7 J+ E
  21. void ADC_Config_SetDMA();" {1 p0 z! n1 V

  22. 6 W. p5 p6 v* ?. I; @+ B+ S
  23. uint16_t ADC_GetData_NotUseDMA(uint8_t channel);
    ' g6 d# Q1 f$ z) t. v
  24. uint16_t ADC_GetAverageData_NotUseDMA(uint8_t channel, uint16_t count);+ p9 D" q1 I+ v5 a
  25. uint16_t ADC_GetData_UseDMA(uint8_t channel);
    * Z1 d: D1 X8 p3 y+ g/ {+ b9 _
  26. uint16_t ADC_GetAverageData_UseDMA(uint8_t channel);( _5 C$ }/ s3 k% ]0 W

  27. / F5 s5 U1 h; f; J
  28. #endif * r* o3 F- [. ?$ v( D9 v
复制代码
+ Y) B* a5 H" {1 \( L) M: z/ J
源文件( |* s3 J9 J: K* H' J# D
  1. #include "adc_ext.h"* s# \: t: C# b
  2. ; h/ t' B  a9 ~% _! `/ v! z
  3. volatile uint16_t ADC_Data[ADC_CHANNEL_NUM];
    7 x; Q, r3 S/ q  Y& v
  4. volatile uint16_t ADC_DMA_Value[ADC_DMA_CHANNEL_DEEPTH][ADC_DMA_CHANNEL_NUM];9 F8 S, ]+ F' Z& H( A2 L2 c
  5. & v  K- r6 ~: B; {$ _
  6. /**% X) f* ^' n4 Y3 H5 R- C
  7. * @brief 预置的ADC配置1,不使用DMA传输
    * b( B8 C* I6 ]+ j, z9 d3 q6 K# Q3 R
  8. */
    ) M" j" c" P) Y9 A- m- f* G
  9. void ADC_UserConfig1()3 V; M# D: o. G$ k, E6 ~9 \9 ^, ~
  10. {
    2 W& |, R& \, v) {, Z! b
  11.         GPIO_ConfigPort('A', 0, GPIO_Mode_AIN, 0);
    $ u" f% {" K  t8 U; g0 n

  12. : O+ a) ^$ ]4 o7 p) J. s- D
  13.         ADC_Config_NotUseDMA();  H& E: E/ |- }7 C
  14. }$ j+ F- J1 ~- Z8 M. T
  15. " A; j3 l# B# A+ L2 Y8 b) V, x
  16. ' q, e( {! f& P  O
  17. /**
    + c! d+ B. {9 j; b% L5 y  ~
  18. * @brief 预置的ADC配置2,使用DMA传输
    6 p" e6 b  l9 ~+ Z/ t1 r' w
  19. */
    ' m3 B/ m4 t  p, q$ i. S# h: A' E
  20. void ADC_UserConfig2()
    # [, l; K% G' J' n
  21. {1 L' E3 l( S/ W' D& ^3 Y0 F
  22.         GPIO_ConfigPort('A', 0, GPIO_Mode_AIN, 0);
    , G+ U% V! k2 q6 I
  23.         GPIO_ConfigPort('A', 1, GPIO_Mode_AIN, 0);
    . E2 [6 x5 q% h6 V& s9 b
  24.         GPIO_ConfigPort('A', 2, GPIO_Mode_AIN, 0);& V- d* \" v" f# v8 ?# X
  25.         GPIO_ConfigPort('A', 3, GPIO_Mode_AIN, 0);
    ( c/ `  t$ m6 o2 [4 P3 p
  26.         
    : B3 Q8 G- q  h2 V, g8 I* F( E. X, w
  27.         ADC_Config_SetDMA();
    : \1 y; r- l5 q8 L6 W( q( J7 K' k
  28.         ADC_Config_UseDMA();
    0 h& ^/ \0 [9 O
  29. }
    $ H6 F+ d, K3 H
  30. 3 {2 O: \3 R( j+ L$ j  \
  31. - G) K. W1 F. h* ?5 Y4 j
  32. /**1 S3 k$ z! Q% G% q
  33. * @brief 不使用DMA进行数据传输时的ADC配置
    - G& G+ _) ~$ ?" g5 O
  34. *                 由于ADC 规则组数据寄存器 ADC_DR 只有一个,是一个 32 位的寄存器,
    ( C' u8 w) s4 G( x
  35. *                 只有低 16 位有效并且只是用于独立模式存放转换完成数据。
    & s4 {3 Z/ S/ T  v
  36. *                 如果使用多通道转换,那转换的数据就全部都挤在了 DR 里面,前一个时间点转换的通道数据,
    - Q: J) k' R8 K3 G% @( c
  37. *                 就会被下一个时间点的另外一个通道转换的数据覆盖掉,所以当通道转换完成后就应该把数据取走。
    + D1 }' f) q" e8 l
  38. *( F/ L* B, ^- h9 d5 H; z, L
  39. *                 因此不使用DMA模式的时候,每次只能读取一个通道的数据* ]+ _+ `( Q4 T  ]9 r
  40. */& I) S6 O" B  \1 @( Z$ O% h! q
  41. void ADC_Config_NotUseDMA()
    ! G1 {" f& z6 c8 x5 a1 r% C
  42. {9 c. V2 ?8 [) }/ ]* ~6 y4 a* D  i
  43.         /**
    # I1 b) I" }( O7 V1 n
  44.          * Configuration of ADC1: a6 w7 y9 C3 m, ^2 Q
  45.          */$ X5 y2 @- j" }/ n
  46.         ADC_InitTypeDef ADC_InitStructure;
    3 n) S2 `& g+ ]( B# A4 y  p7 g
  47. / Y4 s  X8 E) L% {3 R+ P
  48.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);                                                                        //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M: k7 ?4 W( A6 e) z
  49.         ADC_DeInit(ADC1);                                                                                                        //复位ADC1
    6 |, ?- d( ?9 G( v$ u
  50. : h+ h$ E' A1 |  A1 m
  51.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                                        //ADC工作模式:ADC1和ADC2工作在独立模式9 [: L8 _7 Z9 X( ]+ E
  52.         ADC_InitStructure.ADC_ScanConvMode = DISABLE;                                                //模数转换工作在单通道模式
    2 L1 Z% @2 B; f! w0 e/ P
  53.         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                                        //模数转换工作在单次转换模式* i6 l3 G$ U! ~9 |( T" e1 \8 q
  54.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动7 P3 D9 X% k& C
  55.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                                //ADC数据右对齐
    5 G/ |9 T# Q( L& P2 d& V
  56.         ADC_InitStructure.ADC_NbrOfChannel = ADC_CHANNEL_NUM;                                //顺序进行规则转换的ADC通道的数目4 u  F' r4 _. Z$ c& E* h1 v4 y
  57.         ADC_Init(ADC1, &ADC_InitStructure);                                                                        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器; M; m2 k9 r& `6 k

  58. * Q+ N2 ^3 Z) k- S3 e8 F# B- N
  59.         //        ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_71Cycles5);        //ADC1,ADC通道,采样时间为239.5周期7 x; {0 W" [* Q/ ~- c5 D) ~) d

  60. . P  b( Z1 a+ `9 @
  61.         ADC_Cmd(ADC1, ENABLE);                                                                                                //使能指定的ADC1
    ( R) b, N* b$ _1 w) D
  62. 8 a& |, e' J( t: a% e# F
  63.         ADC_ResetCalibration(ADC1);        //使能复位校准
    3 L' _' T" f/ \  u

  64. 4 U/ \" _3 P# w7 l5 P
  65.         while (ADC_GetResetCalibrationStatus(ADC1))* V8 `' V+ G/ ^
  66.                 ;        //等待复位校准结束
    & q6 M4 C9 V6 {; U( Q( ?
  67. ( b0 E* ?7 a1 F; Q3 O5 Y
  68.         ADC_StartCalibration(ADC1);         //开启AD校准
    * A9 Y8 V7 g" R* X4 X( p. S

  69. 4 R- X% J; G5 Y6 ^" ]4 y
  70.         while (ADC_GetCalibrationStatus(ADC1))
    " Z& k$ G$ U8 }5 `$ j7 T/ ]
  71.                 ;         //等待校准结束( c0 W9 Y, U5 q" V  x( F( \( i

  72. . C( x+ I3 |  {# m
  73.         //        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能
    ) w7 N& Z9 T. o5 v: `0 E" E
  74. }7 H4 c* s" ^4 j! i0 Q( a
  75. 4 Q4 M& B6 a% \" {* ?

  76. 6 t4 z% }' _, A0 i+ z: |% u
  77. /**( [6 ?3 n" w- s) r
  78. * @brief 使用DMA进行数据传输时的ADC配置
    ' h6 G! f* R4 d( y3 D
  79. *                 注意规则通道的数量需要根据实际项目进行调整- V, Z$ E* v5 F& w- E
  80. */
    - \; i1 F7 C+ ^+ ?$ ?+ i
  81. void ADC_Config_UseDMA()2 v  `4 q: [  p" o$ T, w* J6 H
  82. {/ j7 i( M, a7 o' H0 Y3 d6 }  N
  83.         /**
    : a; k' a, N, G* |. z0 \
  84.          * Configuration of ADC
    5 a1 n+ |. O: [4 |% K/ Z
  85.          */; \! A8 L1 ~- P) [
  86.         ADC_InitTypeDef ADC_InitStructure;8 ?' u) h$ ^0 B6 M! }% c; C

  87. % K# Q0 C3 v- w! f- x
  88.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);                                                        //使能ADC1通道时钟9 ]+ j' z# w" W
  89.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);                                                                                                //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M" q! r1 ?) a- l- _5 h2 Y4 Q
  90.         ADC_DeInit(ADC1);                                                                                                                                //复位ADC1
    / N/ ]+ W; n3 I8 g7 ?
  91. - F" P' t& {, @5 |
  92.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    9 p$ ?- L9 ~( m* S; f% e+ b7 b
  93.         ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                                                        //通道扫描
    ( V9 Y' |! n( `2 b" u" Q
  94.         ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                                                                //连续转换0 p, j! U! U" O% ?
  95.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    . V/ j5 ^. |, h4 A
  96.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;! @# m% t  c; d- [
  97.         ADC_InitStructure.ADC_NbrOfChannel = ADC_CHANNEL_NUM;  P+ |1 M! m) V# ?+ _( \% _# S
  98.         ADC_Init(ADC1, &ADC_InitStructure);/ q5 [/ e  {9 g' g. g  Q
  99. % o$ |8 s- x: z, s8 G5 s
  100.         ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);        //通道1转换结果保存到ADCConvertedValue[0~10][0]: z2 |2 j! d% j8 x* q4 A, N
  101.         ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5);         //通道2转换结果保存到ADCConvertedValue[0~10][1]& u* t6 h. ^8 U4 f) i
  102.         ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5);         //通道3转换结果保存到ADCConvertedValue[0~10][2]
    3 R0 P( J  A) |8 ?8 R
  103.         ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5);         //通道4转换结果保存到ADCConvertedValue[0~10][3]
    / u4 ]9 P3 j' v7 j
  104.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5, ADC_SampleTime_239Cycles5);         //通道5转换结果保存到ADCConvertedValue[0~10][4]
    $ p4 v2 \1 Q( I* F) E; T* t" q
  105.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_239Cycles5);         //通道6转换结果保存到ADCConvertedValue[0~10][5]
    + O3 K6 s5 H/ R2 T2 [" A5 Q
  106.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 7, ADC_SampleTime_239Cycles5);         //通道7转换结果保存到ADCConvertedValue[0~10][6]) f% T% k- K! g" g  W6 s" _7 f" h
  107.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 8, ADC_SampleTime_239Cycles5);         //通道8转换结果保存到ADCConvertedValue[0~10][7]9 |  b* k$ m; v4 h9 _" M# c
  108.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 9, ADC_SampleTime_239Cycles5);         //通道9转换结果保存到ADCConvertedValue[0~10][8]
    1 G9 I; a! K- ~7 L
  109.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 10, ADC_SampleTime_239Cycles5);         //通道10转换结果保存到ADCConvertedValue[0~10][9]
    ) A& I5 v1 M- l3 R& n
  110.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 11, ADC_SampleTime_239Cycles5);         //通道11转换结果保存到ADCConvertedValue[0~10][10]
    ; b# Q- ?' A. O  K; }# M
  111.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 12, ADC_SampleTime_239Cycles5);         //通道12转换结果保存到ADCConvertedValue[0~10][11]
    , A" l* Q) i" R9 u" A
  112.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 13, ADC_SampleTime_239Cycles5);         //通道13转换结果保存到ADCConvertedValue[0~10][12]
    ; L( [  w6 T* C: h) Q
  113.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 14, ADC_SampleTime_239Cycles5);         //通道14转换结果保存到ADCConvertedValue[0~10][13]0 f4 T0 c7 e/ K8 k! M
  114.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 15, ADC_SampleTime_239Cycles5);         //通道15转换结果保存到ADCConvertedValue[0~10][14]1 n" N  A# u" k  J1 A
  115.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 16, ADC_SampleTime_239Cycles5);         //通道16转换结果保存到ADCConvertedValue[0~10][15]
    9 X7 U  S. x# w/ H% S

  116. 3 k; t6 Q$ t- N
  117.         ADC_DMACmd(ADC1, ENABLE); //开启ADC的DMA支持8 ~! [/ R, A3 R  t
  118.         ADC_Cmd(ADC1, ENABLE);
    4 T& G. t8 ~, t$ n4 M
  119.         ADC_ResetCalibration(ADC1);
    ! H1 ?. B2 @; B5 ?6 P
  120.         while (ADC_GetResetCalibrationStatus(ADC1))# ?6 w+ J6 y0 q2 U) b! C( a
  121.                 ;
    ! @- w+ j% A8 a) n9 {
  122.         ADC_StartCalibration(ADC1);6 N. s& o7 k: e; g; U5 ?; `
  123.         while (ADC_GetCalibrationStatus(ADC1)), c$ t( L8 Q- z. a( g2 ?. A
  124.                 ;
    4 k5 j; l, u- b6 k5 Z
  125.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能( y# L) z! S; P
  126. }# s2 X! P$ r9 U% q/ e' \. n# q, g

  127. , w! ~+ a- [! ~: h

  128. : K3 O+ L, v# p; A% _
  129. /**
    , n1 [+ v- c2 m  o( L
  130. * @brief 使用DMA进行数据传输时的DMA配置4 D. d0 j% f9 O; {) u
  131. */
    1 c+ ]8 ]9 d4 J& Q* B
  132. void ADC_Config_SetDMA()( E5 T* f' N# b# y+ \( n2 }
  133. {- W1 ^/ R$ o! h; W% J' }0 X) v
  134.         /**
    $ b# U" h, Z9 I* ?2 {7 ^% m4 N
  135.          * Configuration of DMA  {/ M( C$ W+ G; @6 d- q/ t( l
  136.          */' ~3 X! R+ H7 Q1 j; O. S. O
  137.         DMA_InitTypeDef DMA_InitStructure;
    " ^0 Z7 V) g0 I$ M
  138.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                                                                //使能时钟
    3 n! D. ?! f7 V: H6 x* N
  139.         DMA_DeInit(DMA1_Channel1);                                                                                                                //将通道一寄存器设为默认值
    # h% r  e3 {% `# w% S" Z

  140. % z0 x( c% q2 G5 O' M4 G" z4 X# {1 V
  141.         DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(ADC1->DR);                                //该参数用以定义DMA外设基地址
    0 U. M2 I0 l' ?  @2 j
  142.         DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) &ADC_DMA_Value;                                //该参数用以定义DMA内存基地址(转换结果保存的地址)5 B8 K. Y/ M$ c2 L+ Y- y
  143.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                                                //该参数规定了外设是作为数据传输的目的地还是来源,此处是作为来源
    : D/ X* O7 g0 c6 _. J+ S
  144.         DMA_InitStructure.DMA_BufferSize = ADC_DMA_BUFFER_SIZE;                                                        //定义指定DMA通道的DMA缓存的大小,单位为数据单位。这里也就是ADC_DMA_Value的大小
    2 R( Q# s8 V9 x8 f3 H+ l& ~) x9 m
  145.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                                //设定外设地址寄存器递增与否,此处设为不变 Disable
    6 y4 g. |4 z7 y* w; c1 B. M
  146.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                                        //用来设定内存地址寄存器递增与否,此处设为递增,Enable5 ^0 [( ~; u0 S
  147.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;                //数据宽度为16位% r1 A! Z# p* N# Z, y
  148.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                                //数据宽度为16位
    2 R  G* ]7 j5 ?* O
  149.         DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                                                 //工作在循环缓存模式5 X3 K3 Q- P1 m2 i+ X% A8 L- \1 C
  150.         DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                                         //DMA通道拥有高优先级 分别4个等级 低、中、高、非常高! p# j3 `3 p" \' \3 X3 A
  151.         DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                                                         //使能DMA通道的内存到内存传输
    ' d0 {+ d- S$ S/ c) P

  152. / O4 o, q: }! W8 m" {4 \
  153.         DMA_Init(DMA1_Channel1, &DMA_InitStructure);                                                                         //根据DMA_InitStruct中指定的参数初始化DMA的通道: o$ H+ ]2 ]4 b9 b
  154.         //        DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE);$ E! t. J9 I6 N5 L5 m" V. e1 U" R7 k
  155.         DMA_Cmd(DMA1_Channel1, ENABLE);                                                                                                        //启动DMA通道一
    # K& X4 D& G: j+ c' Q
  156. }9 X5 w1 y8 K* l. F5 ~

  157. ' _$ D; f5 c5 t, ?5 V, \
  158. 3 g4 ~7 D* \( h- C9 ^4 K
  159. /*** @  F" e9 C% H/ G$ Z$ B" M
  160. * @brief 不使用DMA传输时,获取ADC的采样数据
    ) k' `; g3 V+ Q
  161. * @param channel: ADC的采样通道
    2 p3 T' d; M7 V9 _( W8 F6 m
  162. * @return ADC的单次采样结果  L  D. C$ E4 V$ ~( a
  163. */! o6 w9 K6 r& I: H( z- n
  164. uint16_t ADC_GetData_NotUseDMA(uint8_t channel)
    ; ^; D  I; p: E3 U6 A% v1 L& R/ r- ?
  165. {
    * _  A- Q. u+ N# U+ w
  166.         //设置指定ADC的规则组通道,一个序列,采样时间/ y+ T8 v3 c  {! a& T7 j6 F
  167.         ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_71Cycles5);        //ADC1,ADC通道,采样时间为239.5周期3 |3 M: ?  O" z& T0 p
  168. + {& a; |8 m) `: s  m9 p2 u
  169.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能
    ( [' n9 Z! M3 c, p* b* X1 @

  170. / k$ l7 S* W* b7 t& ^
  171.         /**
    ; T( v/ w  [% [, r# d
  172.          * 通过查询的方式获取了ADC的转化结果,: P7 F: s4 u! j1 L1 [- q9 }( M6 M4 H
  173.          * 也可以通过中断的方式获取ADC的转换结果# t! m+ {0 o) G2 I& g+ y0 M4 C) J$ T
  174.          */
    % a' ?* R, u: @; A- o/ S( d- g
  175.         while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)): {1 f- v) y" G9 U8 n, O
  176.                 ;                //等待转换结束
    - t( s9 T$ u! d, E  t! s6 b
  177.         return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果
    8 G9 n! T; ]+ i+ I' [
  178. }9 {2 x  p3 I5 M; Q+ c

  179. / _  l/ o! J4 a" Y% ^

  180. ' O8 z* x9 m  e- P- q! G/ W
  181. /**! X, w3 X) F( g- \  E2 m% L
  182. * @brief 不使用DMA传输时,获取ADC采样数据的平均值0 C  |6 F, B8 X! Y) c: \: z
  183. * @param channel: ADC的采样通道$ W8 W5 V+ K9 c7 z$ [8 _* j$ w  a
  184. * @param count: 计算平均值的采样数量% \, E* ~2 r6 E( Q' n/ j
  185. * @return ADC的单次采样结果的平均值4 N* [. d* W" A& ?
  186. */
    7 E% N& V5 y+ F) H
  187. uint16_t ADC_GetAverageData_NotUseDMA(uint8_t channel, uint16_t count)! q6 K) e. X4 |3 \8 C# s# u: {
  188. {7 |8 g6 S) p9 ^5 j1 W2 Q5 Q
  189.         uint32_t temp_val = 0;
    # c* ?% b. z" t% r$ M! o

  190. & N/ _; y  i4 z' e- b" Z
  191.         for (uint8_t t = 0; t < count; t++)
    & n2 M7 d; {- E9 j. S7 I7 p5 y5 S
  192.         {5 p" |$ ~: v' l' c# }1 {
  193.                 temp_val += ADC_GetData_NotUseDMA(channel);
    * C) L: T% l5 C3 R8 w1 x9 ~
  194.         }3 y7 R, C8 n4 ]9 I
  195. # m: K( |9 N  y4 R. f( X
  196.         ADC_Data[channel] = temp_val / count;
    2 b7 m& @; ?  ?$ N
  197. 2 G+ M# j1 m" Z6 p& u  `
  198.         return ADC_Data[channel];
    - o" l0 @7 V4 F
  199. }% @1 S; \% x* M
  200. * \/ O. Y6 f6 E, s, c
  201. . S6 X: ]$ @" I! y5 E9 I; c$ _
  202. /**' n, i7 B) b, Z3 n
  203. * @brief 获取通过DMA传输的采样数据) ^7 k7 z6 E" G" Q2 Y
  204. * @param channel: ADC的采样通道
    5 x; d6 a- w6 P% Z# B
  205. * @return ADC的采样数据# W% y! \% b2 G4 U4 L
  206. */
    / l3 M6 H3 J, N6 J9 i9 K
  207. uint16_t ADC_GetData_UseDMA(uint8_t channel)
    - T  F9 ]4 d" x0 Z
  208. {
    2 }) A$ M+ Q; A, Z; y) l* ?9 {
  209.         return ADC_DMA_Value[0][channel];
    ; B0 D/ ?1 y- B* `4 i* h
  210. }5 ?+ p$ L' Q' j& n) y  K( P: g

  211. $ h8 M+ z6 }! }" b" [; P
  212. ; g6 D2 S8 E' T& Z
  213. /**
    4 t8 F1 ~$ Q( F. w1 z2 B; u
  214. * @brief 获取通过DMA传输的采样数据(求平均值,过采样)5 t$ o" ?9 E. @0 Y
  215. * @param channel: ADC的采样通道: o/ h5 q; i3 I0 v/ v( g7 A4 h1 q. Q9 a
  216. * @return ADC的采样数据# N, N5 j* h: K4 D' n* H
  217. */# ]4 G, t) U8 V: p
  218. uint16_t ADC_GetAverageData_UseDMA(uint8_t channel)
    - s+ {. Z$ F7 L( z+ Y7 A% L; p: ^
  219. {$ y0 e2 T+ n4 y, ~! a! r
  220.         uint32_t sum = 0;2 }* f7 K6 Q, J, ^% t

  221. 3 c# m+ U$ P" X1 T
  222.         for (uint8_t j = 0; j < ADC_DMA_CHANNEL_DEEPTH; j++)
    # F* W/ |6 O7 D. d5 B0 \
  223.         {
    " F/ P6 L* \( i- V, z! c/ r. i
  224.                 sum += ADC_DMA_Value[j][channel];
    6 f+ X$ L" z& q0 S
  225.         }
    $ A7 d" e6 T6 h; ]* h; m6 g3 W

  226. ; g8 b$ n) J7 p4 l& ]( Y/ t
  227.         return sum / ADC_DMA_CHANNEL_DEEPTH;                                                //求平均值并转换成电压值
    : Z) {& q) t& _- l
  228. }
复制代码

) K# |+ v, u8 z9 e0 `+ X2 M基于STM32F407
  D+ _4 `4 Y" B头文件

5 k8 a+ q' `: e# u
  1. #ifndef __ADC_EXT_H__
    $ ?# B% F6 a' T% g3 H; N8 q
  2. #define __ADC_EXT_H__        6 I, ?* T9 ^8 j
  3. 8 f: I( e$ w4 @$ M3 L
  4. #include "stm32f4xx_conf.h"
    6 x8 G$ @  }3 i! J
  5. #include "stm32f4xx.h"2 O3 ?3 z# C) O% n/ H

  6. 9 w  g3 A. j; S# t  w  B& b
  7. #define ADC_CHANNEL_NUM                                        4
    3 C; F- U2 Z4 H3 G

  8. # a5 [5 \, f$ T5 |
  9. #define ADC_DMA_CHANNEL_DEEPTH                        10
    * P4 {- G% l( n
  10. #define ADC_DMA_CHANNEL_NUM                                ADC_CHANNEL_NUM
      }1 k0 i% l6 W) g' o
  11. #define ADC_DMA_BUFFER_SIZE                                (ADC_DMA_CHANNEL_NUM * ADC_DMA_CHANNEL_DEEPTH)
    2 k: i2 a0 s! r/ y* C: a; Q$ Z
  12. $ w( e' Z; q3 N
  13. extern volatile uint16_t ADC_Data[ADC_CHANNEL_NUM];5 V$ d4 s. ]1 ]0 l2 k
  14. extern volatile uint16_t ADC_DMA_Value[ADC_DMA_CHANNEL_DEEPTH][ADC_DMA_CHANNEL_NUM];. }$ Q8 d" C1 K% n/ C/ M

  15. 7 Z2 C7 F8 w8 s3 I' I
  16. void ADC_UserConfig1();
    $ B- T5 c# c3 Z  w) T0 \( f
  17. void ADC_UserConfig2();2 H% [% w& \5 i0 q# j- b

  18. 0 n& Z( B0 F+ Y9 D% U+ T
  19. void ADC_Config_NotUseDMA();: m6 h& r8 F; y, }7 n6 V+ c* h# s% L
  20. void ADC_Config_UseDMA();
    4 ?4 k8 I) C$ h" B0 ]. i# Q& q
  21. void ADC_Config_SetDMA();+ z1 O$ N" h3 Y3 W" j. c' L% ^
  22. ( d; G$ t3 s: S2 Z3 w2 k! G& Y3 y
  23. uint16_t ADC_GetData_NotUseDMA(uint8_t channel);1 I/ ^8 R5 X' E! d
  24. uint16_t ADC_GetAverageData_NotUseDMA(uint8_t channel, uint16_t count);
    - [; x& l8 r* y8 |
  25. uint16_t ADC_GetData_UseDMA(uint8_t channel);
    6 \/ D) M+ G  m+ |& |0 f/ Z4 Q2 T4 S
  26. uint16_t ADC_GetAverageData_UseDMA(uint8_t channel);  Z1 r; U0 l  c
  27. * F% g' w3 H+ M2 E
  28. #endif
复制代码
8 b: ^" s" y7 \5 `3 S. M9 q
源文件7 T8 \; k# R% U9 y
  1. #include "adc_ext.h", O9 R1 A9 x1 x  l

  2. * F, ]8 m9 |. {1 R5 k5 M0 W
  3. /**4 [8 o, V0 O. u7 P" F
  4. * ADC时钟  U  `0 Q8 C) s8 {% T+ ?
  5. *3 f) R4 e4 g* n2 Z! a0 u
  6. * ADC输入时钟 ADC_CLK 由 PCLK2 经过分频产生,最大值是 36MHz,典型值为30MHz
    - h) T: f& Q' R1 w4 f6 l: K
  7. * 分频因子由 ADC 通用控制寄存器 ADC_CCR 的 ADCPRE[1:0]设置,可设置的分频系数有 2、4、6 和 8
    * w0 V- Q, ~- k! Q# N+ {
  8. * 对于STM32F407的PCLK2=HCLK/2=84MHz,所以程序一般使用 4 分频或者 6 分频) O' m! x7 U$ _( ^, P8 H! H
  9. */
    2 X( I* f0 V- Q/ U

  10. 1 h/ _# w8 x/ R5 Y; ^- w
  11. /**+ M7 I0 R' q2 R6 u3 ]$ i: D
  12. * 采样时间
      v8 d7 W, ^0 G& G/ T) i
  13. *' Y+ L8 g4 u, H: k/ J
  14. * ADC 需要若干个 ADC_CLK 周期完成对输入的电压进行采样,$ s1 i9 D4 i8 F# m" |; N( \
  15. * 采样的周期数可通过ADC 采样时间寄存器 ADC_SMPR1 和 ADC_SMPR2 中的 SMP[2:0]位设置。
    ' \& A. W& R) A; ?
  16. * 每个通道可以分别用不同的时间采样。
    4 D$ H* `' A7 Q; T3 H: j  X
  17. * 其中采样周期最小是 3 个,即如果我们要达到最快的采样,那么应该设置采样周期为 3 个周期。& a! Y- ?4 F! D0 q) b' }8 Q/ e
  18. * 这里说的周期就是 1/ADC_CLK。
    6 p3 P* K( S" p' Q
  19. *// @7 m4 B" R* @- Z3 x. f

  20. * a& u- `" l$ Q7 U) D' I# t
  21. /**& Z+ h$ O' q1 `3 f8 P
  22. * 注意本库函数只实现了ADC1的配置与采样,ADC2与ADC3的配置与使用方法与此类似, M2 f& P* I) ]* b5 o
  23. */: d3 u" m1 Y; v  }, B
  24. 9 o% H; T1 W0 F; [) w: g. |
  25. volatile uint16_t ADC_Data[ADC_CHANNEL_NUM];! Q. N/ o. s7 X* N2 S- C
  26. volatile uint16_t ADC_DMA_Value[ADC_DMA_CHANNEL_DEEPTH][ADC_DMA_CHANNEL_NUM];% p2 k7 \* _8 V
  27. 2 B' H0 w) J5 f3 N& k
  28. /**" y# ]" F# ?- ]$ r" |; a. n
  29. * @brief 预置的ADC配置1,不使用DMA传输
    ! i6 o# v4 |* z/ [# W
  30. */5 {# U% P/ `* D, L- @1 ^
  31. void ADC_UserConfig1()
    # ^7 C+ L9 P. I( j3 u
  32. {7 l6 C; _& l) M
  33.         GPIO_ConfigPort('A', 0, GPIO_Mode_AN, GPIO_OType_OD, GPIO_PuPd_NOPULL, 0);" E; k8 }6 t  T* d" @
  34.         
    3 j5 Q/ P8 v( M
  35.         ADC_Config_NotUseDMA();
    ' V" u' n2 d6 \( n4 x3 D3 T* P
  36. }
    + F. ?3 H3 C: l5 b0 G

  37. , H' F+ D. A" L
  38. / V4 i. T/ Q2 C- K9 h; b  C. Y4 X
  39. /**
    ; E) G4 @3 w" x8 z! l, O! R  W
  40. * @brief 预置的ADC配置2,使用DMA传输# Q- r& \; f: f
  41. */$ q% E) Q$ f, ?  f) V
  42. void ADC_UserConfig2()
    5 `# Z6 [2 G2 }0 ]1 n
  43. {
    0 [$ ?: p" O. |* \% x, }& m
  44.         GPIO_ConfigPort('A', 0, GPIO_Mode_AN, GPIO_OType_OD, GPIO_PuPd_NOPULL, 0);
    9 z8 I5 V3 ]' c2 u4 k* p
  45.         GPIO_ConfigPort('A', 1, GPIO_Mode_AN, GPIO_OType_OD, GPIO_PuPd_NOPULL, 0);
    5 |, @# A0 ]2 @- G9 i
  46.         GPIO_ConfigPort('A', 2, GPIO_Mode_AN, GPIO_OType_OD, GPIO_PuPd_NOPULL, 0);
    4 x2 @% w7 v6 u
  47.         GPIO_ConfigPort('A', 3, GPIO_Mode_AN, GPIO_OType_OD, GPIO_PuPd_NOPULL, 0);
    6 T2 A+ K0 C0 _1 g$ L
  48.         
    ! ^7 u6 }1 s: ^
  49.         ADC_Config_SetDMA();+ W, l& F5 D& K% f7 ~/ M
  50.         ADC_Config_UseDMA();
    . m' t- R# d6 O( e8 M% e5 [: X+ b- r
  51. }9 k6 Z: E6 h* \4 @8 b6 `' b

  52. / ]. p- |& r- ?) E
  53. " Q& k7 e: h( P6 t$ r) B5 D
  54. /**
    * p2 d0 \' T3 Q. N
  55. * @brief 不使用DMA进行数据传输时的ADC配置
    1 T# b8 D/ ]# P5 \$ L9 e9 a
  56. *                 由于ADC 规则组数据寄存器 ADC_DR 只有一个,是一个 32 位的寄存器,& s* z+ N9 T7 t/ q# C2 n. y  G
  57. *                 只有低 16 位有效并且只是用于独立模式存放转换完成数据。# S+ z+ w+ _& V
  58. *                 如果使用多通道转换,那转换的数据就全部都挤在了 DR 里面,前一个时间点转换的通道数据,
    2 g* s+ f7 w& @6 ]9 r
  59. *                 就会被下一个时间点的另外一个通道转换的数据覆盖掉,所以当通道转换完成后就应该把数据取走。# V* Q5 }: l) c6 _: v, R# W2 M
  60. *
      q5 v& w* _6 g! Z& R
  61. *                 因此不使用DMA模式的时候,每次只能读取一个通道的数据
    + }- g9 J& e# k9 D4 P$ U
  62. */0 B' Q' ?' O/ x4 L" e
  63. void ADC_Config_NotUseDMA()
    ; h+ U1 P& Q& l: D0 C! J
  64. {1 G9 X3 {! a3 P
  65.         /**; f/ K% C" ^" I: d- [6 H
  66.          * Configuration of ADC) }6 }% X+ s; x1 X1 |
  67.          */
      O4 `8 w: r: M/ D

  68. % j7 c- H# z" K0 y, \1 Q) l
  69.         ADC_CommonInitTypeDef ADC_CommonInitStructure;* y/ p! o# G; m

  70. & p/ B5 N. Q, ]/ I2 D
  71.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);                                                                                                //使能ADC1时钟
    ; _/ d8 |. Z8 t7 P
  72.         ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;                                                                                //独立ADC模式( ]( Q8 Z: [' t0 D. N9 y3 Y/ M0 w  n# s
  73.         ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;                                                                                //ADC时钟为fpclock/分频; N3 g) ^% L; Q4 Q4 T: {
  74.         ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;                //禁止DMA直接访问模式! _+ z! N& Q& j! l+ H3 j/ T
  75.         ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;        //采样时间间隔( O2 s# N5 q+ |* @- y4 L

  76. 6 ~7 V% a! p/ @5 s1 O
  77.         ADC_CommonInit(&ADC_CommonInitStructure);) T1 _8 L% f  Z% P" h& \

  78. . h. M! M. g5 b
  79.         ADC_InitTypeDef ADC_InitStructure;
    / {' _; T+ h% W% G3 N4 b- k9 Q

  80. 0 }( ~# P4 O* L; f# j" F6 Z  u
  81.         ADC_StructInit(&ADC_InitStructure);0 c. o$ V$ K! E
  82.         ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;                                                                //设置ADC的分辨率12位! I5 l! b- o4 a# o/ L8 ]
  83.         ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                                                                        //通道扫描模式
    6 D  _( P" Q/ P2 @3 o7 \8 G
  84.         ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                                                                //连续转换模式
    4 Y& C+ _" c+ `& F8 S0 D4 L' a/ B! ?

  85. . P1 a0 f' ?6 k; `- _: f7 u
  86.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None;        //禁止外部边沿触发. T, U  g( w8 H9 D2 d: q" b( X! a5 z) i
  87.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;                //外部触发通道
    7 h! W3 \; Y8 W+ i. d
  88.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                                                                //设置数据右对齐# {7 B$ E- O# l) ~) t; H: t
  89.         ADC_InitStructure.ADC_NbrOfConversion = 1;                                                                                                        //设置转换通道,固定为1
    % U7 ~- S$ r) M& O
  90.         ADC_Init(ADC1, &ADC_InitStructure);$ j# H; @8 v4 g! T( Q4 Y
  91. ; z0 X; o  }4 @/ R! N
  92.         ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_56Cycles);                        //配置 ADC 通道转换顺序和采样周期
      x- T: k; \1 M8 T9 y2 I
  93. " H6 q3 D4 u4 a! [% t) E
  94.         //        ADC_ITConfig(RHEOSTAT_ADC, ADC_IT_EOC, ENABLE);                                                                                                //ADC 转换结束产生中断,可以在中断服务程序中读取转换值! D& M1 Z) W/ U% m* ]

  95. # U& R, _" f& B; q/ }! J
  96.         ADC_Cmd(ADC1, ENABLE);                                                                                                                                                                                                //使能ADC+ D/ o& G$ j; x
  97. }- e# R8 w8 p/ _: d; _+ ~( U
  98. , N; }& D+ r3 U! e
  99. & O, B2 Z, @* `1 s  ^0 |
  100. /**4 @) S% ^7 J$ {1 n
  101. * @brief 使用DMA进行数据传输时的ADC配置  J6 M% c* b  J! K! u
  102. *          注意规则通道的数量需要根据实际项目进行调整
    " z) \5 N* w2 B( F$ r* Y, a: T
  103. */* i3 L; j4 V3 J+ J" Z2 {+ M! n, \% o
  104. void ADC_Config_UseDMA()1 a9 g9 l4 Q2 e5 R' @; G
  105. {
    4 J6 U" E! _$ Z& g2 n; f
  106.         /**% ~4 y3 c! |* X9 R
  107.          * Configuration of ADC
    " ~  x& I  W! b- ]+ _% z
  108.          */( M: @0 R. T3 B5 r8 z/ E
  109.         ADC_CommonInitTypeDef ADC_CommonInitStructure;) }" O: q3 r% i% w

  110. 9 D0 h0 ~1 \) s; A5 f
  111.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);                                                        //使能ADC1时钟
    ' L' b% E( H' p
  112.         ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;                                        //独立ADC模式* H6 y: ], d+ T
  113.         ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;                                        //ADC时钟为Fpclock/分频
    ( U, k7 d, R& L- \
  114.         ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;                //禁止DMA直接访问模式
      {& G3 X& c( x
  115.         ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;        //采样时间间隔7 r# m, u0 Q. i& y

  116. 3 n0 b3 B3 R5 q3 r& J; r
  117.         ADC_CommonInit(&ADC_CommonInitStructure);
    . A, `! F& i/ l  U7 C
  118. 5 F- q& W: }: d3 Z: s+ M6 R
  119.         ADC_InitTypeDef ADC_InitStructure;
    6 |# b, z6 a: q  b" G; B1 [) V

  120. 1 i/ n, [7 n# j, o8 N6 b( H
  121.         ADC_StructInit(&ADC_InitStructure);
    : M2 k2 w, R* p3 Z" ^% Z
  122.         ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;                                                                //设置ADC的分辨率12位5 @8 r5 x; f9 u
  123.         ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                                                                        //通道扫描模式
    % o: I6 |) F$ v% v/ ?
  124.         ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                                                                //连续转换模式
    . f1 O+ r5 U. L. t2 l
  125. 1 R: m: ~& [% X- K9 ~! V6 G
  126.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None;        //禁止外部边沿触发
    9 n8 s, i, J9 F5 O6 N4 E
  127.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;                //外部触发通道
    2 L% p( M" e- n3 s% H% `5 h
  128.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                                                                //设置数据右对齐
    , w& C# Y  L' y  A! Q
  129.         ADC_InitStructure.ADC_NbrOfConversion = ADC_CHANNEL_NUM;                                        //设置转换通道
    1 U8 L! H1 ]" k  h( S
  130.         ADC_Init(ADC1, &ADC_InitStructure);8 s2 f/ r& J  c9 J

  131. # x: W# y/ y7 f2 f
  132.         ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);                //通道1转换结果保存到ADCConvertedValue[0~10][0]
    & o+ u& ^" {7 E; C$ Y: f+ g! {; y
  133.         ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_3Cycles);                 //通道2转换结果保存到ADCConvertedValue[0~10][1]
    ' j- O8 B) k" x5 }$ U- G& @
  134.         ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_3Cycles);                 //通道3转换结果保存到ADCConvertedValue[0~10][2]  A- @. ?$ E0 ~+ l, {* g; p1 K1 Z3 B# V
  135.         ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_3Cycles);                 //通道4转换结果保存到ADCConvertedValue[0~10][3]
    . _% V% O5 o+ p( ~
  136.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5, ADC_SampleTime_3Cycles);                 //通道5转换结果保存到ADCConvertedValue[0~10][4]
    ! I" v5 B( S1 @
  137.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_3Cycles);                 //通道6转换结果保存到ADCConvertedValue[0~10][5]; S* K' k: Y, H2 ]/ {# W
  138.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 7, ADC_SampleTime_3Cycles);                 //通道7转换结果保存到ADCConvertedValue[0~10][6]! }- T$ X; I/ I' y% r
  139.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 8, ADC_SampleTime_3Cycles);                 //通道8转换结果保存到ADCConvertedValue[0~10][7]1 e% S3 e& d$ j0 _4 G+ f, h
  140.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 9, ADC_SampleTime_3Cycles);                 //通道9转换结果保存到ADCConvertedValue[0~10][8]
    7 r: A7 B; t3 A& o+ n
  141.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 10, ADC_SampleTime_3Cycles);         //通道10转换结果保存到ADCConvertedValue[0~10][9]
    ; X, I7 t" j  ^% p
  142.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 11, ADC_SampleTime_3Cycles);         //通道11转换结果保存到ADCConvertedValue[0~10][10]
    & n6 o3 V# E5 D! J8 O. e
  143.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 12, ADC_SampleTime_3Cycles);         //通道12转换结果保存到ADCConvertedValue[0~10][11]) C) |' \- U* Q# u; V
  144.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 13, ADC_SampleTime_3Cycles);         //通道13转换结果保存到ADCConvertedValue[0~10][12]
    $ F4 T. X5 H' }6 y6 \3 y6 A
  145.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 14, ADC_SampleTime_3Cycles);         //通道14转换结果保存到ADCConvertedValue[0~10][13]
    9 @( J- K3 ~0 Q
  146.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 15, ADC_SampleTime_3Cycles);         //通道15转换结果保存到ADCConvertedValue[0~10][14]
    $ W4 Y" b: V0 e" ]& c2 ?
  147.         //        ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 16, ADC_SampleTime_3Cycles);         //通道16转换结果保存到ADCConvertedValue[0~10][15]
    ; o# ?+ i1 }6 @" b! q5 I2 ~

  148. ) u' E7 r+ ^5 N" R% H% {
  149.         ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);                                                                                                        // 使能 DMA 请求 after last transfer (Single-ADC mode)% H, o0 Y5 g6 z; F' u9 R$ Z
  150.         ADC_DMACmd(ADC1, ENABLE);                                                                                                                                                                                 //开启ADC的DMA支持# U9 _9 I1 g8 z% x
  151.         ADC_Cmd(ADC1, ENABLE);                                                                                                                                                                                                //使能ADC
    , I9 e, p5 C8 f  n8 @
  152.         ADC_SoftwareStartConv(ADC1);                                                                                                                                                                                //开始ADC转换,软件触发
    5 S# l  n% `5 ^( e% V* q
  153. }- c' ^% N  z, q
  154. & [% j7 R& y. L2 g9 E: L

  155. 3 m& H3 D. s# C2 A) r2 O8 L) r+ e; A
  156. /**$ Q( L; A; U* O- `5 K) D
  157. * @brief 使用DMA进行数据传输时的DMA配置
    7 u4 P: t! U% E* ?& |# I$ w
  158. */
    % t* L6 ^9 [  ~; b) w7 @
  159. void ADC_Config_SetDMA()
    0 X2 Z5 e& B$ C& q! |* d
  160. {* u: q9 B- N* R& c3 k2 P# i% q
  161.         /**# ~- w- ~/ t9 {2 Z( I6 v
  162.          * Configuration of DMA
    / I1 [# ?: D- ?+ k% k
  163.          */
    2 B2 L& T, m7 C! ^" L3 u
  164.         DMA_InitTypeDef DMA_InitStructure;
    % q4 j4 d! h2 D! ~4 w
  165.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);                                                                //使能时钟
    9 |1 ^  W2 V4 A8 P# p: U! H# @
  166.         DMA_DeInit(DMA2_Stream0);                                                                                                                                                                //将通道一寄存器设为默认值' }# _% @6 z/ x' [7 O! j5 ]
  167. 0 M4 n6 _8 M, S' p' m9 Q- `
  168.         DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(ADC1->DR);                                //该参数用以定义DMA外设基地址: |, E% m: B! u" E
  169.         DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &ADC_DMA_Value;                        //该参数用以定义DMA内存基地址(转换结果保存的地址)
    + a( L! L2 h0 b! {- j2 @2 c, {
  170.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                                                        //该参数规定了外设是作为数据传输的目的地还是来源,此处是作为来源
    + N% w- T* n2 D# c
  171.         DMA_InitStructure.DMA_BufferSize = ADC_DMA_BUFFER_SIZE;                                                                //定义指定DMA通道的DMA缓存的大小,单位为数据单位。这里也就是ADC_DMA_Value的大小+ c: _3 t6 v4 B( j
  172.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                                        //设定外设地址寄存器递增与否,此处设为不变 Disable2 R% R8 B0 I0 j" Q( Z$ y
  173.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                                        //用来设定内存地址寄存器递增与否,此处设为递增,Enable$ @/ {3 x8 S' a: o0 [. I+ L. y5 Y
  174.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;                //数据宽度为16位
    ) A8 c9 D2 `8 T9 W0 [5 e
  175.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                                //数据宽度为16位; G7 A' ~" A9 |5 x& a, v/ \  c
  176.         DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                                                                 //工作在循环缓存模式
    & J5 q1 G1 \- K8 ~& ^5 Z8 c
  177.         DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                                                                 //DMA通道拥有高优先级 分别4个等级 低、中、高、非常高) Z+ O& g2 @* g8 |
  178.         DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                                                        //禁用DMA的FIFO模式,使用直连模式
    + y: `% m5 V0 L5 ^  x8 P
  179.         DMA_InitStructure.DMA_FIFOThreshold  = DMA_FIFOThreshold_HalfFull;3 _# \6 O# u4 C+ i
  180.         DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    ( @! Z9 |2 i& ?
  181.         DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;% G8 Y; z3 F! g/ X1 [$ p
  182.         DMA_InitStructure.DMA_Channel = DMA_Channel_0;                                                                                        //选择DMA通道
    0 J( z* }: V4 h+ w5 K
  183. & ]) |3 y% [  f1 {. m% U
  184.         DMA_Init(DMA2_Stream0, &DMA_InitStructure);                                                                                                         //初始化DMA流
    ) X) j" N, o2 B, B, a/ w! x
  185.         DMA_Cmd(DMA2_Stream0, ENABLE);                                                                                                                                        //使能DMA流
    / e4 s$ L- d9 s; L5 S0 U' j$ a
  186. }
    " E. }- o' G# k; o9 Z

  187. ' _  o1 Z: L4 A" g2 S* n* ?
  188. + X/ W) Q$ \8 N3 j+ w- I
  189. /**% P6 Z% U% v5 s) \# K- v
  190. * @brief 不使用DMA传输时,获取ADC的采样数据
    . |' n: n) T5 W* u7 t
  191. * @param channel: ADC的采样通道  n- V$ Q2 w* s. ?0 {
  192. * @return ADC的单次采样结果
    3 z) q/ c. e+ _# `1 i% R
  193. */
    . U! E( ^% p, }& X
  194. uint16_t ADC_GetData_NotUseDMA(uint8_t channel)6 w% n; \7 w8 `+ V; g) u. e. }; |
  195. {
    ' v( d" u  P3 D& X( Q
  196.         ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_56Cycles);                        //配置 ADC 通道转换顺序和采样周期
    $ L; H2 {/ x# T' S0 p) U- c! D$ e
  197.         ADC_SoftwareStartConv(ADC1);                                                                                                                                                        //使能指定的ADC1的软件转换启动功能& D7 L& @) Q* t

  198. : {1 r9 b6 w+ ?4 f5 C
  199.         /**
    & M/ M1 ]" B3 c  e, i
  200.          * 通过查询的方式获取了ADC的转化结果,
    5 N* F+ }5 T  k7 d
  201.          * 也可以通过中断的方式获取ADC的转换结果+ B$ T; @) m/ s7 A* b: R
  202.          */
    ) r6 v) Q& @& E' e1 _
  203.         while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));                                                                                        //等待转换结束
    1 V7 Q3 i& j5 [. n
  204. " V) U1 [! c* w7 m
  205.         return ADC_GetConversionValue(ADC1);                                                                                                                        //返回最近一次ADC1规则组的转换结果
    : q, Q5 G5 e9 w* z
  206. }
    3 t8 Z  B7 o; L4 a

  207. . f3 W9 I, r: ]' y$ ?9 p5 |

  208. ) K0 @8 M. h8 {9 k, b  k( n9 s
  209. /**7 [& {( r+ g/ Y0 I& u; K( L
  210. * @brief 不使用DMA传输时,获取ADC采样数据的平均值8 G, B4 @5 z. N8 z0 p, Q/ r
  211. * @param channel: ADC的采样通道
    ( U1 V3 \& g9 ^$ B/ _# u- o
  212. * @param count: 计算平均值的采样数量
    7 B  p8 N: X( P; y  ]4 |
  213. * @return ADC的单次采样结果的平均值) ]/ c7 z: o: z% Y
  214. */
    " e1 v7 [# g; j
  215. uint16_t ADC_GetAverageData_NotUseDMA(uint8_t channel, uint16_t count)
    % Q9 l" R$ w8 _) ]. R, @
  216. {
    : K  {/ m6 t/ D$ e
  217.         uint32_t temp_val = 0;
    5 E4 H3 ?$ G) ~; d8 X+ M, U
  218. 8 o. n9 P/ [: t1 q4 ], U! H
  219.         for (uint16_t t = 0; t < count; t++)- r, l9 n# T3 ?9 Y
  220.         {
    2 b1 w. A' w9 w
  221.                 temp_val += ADC_GetData_NotUseDMA(channel);
    / F1 x2 r+ K6 g5 a
  222.         }
    7 e# O& l- Y9 h# ~2 P0 r

  223. % ~  f4 B7 T8 x; u  a
  224.         ADC_Data[channel] = temp_val / count;" v. a0 W) q* z
  225. ! C  X; o" O! F3 E  n2 {+ D6 z9 n
  226.         return ADC_Data[channel];# z, W) |, v5 N5 `
  227. }
    0 ]8 o& u. m7 v
  228. + q- {# L# A" D7 v
  229. /**
    * a5 L) p% `! a, I7 @' t# F) B# O
  230. * @brief 获取通过DMA传输的采样数据/ Y" d3 T, N( D/ l$ Q' |. N
  231. * @param channel: ADC的采样通道
    # H$ r) Y2 j& H; `& B; h" I
  232. * @return ADC的采样数据( ^; z0 Z. b2 z( f6 ]
  233. */
    - q" m) m7 `' D9 U  [
  234. uint16_t ADC_GetData_UseDMA(uint8_t channel)
    3 X2 A# C3 Z2 {. Z. e( v2 y: T
  235. {
    & C: N+ T( w+ R- r7 [  Z
  236.         return ADC_DMA_Value[0][channel];4 a9 x% Q" G. y1 B  v" _
  237. }
    ' m& T: r: o+ M  R9 e1 B0 o
  238. . S8 ~' |5 j% y0 ^. r1 M' X
  239. % ]% A- _! B1 ]# G0 ~; |' r
  240. /**8 X  u, Z* g% ?: p$ ?: C9 l
  241. * @brief 获取通过DMA传输的采样数据(求平均值,过采样)+ _2 p" G7 G4 U3 B. L5 G% U
  242. * @param channel: ADC的采样通道- j/ b0 S$ J& E% w8 f0 o- A
  243. * @return ADC的采样数据& u& X* m" k6 P) V
  244. */% g3 F, i% p' u  r! b9 q6 x- m+ p1 w
  245. uint16_t ADC_GetAverageData_UseDMA(uint8_t channel)
    ) p, F1 Z, s3 b% }) C
  246. {
    $ v, H8 o2 Q. A5 f
  247.         uint32_t sum = 0;
    # L1 f' Z2 G* D: t( G1 L

  248. 3 g5 I% }5 n: t' K0 i
  249.         for (uint16_t j = 0; j < ADC_DMA_CHANNEL_DEEPTH; j++)" u; n" S) C6 @) z& m* m8 p: F- ?
  250.         {  g4 ?2 _- f& g' y* @
  251.                 sum += ADC_DMA_Value[j][channel];/ N+ Z- a/ X8 v
  252.         }. Z1 \3 _2 z* }8 g2 [' P/ a
  253. + _8 }/ W/ `! h) D$ u8 f$ F
  254.         return sum / ADC_DMA_CHANNEL_DEEPTH;                                                //求平均值并转换成电压值& J6 f8 C( }3 z  x( p# ~" @
  255. }
复制代码

4 T) j9 D* Q1 @( X使用指南
. z' u, p6 y) S' x/ S/ ~由于使用了相同的功能逻辑与函数名(即头文件相同),STM32F103与STM32F407的ADC扩展函数库在使用方法上是相同的。由于在ADC扩展库中提供的模板配置函数中已经完成了GPIO外设与ADC外设的配置,因此可以直接调用一步完成ADC使用前的初始化工作。) z. k9 V4 e% X. F% ?8 L( ?' b
) l5 F1 Q. d3 p+ [' G; n
单次单通道采样(不使用DMA)
( J$ a+ f" i2 ~8 r' @! V% U配置ADC- b( X1 [* B0 G4 K1 `* |
  1. void Periphl_ConfigAll()7 b; g- e  Z8 p' h
  2. {5 H0 ~9 k! X9 [( a( c
  3.         /*省略无关代码*/! |3 h2 m7 y- d3 L  i+ }
  4.         ADC_UserConfig1();; t4 \. U! X5 E$ [0 e
  5.         /*省略无关代码*/& \: G  l* Q3 w& T3 }* Y, p+ c
  6. }
复制代码

2 @% ^' I9 ?1 D, c) m启动采样并获取数据# d; n/ Y1 T6 t, x0 B- b5 Y1 [/ _2 Q
采集的数据保存在全局数组ADC_Data[ADC_CHANNEL_NUM]中,同时也可以调用相应的函数返回对应的结果。
! I2 |- F6 V: T+ J1 [0 B调用uint16_t ADC_GetData_NotUseDMA(uint8_t channel)完成一次数据采集。
8 T" y: P2 a' E调用uint16_t ADC_GetAverageData_NotUseDMA(uint8_t channel, uint16_t count)连续采集count个数据后,返回数据采集的平均值。
: \& ?9 e" ?3 I' p1 Q
0 S7 r: f$ v" t# _
# j4 |( X6 m4 C# ]3 ^! c连续多通道采样(使用DMA)
+ K: T) B2 A$ i7 I配置ADC, Q' R2 F( N: A3 d( Q- L! J! l
  1. void Periphl_ConfigAll()# j3 m% w* g7 B, b2 Z$ m. M. B
  2. {) x6 Z* `6 |3 w6 F5 ^+ V
  3.         /*省略无关代码*/
    , P  W) `. |7 g
  4.         ADC_UserConfig2();# D/ w) F8 E" ?# l( }8 b5 h1 u: N
  5.         /*省略无关代码*/
    ; a1 T' q" I" S
  6. }
复制代码

0 n( H( B% R: o1 b2 j获取数据
1 I  o+ i0 D1 W/ J. G8 J在配置完ADC的DMA传输后就已经自动打开了ADC采样,采样的数据保存在全局二维数组ADC_DMA_Value[ADC_DMA_CHANNEL_DEEPTH][ADC_DMA_CHANNEL_NUM]中,同时也可以调用相应的函数返回对应的结果。
+ \1 ^: [% N" L    调用uint16_t ADC_GetData_UseDMA(uint8_t channel)返回一次数据采集结果。- i% }; W( K6 Y( {9 Z; q2 A; Y
    调用uint16_t ADC_GetAverageData_UseDMA(uint8_t channel)返回数组中保存的最近的ADC_DMA_CHANNEL_DEEPTH个数据的平均值。! o* R: u1 i+ h2 H

; H# Y7 p' J- I) s- R0 }. c一般情况下,由于DMA的采样速度很快,调用uint16_t ADC_GetAverageData_UseDMA(uint8_t channel)返回一个平均值作为采样的结果是比较推荐的。这也是利用了过采样技术提高了数据的稳定性与分辨率。
" x0 v5 }9 ^3 r+ y0 b3 `/ \3 y! |/ X& d7 ^3 ?
在FreeRTOS任务中
# [7 S9 _5 {6 Q+ U+ Z
可以创建一个任务完成ADC初始化与数据轮询的工作,但需要注意的是片上ADC的快速配置函数(ADC_UserConfig2())只能调用一次,否则可能会出错。也就是说要么在程序启动的地方配置ADC,要么在任务开始的地方配置ADC,但不能两处同时配置ADC。! r0 j& d9 b( M- k  K) q5 Q/ q1 {
; \, m  M. z2 b7 L8 \$ p5 ?& j
  1. void McuAdcDaq_task(void *pvParameters)
    $ Z. h$ J' z2 b: c; |4 o
  2. {+ S9 H6 @2 G1 B6 b# G) |
  3.         ADC_UserConfig2();
    ! X7 a1 }' g) k/ ]8 }
  4. ( e  U  `4 @$ x  x
  5.         TickType_t ticks = xTaskGetTickCount();3 m: z) k4 y. n) ?9 P$ \
  6.         while (1)
      ~/ i5 A& W6 ?! s% q" e
  7.         {
      |2 F( ?5 R' Y. C( _4 v
  8.                 User_RefreshSensor();
    6 x  S3 E) W* t+ H. s' `4 T3 r
  9.                 User_MB_RefreshInputRegister();
    ; c1 S% ?& j- W# R) X9 F
  10. " r7 H+ n: o3 F1 [
  11.                 //100ms 一个处理周期- {8 D' x) X, E6 q0 \7 f* N
  12.                 vTaskDelayUntil( &ticks, 100);
    ) H3 C. D2 @: m6 v* f
  13.         }
    / l  ~" z0 K# A( X  F
  14. }
复制代码
# v8 C! x" z; {

. Y' x7 w# ]* z* C; ~; G9 h" v4 D' B* p) _1 U7 S
) }; y; p; w! X# j
收藏 评论0 发布时间:2022-4-13 17:00

举报

0个回答

所属标签

相似分享

官网相关资源

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