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

基于STM32采集电压的经验分享—ADC多通道

[复制链接]
攻城狮Melo 发布时间:2023-3-18 14:46
ADC详解
) |9 B$ w9 N: Z前面的博客中详细介绍了STM32中ADC的相关信息,这篇博客是对ADC内容的一个总结提升,ADC的详细介绍:ADC详解6 o, U! G4 }- \* B; R7 @: O+ D

" o9 ~( h( U' P5 l0 K程序说明
$ d( [  d# ~4 `1 X  @7 H为了使这次代码阅读方便,博主没有在头文件中宏定义变量,都是直接采样库函数中的规定形参。此次采用多通道采集电压,使用ADC1的通道10、11、12、13、14、15一共六个通道,采用DMA将转换结果传输至内存。  f1 h! j; q9 f! k1 z; G- F% E& a
6 D( E; @8 d2 j* J6 C' F! ?+ y
7 W2 N+ h" a( H6 p, A; ^& X
函数主体
4 T4 q5 a, |* e/ r7 Q$ L引脚配置' |& }1 q6 n9 t' B! [1 b
引脚配置的时候,将所有引脚一次性配置好,过于简单,不作详细说明。
% r% d5 }- `# _: p9 r6 i
  1. void ADC_GPIO_Config(void)
    ' s( S- b$ k& v0 z" \  v+ Z
  2. {% i. Q$ x  c! N
  3.         GPIO_InitTypeDef   GPIO_InitStruct;
    ( R9 Z0 w+ L$ @2 Z/ E
  4.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,  ENABLE);0 Y) K  }: v- j  y, H) o
  5.        
    $ F9 ?" U# C2 y* k+ W+ q
  6.        
    : A% N9 I, `& k
  7.         GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN ;
    $ v2 e( A2 b) K. r  e# W
  8.         GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|
    $ N: P& I+ q0 x' b4 }
  9.                                                                 GPIO_Pin_1|
    8 d6 l1 ~# h, S) a; B8 j
  10.                                                                 GPIO_Pin_2|. q7 T. L1 Q3 J0 X
  11.                                                                 GPIO_Pin_3|
    0 t7 h; z- m2 ^8 R4 x& c
  12.                                                                 GPIO_Pin_4|
    8 b* l) \6 ^  `1 w4 s3 S& H
  13.                                                                 GPIO_Pin_5;4 A  g% F" c/ z2 L% D5 R1 B$ [
  14.        
    ' t* G( G1 T' r1 j! R# `
  15.         GPIO_Init(GPIOC , &GPIO_InitStruct);
    3 H! a, F0 r) d% j
  16. }
    ' N# h3 s  N8 M: A
  17. : p! d: Y; i6 W% i9 N
复制代码

% q0 W5 K2 l. L3 L9 V7 TADC和DMA配置
# S+ W8 E1 x! v此函数中主要配置了ADC的相关信息和DMA的信息。: O( w5 s; a6 z: f" U
  1. uint16_t result[6]={0,0,0,0,0,0};" b9 ]9 |$ |/ h
  2. / d+ Q# y9 J- K& q! |3 m& I
  3. void ADC_DMA_COnfig(void)+ K$ T0 r% x8 r7 Q. U
  4. {
    ; Q! |9 A# ~5 U3 k7 o  C
  5.         ADC_InitTypeDef  ADC_InitStructure;  x+ z/ \& e- Z4 D9 m  w
  6.         DMA_InitTypeDef DMA_InitStructure;
    1 s$ b& c) M9 U5 O  P
  7.        
    3 v2 ~0 |: Y+ _- f" S, O3 s
  8.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,  ENABLE);( k8 ]" f2 H9 j% j, I
  9.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);! R9 O3 j" ^5 F2 z* _. \. o4 d2 I
  10.         % ?, R8 o' G! }( X1 l
  11.         /* 复位DMA1的通道1 */
    ' s* X- ]& m! y
  12.         DMA_DeInit(DMA1_Channel1);7 J3 B- J& Y- s4 F! N& J8 W& u
  13.         ( c7 L& U- n/ D  U
  14.         // 配置 DMA 初始化结构体
    6 `) O) B/ D9 ^# [
  15.         // 外设基址为:ADC 数据寄存器地址
    5 [9 V- }, s6 T8 z
  16.         DMA_InitStructure.DMA_PeripheralBaseAddr = ( u32 ) ( ADC1_BASE+0x4c);
    8 ~0 b/ ]9 w5 F' R& d. j$ j
  17.         % f* d( q' o9 |9 G8 `4 S
  18.         // 存储器地址
    : q/ `# ~, B% J
  19.         DMA_InitStructure.DMA_MemoryBaseAddr = (u32)result;; o) E8 p9 `; C  e% {. y# U" E$ Z
  20.         + a5 J; b, k6 ?. Z2 |& \
  21.         // 数据源来自外设
    ; C3 w4 }% @1 s7 p* c6 W3 x' p
  22.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    * i; G6 z. C1 e
  23.         ! a3 L! S+ ]) r1 g( W, k* o+ B" M
  24.         // 缓冲区大小,应该等于数据目的地的大小+ \0 _: A2 r& B  G
  25.         DMA_InitStructure.DMA_BufferSize = 6;- ^1 W5 K' ?3 {. V: x" C
  26.        
    . `6 C$ D4 n+ @; J4 n
  27.         // 外设寄存器只有一个,地址不用递增
    + v. _; I  a& z7 S
  28.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;4 @  H- |; p9 p$ z  D! ~; J

  29. 0 t1 j3 t9 e6 U2 r/ e+ r! E" E; B
  30.         // 存储器地址递增
    + ]! y2 [% q. d% {( V/ k
  31.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 0 d8 u2 D+ P; Y8 e; H- h( l
  32.         2 |* D( T. b+ {
  33.         // 外设数据大小为半字,即两个字节
    1 `& e9 v; d% J0 b% e; }* z! j
  34.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;2 A; H& o, n0 L1 ?
  35.         9 \+ ~  x) h+ z. s+ E  F
  36.         // 内存数据大小也为半字,跟外设数据大小相同) \8 D$ ]* b0 B
  37.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    : |8 K2 _7 y2 r  d8 L
  38.        
    ( p5 m* o+ n! K9 v3 q- G0 Z
  39.         // 循环传输模式
      K/ c6 |7 E' f/ S
  40.         DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;       
    & ], p0 o3 F# ^3 _
  41. , @- }' e' e- }, O2 f/ k7 B1 K1 h# o
  42.         // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
    ( Q7 {# p% S  ?/ X* l1 X
  43.         DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    1 M" `, r5 ^% s6 {* o! k" {
  44.         % S2 C  Y" F  Z+ {
  45.         // 禁止存储器到存储器模式,因为是从外设到存储器1 D# z* @8 p" C) _
  46.         DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    & j& D2 u* L) J: L1 l0 y9 K4 I) i
  47.        
    ' K& L7 i: a/ ?& c
  48.         // 初始化DMA0 o4 }' o3 r$ f3 @' Y
  49.         DMA_Init(DMA1_Channel1, &DMA_InitStructure);/ [. q3 b' Q' n7 X+ W2 X( U% R: @' Y3 ?
  50.        
    8 ^5 W/ Y7 k! \* `
  51.         // 使能 DMA 通道
    ( n, J+ t; N, ^3 g# N4 K9 a
  52.         DMA_Cmd(DMA1_Channel1 , ENABLE);
    1 x* A0 J8 Y: v, E' m
  53.        
    % P. @  |) u* D+ B
  54.         4 u- v8 X, _4 T' P; N
  55.         // ADC 模式配置
    / C" [, m6 U3 P5 l
  56.         // 只使用一个ADC,属于单模式$ i3 q) S+ M5 f6 P7 X* I% C8 R
  57.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    " x7 K7 r$ S* n; n. |5 }% F& j
  58.         9 u- v2 _' k0 p4 G: W
  59.         // 扫描模式* B+ L# J" Y; A/ c
  60.         ADC_InitStructure.ADC_ScanConvMode = ENABLE ;
    / r* n% {. T% t9 ~; x/ L

  61. % F, J9 D' p1 b4 g
  62.         // 连续转换模式
    9 j/ m- k! l+ V$ d  @5 u
  63.         ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;1 F0 `, ~* \4 h! C' l& j

  64. % d: E) b- v2 j  _
  65.         // 不用外部触发转换,软件开启即可
    * N3 W' f. ^, O! \+ _5 O
  66.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    $ i# {' Q0 o+ l2 d

  67. 0 a$ Z3 q( c7 ~3 d# K1 C' s
  68.         // 转换结果右对齐  w# I" y8 v- [7 M, T$ Y. g9 `* b
  69.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    9 H, w$ {2 c/ T- ^+ [
  70.        
    ; X/ T0 j7 o- G. u& x4 y
  71.         // 转换通道个数
    8 Z; a$ d# k" ?9 G3 Q/ Y
  72.         ADC_InitStructure.ADC_NbrOfChannel = 6;       
    * D) D. V& @% |# r: l0 _- B: Y
  73.                 ! ~, v  F$ l2 h' t" _0 x5 L# M
  74.         // 初始化ADC0 F& d& n  K, o, B
  75.         ADC_Init(ADC1, &ADC_InitStructure);4 K, `: H$ I$ F. d6 V
  76.        
    & ?# G8 [: m( `' }
  77.         // 配置ADC时钟为PCLK2的8分频,即9MHz
    ) X0 r% @# b/ G6 D3 \: L' j
  78.         RCC_ADCCLKConfig(RCC_PCLK2_Div8); + U( L$ B3 h/ ]7 r, n3 c
  79.        
    " U. V2 X* e) k- N! I2 S1 ~
  80.         // 配置ADC 通道的转换顺序和采样时间- ^) T% k- y. r8 q" S1 N
  81.         ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);5 F6 Y6 T/ k$ m) r) v2 r# L* ~
  82.         ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_55Cycles5);
    - g: v1 x' |1 H8 l2 F* I! T- y
  83.         ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, ADC_SampleTime_55Cycles5);
    8 C/ f3 ^" `1 c( f/ v) B, e" U" o
  84.         ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_55Cycles5);
    * n  b9 H" o, U
  85.         ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 5, ADC_SampleTime_55Cycles5);
    $ M/ J7 d5 U; V1 c# b% M
  86.         ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 6, ADC_SampleTime_55Cycles5);0 D8 v4 D, T# l8 I  K1 }
  87.        
    " r. ]1 l  Z0 f/ p
  88.         // 使能ADC DMA 请求
    , c" a! f( l- O4 H; A- J5 T6 M1 X
  89.         ADC_DMACmd(ADC1, ENABLE);) ~' c' [6 U6 D% K# J! w9 \$ N
  90.         7 X$ U$ }  E) q% o
  91.         // 开启ADC ,并开始转换4 M2 A: f  u; @5 C$ ~# b
  92.         ADC_Cmd(ADC1, ENABLE);9 s  F- d. }: G6 R4 o
  93.        
    + p1 C+ R$ H) B% g% f& b
  94.         // 初始化ADC 校准寄存器  
      J3 G1 R1 C+ F' Q8 y  |9 M0 I5 y0 b
  95.         ADC_ResetCalibration(ADC1);
    3 \& x7 x  k0 u7 B1 Q
  96.         // 等待校准寄存器初始化完成  K6 s7 \9 F; G% u2 L8 Q
  97.         while(ADC_GetResetCalibrationStatus(ADC1));
      f/ T- Y, L7 M9 Z6 A/ E9 b8 T7 D
  98.        
    ) z% n) J# w' D. c2 @
  99.         // ADC开始校准
    4 B& J) R7 a3 J2 q
  100.         ADC_StartCalibration(ADC1);
    + @. Q# J9 D: H' @
  101.         // 等待校准完成2 O% e8 Y- s! L8 m/ g
  102.         while(ADC_GetCalibrationStatus(ADC1));
    . @. Y  {" G+ {) Z6 u
  103.         " Q% `$ z# V) {9 k/ f- W
  104.         // 由于没有采用外部触发,所以使用软件触发ADC转换
    . n1 g. x9 y9 G: s
  105.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);7 ]7 Y( |8 r- B0 |
复制代码
0 i* _3 s2 ?4 {+ a9 [$ S
函数开头定义了ADC和DMA的结构体变量,并且打开了俩个外设的时钟(DMA挂载在AHB总线上)。DMA模块可以参考之前写的博客:DMA8 F4 w  J) D, c" H' m" u) V/ g
这次DMA传输是从外设到内存,直接从ADC的数据寄存器中取数据,然后传输到全局数组变量result中。剩下的都在函数中作了详细注解。  X5 x+ o) F( z3 l# |. x
7 R3 v9 G* G# \+ p+ b# ^
1 v: P8 P2 d) _5 A5 M: u
主函数
2 _7 j& C! S% k
  1. #include "stm32f10x.h"! H* u, @1 n# i  F
  2. #include "usart.h". P0 O+ X+ g8 R4 t3 P+ J6 N
  3. #include "adc.h"
    # }% N7 N- g4 ~7 R* G0 U; o

  4. - Y$ I* e$ z- Q. U' M: ^, T

  5. , y: e* X  a6 f2 H
  6. % ~7 a+ B) L5 x
  7. extern uint16_t result[6];
    . J7 w6 c1 I' Y/ G& B0 D
  8. float voltage[6];- w  W) o# F9 ~9 Y6 G9 x

  9. # J; {1 W: O* f/ u/ s+ p' u- I

  10.   V8 w( k$ }+ t9 H) u5 M
  11. void delay(void)6 ]/ K. ~4 r/ z
  12. {8 w: l& J% y3 v
  13.         uint32_t k=0xffffff;
    : F3 r4 i# ]" A4 l* y; Y; j
  14.         while(k--);5 S0 ]' g& i& V# i8 ]* Z
  15. }( X4 A3 L+ G# L# S$ \9 X

  16. ! `% F, @/ }+ k& \7 v
  17. int main(void)
    . F7 u' c4 k+ G, I, V' m( j( l
  18. {
    6 E( U$ q5 Q8 n+ p1 ?3 i: c/ s( m
  19.         uint8_t n;+ G8 ?+ f( t6 d5 ^
  20.         /* 配置串口 */5 N0 r* _5 e" h: h6 I* Q9 F
  21.         DEBUG_USART_Config();+ H+ A7 W) ]0 \; d, E6 l
  22.         /* 有关ADC的函数打包 */
    : Z2 Q# }+ q8 F( {
  23.         ADCx_Init();
    + B1 R" o& R3 @' B
  24.         while(1)
    0 [0 ]5 c9 R6 F' Y6 K6 i1 C, b
  25.         {" m6 w( W3 ?* r- u0 n
  26.                 for(n=0;n<6;n++)
    ! i7 j8 l2 _% N; i1 I: j5 m% l0 e" c& _
  27.                 {- O0 k7 D4 P$ ?/ r
  28.                     /* 转换为实际电压 */' }; c) |8 ~2 o0 M0 t, K
  29.                         voltage[n]=(float) result[n]/4096*3.3;6 V. q- \) J1 b- e
  30.                         printf("\n通道%d的值为:%fV\n",n,voltage[n]);
    0 A5 ^; d, P7 {. |0 A6 N
  31.                 }6 b2 `6 V- A0 M: j. C+ M
  32.                 delay();; _5 S  V$ D1 g# ?: B: Q
  33.         }0 X9 Y# }% r9 |$ {- @
  34. }
    2 Y& U0 Z; q6 C' X6 D
  35. & t  p5 x: R4 a# e
复制代码
7 U" D( x3 d2 H+ \+ W, w$ n" |: [
主函数中也有相应注解。9 r# Z9 L% }% }
————————————————! g+ U2 E& }/ y/ _# G
版权声明:Aspirant-GQ
8 i1 o" b1 ~3 d- {
# B1 |9 k! {7 E5 `) J5 s. `# ^
赞 收藏 评论0 发布时间:2023-3-18 14:46

举报

0个回答

所属标签

相似技术帖

官网相关资源

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