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

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将停止,直到下次启动。

+ }4 m& G" _) t. ]+ r3 N$ z

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

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

; ]0 i+ I/ p, k6 n" U4 k9 ?3 N, Q

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

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

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

  T/ z; Y2 \$ C0 Q

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 。

  C& {0 \7 k' i* B9 @$ n
2.3. ADC规则序列寄存器(ADC_SQR1~3)

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

- h: Y- m/ X+ V- x4 ?" ~4 @1 {) e: v1 y

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

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


2 A( k/ E4 d% n

2.5. ADC状态寄存器(ADC_SR )

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

1 s, K1 a) F1 s- G; x

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>1 V# Y' P: }! `) P' W
  2. #include "adc.h"
    # k# R& y* L3 C& t/ S! a
  3. //ADC 驱动代码                                      2 z% M5 Q, W) i0 T1 a" H5 a! N5 w: r
  4. //初始化ADC
    ; y- M" p/ g8 N4 }4 Z* K
  5. //这里我们仅以规则通道为例
    8 n/ ~$ l$ a0 s3 [$ L" t: z
  6. //我们默认将开启通道0~3                                                                                                                                           $ ^5 b+ h7 _' |
  7. void  Adc_Init(void)6 H8 `: g# N! A
  8. {    - R( P! t# I! j6 \4 L' n
  9.         //先初始化IO口
    ) G1 S" n. t, {, f
  10.         RCC->APB2ENR|=1<<2;    //使能PORTA口时钟 # W" q+ y, p7 ], p6 {! m
  11.         GPIOA->CRL&=0XFFFF0000;//PA0 1 2 3 anolog输入
    8 X3 D: G7 {8 B" `* I/ e) c
  12.         //通道10/11设置                         
    % @8 m* m/ T/ h$ ~
  13.         RCC->APB2ENR|=1<<9;    //ADC1时钟使能          
    2 }8 @6 c. k( |2 ?  F3 ?
  14.         RCC->APB2RSTR|=1<<9;   //ADC1复位
    ) c0 E- @4 t# W2 s" S) R
  15.         RCC->APB2RSTR&=~(1<<9);//复位结束            - ~. o8 W; Y6 J; [* Y/ b
  16.         RCC->CFGR&=~(3<<14);   //分频因子清零        ) d0 r0 U6 q4 n9 |9 m9 A: G
  17.         //SYSCLK/DIV2=12M ADC时钟设置为12M,ADC最大时钟不能超过14M!
    # j9 A+ d3 |7 j2 _5 g! Y0 C& ]
  18.         //否则将导致ADC准确度下降!
    + e: G0 Z, Z1 W5 `
  19.         RCC->CFGR|=2<<14;               
    ! Q, V5 Y: R$ R! j9 i/ P! ^( y
  20. " C4 n! O( }/ b5 `
  21.         ADC1->CR1&=0XF0FFFF;   //工作模式清零/ `' S8 B" Z7 @+ w' k  F
  22.         ADC1->CR1|=0<<16;      //独立工作模式  
    " |. G  j' ?* K8 A* ]
  23.         ADC1->CR1&=~(1<<8);    //非扫描模式          + ]  g) m% F6 c) C$ s% Z
  24.         ADC1->CR2&=~(1<<1);    //单次转换模式3 |1 r& P$ n1 J) j1 N
  25.         ADC1->CR2&=~(7<<17);           $ l3 O% F5 M  B) h1 _5 a
  26.         ADC1->CR2|=7<<17;           //软件控制转换  
    3 p/ J; U4 B( M  H0 n* r
  27.         ADC1->CR2|=1<<20;      //使用用外部触发(SWSTART)!!!        必须使用一个事件来触发
    4 ?. t, v1 n4 [) h* ^. }
  28.         ADC1->CR2&=~(1<<11);   //右对齐         
    $ {- R( C" F5 m2 U+ K
  29.         ADC1->SQR1&=~(0XF<<20);
    $ S8 L/ ~: E& l% l
  30.         ADC1->SQR1&=0<<20;     //1个转换在规则序列中 也就是只转换规则序列1                           
    . ]$ r  n) j2 ^; o; u
  31.         //设置通道0~3的采样时间) W0 G2 \! D# N. [2 D  j8 u
  32.         ADC1->SMPR2&=0XFFFFF000;//通道0,1,2,3采样时间清空          % K  L$ P7 f9 P
  33.         ADC1->SMPR2|=7<<9;      //通道3  239.5周期,提高采样时间可以提高精确度         
    4 w  G2 n7 U) Q9 e$ [2 z! p; y$ m
  34.         ADC1->SMPR2|=7<<6;      //通道2  239.5周期,提高采样时间可以提高精确度         
    4 J4 E* A  |7 j( j+ A/ V
  35.         ADC1->SMPR2|=7<<3;      //通道1  239.5周期,提高采样时间可以提高精确度         
    $ r. b" }6 j( |7 B
  36.         ADC1->SMPR2|=7<<0;      //通道0  239.5周期,提高采样时间可以提高精确度         
    6 i3 N; B+ ]8 S) z
  37. * L* b% P1 \( N( m
  38.         ADC1->CR2|=1<<0;            //开启AD转换器         3 N+ Q& G3 X  [, L, _. d
  39.         ADC1->CR2|=1<<3;        //使能复位校准  
    " t' l! d$ U3 N7 B9 ^+ l
  40.         while(ADC1->CR2&1<<3);  //等待校准结束                          5 A: e3 k$ I( X& d6 O: R
  41.     //该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。                  
    ! V8 {+ j$ u& L1 Y' s3 u  i
  42.         ADC1->CR2|=1<<2;        //开启AD校准          
    ( n' h  W" a9 G
  43.         while(ADC1->CR2&1<<2);  //等待校准结束
    2 r( z$ x% R5 X
  44.         //该位由软件设置以开始校准,并在校准结束时由硬件清除  
    # p6 ?: P+ u6 N. O. f
  45. }                                  * |* A0 K( P1 K$ T7 r
  46. //获得ADC值, R$ Y$ g: }' E6 D- t
  47. //ch:通道值 0~3% b. I) e& k) {( u9 F( m# T
  48. u16 Get_Adc(u8 ch)   
    1 z6 j' w* ~' n; F
  49. {1 C& g/ g# n- T' F4 J
  50.         //设置转换序列                           
    ; b/ {& Q" K6 K
  51.         ADC1->SQR3&=0XFFFFFFE0;//规则序列1 通道ch; i$ ^8 @3 ?5 X
  52.         ADC1->SQR3|=ch;                                              % A# }9 h" b9 R' ~' Y3 A) H# A
  53.         ADC1->CR2|=1<<22;       //启动规则转换通道 ! E6 U. m. `1 r/ v' ~
  54.         while(!(ADC1->SR&1<<1));//等待转换结束                   
    / V+ o& x& V) v8 I( @0 c! C: P
  55.         return ADC1->DR;                //返回adc值        / k+ [' S3 `7 W
  56. }
复制代码
2 P6 L& [$ w: A7 K  t1 u% k
  1. #include <stm32f10x_lib.h>
    5 K# s! H* f/ _4 V4 Q
  2. #include "adc.h"
    2 ^! l' E( d+ d  O# F3 U9 X  _
  3. //ADC 驱动代码                                     
    5 y# r9 {+ I& M
  4. //初始化ADC
    ' u" D. H% k8 l1 |# j
  5. //这里我们仅以规则通道为例
    ) z5 B2 k& g6 m. h
  6. //我们默认将开启通道0~3                                                                                                                                          
    7 I8 U/ Z9 w7 G2 @7 J0 i
  7. void  Adc_Init(void)
    ) |. m% ^* B0 f/ @1 ^
  8. {   
    ( X& _$ |; z. F; O
  9.         //先初始化IO口6 R- r7 h2 j$ e4 H
  10.         RCC->APB2ENR|=1<<2;    //使能PORTA口时钟 , q7 K$ L# ~1 J0 V# e1 `
  11.         GPIOA->CRL&=0XFFFF0000;//PA0 1 2 3 anolog输入( ~* Y# k+ V2 N* s
  12.         //通道10/11设置                         7 F" {: P& j6 |' x* i- U
  13.         RCC->APB2ENR|=1<<9;    //ADC1时钟使能          # z8 W- n3 R$ W" X
  14.         RCC->APB2RSTR|=1<<9;   //ADC1复位# _6 N5 f% |1 @( b: |
  15.         RCC->APB2RSTR&=~(1<<9);//复位结束            
    - @4 P- r  J$ f. ]2 U5 I
  16.         RCC->CFGR&=~(3<<14);   //分频因子清零        ) ]5 D3 ~) G; Z( `
  17.         //SYSCLK/DIV2=12M ADC时钟设置为12M,ADC最大时钟不能超过14M!
    / o9 |' Q; @- H9 E8 y
  18.         //否则将导致ADC准确度下降!
    - W, A: y6 @) D# Y) s
  19.         RCC->CFGR|=2<<14;               9 w* Y% H3 g/ E& x: A& p

  20. " g% P8 Q; M' Y: x9 g6 B# s# i* ~
  21.         ADC1->CR1&=0XF0FFFF;   //工作模式清零
    : w& _. F! g, A6 c3 y2 O
  22.         ADC1->CR1|=0<<16;      //独立工作模式  , k6 q$ P, _- x* M$ Q9 h
  23.         ADC1->CR1&=~(1<<8);    //非扫描模式          9 H: m0 l' z$ [& [
  24.         ADC1->CR2&=~(1<<1);    //单次转换模式
    / B. s3 \( E6 _  F2 C
  25.         ADC1->CR2&=~(7<<17);           + a/ W3 ]# k) ~8 R3 S
  26.         ADC1->CR2|=7<<17;           //软件控制转换  0 d  B7 i2 S, g) n4 Y4 G3 Z2 A
  27.         ADC1->CR2|=1<<20;      //使用用外部触发(SWSTART)!!!        必须使用一个事件来触发1 ?% }+ I9 W2 c4 o
  28.         ADC1->CR2&=~(1<<11);   //右对齐         $ l% T) G! Z: x) \0 Q3 P
  29.         ADC1->SQR1&=~(0XF<<20);) i! O  c' y- n: S4 z& }
  30.         ADC1->SQR1&=0<<20;     //1个转换在规则序列中 也就是只转换规则序列1                            ; F" l& B+ t. @" E6 W
  31.         //设置通道0~3的采样时间" K- x/ }, s3 _' X! R9 N
  32.         ADC1->SMPR2&=0XFFFFF000;//通道0,1,2,3采样时间清空          ; n1 f7 @% M; C/ Q) Q4 r
  33.         ADC1->SMPR2|=7<<9;      //通道3  239.5周期,提高采样时间可以提高精确度         
    1 O+ C% U+ w: K. i0 Z4 z! {
  34.         ADC1->SMPR2|=7<<6;      //通道2  239.5周期,提高采样时间可以提高精确度         
    , @. {& E6 v. B7 e. o% u0 X
  35.         ADC1->SMPR2|=7<<3;      //通道1  239.5周期,提高采样时间可以提高精确度         
    ! @- Q; m9 j  ^& `( ]
  36.         ADC1->SMPR2|=7<<0;      //通道0  239.5周期,提高采样时间可以提高精确度         
    0 t- D" L2 y! U0 v

  37. + M4 s$ y) f/ V. q5 x5 W0 M7 ?8 Q
  38.         ADC1->CR2|=1<<0;            //开启AD转换器         
    0 E# _5 d# `& O# G- O7 d4 i% W+ ^
  39.         ADC1->CR2|=1<<3;        //使能复位校准  
    # R7 L1 b3 l+ F) i1 [. H
  40.         while(ADC1->CR2&1<<3);  //等待校准结束                          
    1 k, ]* f5 B7 a' a
  41.     //该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。                  $ [4 b0 |$ @6 N; j% h: o
  42.         ADC1->CR2|=1<<2;        //开启AD校准           8 z5 k. M# K; |3 C, R5 v2 W
  43.         while(ADC1->CR2&1<<2);  //等待校准结束! L( H. e$ P3 S8 q
  44.         //该位由软件设置以开始校准,并在校准结束时由硬件清除  2 e# n. O/ F0 j5 z
  45. }                                  
    * K  M& X+ |* N' c
  46. //获得ADC值
    " o$ g$ i* W' j4 `4 I
  47. //ch:通道值 0~3  ^6 s4 l. s( o% |4 Y) E3 l
  48. u16 Get_Adc(u8 ch)   8 Y+ B4 A+ V. {5 t3 v! n
  49. {
    4 J  S% T1 u+ J. R# ~" M9 x
  50.         //设置转换序列                           
    1 j, J  F* G% K" Y7 e' c
  51.         ADC1->SQR3&=0XFFFFFFE0;//规则序列1 通道ch( Z1 ?, K) H. F8 P* @; s% s) k# ^7 O
  52.         ADC1->SQR3|=ch;                                              
    + v/ Q' {# S0 Y3 {5 i
  53.         ADC1->CR2|=1<<22;       //启动规则转换通道
    8 Q, ]7 K1 ^5 Z1 N5 B# z8 R
  54.         while(!(ADC1->SR&1<<1));//等待转换结束                    / L& h- r( v' u9 ]' X! y: K  u# ~
  55.         return ADC1->DR;                //返回adc值        $ i+ S( y9 \* H6 W2 v
  56. }
复制代码
+ X/ }" y( O+ y8 A( {. `; r" S
  • #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
    . B7 R2 [& n8 I% B0 n- A+ ]- u

    5 h4 a+ R! N; }: w& C

6 G3 N" b8 N# G, p7 c; y( V6 E$ g) K0 u/ |
收藏 评论0 发布时间:2022-10-12 15:47

举报

0个回答

所属标签

相似分享

官网相关资源

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