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

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

[复制链接]
STMCU小助手 发布时间:2022-3-20 13:37
  stm32f103系列单片机内部ADC为12位ADC。& Q9 d* S! e9 S
12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部
* E7 _7 o, L% I" Q信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右( p% t5 k' ]- B9 d- N
对齐方式存储在16位数据寄存器中。4 _, \$ j. e+ x# @3 b8 S  c
模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。: U3 _$ ~% t: B7 G7 l- U! c
ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。+ e$ p) e. T" Z% k: n4 P% S" G8 l
; ^; w( P# X7 N  p/ W/ l5 ]; o
ADC 主要特征  [$ V) [; R$ p( x/ {# \

4 e5 t1 W9 E% a● 12位分辨率
0 R) x9 l( {. p5 Q& D5 [& _  q& M! Z8 k
● 转换结束、注入转换结束和发生模拟看门狗事件时产生中断2 k2 X3 j! x( r0 z( K4 o" Q
7 M4 x+ D& S" |  I
● 单次和连续转换模式
) U/ e/ Z% x  Z# b5 ?$ }7 {7 a4 q' C# e7 |
● 从通道0到通道n的自动扫描模式
/ i* S9 F8 w+ R2 m: s& }
% e4 X; l- d- X& _& x* R* m# J! Z2 X● 自校准5 `, @5 {, Z, [/ ]
1 a8 U, j6 m. Z& C  Q# q/ _
● 带内嵌数据一致性的数据对齐
9 I0 b' b0 O! C1 T: |. O& {/ n. @9 u' H
1 o  o* u# O1 k5 N6 w. A# [6 C9 k● 采样间隔可以按通道分别编程
3 T7 D4 C" n$ P- I$ d8 g: j) a% D, S. u: a
● 规则转换和注入转换均有外部触发选项
4 E$ x7 |- M$ z; U& i1 a3 g: V9 w, M: ^2 D  G6 K9 Z
● 间断模式# v* S7 x2 [' \; f  a
4 h* |; u* G" j" P
● 双重模式(带2个或以上ADC的器件)
% F% n/ f$ O1 o- h* y  M2 ]8 ?8 V5 o  r- o. e, ^
下面就用代码演示如何设置ADC单次转换模式- ^& z$ J7 u& C2 y' P0 P3 G8 X

% T; |9 O1 \& Z7 ^0 ^/ t, K+ h
  1. void ADCx_Init(void)
    ) U, S  i% M% A8 X6 u
  2. {8 j/ g7 m4 o8 q6 Y9 Q/ b, S
  3.     GPIO_InitTypeDef GPIO_InitStructure;, L% n3 g9 H1 F" t5 A: ]" s
  4.     ADC_InitTypeDef ADC_InitStructure;1 V  U! @; p# J& x
  5. / e% g) M7 y; M+ m/ J' ~% ~/ t
  6.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
    ( k$ A  J/ ^$ s: i' |, J! C1 w
  7.     RCC_ADCCLKConfig(RCC_PCLK2_Div6);                                        //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M  s2 S0 z. {$ T& P1 R
  8. - i( N  i& M- s. ?
  9.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_2| GPIO_Pin_3| GPIO_Pin_4| GPIO_Pin_5;                                //PA1  U5 G* O6 F" W2 d
  10.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                        //模拟输入8 b) M7 V  q0 G
  11.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  O: Q0 G7 g" D9 o) k
  12.     GPIO_Init(GPIOA, &GPIO_InitStructure);
    4 N+ m3 d. ^5 }/ I

  13. $ }9 V1 u7 O' R0 @. t' H% p' S
  14.     ADC_DeInit(ADC1);
    0 D" S3 P" L5 F7 L- T
  15. + O: h% u7 }" M+ y, h# [$ Q
  16.     ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                //工作在独立模式3 T$ I5 n( g1 L2 z6 A9 J/ F
  17.     ADC_InitStructure.ADC_ScanConvMode = DISABLE;                        //单通道模式( V/ o( i/ j0 F/ N) W. s5 @
  18.     ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                //单次转换模式) h; k: r. U3 W! _/ j% a
  19.     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //软件触发
    6 I( p# ?& p7 L7 a) u
  20.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;         //右对齐
    5 f! a1 W1 @, G# U8 u: Z3 Y
  21.     ADC_InitStructure.ADC_NbrOfChannel = 1;                                        //规则转换ADC通道数! A% J9 Z  P) N4 h% N
  22.     ADC_Init(ADC1, &ADC_InitStructure);
    ) ?& V6 C! Z) `  u- R, \
  23. 8 U( q0 L9 X$ B7 F0 B1 e) O  o. n& _
  24.     ADC_Cmd(ADC1, ENABLE);                                                //使能ADC1
    : }5 N1 l5 _/ S2 [* K8 V2 h" V

  25. : [+ j2 N; w  B/ [: O
  26.     ADC_ResetCalibration(ADC1);                                        //复位校准
    6 Q$ ?& }$ a& e2 N3 v
  27.     while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
    9 `* x3 ]$ N0 Y3 o+ G: b0 q
  28.     ADC_StartCalibration(ADC1);                                        //开启AD校准
    3 [$ |+ u, I' m1 Z
  29.     while(ADC_GetCalibrationStatus(ADC1));                //等待校准结束
    % s. u9 b& @! E' q
  30. " e( O- [) B5 ^
  31. }
复制代码

! W/ p2 }( e$ q% U* G. f  首先初始化IO口,这里的初始化的是ADC抓换通道的0–5,对应的IO口PA0到PA5,将这6个IO口这是为模拟输入模式。接下来在将这几个口设置为ADC口,在设置之前首先将ADC模式复位,然后将ADC设置为单通道单词转换模式,也就是每次只转换一个通道,转换一次后就停止转换,直到接收到下一次转换命令为止。开始转换的命令是由软件来设置的。
: |( o. O. l& R) H- @1 h2 a* j9 r. R6 A$ q4 D
  ADC口初始化好之后,还需要一个读取转换结果的函数,用于读取指定通道的转换值。3 J$ R& w6 e4 b5 |) M& I/ q4 k( d8 V
+ w4 ^5 m3 g$ }
  1. //获取ADC值. d+ g+ S& z1 o& Q% V
  2. //ch:通道号4 c/ W8 B# x) E
  3. u16 Get_Adc( u8 ch )
    ! O+ |$ C6 s! H. T
  4. {
    1 r: n3 d$ T, y
  5.     ADC_RegularChannelConfig( ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期
    2 z6 T6 J( a4 x" N6 H) v. o
  6.     ADC_SoftwareStartConvCmd( ADC1, ENABLE );                                                        //使能ADC1软件启动转换
    5 y) g; N% ?9 }
  7.     while( !ADC_GetFlagStatus( ADC1, ADC_FLAG_EOC ) );                                        //等待转换结束- P, F3 l/ I+ P4 E( g: B
  8.     return ADC_GetConversionValue( ADC1 );                                                                                                                        //返回最近一次ADC1规则组的转换结果
    3 e2 j# t7 T. P* Y5 F0 P  B$ C
  9. }$ h+ `) s. r6 q1 c
  10. / M, v$ X5 L' ?3 f5 ?
  11. u16 Get_Adc_Average( u8 ch, u8 times )
    9 U: c5 L# i$ R) R2 }' X2 Y. U! i
  12. {
    $ |/ K% g, ?+ h% e: A4 l7 x# \/ K
  13.     u32 temp_val = 0;  f$ R# [: k0 E3 b! `3 f
  14.     u8 t;6 `0 m( u) U7 q! T; ^9 k. P
  15.     for( t = 0; t < times; t++ )4 r8 N9 e6 v/ H1 i2 t$ j5 p$ o
  16.     {- ?1 _8 P  x+ F" }: F3 J7 ^
  17.         temp_val += Get_Adc( ch );
    % ^& [' y! j0 @9 x! X
  18.         delay_ms( 5 );2 {& k: b) [% x3 V$ X/ |
  19.     }* K( I5 u, ~8 q" L( K0 l" i; h9 f2 R
  20.     return temp_val / times;
    " e. l, c4 U' h4 `
  21. }
复制代码

1 g3 t4 D3 |' d% x, @Get_Adc()函数用于读取指定通道的ADC转换值,这里的通道必须是初始化函数中初始化过的通道,这个函数每次只读取一次通道值,为了确保转换结果的正确性,需要多次读取通道值取平均值,所以这里Get_Adc_Average()函数就是用来设置多次读取指定通道值,然后取平均值后返回。比如可以设置读取通道1,100次然后取平均值。ADC相关的设置函数就初始化好了,接下来在主函数中调用Get_Adc_Average()函数就可以读取通道值了。
- \  y5 \2 N! y$ C
! O! x7 ^+ u1 i- Z$ R1 ^" O
  1. int main(void)  d0 A4 H% T' A4 n
  2. {4 x- q3 [* h- ]+ H! z- |
  3.     u16 adcx = 0;
    4 `8 i# A9 ~" [' q! k
  4.     float temp;7 S; g- W* ]5 }# i
  5.     delay_init();                       //延时函数初始化# a8 z: Z& g; q
  6.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    8 {; A3 z5 o6 t/ \
  7.     uart_init(115200);
    7 |0 u" w* r8 B" m
  8.     LED_Init();8 o+ F9 _, W6 ?/ U+ p$ }$ t

  9. 7 B* t6 i' Z8 o, K

  10. ) ?  U1 ]1 p9 b0 Z5 l" U9 [8 F
  11.     LED0 = 1;
    % K; b! V- M: V& s1 x7 e5 ]& m
  12.     LED1 = 1;  L* o( x9 d3 L, p* a1 q# A5 z
  13.     delay_ms(500);
    $ [2 r! n$ c5 `6 Z. _+ b6 Y
  14.     LED0 = 0;% ]9 \$ k( C+ V% B: a: E
  15.     LED1 = 0;
      Y2 q6 ?; b' r7 l
  16. # |( N" X# x) w+ `- n, G
  17.     ADCx_Init();
    8 I4 o4 M( k& x5 e. d9 c9 k

  18. 0 d! G) C, W) H" D. o8 e; y/ }
  19.     printf("ADC test!!!\r\n");
    * k- w  e# V3 v3 d4 \
  20.     while(1)" ]: j4 u; I0 T" T/ \# A; r9 t
  21.     {7 L( n8 }+ s) f' u' t3 x( U# o  I
  22.         adcx = Get_Adc_Average(ADC_Channel_0, 10);% Q0 w! y4 G6 d7 L" c
  23.         printf("ch0       num: %d\r\n", adcx);. j- J' l1 j( }- L, v2 y- r
  24.         temp = (float)adcx * (3.3 / 4096);
    ; r& g2 K$ ^% C+ M1 j: y4 [$ e
  25.         adcx = temp * 1000;
    - T; n# e' V2 \' ?
  26.         printf("ch0 adc value: %d\r\n", adcx);! x  D+ `. f, G# M1 S! K! g
  27. $ d. b! Y0 l. ?; H( d- ~
  28.         adcx = Get_Adc_Average(ADC_Channel_1, 10);$ X1 v3 {5 ?: k" {( o$ C
  29.         printf("ch1       num: %d\r\n", adcx);
    4 v7 s! H. h; l; @( X
  30.         temp = (float)adcx * (3.3 / 4096);& h, V$ D& X8 I( l9 \% b1 @
  31.         adcx = temp * 1000;
    # H4 n1 O  Q, Z0 h9 A& X
  32.         printf("ch1 adc value: %d\r\n", adcx);
    * [( V/ H; y6 @7 T( h  E/ `
  33. 6 g* v  T; v$ Q) U+ Y
  34.         adcx = Get_Adc_Average(ADC_Channel_2, 10);# d: c* a, A4 @  r! u# [9 B8 W
  35.         printf("ch2       num: %d\r\n", adcx);
    ' v$ ^2 R' B. I; r( @
  36.         temp = (float)adcx * (3.3 / 4096);9 C/ V9 c2 x, V8 a- [- ]) H/ e. T
  37.         adcx = temp * 1000;
    * n5 ~4 x2 v, J& Q3 S) Z
  38.         printf("ch2 adc value: %d\r\n", adcx);# d- }  U+ z  }
  39. + f/ ?$ ~$ Z4 G5 }! }& w, @& W
  40.         adcx = Get_Adc_Average(ADC_Channel_3, 10);
    4 S3 ^, l  M& a+ e# G
  41.         printf("ch3       num: %d\r\n", adcx);
    ! K5 [9 ]( L" s
  42.         temp = (float)adcx * (3.3 / 4096);4 a% i; `# U/ e) I1 N
  43.         adcx = temp * 1000;& X# ^8 {3 S1 H- E
  44.         printf("ch3 adc value: %d\r\n", adcx);+ y( p  b+ Q! H( z
  45. 4 W* c" h( u6 k
  46.         adcx = Get_Adc_Average(ADC_Channel_4, 10);1 t# i) O* J- J$ f
  47.         printf("ch4       num: %d\r\n", adcx);
    9 |: i4 z8 N. M, e7 ]8 p
  48.         temp = (float)adcx * (3.3 / 4096);2 Q+ `  ]0 b! f8 R1 I& |
  49.         adcx = temp * 1000;) X0 |1 q, g' ^( `! v, ^
  50.         printf("ch4 adc value: %d\r\n", adcx);
    ' z2 O5 E; |# V6 D2 n1 E8 v
  51. - E$ P0 c% {9 D  y  i) S- a
  52.         adcx = Get_Adc_Average(ADC_Channel_5, 10);
    + N6 R0 |1 U' T& h' F; A
  53.         printf("ch5       num: %d\r\n", adcx);) G8 H) ?& Y: @8 F- U+ B6 O( D
  54.         temp = (float)adcx * (3.3 / 4096);
    7 A0 z3 U# `  ?9 f/ a
  55.         adcx = temp * 1000;
    , D; R4 J0 l/ F4 j2 \; G; K) [& u. X
  56.         printf("ch5 adc value: %d\r\n", adcx);
    , W% [% E2 J; U/ T

  57.   W9 |; d' g- z/ {
  58.         LED0 = !LED0;2 s* n) V5 f; D8 j3 d3 b/ t
  59.         delay_ms(500);6 o. c7 }# _0 q! h8 f9 k( X/ R; ]6 Y
  60.     }
    ; S! a* u& s% c% w+ m3 s9 h
  61. }
复制代码
. n" m4 |$ E, L
在主函数中依次读取通道0到通道5的值,读取10次取平均值,然后将转换后的值打印出来。由于ADC为12位,所以转换后的最大值为4096,对应的最大电压值为3.3V,为了方便观察,将转换后的值换换位电压值。$ m9 e. |/ B* |5 n2 e5 n% |

; H1 a" \3 M* L) l1 B$ C: u( W# f# m$ F( v2 Z( C
收藏 评论0 发布时间:2022-3-20 13:37

举报

0个回答

所属标签

相似分享

官网相关资源

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