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

【经验分享】STM32F103单片机ADC功能使用

[复制链接]
STMCU小助手 发布时间:2022-3-20 13:37
  stm32f103系列单片机内部ADC为12位ADC。/ B; b3 Z' s. J2 Q
12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部
4 h0 @9 V" S; I% O% N' w1 o2 B信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右
( B6 c; k, d0 ~! I6 C1 ?& h& }) ], o+ U对齐方式存储在16位数据寄存器中。+ X2 @- n  S! t5 w& O
模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。) |9 U. Q! k% `. h! }
ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。
' r4 I' \- {) [: Q/ W* a# V3 X1 S4 I, @6 \6 l( O9 K
ADC 主要特征/ H9 t6 V) k3 Z. e

  W2 q$ u9 M* l+ `# {: b● 12位分辨率2 C9 f8 l' Q0 [
' c( _2 q: q. M& _0 y
● 转换结束、注入转换结束和发生模拟看门狗事件时产生中断, E! w- {3 L1 `4 y7 i: ?

9 j" T- M: U( V● 单次和连续转换模式; D; Q6 C7 [3 E; w
: ^5 k$ C2 x6 _4 P5 m7 I' T9 o# O9 Y7 Q
● 从通道0到通道n的自动扫描模式
0 T; R" Z$ x1 V
+ F) h1 t! a$ S4 E& }$ z/ `● 自校准
0 D6 r  k) O  d2 l* q- X  P- O- J) Q# d0 ]) p
● 带内嵌数据一致性的数据对齐5 A9 Q: f8 U) t+ U, f0 s' P
5 G) r5 _# _9 U" X$ p8 R/ e# u/ ~
● 采样间隔可以按通道分别编程
1 s! H2 h; r7 M, M2 m0 f! }( `! q8 R  F3 Y% d/ v
● 规则转换和注入转换均有外部触发选项
$ b* Z7 H, }. r1 r- K8 o9 k! `4 K( ?+ x
● 间断模式
9 v0 A; D9 `+ l( p0 h! x# r
% X! B0 ?' ?$ n: G% P7 V6 ^5 i● 双重模式(带2个或以上ADC的器件)( O2 s9 Z/ C0 \0 _" x+ ]

2 Z& X" b' T2 K1 X$ ?% w( Z& H/ F下面就用代码演示如何设置ADC单次转换模式
' I  _' b6 R  t+ q1 ?& d/ M1 N& q8 m4 f3 ^; U& _
  1. void ADCx_Init(void)
    + Q; Y- F' E# |( {# C6 o
  2. {9 J9 i# @/ u# x  f4 P
  3.     GPIO_InitTypeDef GPIO_InitStructure;
    - z5 R4 r: v8 v% A" D3 O; E5 R) G
  4.     ADC_InitTypeDef ADC_InitStructure;
    1 v* x7 |) e+ h+ y
  5. , G- H) `3 B, D3 |0 ]" [* g# k$ p: S3 g
  6.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);  B- n/ `) m2 A) b
  7.     RCC_ADCCLKConfig(RCC_PCLK2_Div6);                                        //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
    , n+ n6 r* x1 \  B  T! f) d! i
  8. & z" F- A* B- r2 A9 H! k8 P
  9.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_2| GPIO_Pin_3| GPIO_Pin_4| GPIO_Pin_5;                                //PA1
    + h- C* o8 W) S) i
  10.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                        //模拟输入; l7 T. A; {) H, t6 P7 l
  11.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;2 p& j) j  e, Y& n. Y
  12.     GPIO_Init(GPIOA, &GPIO_InitStructure);7 V) K$ @  V: p" U" K# W

  13. 4 e$ e, B  k* _( |/ u
  14.     ADC_DeInit(ADC1);- H" v7 x* j% }, B( _

  15. 3 }/ S- @8 E4 G# M+ G* R
  16.     ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                //工作在独立模式* ]' y$ e2 x! K' `
  17.     ADC_InitStructure.ADC_ScanConvMode = DISABLE;                        //单通道模式
    1 j; g, `9 T0 \7 u7 j5 c
  18.     ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                //单次转换模式5 Z- P9 a, M4 g/ {" J5 A' F# V9 u
  19.     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //软件触发5 L. N5 e( t7 ]% m) x
  20.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;         //右对齐
    . u+ h" K+ K/ ?1 z" _
  21.     ADC_InitStructure.ADC_NbrOfChannel = 1;                                        //规则转换ADC通道数
    . ]$ g7 e" r. V% o6 L& h2 U
  22.     ADC_Init(ADC1, &ADC_InitStructure);
    5 }+ n1 \: S7 @( S

  23. - {* _+ m3 @1 m+ e; m" e+ I
  24.     ADC_Cmd(ADC1, ENABLE);                                                //使能ADC15 A$ X8 V8 i" X. r
  25. . o7 b: e5 {) T1 ?; O6 ]" b
  26.     ADC_ResetCalibration(ADC1);                                        //复位校准% U; D. R  m# \2 `% z2 Y1 w
  27.     while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
    3 X+ A3 B2 Z& m6 V- q0 T
  28.     ADC_StartCalibration(ADC1);                                        //开启AD校准& W- r, M2 A' d8 ^: E
  29.     while(ADC_GetCalibrationStatus(ADC1));                //等待校准结束4 x7 \* @8 E2 `& y

  30. ) ?7 o5 ]2 h+ C5 _# R* M8 h6 Y
  31. }
复制代码

+ |! e$ q+ R: w0 }2 H+ }  首先初始化IO口,这里的初始化的是ADC抓换通道的0–5,对应的IO口PA0到PA5,将这6个IO口这是为模拟输入模式。接下来在将这几个口设置为ADC口,在设置之前首先将ADC模式复位,然后将ADC设置为单通道单词转换模式,也就是每次只转换一个通道,转换一次后就停止转换,直到接收到下一次转换命令为止。开始转换的命令是由软件来设置的。$ Y, w9 u5 }+ e. y. B  U

/ y) B& q/ W  Q+ ^  ADC口初始化好之后,还需要一个读取转换结果的函数,用于读取指定通道的转换值。
% G1 n: u* Z+ a/ Z' @5 ~1 {9 x6 v6 E7 I. a7 F8 X( Y+ Q; x% v, R
  1. //获取ADC值* p6 v  G4 k. ^8 J
  2. //ch:通道号
    / l2 M0 v/ b/ V( ^0 P3 m
  3. u16 Get_Adc( u8 ch )7 K. b) t( K% t* P9 z
  4. {
    2 _9 f& K8 Q6 I7 `' I& a
  5.     ADC_RegularChannelConfig( ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期
    ; P. G  }3 _/ i! q$ u3 x. ^
  6.     ADC_SoftwareStartConvCmd( ADC1, ENABLE );                                                        //使能ADC1软件启动转换6 n+ C0 n# a5 S# F; P% k. H! x
  7.     while( !ADC_GetFlagStatus( ADC1, ADC_FLAG_EOC ) );                                        //等待转换结束
    + s0 ~1 p- O/ p. }5 N, d" B
  8.     return ADC_GetConversionValue( ADC1 );                                                                                                                        //返回最近一次ADC1规则组的转换结果
    " c3 {# M- D( l6 ?6 r
  9. }
    % t3 B, K, Q7 e! w0 i
  10. % D6 G1 b  J6 F5 ^/ F. c
  11. u16 Get_Adc_Average( u8 ch, u8 times )$ G0 H( `6 B# N1 h; U5 I0 e  W
  12. {  m0 K! b% E5 W4 n! d7 w
  13.     u32 temp_val = 0;* z9 E- d# k! q+ _/ g! n- b3 K
  14.     u8 t;( J9 u$ Q8 m6 d. O5 _, R9 R* }
  15.     for( t = 0; t < times; t++ ); {, R1 g5 k: }6 f7 C" \
  16.     {$ h# D: g  x" b, `9 N# L
  17.         temp_val += Get_Adc( ch );
    ) M) N9 k& u) |- g
  18.         delay_ms( 5 );
    ! R+ _# q- s4 D/ t# Q5 f2 @/ t. o
  19.     }
    . _$ i& A% j1 m
  20.     return temp_val / times;
    , [& D4 }' e% m& A
  21. }
复制代码

/ T3 e* o$ f  ^4 Y# s, U) xGet_Adc()函数用于读取指定通道的ADC转换值,这里的通道必须是初始化函数中初始化过的通道,这个函数每次只读取一次通道值,为了确保转换结果的正确性,需要多次读取通道值取平均值,所以这里Get_Adc_Average()函数就是用来设置多次读取指定通道值,然后取平均值后返回。比如可以设置读取通道1,100次然后取平均值。ADC相关的设置函数就初始化好了,接下来在主函数中调用Get_Adc_Average()函数就可以读取通道值了。
+ X  M& m( v- j
0 B/ p' U' s# y# ~/ g+ u
  1. int main(void)
    ' v# U3 I! L* C1 h5 m% P
  2. {
    4 U4 N8 i9 m' R: ~4 j7 E, E7 |7 M
  3.     u16 adcx = 0;
    2 p/ |( }* y9 z" _0 v
  4.     float temp;2 G- A9 A/ Z1 _& ~' }
  5.     delay_init();                       //延时函数初始化% d+ p3 ~0 G# s( M
  6.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);( N) e8 |5 [' q" d/ i, J* `
  7.     uart_init(115200);
    6 |6 o* n: f9 O, l4 s
  8.     LED_Init();7 w+ L: z6 ^4 t9 v  I' T6 }6 K: _: x
  9. 3 |( c8 s4 A. h/ e1 x
  10. 0 B* O* c' I: c
  11.     LED0 = 1;
    " _; e5 F7 S5 i; B
  12.     LED1 = 1;
    7 w9 g, ~/ ?! Y% {1 ~" j5 U( m
  13.     delay_ms(500);
    ( Y# r+ X& ^& ~) i% @
  14.     LED0 = 0;
      ?" V' X  B1 O& M0 Q5 `+ q! X5 }
  15.     LED1 = 0;
    % l' ^5 b: l4 z: H. W& H/ u
  16. " N1 v& t4 J; r  q" j
  17.     ADCx_Init();
    5 E3 ]" j8 D; B! N

  18. ) a8 C# f1 m* A: k2 F$ N, a
  19.     printf("ADC test!!!\r\n");+ v( U: O/ C# w! B) Z& ~
  20.     while(1)8 c% H1 U/ R% n, @7 V
  21.     {
    0 d: @. |# A* ?% z' @* F
  22.         adcx = Get_Adc_Average(ADC_Channel_0, 10);
    $ f- b' q- ^2 e) Q
  23.         printf("ch0       num: %d\r\n", adcx);
    2 E, Y) J2 ~7 i& p+ |+ |
  24.         temp = (float)adcx * (3.3 / 4096);
    # a- n$ y$ w! M
  25.         adcx = temp * 1000;: r7 t. c0 s2 K, J5 r
  26.         printf("ch0 adc value: %d\r\n", adcx);
    4 x" k. `1 Q0 Y* m$ M6 E; y
  27. 4 b! a9 i  ?, v8 e7 u& b
  28.         adcx = Get_Adc_Average(ADC_Channel_1, 10);
    % Q6 J7 n5 j% m. _% ~  d! ]
  29.         printf("ch1       num: %d\r\n", adcx);
    : e9 k0 A6 y6 K0 E& K, @3 d' |/ V
  30.         temp = (float)adcx * (3.3 / 4096);9 r: q: t& s. {1 v- Y
  31.         adcx = temp * 1000;
    # i4 H5 g" t9 j6 A9 y1 `
  32.         printf("ch1 adc value: %d\r\n", adcx);# P7 v7 Q/ }) x" Z

  33. # _  O) K9 d. j! z1 o5 a
  34.         adcx = Get_Adc_Average(ADC_Channel_2, 10);1 j$ ~9 F9 t8 a7 y  I. k+ E
  35.         printf("ch2       num: %d\r\n", adcx);
    & X# g; K' A8 h7 S1 H/ ]
  36.         temp = (float)adcx * (3.3 / 4096);
    4 o4 b  Q1 m' m' j% _
  37.         adcx = temp * 1000;1 G  c6 L3 y' s# r6 k
  38.         printf("ch2 adc value: %d\r\n", adcx);7 Q: [) X9 K/ {( ^

  39. , v  y& \$ X5 u, S2 @6 J. i
  40.         adcx = Get_Adc_Average(ADC_Channel_3, 10);1 p' A- l0 b# p1 N
  41.         printf("ch3       num: %d\r\n", adcx);' ^- q; i+ ~% V5 v8 ?" N8 R) z
  42.         temp = (float)adcx * (3.3 / 4096);3 _0 k+ f; N* r& s( x2 a
  43.         adcx = temp * 1000;6 Y# A( Y. O+ L
  44.         printf("ch3 adc value: %d\r\n", adcx);* o9 `, C+ H- A4 l/ `

  45. . S( b- `5 ?6 l: E
  46.         adcx = Get_Adc_Average(ADC_Channel_4, 10);
    2 Q) b" y' z3 a% F  ]! M
  47.         printf("ch4       num: %d\r\n", adcx);1 r' s: j9 k/ C2 R) ]. Z( B
  48.         temp = (float)adcx * (3.3 / 4096);( N) G0 n) N& X3 ]
  49.         adcx = temp * 1000;& U; R- S2 y, {" i3 z
  50.         printf("ch4 adc value: %d\r\n", adcx);
    % t- ~" Y2 `/ T+ Z. R; G
  51. " I  j: V, y1 m8 _
  52.         adcx = Get_Adc_Average(ADC_Channel_5, 10);
    . W9 \8 @% y( Z3 u  `3 W; L
  53.         printf("ch5       num: %d\r\n", adcx);5 J7 j% u& y- K" {/ e3 l  ?
  54.         temp = (float)adcx * (3.3 / 4096);
    # a/ O  _* n' p* Z1 [& c
  55.         adcx = temp * 1000;8 b* A  Q6 P. q* H
  56.         printf("ch5 adc value: %d\r\n", adcx);, D# r3 Y2 d8 `8 K! S2 U
  57. ) K( E4 F6 M1 Q+ p! D9 g
  58.         LED0 = !LED0;
    0 Z. s1 W$ ]& y( p; x. ]! P
  59.         delay_ms(500);8 {* `: ?7 ?- `7 V# y
  60.     }
    # Z3 {* L# O4 \& q- m5 L
  61. }
复制代码
+ O9 N% ?, W% n* t
在主函数中依次读取通道0到通道5的值,读取10次取平均值,然后将转换后的值打印出来。由于ADC为12位,所以转换后的最大值为4096,对应的最大电压值为3.3V,为了方便观察,将转换后的值换换位电压值。# _$ y8 |$ @; y* S
9 I. Z5 x" W) q8 y) {4 u

" x7 E: w" X( `. M7 x
赞 收藏 评论0 发布时间:2022-3-20 13:37

举报

0个回答

所属标签

相似技术帖

官网相关资源

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