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

STM32之ADC转换

[复制链接]
STMCU小助手 发布时间:2022-10-12 15:47
1. ADC简介

stm32f103最少有2个AD模数转换器,每个ADC都有18个通道,可以测量16个外部和2个内部模拟量。最大转换频率为1Mhz,也就是转换时间为1us(在 ADCCLK = 14Mhz,采样周期为1.5个时钟周期时)。最大时钟超过14Mhz,将导致ADC转换准确度降低。stm32的ADC是12位精度的。

stm32的ADC转换有两种通道,规则通道和注入通道,注入通道可以抢占式地打断规则通道的采样,执行注入通道采样后,再执行之前的规则通道采样,和中断类似。本例只使用规则通道实现独立模式的中断采样,这里不再赘述两种通道区别。

stm32的ADC可以由外部事件触发(例如定时器捕获,EXTI线)和软件触发(即在配置相关寄存器时,直接开启采样)。

STM32的ADC在单次转换模式下,只执行一次转换,该模式可以通过ADC_CR2 寄存器的ADON 位(只适用于规则通道)启动,也可以通过外部触发启动(适用于规则通道和注入通道),这是CONT 位为0 。 以规则通道为例,一旦所选择的通道转换完成,转换结果将被存在ADC_DR 寄存器,EOC (转换结束)标志将被置位,如果设置了EOCIE ,则会产生中断。然后ADC将停止,直到下次启动。


! w, L/ D( R& `3 a3 R) q

2. 寄存器简介2.1. ADC控制寄存器(ADC_CR1和ADC_CR2)

ADC_CR1的SCAN 位,该位用于设置扫描模式,由软件设置和清除,如果设置为1 ,则使用扫描模式,如果为 0,则关闭扫描模式。在扫描模式下,由 ADC_SQRx或ADC_JSQRx寄存器选中的通道被转换。如果设置了 EOCIE 或JEOCIE,只在最后一个通道转换完毕后才会产生EOC 或JEOC 中断。

' Y1 p+ Y4 C' `, V2 I

ADCON 位用于开关AD转换器。而CONT 位用于设置是否进行连续转换,我们使用单次转换,所以CONT 位必须为0。CAL 和RSTCAL 用于AD校准。ALIGN用于设置数据对齐,我们使用右对齐,该位设置为0 。

EXTSEL[2:0]用于选择启动规则转换组转换的外部事件,详细的设置关系如下:

这里使用的是软件触发(SWSTART ),所以设置这3 个位为111 。ADC_CR2 的SWSTART 位用于开始规则通道的转换,我们每次转换(单次转换模式下)都需要向该位写 1 。AWDEN 为用于使能温度传感器和Vrefint 。


/ q' x  Q: V! [3 E6 }% @

2.2. ADC采样事件寄存器(ADC_SMPR1 和ADC_SMPR2 )

这两个寄存器用于设置通道0~17的采样时间,每个通道占用 3 个位。

ADC_SMPR2 的各位描述如下

对于每个要转换的通道,采样时间建议尽量长一点,以获得较高的准确度,但是这样会降低ADC的转换速率。ADC的转换时间可以由下式计算:

Tcovn= 采样时间+12.5 个周期

其中:Tcovn 为总转换时间,采样时间是根据每个通道的SMP位的设置来决定的。例如,当ADCCLK=14Mhz 的时候,并设置 1.5个周期的采样时间,则得到:Tcovn=1.5+12.5=14 个周期=1us 。

( {" ~; p* N; K, |4 O
2.3. ADC规则序列寄存器(ADC_SQR1~3)

L[3:0] 用于存储规则序列的长度,我们这里只用了 1 个,所以设置这几个位的值为 0 。其他的SQ13~16 则存储了规则序列中第13~16 个通道的编号(0~17)。另外两个规则序列寄存器同ADC_SQR1大同小异,我们这里就不再介绍了,要说明一点的是:我们选择的是单次转换,所以只有一个通道在规则序列里面,这个序列就是SQ0 ,通过ADC_SQR3的最低5 位设置。

# @# P) i- W% v& p

2.4. ADC规则数据寄存器(ADC_DR)

这里要提醒一点的是,该寄存器的数据可以通过ADC_CR2 的ALIGN位设置左对齐还是右对齐。在读取数据的时候要注意。

8 S7 Q" \& {! m/ u2 p1 M

2.5. ADC状态寄存器(ADC_SR )

这里我们要用到的是EOC 位,我们通过判断该位来决定是否此次规则通道的AD转换已经完成,如果完成我们就从ADC_DR 中读取转换结果,否则等待转换完成。


: D0 u3 F+ Z4 V  A5 Z8 Y

3. 寄存器操作步骤

1 、开启PA口时钟,设置PA0 为模拟输入。

STM32F103RBT6的ADC通道0 在PA 0 上,所以,我们先要使能 PORTA的时钟,然后设置PA 0 为模拟输入。

2 、使能ADC1 时钟,并设置分频因子。

要使用ADC1,第一步就是要使能 ADC1 的时钟,在使能完时钟之后,进行一次 ADC1 的复位。接着我们就可以通过RCC_CFGR设置ADC1 的分频因子。分频因子要确保 ADC1 的时钟(ADCCLK)不要超过14Mhz 。

3 、设置ADC1 的工作模式。

在设置完分频因子之后,我们就可以开始 ADC1 的模式配置了,设置单次转换模式、触发方式选择、数据对齐方式等都在这一步实现。

4 、设置ADC1 规则序列的相关信息。

接下来我们要设置规则序列的相关信息,我们这里只有一个通道,并且是单次转换的,所以设置规则序列中通道数为1 ,然后设置通道 0 的采样周期。

5 、开启AD转换器,并校准。

在设置完了以上信息后,我们就开启AD转换器,执行复位校准和AD校准,注意这两步是必须的!不校准将导致结果很不准确。

6 )读取ADC值。

在上面的校准完成之后,ADC就算准备好了。接下来我们要做的就是设置规则序列 0 里面的通道,然后启动ADC转换。在转换结束后,读取ADC1_DR 里面的值就是了。

硬件设置:我们通过ADC1 的通道0 (PA 0 )来读取外部电压值。

注意:这里不能接到板上5V电源上去测试,这可能会烧坏 ADC!

  1. #include <stm32f10x_lib.h>
    , X/ s- J' N, ]$ e! Z
  2. #include "adc.h"
    ' z+ c3 r- b3 T
  3. //ADC 驱动代码                                      2 C  {2 @1 E5 [) A% I  ^
  4. //初始化ADC
    ! S3 b- f1 i; j5 [$ u1 ]
  5. //这里我们仅以规则通道为例
    * J0 v  h% v" S% @( D3 t
  6. //我们默认将开启通道0~3                                                                                                                                          
    5 A/ T- s3 l0 {
  7. void  Adc_Init(void)
    5 r  k: k. t( t+ u  k5 i7 F) J% h
  8. {    : w3 m4 N5 X8 t- N/ w; j2 h( G) u
  9.         //先初始化IO口! z; i! E  f8 @$ q0 J
  10.         RCC->APB2ENR|=1<<2;    //使能PORTA口时钟
    $ x, M) L# j1 Z5 i2 O. W+ s
  11.         GPIOA->CRL&=0XFFFF0000;//PA0 1 2 3 anolog输入" {" A1 H- |  F+ F5 U+ P
  12.         //通道10/11设置                         
    2 c* S6 P; t+ h1 g
  13.         RCC->APB2ENR|=1<<9;    //ADC1时钟使能          
    9 z" L2 H5 H: Y0 e3 m6 ?
  14.         RCC->APB2RSTR|=1<<9;   //ADC1复位
    " i  D- ^/ m2 M
  15.         RCC->APB2RSTR&=~(1<<9);//复位结束            
    ( i, f- d( K: n
  16.         RCC->CFGR&=~(3<<14);   //分频因子清零       
    3 b/ y7 g! m0 w
  17.         //SYSCLK/DIV2=12M ADC时钟设置为12M,ADC最大时钟不能超过14M!9 k8 ?0 x$ Y/ I' A2 N
  18.         //否则将导致ADC准确度下降!
    3 p. \9 W0 ]2 `
  19.         RCC->CFGR|=2<<14;               1 ^# ]# ^6 u" D2 Z6 ?* S

  20. - z1 Q# X6 a/ H6 @
  21.         ADC1->CR1&=0XF0FFFF;   //工作模式清零
    4 M/ [. K* ]2 O2 d: F! w
  22.         ADC1->CR1|=0<<16;      //独立工作模式  
    : w# e9 h" P! V! z9 f, C
  23.         ADC1->CR1&=~(1<<8);    //非扫描模式          $ ~& x6 A  d# r* V% N
  24.         ADC1->CR2&=~(1<<1);    //单次转换模式" N% w# D' c, M9 D: S% E6 j
  25.         ADC1->CR2&=~(7<<17);          
    # S% y3 ?3 s7 w
  26.         ADC1->CR2|=7<<17;           //软件控制转换  
    , B) V8 D1 ?/ f7 i$ q; `! n  O
  27.         ADC1->CR2|=1<<20;      //使用用外部触发(SWSTART)!!!        必须使用一个事件来触发
    & ?3 y! m" `: e$ h5 j# N6 W; A5 I
  28.         ADC1->CR2&=~(1<<11);   //右对齐         ' ~5 T6 K" }" f5 e% M
  29.         ADC1->SQR1&=~(0XF<<20);
    2 }9 D2 B( z. D. d$ e
  30.         ADC1->SQR1&=0<<20;     //1个转换在规则序列中 也就是只转换规则序列1                           
    : V* _0 ~, i  v. D; h
  31.         //设置通道0~3的采样时间
    # J: D1 n, G1 O- E/ ^
  32.         ADC1->SMPR2&=0XFFFFF000;//通道0,1,2,3采样时间清空          
    3 a/ ?) O! L. M* ~- v: K; U
  33.         ADC1->SMPR2|=7<<9;      //通道3  239.5周期,提高采样时间可以提高精确度         
    4 O2 ?1 m' L9 x  W! }# s
  34.         ADC1->SMPR2|=7<<6;      //通道2  239.5周期,提高采样时间可以提高精确度         " A1 i1 }' ~: N4 A& g8 M: y
  35.         ADC1->SMPR2|=7<<3;      //通道1  239.5周期,提高采样时间可以提高精确度         
    0 M3 Z6 j% ~1 \$ b
  36.         ADC1->SMPR2|=7<<0;      //通道0  239.5周期,提高采样时间可以提高精确度         - N/ N, E: K% E% F, h& v& F
  37. # ?$ Q# u6 D! w, M2 g
  38.         ADC1->CR2|=1<<0;            //开启AD转换器         2 `- E6 V* ?. U. ~1 f( i
  39.         ADC1->CR2|=1<<3;        //使能复位校准  
    9 y& d0 a% ?$ i' x
  40.         while(ADC1->CR2&1<<3);  //等待校准结束                          # i( p1 [) _( T# k  m3 X
  41.     //该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。                  4 r: C7 d' ]6 `
  42.         ADC1->CR2|=1<<2;        //开启AD校准          
    9 L( B' n6 L  f4 w0 S! r: q
  43.         while(ADC1->CR2&1<<2);  //等待校准结束' r" }9 L- F5 d# s0 M1 N) L( K* ]" U
  44.         //该位由软件设置以开始校准,并在校准结束时由硬件清除  
    / Q. o6 E  I# ^4 ?& i4 r/ G
  45. }                                  
    # N3 j/ k! ~4 f6 Z/ b, u* z" a
  46. //获得ADC值  ?* [% w" [# w0 v+ ~. ~
  47. //ch:通道值 0~3
    # Y9 F, t( ~4 C
  48. u16 Get_Adc(u8 ch)   
    " S: A6 r$ _$ @
  49. {, p5 ~1 |: c( [# a: f2 V' L, G2 R
  50.         //设置转换序列                           3 }4 r( w; {& ^: l% m
  51.         ADC1->SQR3&=0XFFFFFFE0;//规则序列1 通道ch$ Z0 g) M9 X' ^8 J$ \# b4 w2 X
  52.         ADC1->SQR3|=ch;                                              4 a; e9 x0 u' f1 g$ ]1 ]
  53.         ADC1->CR2|=1<<22;       //启动规则转换通道 * Z, \  A6 b, T2 k1 V4 V7 }
  54.         while(!(ADC1->SR&1<<1));//等待转换结束                    # J$ u* Z+ k0 U0 G* Q5 v4 h4 n
  55.         return ADC1->DR;                //返回adc值       
    3 c6 E5 |+ Q/ Z4 y9 z4 O
  56. }
复制代码

% i% W' E0 ?7 }1 I
  1. #include <stm32f10x_lib.h>4 D2 ]0 V) p  T% S" u
  2. #include "adc.h"4 |4 G" W+ u( Z% c7 [0 H0 C  \  e
  3. //ADC 驱动代码                                     
    ( _" W7 s( s2 n! Q/ G/ Z
  4. //初始化ADC
    ; L/ [. g$ O; o) m$ H5 o
  5. //这里我们仅以规则通道为例
    ; o8 ]% S: n$ S
  6. //我们默认将开启通道0~3                                                                                                                                          
    : k' L) ]  s" |* n8 x
  7. void  Adc_Init(void)+ i0 f9 Y! `2 L
  8. {    & O* s9 s" ~$ G% j& n
  9.         //先初始化IO口$ r. q3 q* _" a6 \* ?3 I
  10.         RCC->APB2ENR|=1<<2;    //使能PORTA口时钟 - D" W: z6 c! C4 s6 m! _& E
  11.         GPIOA->CRL&=0XFFFF0000;//PA0 1 2 3 anolog输入$ g1 z6 E  X- Q, w- `; K$ {3 E
  12.         //通道10/11设置                         ; F; s$ h' P, g$ I3 t0 F
  13.         RCC->APB2ENR|=1<<9;    //ADC1时钟使能          $ F& |, J2 }! F/ r
  14.         RCC->APB2RSTR|=1<<9;   //ADC1复位
    2 g6 Z  S* `- y; E- J8 x- \
  15.         RCC->APB2RSTR&=~(1<<9);//复位结束            
    : e; {/ F4 ~5 i+ R  E* h) A/ ]
  16.         RCC->CFGR&=~(3<<14);   //分频因子清零       
    ; `* r: T9 z4 s" @: L, B
  17.         //SYSCLK/DIV2=12M ADC时钟设置为12M,ADC最大时钟不能超过14M!
    + s" _4 M  M% v2 h7 _
  18.         //否则将导致ADC准确度下降!
    ! p* |8 F$ A) E# l& g" p5 u3 L
  19.         RCC->CFGR|=2<<14;               ( A; }) l2 i5 X( _' Z
  20. ! D( ?3 d; O) R5 j3 Q
  21.         ADC1->CR1&=0XF0FFFF;   //工作模式清零/ B2 T# C7 b. H
  22.         ADC1->CR1|=0<<16;      //独立工作模式  * V# J( {! O6 h0 |: E
  23.         ADC1->CR1&=~(1<<8);    //非扫描模式          ( v: y8 y* w3 M! _
  24.         ADC1->CR2&=~(1<<1);    //单次转换模式
    # M( k# Z! O% m8 ^
  25.         ADC1->CR2&=~(7<<17);          
    ) N& Z6 s8 L% `& n& Y# B- v
  26.         ADC1->CR2|=7<<17;           //软件控制转换  + D: y$ \$ X3 T, j' e, f4 [! P
  27.         ADC1->CR2|=1<<20;      //使用用外部触发(SWSTART)!!!        必须使用一个事件来触发
    9 N6 h/ C1 C' i' e7 g
  28.         ADC1->CR2&=~(1<<11);   //右对齐         
    6 W1 k9 ?5 O/ I' q2 q
  29.         ADC1->SQR1&=~(0XF<<20);: D- ^% o  W( l) w: v
  30.         ADC1->SQR1&=0<<20;     //1个转换在规则序列中 也就是只转换规则序列1                            2 C$ J3 c4 o* ^' d4 {5 Z4 y$ X
  31.         //设置通道0~3的采样时间
    # C+ w3 R) U6 Z3 X# q
  32.         ADC1->SMPR2&=0XFFFFF000;//通道0,1,2,3采样时间清空          
    % }3 c( [: j0 E9 ^8 Y# i
  33.         ADC1->SMPR2|=7<<9;      //通道3  239.5周期,提高采样时间可以提高精确度         6 ^1 U8 q& |0 c
  34.         ADC1->SMPR2|=7<<6;      //通道2  239.5周期,提高采样时间可以提高精确度         
    6 F8 g* d7 @3 w* M$ U6 F1 c
  35.         ADC1->SMPR2|=7<<3;      //通道1  239.5周期,提高采样时间可以提高精确度         
    / ~4 q$ u2 Q) N
  36.         ADC1->SMPR2|=7<<0;      //通道0  239.5周期,提高采样时间可以提高精确度         8 x- R/ ~) h% Z/ g/ a# x

  37. 3 ~  I6 x8 G5 O* I6 ^
  38.         ADC1->CR2|=1<<0;            //开启AD转换器         / Y0 R- O6 w) F4 {+ [  M' u
  39.         ADC1->CR2|=1<<3;        //使能复位校准  
    ) |! n( v6 E1 R5 d  ]' Z1 i3 `6 x
  40.         while(ADC1->CR2&1<<3);  //等待校准结束                          : n/ v* b9 J7 T0 S: x
  41.     //该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。                  
    + D6 G* Z/ J) G; f3 b
  42.         ADC1->CR2|=1<<2;        //开启AD校准          
    3 Z2 n: N" C, [" D" v
  43.         while(ADC1->CR2&1<<2);  //等待校准结束
    / ~# r% I# q( @' F
  44.         //该位由软件设置以开始校准,并在校准结束时由硬件清除  
    " _2 j6 u% u9 m" i
  45. }                                  $ Q$ C, @* H9 i' ?  ]! P
  46. //获得ADC值& r5 k( a% Z. i
  47. //ch:通道值 0~3$ j5 ?* e: K& R4 |3 J& z1 y
  48. u16 Get_Adc(u8 ch)   
    3 ]" I2 K* _  ]+ ~9 y9 M0 ?5 H7 z
  49. {
    1 u. J) }; f0 g' V8 H9 J  V
  50.         //设置转换序列                           
      J$ p$ _1 @5 C
  51.         ADC1->SQR3&=0XFFFFFFE0;//规则序列1 通道ch2 z: {$ D0 o3 M6 z1 B/ v* W3 c1 t- e
  52.         ADC1->SQR3|=ch;                                              
    & K# D1 F6 T! g5 W$ x/ S5 @
  53.         ADC1->CR2|=1<<22;       //启动规则转换通道
    , _+ {, q3 \0 J" j+ h, |
  54.         while(!(ADC1->SR&1<<1));//等待转换结束                    * Z* K$ G2 Y, P' j
  55.         return ADC1->DR;                //返回adc值        ' w3 Y" w: w2 Q; i* s( G& {
  56. }
复制代码

& I2 D7 o. i3 E$ c6 `/ o9 V9 @) K) A
  • #ifndef __ADC_H
  • #define __ADC_H
  • #define ADC_CH0 0 //通道0
  • #define ADC_CH1 1 //通道1
  • #define ADC_CH2 2 //通道2
  • #define ADC_CH3 3 //通道3
  • void Adc_Init(void);
  • u16 Get_Adc(u8 ch);
  • #endif
    7 Z6 S) v' }* O! Q+ G! s- ^2 \
    ! e+ s; a8 E0 i& e. @
% y2 H6 K  h: K1 j. {. ~
5 g2 s- g" I" p' L- w( ]
收藏 评论0 发布时间:2022-10-12 15:47

举报

0个回答

所属标签

相似分享

官网相关资源

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