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

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同步规则模式的情况下,还添加了多通道同时采样。& Q* W7 \3 [# D
! Z2 g+ M, T; `& S

9 ~5 J; a, d* B; X: N) rADC1和ADC2,工作方式采用了同步规则模式,使得两个ADC可以同时对不同的AD输入进行采集和数据存储和传输,而且相互不影响,也可以确保采样时间的减少,同时两个ADC都是使用4通路同时采集,确保了数据的稳定性。  H3 s  E9 U4 _. E0 n( \1 c
" X1 v6 u( N5 w; t* h' a  S1 U6 v. k
; r+ B' c1 [. L  B
多功能采集显示平台使用的芯片是STM32F103ZET6,片上资源提供了ADC123共3路ADC模块,为了布线方便以及使用的习惯,多功能采集显示平台采用了ADC1的Chanel 4~7,占用IO口PA 4~7,以及ADC2的Chanel 10~13,占用IO口PC 0~3。
5 y' l7 ~3 @5 x2 U. w$ o
. u0 M+ h- Y+ s
: G1 t+ P4 S# F+ _" y
使用时有几点需要注意的:
, H( S' i8 {6 g6 Y9 w. B2 N/ M; v
' }. A& }9 \& F1 A3 p
1.选择正确的模式:ADC_Mode_RegSimult,即DUALMOD[3:0] = 0110,ADC2在双模式中,这些位为保留位
: J  j( Q% s) T% N0 |! y
/ M+ r+ F- j6 M* s+ k5 m* t

, o6 x0 O1 U9 w* d2.开启ADC的DMA,在双ADC模式里,为了在主数据寄存器上读取从转换数据,必须使能DMA位,即使不使用DMA传输规则通道数据。只有ADC1和ADC3能产生DMA请求。所以只需设置ADC1的DMA:ADC_DMACmd(ADC1, ENABLE);& K4 o# I) w: g, i

: P! }2 t& T* U+ L! f6 p

/ |; }" Z9 l- f! C& V3.ADC2的转换数据存在ADC1_DR的高半字;3 v  F5 O0 {$ \) N0 ~1 o

. V5 B1 R- \0 `7 x3 E' H
) X+ [7 W1 K' `+ @7 \4 k
4.不要在2个ADC上转换相同的通道(两个ADC在同一个通道上的采样时间不能重叠)。3 C- U1 i# B1 J( d. T! P
$ ~: P/ T" m! O; v: J" \$ s

3 R& \; O$ e3 O5.ADC2的CR2寄存器的第20位——EXTTRIG:规则通道的外部触发转换模式必须开启(软件启动的时候也要),这样才能利用到ADC1的触发信号。不然的话,需要手动再软启动一次ADC2,例如ADC_SoftwareStartConvCmd(ADC2, ENABLE);
5 [" z" |" G2 P6 V' [4 V3 u$ y1 e$ W; Y9 {5 S0 O! u& C4 F0 d; Q. z
; I4 M( A# J; z9 Y, M# ^( G7 I
但是,假如你设置了这个位之后,就不需要手动软启动ADC2了,所以考虑到同步,这样比较好。用ADC_SoftwareStartConvCmd(ADC2, ENABLE);为什么可以,一方面它 也设置了EXTTRIG位,另一方面也设置了SWSTART。但我觉得先用ADC_ExternalTrigConvCmd(ADC2, ENABLE);的话,一会只要ADC1一启动,两者就同 时启动了,这样更正确一点。
7 B4 u! L$ `* l9 e7 r& r9 Y' M& B$ P9 A5 Q/ e

5 H1 b$ x4 B& m+ M% h' N以下是ADC1配置代码和使能代码:
1 H# `$ t: r1 B0 I: |8 {6 \
  1. //初始化ADC1  
    0 y5 f- N7 U" N! Z% U5 m- \# v" ^
  2. //这里采用多通道连续采样,并用DMA1的通道传送  
    * v3 @" ^+ T( \% ]% ?: m0 Q7 v; C
  3. //我们默认将开启通道4~7  / [/ o& |% z9 \
  4. //相应管脚PA4~7  
    5 O3 B: l$ C* L9 R
  5. void Adc1_Multi_Init(void)  
    # T# `& j! t! d1 B2 G
  6. {     
    * q+ I+ c8 Q; ~6 t2 X
  7.     ADC_InitTypeDef ADC_InitStructure;   * u. b7 B; u' i8 q6 C0 H3 s
  8.     GPIO_InitTypeDef GPIO_InitStructure;  & A( i6 b5 k+ c; |: Q6 w/ c
  9.   & E9 R% L: e3 c* X
  10.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1    , ENABLE );   //使能ADC1通道时钟  
    ) T7 ~. ^/ m8 x: ~) U. p
  11.    ; W. L( o+ R: b8 E: ~5 s
  12.   
    8 @' Z3 {; E* a1 j  e& p
  13.     RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M  9 b, G2 x. _3 x% V
  14.   8 T7 @4 I8 p3 Y+ d( p  L3 ?
  15.     //PA1 作为模拟通道输入引脚  - B' F3 e! E9 k6 H# _. F
  16.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;  . \8 [/ c& B7 v7 D+ W! D
  17.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;       //模拟输入引脚  
    $ B9 E# P3 Q  ]' Q
  18.     GPIO_Init(GPIOA, &GPIO_InitStructure);   
    5 y; g" Q9 J2 @; d; f7 J
  19.   4 m7 S* R  W6 p2 Y
  20.     ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值  % U' e3 L# w4 C. v) p: Q/ C
  21.   ; i" Z* l7 H$ p8 B
  22.     ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;    //ADC工作模式:ADC1同步规则组模式  
    + M6 q2 J9 Y+ K' Q+ F. x
  23.     ADC_InitStructure.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式  
    , d7 d' y) e! z
  24.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在连续转换模式  9 q# o/ Y% G" l" M9 h
  25.     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动  
    ! I* h; j) L. b
  26.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //ADC数据右对齐  3 C9 p- K, M4 k/ _# u, k& U0 d; `2 p
  27.     ADC_InitStructure.ADC_NbrOfChannel = 4; //顺序进行规则转换的ADC通道的数目  3 W: F! E* s- V
  28.     ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器     / u, I0 R- w" X( N1 F' q
  29.   0 B% a# u% J5 u4 P
  30.     ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_239Cycles5 );  2 p+ j" N% s1 ~: K$ W. q) E) l4 j
  31.     ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_239Cycles5 );  / J* B! K% B- {: c2 {! _) @' ~/ h9 K9 v
  32.     ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 3, ADC_SampleTime_239Cycles5 );  
    ( K* E: ]# S5 [
  33.     ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 4, ADC_SampleTime_239Cycles5 );  
    : d' _: ?9 B  ?) [) D) M! p
  34.   
    0 P) g/ m& O+ O7 ~
  35.     // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)  " w& w. `; m! \/ r
  36.     ADC_DMACmd(ADC1, ENABLE);  0 W4 i1 T8 b: S- Q; T' L( a
  37. }     
    9 q, X3 [4 v7 C
  38. //计算多通道ADC值  0 R' n3 S+ ^* L6 K) J
  39. //AD_Value[]是DMA目标地址的数组空间  ' U) o& q) y+ u- K
  40. u16 Get_Multi_Adc1(void)  , f( v) {$ T: T
  41. {  & `2 G$ u) |, d( [
  42.     u32 temp_val=0;  7 U/ y' O9 O# C6 Z+ e- K
  43.     u8 t;  
      B3 d! k2 {8 Y9 B" y
  44.     for(t=0;t<4;t++)  7 b& X) g) V& x  S- m
  45.     {  # k: U0 x! [8 L* t9 C
  46.         temp_val+=(AD_Value[t] & 0xffff);  
    0 U; w( k, q) y9 g
  47.     }  % s( L% s' j: H4 A" r0 q
  48.     return temp_val/4;    S/ ^; \6 H* |5 w/ L! f
  49. }
复制代码
主要需要修改的是这句话,使得ADC处于同步规则组模式。
3 f+ Q( }5 G3 V
  1. <strong>ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;  //ADC工作模式:ADC1同步规则组模式</strong>
复制代码
AD_Value[]是32位的,用于DMA传送的目标的ADC数据数组。其中高16位是ADC2的数据,地16位的是ADC1的数据。
8 \7 _; b2 b7 `+ v$ f5 X2 x; Z& ^. P- e, K! o
9 h7 R5 ~7 q6 a9 \3 i

7 h- @  t  ~. u; X1 u其次是ADC2配置代码和使能代码:
/ \  N4 j# M/ Q7 F! S  ~
  1. //初始化ADC2  
    . j2 s9 D9 \# l- Z: s
  2. //这里采用多通道连续采样,并用DMA1的通道传送  0 b4 E  f- Z% H2 l  K3 k
  3. //我们默认将开启通道10~13  ! O9 n, k  g# S$ l( z
  4. //相应管脚PC0~3  4 f$ r# k* e6 x9 @9 l& Q
  5. void Adc2_Multi_Init(void)  & d% ~" H2 D; T3 O- M& p
  6. {     2 X9 S# ?, z1 i! C( N' [: e+ d
  7.     ADC_InitTypeDef ADC_InitStructure;   
    # t, h: l9 E2 V, S, ~! a7 Y& H
  8.     GPIO_InitTypeDef GPIO_InitStructure;  
      w6 A$ s9 {. W6 N1 B/ ~
  9.   
    . c2 X9 w* a. Q2 y( |/ }1 v
  10.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |RCC_APB2Periph_ADC2    , ENABLE );   //使能ADC2通道时钟  
    ! k, S/ \+ A$ B- n6 G) U) [
  11.    2 n' P) S% a; r8 ^" ?( T$ ]
  12.   & a  o5 m: d" d4 w9 y
  13.     RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M  
    2 V  V" ^5 M% X% [$ G- o# r7 ^
  14.   
    ) ~1 t! u9 i6 N! V# |0 i5 e
  15.     //PB0,1 作为模拟通道输入引脚  
    7 ~9 p0 n& ~! p: T
  16.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;  5 K5 w( z- I4 u" M7 C( N( A
  17.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;       //模拟输入引脚  
    7 `+ j( U: Q2 ]9 m% i
  18.     GPIO_Init(GPIOC, &GPIO_InitStructure);    % q9 {# w" B# j# e$ p5 H6 ^( O
  19.   7 Y* ^3 F5 w$ R: ~2 ]& }
  20.     ADC_DeInit(ADC2);  //复位ADC2,将外设 ADC2 的全部寄存器重设为缺省值    {$ U" Q  t/ Y
  21.   
    $ k# F1 z, ?: p, d/ b
  22.     ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;    //ADC工作模式:ADC1同步规则组模式  ( O  p& d. D7 ?( a5 Y! a; r" f& I
  23.     ADC_InitStructure.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式  
    + H5 M' K3 \4 k5 p/ [2 |" @7 b
  24.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在连续转换模式  $ `5 ?8 l, j8 S0 n+ U0 S
  25.     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动  
    : Z& a+ P7 U: G! B, I4 W
  26.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //ADC数据右对齐  
    2 J8 v( t& E' A0 Q+ Q  n. @( g. S7 a
  27.     ADC_InitStructure.ADC_NbrOfChannel = 4; //顺序进行规则转换的ADC通道的数目  8 T- s  g9 S. `
  28.     ADC_Init(ADC2, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器     
    6 A8 U! `7 d  |2 }6 Z
  29.   : o: w' ]7 {/ q' n$ I0 |$ m
  30.     ADC_RegularChannelConfig(ADC2, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5 );  
    . ]# n" t2 d7 x$ o1 i- B9 u
  31.     ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 2, ADC_SampleTime_239Cycles5 );  $ m  m( w+ c) A! G" ~' w# q; \
  32.     ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 3, ADC_SampleTime_239Cycles5 );  , |* G" o  S7 W% T
  33.     ADC_RegularChannelConfig(ADC2, ADC_Channel_13, 4, ADC_SampleTime_239Cycles5 );  * J6 w4 V5 C& m+ [8 i6 y3 S
  34.   : J7 Y- U) u* b6 y! _7 M4 C7 H7 x6 M
  35.     ADC_ExternalTrigConvCmd(ADC2, ENABLE);                                        //使能ADC2的外部触发模式   
    9 f! q/ f! X8 D
  36.   
    ! u2 ^% o7 n1 }) s, z  a0 C
  37.     // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)  
    ( F% _- {: L9 A' J" R- f+ H8 k) q/ ~7 f7 ^
  38.     //ADC_DMACmd(ADC2, ENABLE);  # I9 Z3 w  f0 n4 e' ]8 B/ ^) }
  39. }   
复制代码
  1. //计算多通道ADC值  ) W1 J( N$ |* K9 u
  2. //AD_Value2[]是DMA目标地址的数组空间  
    * Z# ~0 P8 v' j7 w
  3. u16 Get_Multi_Adc2(void)  
    7 A% h6 M6 u  Q& k5 l
  4. {  
    9 d9 f0 l- N+ r" f+ q3 Q- H
  5.     u32 temp_val=0;  % t: i; k' C# s( n1 o) s. U9 u# R% c
  6.     u8 t;  
    . l; l+ I# S7 I9 o, [, q' L. X# }
  7.     for(t=0;t<4;t++)  9 N, p5 V! c( z- R
  8.     {  
    ! Q% V8 m' N' j. v
  9.         temp_val+=((AD_Value[t]>>16) & 0xffff);    W! |7 t. _; Q' B, x8 T
  10.     }  6 c/ J* C, d6 Q: H& c4 U
  11.     return temp_val/4;  
    , I1 l, ^) B9 i9 v
  12. }
复制代码
ADC2主要需要添加下面语句,用于ADC1触发ADC2的工作。
, `, C0 f. s% g; {' x
  1. ADC_ExternalTrigConvCmd(ADC2, ENABLE);//使能ADC2的外部触发模式
复制代码
AD_Value[]是32位的,用于DMA传送的目标的ADC数据数组。其中高16位是ADC2的数据,地16位的是ADC1的数据。这里使用AD_Value[t]>>16进行移位操作,获取数据。$ U! q$ f7 f- Y* S

" Y! R4 L5 _& ?+ m6 a. |

' t! c, H, c( \: k
% A! Y) }6 ^3 @1 x1 E
收藏 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 手机版