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

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

[复制链接]
STMCU小助手 发布时间:2022-3-20 13:37
  stm32f103系列单片机内部ADC为12位ADC。
9 k1 S4 y" l4 p1 s$ Q9 G* Q12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部
2 s3 c! N3 a1 o信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右
& ^" B  }: L/ t& x! Q- y* e对齐方式存储在16位数据寄存器中。
" v4 G6 ]; k9 R7 l: M模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
6 [2 C% q6 ^7 k2 eADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。! o& y3 F+ [+ T# I$ a6 t

9 ?- _& R4 s- i: k. H# P1 L9 kADC 主要特征8 l0 O, [" J5 u$ t
/ C8 d& n' k5 ^1 D
● 12位分辨率4 |7 Q1 N+ `5 I; r  @7 |

8 X! p6 e& m' I9 ]● 转换结束、注入转换结束和发生模拟看门狗事件时产生中断
5 g) q2 I# F2 h* \- G# ~: H( I8 h1 X. _! s9 s: X2 b
● 单次和连续转换模式9 \( z: K& Q* e4 {
" l8 j" j  t# Q
● 从通道0到通道n的自动扫描模式
5 K! P( y- e: G3 t* }" U  h8 G% @1 I2 v( `
● 自校准
( ~4 S9 S' r+ u; G% ]4 g5 d
6 H* n. M! ^5 Y( i% t● 带内嵌数据一致性的数据对齐) X" h1 ]$ \: ~9 Z! _8 S

- {! d2 s2 F' ]  D- E/ C# i● 采样间隔可以按通道分别编程
6 M1 q6 T' c6 y9 }+ O; s& }: D$ Z$ |4 `
● 规则转换和注入转换均有外部触发选项; @% u8 w  W  D7 W

& \: y' Z) X6 b8 o● 间断模式
" ^7 o) m3 ^( s: t6 \* y7 e: v' J) F" r8 e
● 双重模式(带2个或以上ADC的器件)/ R) X3 |2 _' k
2 |( D# R% J0 W# i5 \
下面就用代码演示如何设置ADC单次转换模式
) U8 o" A; O' M2 ^5 Q' I# T; N, F* H2 `  A, P( k5 K/ H
  1. void ADCx_Init(void)7 i1 n# R6 i/ R! M" V) P
  2. {4 E+ W0 \3 K8 g% A/ l
  3.     GPIO_InitTypeDef GPIO_InitStructure;4 `1 |2 O4 Q0 P6 c2 K: w3 z
  4.     ADC_InitTypeDef ADC_InitStructure;
    2 l7 `8 M* U/ ~/ G+ i7 R! G% N

  5. 6 X( a$ Q1 O1 i3 q
  6.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);& [0 \: `8 V1 v# D
  7.     RCC_ADCCLKConfig(RCC_PCLK2_Div6);                                        //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M1 p& y/ T5 L* ]
  8. ) t, \& c. p* c" L1 P! U- O
  9.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_2| GPIO_Pin_3| GPIO_Pin_4| GPIO_Pin_5;                                //PA17 D0 }9 B8 i' R3 O! L
  10.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                        //模拟输入* m, {" x/ G, {: R7 F
  11.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    5 d; a5 A0 P, F6 ]# E
  12.     GPIO_Init(GPIOA, &GPIO_InitStructure);
    ' R% u: E6 l; P

  13. ) m$ D$ h9 C) b1 M9 H# i* y5 H
  14.     ADC_DeInit(ADC1);0 N- B: ~0 A4 V+ d
  15. 4 B% o# R% b) n, T$ N% c
  16.     ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                //工作在独立模式
    . d6 H1 {( x2 `1 z% K& `
  17.     ADC_InitStructure.ADC_ScanConvMode = DISABLE;                        //单通道模式+ Q- ?* y; J- Q: m+ Y/ e* g) p
  18.     ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                //单次转换模式3 F3 N& g" |2 I" U- b
  19.     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //软件触发. s0 T' d! W! k
  20.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;         //右对齐
      {; D6 Q* M0 P( ?3 L% C& W
  21.     ADC_InitStructure.ADC_NbrOfChannel = 1;                                        //规则转换ADC通道数
    4 w1 z  |/ I4 G
  22.     ADC_Init(ADC1, &ADC_InitStructure);
    $ s% t0 _1 h' p* O5 [
  23. : C' c0 o  d# D' [
  24.     ADC_Cmd(ADC1, ENABLE);                                                //使能ADC1" K1 o) }& X: ^! L9 Q' W
  25. " x3 \* _1 Z' Z1 ~) h
  26.     ADC_ResetCalibration(ADC1);                                        //复位校准$ a: ?$ t, ^0 X# n* n# H6 `
  27.     while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
      S% |6 `, F: b
  28.     ADC_StartCalibration(ADC1);                                        //开启AD校准
    6 W9 y! H8 U6 Y( L! H, B: U3 K
  29.     while(ADC_GetCalibrationStatus(ADC1));                //等待校准结束4 [6 C7 _3 \& H6 G, K! V

  30. * s+ {: [" I4 l7 ~9 W6 g
  31. }
复制代码

/ l/ x0 [+ D8 u5 [4 ]5 B1 s$ b+ t  首先初始化IO口,这里的初始化的是ADC抓换通道的0–5,对应的IO口PA0到PA5,将这6个IO口这是为模拟输入模式。接下来在将这几个口设置为ADC口,在设置之前首先将ADC模式复位,然后将ADC设置为单通道单词转换模式,也就是每次只转换一个通道,转换一次后就停止转换,直到接收到下一次转换命令为止。开始转换的命令是由软件来设置的。1 D; [7 S8 X# x
8 n$ K! j3 t+ x$ Y8 ]
  ADC口初始化好之后,还需要一个读取转换结果的函数,用于读取指定通道的转换值。# E. F7 v& ~: J( m6 p5 p# u8 d
8 T* @3 w1 g6 r& x
  1. //获取ADC值
    7 l- p. b9 k7 {5 `
  2. //ch:通道号1 e. M* R' n/ S
  3. u16 Get_Adc( u8 ch )+ I: U# Q$ o2 Z6 L/ p* J
  4. {
    7 Z+ d( e, W$ [0 ^, i
  5.     ADC_RegularChannelConfig( ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期
    ' P9 D& {& e& A4 H+ y( K4 B7 T& B
  6.     ADC_SoftwareStartConvCmd( ADC1, ENABLE );                                                        //使能ADC1软件启动转换6 U3 T) p: V% x: `  A4 o
  7.     while( !ADC_GetFlagStatus( ADC1, ADC_FLAG_EOC ) );                                        //等待转换结束  A/ G: F9 e8 D
  8.     return ADC_GetConversionValue( ADC1 );                                                                                                                        //返回最近一次ADC1规则组的转换结果
    2 x9 E( Z# r$ R( W& Z
  9. }
    & R4 P) s9 R( |4 R

  10. # y" H/ ?/ g- Z
  11. u16 Get_Adc_Average( u8 ch, u8 times )
    . g9 t6 W: O7 z5 S
  12. {- @+ J/ W  P+ O, @
  13.     u32 temp_val = 0;
    5 x# @% j% @$ ^5 I* O5 L
  14.     u8 t;
    - j7 R9 G2 m: X/ e
  15.     for( t = 0; t < times; t++ )
    ; Y  l1 E7 k% D+ z  ]
  16.     {) r. g1 [  a5 x# r* e* Y, h; @- z
  17.         temp_val += Get_Adc( ch );
    8 b! r2 g* n; y& ?7 h9 z& s
  18.         delay_ms( 5 );
    - O6 Z$ k$ @; W  S' r- `
  19.     }
      z' ~( a6 R6 I$ S- ^
  20.     return temp_val / times;
    ) t& D8 o: X4 f9 a# N  f5 ~
  21. }
复制代码
7 _% z. v% R7 N
Get_Adc()函数用于读取指定通道的ADC转换值,这里的通道必须是初始化函数中初始化过的通道,这个函数每次只读取一次通道值,为了确保转换结果的正确性,需要多次读取通道值取平均值,所以这里Get_Adc_Average()函数就是用来设置多次读取指定通道值,然后取平均值后返回。比如可以设置读取通道1,100次然后取平均值。ADC相关的设置函数就初始化好了,接下来在主函数中调用Get_Adc_Average()函数就可以读取通道值了。
) R' [$ |; N# @+ @  [0 I; W$ Y7 w: j$ N
  1. int main(void)
    . F& ]2 ]% v, R7 v$ E- q
  2. {
    : y' Y1 w8 i, T0 q% I
  3.     u16 adcx = 0;
    * r. e: a, m0 w8 q2 x
  4.     float temp;2 ]9 h4 B4 E+ k2 L4 x* E
  5.     delay_init();                       //延时函数初始化. n( O# ~1 w4 D" y$ E, Z" x; ^
  6.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    6 d' x/ z) S- i) ?' h+ w
  7.     uart_init(115200);, S% C- u8 Y4 S" e( K; Z
  8.     LED_Init();! {3 e$ r; B) u: g: N, M; t

  9. - \% }( D  W# J

  10. ) r# X4 \2 i* h1 T( B
  11.     LED0 = 1;+ T3 z  j3 X% U4 |5 k
  12.     LED1 = 1;. N, u* l  M9 l. X7 i# @
  13.     delay_ms(500);0 ]( w2 P5 v# f( @
  14.     LED0 = 0;
    ) U1 k% K6 I+ v) k
  15.     LED1 = 0;
    + ?7 ]7 _0 X9 }' b) o' Y

  16. : V$ @' j, p  l; o/ ]" G
  17.     ADCx_Init();
      ]& G4 u7 U; p8 Q: X
  18. ! |& @' b( W* m' i
  19.     printf("ADC test!!!\r\n");( {2 d$ _/ u# ?, P$ |' R. U
  20.     while(1)
    $ }7 W! Y% N8 M/ _* p# O2 s% Y
  21.     {
    9 t( {+ `- M8 w5 r% s% r
  22.         adcx = Get_Adc_Average(ADC_Channel_0, 10);
    % @& X  W. Y( o* j9 Q
  23.         printf("ch0       num: %d\r\n", adcx);% J1 A& X0 ^7 J0 x
  24.         temp = (float)adcx * (3.3 / 4096);
    ' r9 c9 r! Q3 E" |
  25.         adcx = temp * 1000;/ u! x; x6 e/ p
  26.         printf("ch0 adc value: %d\r\n", adcx);# X2 M; ]! ]8 M8 y6 I2 H- Q9 l  X
  27. " t: P1 h: S: I8 r6 e; A
  28.         adcx = Get_Adc_Average(ADC_Channel_1, 10);
    5 Z" i9 P0 {: F% `- O' r
  29.         printf("ch1       num: %d\r\n", adcx);
    7 z/ t+ `( x7 t1 ~3 h# ?- b
  30.         temp = (float)adcx * (3.3 / 4096);. l. I) k% G0 I+ m- J
  31.         adcx = temp * 1000;
    ) n0 [) L1 c. y4 i- Z9 x( d
  32.         printf("ch1 adc value: %d\r\n", adcx);9 f, K$ w' ]8 B' Z

  33. : S7 d; y8 l2 x3 @. D6 g
  34.         adcx = Get_Adc_Average(ADC_Channel_2, 10);1 z3 |/ y6 ?  e3 @4 w
  35.         printf("ch2       num: %d\r\n", adcx);
    ' \4 x' z( E3 {# w5 W* A" o
  36.         temp = (float)adcx * (3.3 / 4096);3 Z! @* k- Z% @9 @. c& s! o* {
  37.         adcx = temp * 1000;0 G% b& y) ~, o: Q9 T
  38.         printf("ch2 adc value: %d\r\n", adcx);; J7 L$ F4 {  l6 F& |) |

  39. 4 w$ n) u) G: }# D6 v9 a' I, a
  40.         adcx = Get_Adc_Average(ADC_Channel_3, 10);
    ( {! p1 u; ^" S5 S& O- x# z  m* f$ s
  41.         printf("ch3       num: %d\r\n", adcx);* ~6 Y: s2 X* E, l
  42.         temp = (float)adcx * (3.3 / 4096);4 O+ X3 `2 _, H  v% j! s6 Q
  43.         adcx = temp * 1000;1 ~* v2 d, ^, q
  44.         printf("ch3 adc value: %d\r\n", adcx);
    7 \* O" p5 y( J! Y& X+ w' ]

  45. : ^: ^8 V: E, B# \' N3 A
  46.         adcx = Get_Adc_Average(ADC_Channel_4, 10);- v3 `" L& }, k) q' g( `: p
  47.         printf("ch4       num: %d\r\n", adcx);  G! e$ F5 Y1 r# _5 K: \
  48.         temp = (float)adcx * (3.3 / 4096);1 i% P+ y6 i! C- h" D7 {
  49.         adcx = temp * 1000;
    ' }' t2 x' ]* Z) k" D' w) Q
  50.         printf("ch4 adc value: %d\r\n", adcx);
    ; ?. O! Y, ]9 l5 N: C
  51. - I! C/ V' e1 j( ]
  52.         adcx = Get_Adc_Average(ADC_Channel_5, 10);
    / W' L5 }9 H4 E' [8 N+ N
  53.         printf("ch5       num: %d\r\n", adcx);
    1 s: [" ?1 f5 t( U
  54.         temp = (float)adcx * (3.3 / 4096);9 z" Z6 M  S* k8 L+ [1 Q
  55.         adcx = temp * 1000;. C. c+ F3 i* q0 N" F/ I5 @
  56.         printf("ch5 adc value: %d\r\n", adcx);9 _4 W; E4 P/ I6 g" h

  57. 6 w. n7 g* L/ f( @$ L
  58.         LED0 = !LED0;- [" Y2 f$ O3 E' `5 F* Z; q
  59.         delay_ms(500);
    % C$ P( O1 M/ j4 a# F) m; ?/ ~" \
  60.     }. l8 ?! L: T: X$ O  ]' g% U
  61. }
复制代码

- Q9 F2 O" m# \# {( m在主函数中依次读取通道0到通道5的值,读取10次取平均值,然后将转换后的值打印出来。由于ADC为12位,所以转换后的最大值为4096,对应的最大电压值为3.3V,为了方便观察,将转换后的值换换位电压值。
8 T. f( t7 l8 t! e7 D! X
* g- I% L  V! x% [2 v' o9 d5 N
! ]8 F3 U* z8 a7 H; k! t3 n
收藏 评论0 发布时间:2022-3-20 13:37

举报

0个回答

所属标签

相似分享

官网相关资源

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