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

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同步规则模式的情况下,还添加了多通道同时采样。
: [( B6 v' C  u2 Y
; I2 A" s! E. K0 S6 Z( A/ O

. Z( a* ?- T+ {4 x2 l, qADC1和ADC2,工作方式采用了同步规则模式,使得两个ADC可以同时对不同的AD输入进行采集和数据存储和传输,而且相互不影响,也可以确保采样时间的减少,同时两个ADC都是使用4通路同时采集,确保了数据的稳定性。5 _' j6 j* a  e5 J+ p! j

9 `& ~& H' l5 I7 g+ Z9 Y

) h( Z! @3 T  ^# j多功能采集显示平台使用的芯片是STM32F103ZET6,片上资源提供了ADC123共3路ADC模块,为了布线方便以及使用的习惯,多功能采集显示平台采用了ADC1的Chanel 4~7,占用IO口PA 4~7,以及ADC2的Chanel 10~13,占用IO口PC 0~3。7 b& k) u$ F: w4 t5 o7 _+ H( M

- b& x$ C1 X) F5 w" ^

: Y+ c* p& T6 a% m( Y3 s. B使用时有几点需要注意的:
$ [7 W  [6 L4 f5 q! Q% U( N) O' l5 e6 {; Z! ?" |) _
2 y3 k) J. V/ }; w6 D: Q' U: M
1.选择正确的模式:ADC_Mode_RegSimult,即DUALMOD[3:0] = 0110,ADC2在双模式中,这些位为保留位# ^. C; }) E- j$ T3 G% r% d# l- ?

2 m9 R. Y5 s7 p% K- q

. J4 g% @8 h2 n' e. M2.开启ADC的DMA,在双ADC模式里,为了在主数据寄存器上读取从转换数据,必须使能DMA位,即使不使用DMA传输规则通道数据。只有ADC1和ADC3能产生DMA请求。所以只需设置ADC1的DMA:ADC_DMACmd(ADC1, ENABLE);: v  J, q$ j; E; ]9 ?
, l! L7 E0 L4 B* e: K
0 N8 I* @: u- B  ^: X
3.ADC2的转换数据存在ADC1_DR的高半字;
2 L9 \+ A! _( l- h. u0 g: j
; K+ `6 w* ~2 H1 X: Q( x' S9 I

* n/ X% {2 e0 _# @2 Y1 k4.不要在2个ADC上转换相同的通道(两个ADC在同一个通道上的采样时间不能重叠)。
1 x1 q$ F; g" n% c6 W
  q& K& }! h8 K8 b1 L

/ E$ v/ ]4 s% S4 S5.ADC2的CR2寄存器的第20位——EXTTRIG:规则通道的外部触发转换模式必须开启(软件启动的时候也要),这样才能利用到ADC1的触发信号。不然的话,需要手动再软启动一次ADC2,例如ADC_SoftwareStartConvCmd(ADC2, ENABLE);
4 {) |; F7 O2 r. X4 W1 S
  W8 b2 a4 @+ m* U: k7 i' o0 _6 |
/ X- S. Q0 x9 X3 s
但是,假如你设置了这个位之后,就不需要手动软启动ADC2了,所以考虑到同步,这样比较好。用ADC_SoftwareStartConvCmd(ADC2, ENABLE);为什么可以,一方面它 也设置了EXTTRIG位,另一方面也设置了SWSTART。但我觉得先用ADC_ExternalTrigConvCmd(ADC2, ENABLE);的话,一会只要ADC1一启动,两者就同 时启动了,这样更正确一点。8 q; ?: i, B& ]3 ?0 j9 T" u
1 ?/ [- {4 _% V. [
- x% |3 M. P: i0 n( k
以下是ADC1配置代码和使能代码:" m; Q$ z3 l# j. F% N; u6 ~
  1. //初始化ADC1  
    5 d8 \, E! L& h: |3 Z/ q
  2. //这里采用多通道连续采样,并用DMA1的通道传送  5 h% V" B3 N& A3 L' {  ~
  3. //我们默认将开启通道4~7  8 D" ?' i7 }0 n
  4. //相应管脚PA4~7  
    ' i1 z2 v9 h- c# e6 `% I
  5. void Adc1_Multi_Init(void)  $ x: @, C! b! q6 o& M; t- t
  6. {     
    ' X! j' h. Z; l
  7.     ADC_InitTypeDef ADC_InitStructure;   
    6 K+ u; |" P2 E
  8.     GPIO_InitTypeDef GPIO_InitStructure;  
    % l, z% I, [5 ?$ c0 `6 q# C
  9.   ; p" R- x6 R4 Y6 ~2 \
  10.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1    , ENABLE );   //使能ADC1通道时钟  ( h: B+ r9 m) U: N2 I4 _, O
  11.    4 j( o4 _; p- ~1 Y+ t9 G8 R
  12.   8 \* O, n; M  G/ o6 f
  13.     RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M  ( s8 S" k, L2 v- M% h
  14.   
    7 \  B' U9 B5 d! \
  15.     //PA1 作为模拟通道输入引脚  . L9 i% N: q. U+ r. `
  16.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;  
    1 g# s( D7 U0 X
  17.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;       //模拟输入引脚  * B' B3 [, d: F- @% Z# ]
  18.     GPIO_Init(GPIOA, &GPIO_InitStructure);    ) @/ D$ z: L6 c% _6 o" m5 s) i
  19.   - e- L) E; X6 g
  20.     ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值  
    / Y! w: k5 e4 l+ Y# V6 Y* r
  21.   ( ]: `  `) B) S) \9 V
  22.     ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;    //ADC工作模式:ADC1同步规则组模式  % @* \+ m/ x4 G# p% y4 s- X# S! ?
  23.     ADC_InitStructure.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式  6 {# K6 E: H9 }0 x
  24.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在连续转换模式  * h( g0 ^% u$ c8 P
  25.     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动  
    ' [  ~8 O$ v2 X; p( H
  26.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //ADC数据右对齐  % o% K# B. ^8 M  o! k: @( y" W
  27.     ADC_InitStructure.ADC_NbrOfChannel = 4; //顺序进行规则转换的ADC通道的数目  8 i5 C' V6 R( W& w6 k
  28.     ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器     ; X. v% w8 d1 F- M" b4 m
  29.   
    9 {) T) l  x6 D2 u; C  M
  30.     ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_239Cycles5 );  
    9 b5 y8 T" O6 q3 q+ v, j# ?# W
  31.     ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_239Cycles5 );  , I( w! z6 q% U: W/ H- z- I
  32.     ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 3, ADC_SampleTime_239Cycles5 );  
    + E. `, e& h, T8 c% g+ L
  33.     ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 4, ADC_SampleTime_239Cycles5 );  . ^6 d# s; F" b* C/ w/ c1 Q4 W
  34.   
    % v: D, q: Z7 {
  35.     // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)  
    ( Q( D7 }1 |6 H& H4 U, Y; ]
  36.     ADC_DMACmd(ADC1, ENABLE);  
    3 p/ g! i# l, ^# L
  37. }     # U; |8 H( Z; A$ r" _
  38. //计算多通道ADC值  
      z1 U. ~* a( b6 T9 L
  39. //AD_Value[]是DMA目标地址的数组空间  / S$ ~  [/ ?: G9 i6 E
  40. u16 Get_Multi_Adc1(void)  " h0 i2 T# }  F/ u4 G9 f( ?4 o
  41. {  
    % @+ ]! K0 p. x* D
  42.     u32 temp_val=0;    [, h* M, p* _9 L1 ^
  43.     u8 t;  
    $ Z0 M2 E8 D# [4 t
  44.     for(t=0;t<4;t++)  
    5 o$ C6 _: C* D9 u& @
  45.     {  7 X- q" O& P7 G1 K0 I* P( W) r2 A
  46.         temp_val+=(AD_Value[t] & 0xffff);  / u- B" G' X: ?) C/ E3 z/ \6 }
  47.     }  
    2 ^0 g) f% d. T7 b
  48.     return temp_val/4;  9 V) I! w. n3 g9 Z& u
  49. }
复制代码
主要需要修改的是这句话,使得ADC处于同步规则组模式。' v9 A1 E# w- S0 b
  1. <strong>ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;  //ADC工作模式:ADC1同步规则组模式</strong>
复制代码
AD_Value[]是32位的,用于DMA传送的目标的ADC数据数组。其中高16位是ADC2的数据,地16位的是ADC1的数据。$ f6 @8 v1 D2 u/ Z4 V+ ^
$ c! q& L  T7 B1 ~1 W. B
) e  i2 S. x, [5 j$ }6 O0 K  |! E, A
) a4 ^. i' L  h" h. k9 j: i
其次是ADC2配置代码和使能代码:: X0 [$ Q! |+ i' P0 i
  1. //初始化ADC2  
    : f6 Q7 @0 S$ S0 \# V3 E- Z( R
  2. //这里采用多通道连续采样,并用DMA1的通道传送  ' A$ ?# B: L& f, Z
  3. //我们默认将开启通道10~13  6 Q  j+ l$ [, [( [0 _$ f4 Z; O
  4. //相应管脚PC0~3  
    , D/ m# }) x1 O3 q  a
  5. void Adc2_Multi_Init(void)  ) R; |$ i& V; S  k" ^. Q
  6. {     
    3 j1 {* S! W8 E( R7 d+ D/ |* d1 U+ V
  7.     ADC_InitTypeDef ADC_InitStructure;   3 ]2 w) z" P2 [! M
  8.     GPIO_InitTypeDef GPIO_InitStructure;  
    / i3 f: H. o0 ~+ s$ D
  9.   $ m3 @7 ]! r& o
  10.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |RCC_APB2Periph_ADC2    , ENABLE );   //使能ADC2通道时钟  0 v2 \4 E; D" F0 N7 @
  11.    5 v( C3 e: ~* \' @- n- d8 I$ J
  12.   6 z. ?3 c$ x' [4 h
  13.     RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M  
    # X4 @( P- e7 B: I8 t9 w. W
  14.   5 G5 {! N  e" C, _: {
  15.     //PB0,1 作为模拟通道输入引脚  
    * M( T4 K* q- S% L% T! e' W
  16.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;  9 Z" @& u6 @: A& v$ \+ N* z
  17.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;       //模拟输入引脚    N  T5 B+ k" U: ^1 m0 _) Y3 f
  18.     GPIO_Init(GPIOC, &GPIO_InitStructure);    ) b9 A# a) }. r/ Z  h
  19.   
    - [6 H8 ]/ d/ ]; ?" R! ]0 F
  20.     ADC_DeInit(ADC2);  //复位ADC2,将外设 ADC2 的全部寄存器重设为缺省值  
    & ]2 ~+ F: r  h" Q9 t" H' Y; y) ]" T" p
  21.   
    4 o0 C& S: h& t2 @1 F5 h& @3 M/ k
  22.     ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;    //ADC工作模式:ADC1同步规则组模式  
      p& T7 a$ C0 P: G1 V, ?
  23.     ADC_InitStructure.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式  
    5 U3 u. B. {1 k
  24.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在连续转换模式  
    ' `3 X, g5 `2 D) p; B( w
  25.     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动  : G! F# @3 S& ?& h+ C6 R
  26.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //ADC数据右对齐  3 o9 r! k8 y4 U7 n
  27.     ADC_InitStructure.ADC_NbrOfChannel = 4; //顺序进行规则转换的ADC通道的数目  ' n( n  Y) m" U4 x" N( n  U
  28.     ADC_Init(ADC2, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器     6 h0 }$ _9 r) O; ]; o; ~
  29.   ; x: `4 D1 g9 j0 x- ]
  30.     ADC_RegularChannelConfig(ADC2, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5 );  : X0 `# H  q6 i" |2 {$ T# U/ N
  31.     ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 2, ADC_SampleTime_239Cycles5 );  6 v' y* v1 G6 G7 x: \- Q
  32.     ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 3, ADC_SampleTime_239Cycles5 );  
      l7 c8 T5 B0 v' E: |+ I
  33.     ADC_RegularChannelConfig(ADC2, ADC_Channel_13, 4, ADC_SampleTime_239Cycles5 );  & _8 y5 o1 V" F: {( X  R4 I+ h
  34.   8 z! j  C6 d& w8 x: A4 l
  35.     ADC_ExternalTrigConvCmd(ADC2, ENABLE);                                        //使能ADC2的外部触发模式   3 J9 {5 j- f+ l+ B1 x( X% A7 ~: d
  36.   * t: f# I4 c1 N, c2 U
  37.     // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)  
    : M/ p8 H/ ^+ H
  38.     //ADC_DMACmd(ADC2, ENABLE);    s) W( {7 a, z* l+ k
  39. }   
复制代码
  1. //计算多通道ADC值  7 ~6 v: T$ z+ @# I$ v
  2. //AD_Value2[]是DMA目标地址的数组空间  
    + o/ Y' s6 ?: s  Q/ r
  3. u16 Get_Multi_Adc2(void)  / r( N) n! i8 P- [9 p7 B3 j
  4. {  
    " f# `$ `  T3 c: J
  5.     u32 temp_val=0;  
      h2 B5 u9 r3 [; s3 Q; G8 g7 @0 \
  6.     u8 t;  * I8 X4 W) N4 }
  7.     for(t=0;t<4;t++)  
    . K+ y) S% o5 H4 U0 v. W" f
  8.     {  3 K- x9 ]9 E/ T8 M, P6 s8 y! H& E
  9.         temp_val+=((AD_Value[t]>>16) & 0xffff);  
    4 i: V. _" ~, {3 W" I* J
  10.     }  
    8 D& r% z' q; O  S! L. B
  11.     return temp_val/4;  
    5 a0 B8 |# z2 d* x$ I0 E0 g
  12. }
复制代码
ADC2主要需要添加下面语句,用于ADC1触发ADC2的工作。- S- F; b; {$ n, e8 w4 M. v% ~' e
  1. ADC_ExternalTrigConvCmd(ADC2, ENABLE);//使能ADC2的外部触发模式
复制代码
AD_Value[]是32位的,用于DMA传送的目标的ADC数据数组。其中高16位是ADC2的数据,地16位的是ADC1的数据。这里使用AD_Value[t]>>16进行移位操作,获取数据。
- p( A* Q% W( ]' z& M& D4 N" V! }
) U6 f4 H- q4 G
0 y1 U0 y7 Q) L

, l3 T1 R+ f: U6 C/ s% [
赞 收藏 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管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版