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

STM32f103的数电采集电路的双ADC的设计与使用

[复制链接]
liming-367095 发布时间:2017-7-18 13:43
STM32f103的数电采集电路的双ADC的设计与使用
STM32F103C8T6拥有3个ADC,其独立使用已经在本文的3.1.3里面有详细的介绍,这里主要是介绍双ADC的同时使用,即STM32的同步规则模式使用。在此模式在规则通道组上执行时,外部触发来自ADC1的规则组多路开关(由ADC1_CR2寄存器的EXTSEL[2:0]选择),它同时给ADC2提供同步触发。此功能必须使用DMA通道。同时两组数据是公用一个寄存器,ADC1数据在低16位,ADC2数据在高16位。由于保证数据稳定,在双ADC同步规则模式的情况下,还添加了多通道同时采样。( z5 x! o& u+ Y8 W8 T" \3 b
5 d+ O; @5 O" i$ U2 c% K

' R) `  D; U' o$ t4 k: L9 l* OADC1和ADC2,工作方式采用了同步规则模式,使得两个ADC可以同时对不同的AD输入进行采集和数据存储和传输,而且相互不影响,也可以确保采样时间的减少,同时两个ADC都是使用4通路同时采集,确保了数据的稳定性。* `, ~: [# i5 w5 W8 |
( j) J9 ?/ I9 i( `$ ^
, F" S, h. X* m3 `# ~6 b
多功能采集显示平台使用的芯片是STM32F103ZET6,片上资源提供了ADC123共3路ADC模块,为了布线方便以及使用的习惯,多功能采集显示平台采用了ADC1的Chanel 4~7,占用IO口PA 4~7,以及ADC2的Chanel 10~13,占用IO口PC 0~3。
2 H/ T. A: a1 W
$ u' h" s. p6 G! L% J) U) R" i

, ?! F2 i. {' C' z1 Q3 e! x9 j" C使用时有几点需要注意的:& e4 D3 x/ x  ^. ?( S( E6 J" {" F# d
6 `; ^  }% _$ J, {- e

! a9 ~4 b; I; q- i/ V1.选择正确的模式:ADC_Mode_RegSimult,即DUALMOD[3:0] = 0110,ADC2在双模式中,这些位为保留位* }( U; h* Y. H8 ?! n6 V" m) N

1 W5 r# g! P, m
7 ]; l* O% x9 i2 c- H# _
2.开启ADC的DMA,在双ADC模式里,为了在主数据寄存器上读取从转换数据,必须使能DMA位,即使不使用DMA传输规则通道数据。只有ADC1和ADC3能产生DMA请求。所以只需设置ADC1的DMA:ADC_DMACmd(ADC1, ENABLE);. C' N+ T4 O- h3 }' q9 J$ _
5 r7 a2 R8 B* O% T5 C
  \2 z2 w- t4 h/ y" F% N
3.ADC2的转换数据存在ADC1_DR的高半字;
: P5 A# U5 m3 R: e3 L6 v8 K5 s
! x; G  M3 N. p
) S' R! D: u4 q. r4 v
4.不要在2个ADC上转换相同的通道(两个ADC在同一个通道上的采样时间不能重叠)。
$ c: u& U1 c% p- Y; `8 |- Y7 V4 K; u- ]- W7 |' p( E; `
# f' r  U  ?: R- D
5.ADC2的CR2寄存器的第20位——EXTTRIG:规则通道的外部触发转换模式必须开启(软件启动的时候也要),这样才能利用到ADC1的触发信号。不然的话,需要手动再软启动一次ADC2,例如ADC_SoftwareStartConvCmd(ADC2, ENABLE);
; _) T% F$ Y( _: _0 t& h2 z  }
8 q2 @6 ^* ]+ y! _; c5 L( s: A0 c
3 \1 U7 `5 ]) ?0 y8 N
但是,假如你设置了这个位之后,就不需要手动软启动ADC2了,所以考虑到同步,这样比较好。用ADC_SoftwareStartConvCmd(ADC2, ENABLE);为什么可以,一方面它 也设置了EXTTRIG位,另一方面也设置了SWSTART。但我觉得先用ADC_ExternalTrigConvCmd(ADC2, ENABLE);的话,一会只要ADC1一启动,两者就同 时启动了,这样更正确一点。+ b4 z- {9 o8 X$ }4 r5 o& V- ]" {

, N2 x- Y6 H3 B1 V0 n8 h8 P

2 a% O3 q% f' c3 r! t6 D以下是ADC1配置代码和使能代码:3 Z( B0 w/ G8 A) e1 M+ W
  1. //初始化ADC1  
    6 m' L4 q! e1 h7 W# {" J
  2. //这里采用多通道连续采样,并用DMA1的通道传送  ) c6 T" K, H  d' T9 R7 c/ v. w
  3. //我们默认将开启通道4~7  9 H' Z$ [8 h$ `: J6 j8 d3 Z3 y
  4. //相应管脚PA4~7  
    ) X4 j5 L0 q. _1 g1 q$ @6 S( V: X8 S& r
  5. void Adc1_Multi_Init(void)  $ L4 }8 t& a: P
  6. {     4 _/ `1 q! o. p5 R& B
  7.     ADC_InitTypeDef ADC_InitStructure;   ( c! E& ]9 b) Z8 o/ E+ R+ R3 |1 n) K- C
  8.     GPIO_InitTypeDef GPIO_InitStructure;  ' K/ w: Q* ~% R9 W& b" N) I$ b
  9.   
      |% I" e5 G- M% E. R7 j) f
  10.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1    , ENABLE );   //使能ADC1通道时钟  , j" W: u- Z" d5 \( Y- e, o
  11.    8 G3 A" p' M+ r8 ~: {0 h+ L
  12.   # N" p3 f9 |! o0 R. X
  13.     RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M  8 z* [- w/ O# c1 i3 }' Z) |
  14.   
    6 j: h( J( U$ T8 h7 K  M& k
  15.     //PA1 作为模拟通道输入引脚  
    * B$ @% ^+ @. b
  16.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;  
    ( ^" W3 p  b1 A- n
  17.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;       //模拟输入引脚  
    # s) N) Q3 i3 v. _2 _
  18.     GPIO_Init(GPIOA, &GPIO_InitStructure);    $ D7 o# `. q2 G( o. R$ G7 R
  19.   
    , A4 F3 w4 x$ j6 x" a7 O% R
  20.     ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值  ( b' f% _: x8 P2 H/ @( Z/ F
  21.   
    0 E& t3 R+ C2 b# l* n
  22.     ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;    //ADC工作模式:ADC1同步规则组模式  
    6 |+ Z1 i6 p- B1 m3 E
  23.     ADC_InitStructure.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式  
    * }# q4 @6 X) F
  24.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在连续转换模式  , V- z. ]* f+ d2 T- K
  25.     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动  : G) `1 C3 H% j  d- @; @
  26.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //ADC数据右对齐  / ]6 e4 |3 w. x; S) p$ k# W: n
  27.     ADC_InitStructure.ADC_NbrOfChannel = 4; //顺序进行规则转换的ADC通道的数目  1 M2 [8 t6 H% z0 e1 n2 @
  28.     ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器     
    $ R6 l" p: K0 ?2 M0 b8 `  G
  29.   . V* |2 n1 Z3 Q& ~1 ~3 O& f
  30.     ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_239Cycles5 );  * s8 V& n' h0 ~$ c/ @  G7 N0 q
  31.     ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_239Cycles5 );  
    8 p2 B0 D& A' Y6 s9 F! G
  32.     ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 3, ADC_SampleTime_239Cycles5 );  
    5 Q: U! g. U* G
  33.     ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 4, ADC_SampleTime_239Cycles5 );  
      X* l. e6 j8 Y7 q* n% C
  34.   
    + `: F5 E) K$ d) l& x' N* b
  35.     // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)  $ L# A% o0 N1 M$ j. \3 \7 ]
  36.     ADC_DMACmd(ADC1, ENABLE);  & L. a9 @* d! J! I: f
  37. }     / ?5 R# z/ \: Z' i, v
  38. //计算多通道ADC值  
    " u! ~. l. m4 s4 Z+ h5 y% V
  39. //AD_Value[]是DMA目标地址的数组空间  8 B) G4 x9 i3 i, J! t- u
  40. u16 Get_Multi_Adc1(void)  
    ( x  {" x/ z3 i; n
  41. {  ( C- T% b  K8 i" w0 L
  42.     u32 temp_val=0;  
    ' o* @% Y( \" O
  43.     u8 t;    _4 j: e% ^2 w4 k5 ^
  44.     for(t=0;t<4;t++)  . @* K  b$ E( Y: ]2 u4 G
  45.     {  . Z! d; o! l! P: h
  46.         temp_val+=(AD_Value[t] & 0xffff);  - r& [+ ~1 u* a6 t
  47.     }  % N% k) V. a4 r7 H' k
  48.     return temp_val/4;  
    4 M  S4 s" U' `" [& |8 n5 @% j' K
  49. }
复制代码
主要需要修改的是这句话,使得ADC处于同步规则组模式。
$ p" C. l: w# F6 g$ [' J
  1. <strong>ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;  //ADC工作模式:ADC1同步规则组模式</strong>
复制代码
AD_Value[]是32位的,用于DMA传送的目标的ADC数据数组。其中高16位是ADC2的数据,地16位的是ADC1的数据。
' L1 E" K8 ]$ z( R% S# t! ?" Z+ d9 O! [; z* Y
3 n6 T# ]9 g, K  u' Q* y

2 e) t0 {3 j! N# [5 ~. U其次是ADC2配置代码和使能代码:
% K  p  d8 l1 F3 @* T* U2 s% `
  1. //初始化ADC2  
    2 {- d6 U- W& D& f- L; S7 K2 }) b
  2. //这里采用多通道连续采样,并用DMA1的通道传送  ; F8 J1 P; H6 p# K
  3. //我们默认将开启通道10~13  
    ) X% @) t" \; L% O  R  Q
  4. //相应管脚PC0~3  % D, p; S& O6 [* i; v: u6 S. {+ U
  5. void Adc2_Multi_Init(void)  . ?6 ~% x7 ~( T% R
  6. {     1 B! H7 g' m% q1 \) F
  7.     ADC_InitTypeDef ADC_InitStructure;   
    , f3 O0 x/ f! I& w# f0 A$ L) x
  8.     GPIO_InitTypeDef GPIO_InitStructure;  
    * r( I% f) e! u1 X7 a) b
  9.   ( W& |0 N9 Z, p. T# l$ Z+ Q; ^4 c
  10.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |RCC_APB2Periph_ADC2    , ENABLE );   //使能ADC2通道时钟  4 G4 X- ~$ C; N
  11.    
      }# ?. f' z6 o( z
  12.   : U( w# B# c$ _- ?& V
  13.     RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M  . y! l! U8 L( F* I- n. j/ t
  14.   " T2 A" f1 u0 V$ X
  15.     //PB0,1 作为模拟通道输入引脚  
    $ {8 m1 Y% n0 r# a
  16.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;  2 p3 v) h. o& d% _2 f/ X6 u
  17.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;       //模拟输入引脚  - i3 L& Z3 u7 F$ g& G
  18.     GPIO_Init(GPIOC, &GPIO_InitStructure);   
    0 I4 v# {8 q; l; E5 P0 C, v; \! }/ b
  19.   
    7 T& d! Y2 x( |% j' ^$ i
  20.     ADC_DeInit(ADC2);  //复位ADC2,将外设 ADC2 的全部寄存器重设为缺省值  $ _* y* \& E' j3 R& G, Z
  21.   * D3 e: d$ y# K: t) p
  22.     ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;    //ADC工作模式:ADC1同步规则组模式  ; h" N" d% X1 b( ?% j0 ?
  23.     ADC_InitStructure.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式  
    % X; [8 a1 r& m5 }6 y) j1 m
  24.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在连续转换模式  
    . v9 `" E7 a* A+ y/ l7 `
  25.     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动  
      s; ~. L! J8 z( m( J' \" g
  26.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //ADC数据右对齐  
    4 B! I( O! q8 q/ |/ u
  27.     ADC_InitStructure.ADC_NbrOfChannel = 4; //顺序进行规则转换的ADC通道的数目  
    & y3 G% B9 |: |) ^
  28.     ADC_Init(ADC2, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器     2 A& U  H# [) m- T+ s
  29.   # C  j0 J' e, K) N% m  ?* F
  30.     ADC_RegularChannelConfig(ADC2, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5 );  
      P2 H; c  X& c9 i9 V
  31.     ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 2, ADC_SampleTime_239Cycles5 );  / B1 N- n' K  p1 z- Y2 R; a
  32.     ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 3, ADC_SampleTime_239Cycles5 );  & ]. ^  \- A, ~9 E$ L- m
  33.     ADC_RegularChannelConfig(ADC2, ADC_Channel_13, 4, ADC_SampleTime_239Cycles5 );  1 S5 k% C& a$ s! Q/ z2 h4 ]
  34.   
    8 G6 ?, U- A7 `, F; R4 L
  35.     ADC_ExternalTrigConvCmd(ADC2, ENABLE);                                        //使能ADC2的外部触发模式     e0 m4 I7 w* K
  36.   
    , w& D  C- i  G( Q
  37.     // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)  9 |  ]% R2 t) b: E9 v) E
  38.     //ADC_DMACmd(ADC2, ENABLE);  0 W0 P8 O9 ~* u$ R9 b. f7 `, F
  39. }   
复制代码
  1. //计算多通道ADC值  + Y6 B3 [. w; T/ e/ |" q' `  d
  2. //AD_Value2[]是DMA目标地址的数组空间  3 J, @$ C% A- {2 m
  3. u16 Get_Multi_Adc2(void)  
    2 w. [' A% o! C2 U, M6 N) Q
  4. {  1 ?2 h' s5 c: `- \( ~: f8 n
  5.     u32 temp_val=0;  8 ^, V: R9 w4 E* |2 z
  6.     u8 t;  
    # y* D5 r' d$ k" d% N' v5 l/ Q2 ?( B
  7.     for(t=0;t<4;t++)  
    3 W5 D1 k; k, n, I
  8.     {  + ^7 j9 c+ d! C( j
  9.         temp_val+=((AD_Value[t]>>16) & 0xffff);  0 W/ m8 g4 v8 P
  10.     }  - J7 D2 c) t" U. I$ f
  11.     return temp_val/4;  
    # }" E4 q9 o' [2 M) ^5 G9 n
  12. }
复制代码
ADC2主要需要添加下面语句,用于ADC1触发ADC2的工作。/ ]. P2 A% D& E' [! U  r
  1. ADC_ExternalTrigConvCmd(ADC2, ENABLE);//使能ADC2的外部触发模式
复制代码
AD_Value[]是32位的,用于DMA传送的目标的ADC数据数组。其中高16位是ADC2的数据,地16位的是ADC1的数据。这里使用AD_Value[t]>>16进行移位操作,获取数据。0 |# G3 @5 t# @7 G7 h" D$ |3 K
/ }' X/ ?+ ^4 Z4 n1 `

. }9 @9 e; T- M7 u: q
5 Y( N/ @# I9 K1 j" m7 B0 Q, l
收藏 2 评论1 发布时间:2017-7-18 13:43

举报

1个回答
Ein 回答时间:2017-11-2 17:27:26
请教一个问题,使用AD_Value[t]>>16取高16位数据的时候,DMA同时也在向AD_Value写入数据,取出的数据多半会产生混乱。请问这个问题如何解决?

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版