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

【MCU实战经验】+ STM32 ADC多通道转换

[复制链接]
Johnson wang 发布时间:2014-4-23 12:06
STM32 ADC多通道转换
5 C, F! O, {/ N% [$ t描述:用ADC连续采集11路模拟信号,并由DMA传输到内存。ADC配置为扫描并且连续转换模式,ADC的时钟配置为12MHZ。在每次转换结束后,由DMA循环将转换的数据传输到内存中。ADC可以连续采集N次求平均值。最后通过串口传输出最后转换的结果。
1 D& b- }& X# g% z% I程序如下:$ |- \; r) A) h7 _+ y: |6 F6 p$ q
#include "stm32f10x.h"        //这个头文件包括STM32F10x所有外围寄存器、位、内存映射的定义! V8 C( Q* ], K1 i8 H+ Z
#include "eval.h"             //头文件(包括串口、按键、LED的函数声明)
% v4 E5 K6 K, ^5 B) {% C) d#include "SysTickDelay.h"      4 S& O$ b. A3 c, F
#include "UART_INTERFACE.h"
: O! @; Q. q7 z3 B#include ) g5 J9 }4 a/ N
 
8 G7 Y( h! y, S# ~#define  N   50               //每通道采50次
. J& y+ B4 ]% s2 F' i. W5 S#define  M  12               //为12个通道1 t8 u1 R, S' `1 P' S" E
 
" |& b4 T) ]% H4 X0 \vu16  AD_Value[N][M];   //用来存放ADC转换结果,也是DMA的目标地址
6 k8 L; R2 j6 g6 U1 B3 dvu16  After_filter[M];    //用来存放求平均值之后的结果
) A* g8 `: g( c# ^, G6 ^" |int         i;
2 @, B6 Z0 i% Q! Q6 b+ v( X6 K* Y+ O 0 r$ I% d- x1 z$ o; V, e9 O& y% r
 ! Q  B7 Z( D, R$ s8 Y0 O# t( V, v
/*GPIO管脚的配置
3 _0 U/ H) l* m选用ADC的通道0  1  2  8  9  10  11  12  13  14  15,分别对应的管脚为PA0  PA1  PA2  PB0  PB1  PC0  PC1  PC2  PC3  PC4  PC5/ Z4 B  t  w9 ^" C7 d" L- ?
串口使用USART1其中TX为PA9,RX为PA10 */9 o+ z9 h3 W3 k/ `$ R
void GPIO_Configuration(void)( ~# d" |$ z! |5 J* W
        {
# `/ J5 o% R0 X  l8 p5 M+ A+ E        GPIO_InitTypeDef  GPIO_InitStructure;
- L' E: Z& J4 J& H1 o                /* Configure USART1 Tx (PA.09) as alternate function push-pull */
" O$ _4 b9 n' X        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;0 ^3 D/ j- x% ^' f
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //因为USART1管脚是以复用的形式接到GPIO口上的,所以使用复用推挽式输出
4 ]7 m5 d+ R+ I0 U: K! Y- C        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;$ F' {& L0 U7 ~( j  p$ P; x
        GPIO_Init(GPIOA, &GPIO_InitStructure);
2 j8 _1 Y; {/ J        7 {" L# R. {5 A6 i, N2 D
        /* Configure USART1 Rx (PA.10) as input floating */8 x% p4 ?6 s5 y
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;: k9 D0 ?! o2 O  ~+ d% g
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;! t' c* x/ Z. Q/ c  G. `- Y
        GPIO_Init(GPIOA, &GPIO_InitStructure);5 M! V" b6 ]7 ~
 
7 B2 q2 a5 J6 e        3 X7 Z  P/ o: ]4 N  u
 
# @2 q& ^, S; L& Z: K" ^: k9 f+ L# {        //PA0/1/2 作为模拟通道输入引脚                         4 m3 M7 y/ `' u# W- ]* Z( _! y
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0| GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
0 e5 K( [- G% A, h7 H  u4 b. B# f        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚2 V, b2 y3 L8 @% M4 V- v  K
        GPIO_Init(GPIOA, &GPIO_InitStructure);
" f$ l1 k+ s5 A$ i5 D& R& V % H6 o7 O& C0 E  h  a- K1 o" B. X
        //PB0/1 作为模拟通道输入引脚                         
' D3 A: Q: {8 G4 Y+ c. p        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;6 _# Z' A4 y8 V# |6 I
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
, _8 }4 A4 s* S& y        GPIO_Init(GPIOB, &GPIO_InitStructure);3 T1 B3 p5 \+ Y( \9 h0 }0 a: I0 A$ q# h
 
! x4 o$ n6 z7 S2 l1 D        //PC0/1/2/3/4/5 作为模拟通道输入引脚                         . i" R2 a5 r; X. N) p2 I6 y
           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;
6 ?& P0 m: r$ F$ y% ^$ G        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
& `& R4 L* \4 j2 n4 b        GPIO_Init(GPIOC, &GPIO_InitStructure);3 K' l0 M3 b' H# l, N  p
        }( ]" l0 a+ D# s8 M# c. e. c! B
 
) l( M7 n7 n; R; a7 S: }- s}
$ a% o" [+ b  K0 F ! }: ^8 ~, X0 M' g
/*配置系统时钟,使能各外设时钟*/
6 @6 U' z! |! r* Qvoid RCC_Configuration(void)
: ]- }+ g- H  k( c, k( {        {0 _/ c  ~7 p' D
           ErrorStatus  HSEStartUpStatus;
, a) g6 M  F2 E% b 
' r; c. i* p3 }) x. E1 d+ E     RCC_DeInit();                     //RCC 系统复位7 e# F, I* Q$ Z( i
     RCC_HSEConfig(RCC_HSE_ON);      //开启HSE, ?$ h; [5 ?7 s  s% n$ N
     HSEStartUpStatus = RCC_WaitForHSEStartUp();  //等待HSE准备好+ W4 G) w* `6 M8 b6 ^3 L
     if(HSEStartUpStatus == SUCCESS)$ \( I) P9 \/ n  D
     {! o: N" r* r! Y: L% g
       FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //Enable Prefetch Buffer4 P8 ^* ?  o( k  q, ~4 I% L  J
       FLASH_SetLatency(FLASH_Latency_2);      //Set 2 Latency cycles
1 u! \! m0 g0 c8 j4 C       RCC_HCLKConfig(RCC_SYSCLK_Div1);   //AHB clock  = SYSCLK
; u7 [) p, f$ t- i       RCC_PCLK2Config(RCC_HCLK_Div1);   //APB2 clock = HCLK  |* o2 `% D9 s, N
       RCC_PCLK1Config(RCC_HCLK_Div2);   //APB1 clock = HCLK/2; }6 s4 ^3 `3 X  E9 @
       RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_6); //PLLCLK = 12MHz * 6 = 72 MHz
9 e1 `, _/ v4 O" S. L: S% g; V       RCC_PLLCmd(ENABLE);          //Enable PLL
$ r* K# V4 Y# |0 k" o% h+ P/ S       while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);  //Wait till PLL is ready  
' [1 C' n5 H  I3 Q       RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //Select PLL as system clock source
/ G7 A6 M7 x6 K( @' f       while(RCC_GetSYSCLKSource() != 0x08);   //Wait till PLL is used as system clock source
. Y( z& t& q; I! i% d       /*使能各个外设时钟*/
! Q& T+ c% t8 ]% B% P& {# B' s       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB# @9 r' X' h" C& W0 k4 J
            | RCC_APB2Periph_GPIOC |RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO |RCC_APB2Periph_USART1, ENABLE );          //使能ADC1通道时钟,各个管脚时钟3 s& W/ `& [8 D1 r/ k
        /* Configure ADCCLK such as ADCCLK = PCLK2/6 */ 0 l. w2 R( c6 C/ p& M1 V2 J
       RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //72M/6=12,ADC最大时间不能超过14M2 c% n+ r" X* J0 E
       RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);        //使能DMA传输8 Q$ e; P0 v+ h7 |
         , A% E, u7 P/ ~8 r3 u6 J
        }
% m- S2 |7 }1 V/ D  }1 l3 G9 j* s; [* R& K: X$ g* P
 
* e" p  ~7 w' s' ?% b7 T- c+ {/*配置ADC1*/- i- @7 ^. ^* @6 u! [
void ADC1_Configuration(void)! j0 ^4 q: @  B: p6 W+ U
    {, j- \& e8 @! F2 F
         ADC_InitTypeDef  ADC_InitStructure;# S+ d* V: ^& {) w. u% Z& h
 
: a$ _% m  i% q# u7 o         ADC_DeInit(ADC1);  //将外设 ADC1 的全部寄存器重设为缺省值/ \# H2 K# m2 ^0 g2 r. e1 |
        
9 B6 {3 G" H' B1 f9 \        /* ADC1 configuration ------------------------------------------------------*/
1 n4 I( w$ H( P" G        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式% `; P, e  ]# k# U1 ~
        ADC_InitStructure.ADC_ScanConvMode =ENABLE;        //模数转换工作在扫描模式) ?& L  v& a/ x) \" d+ L& R. p4 Q
           ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;        //模数转换工作在连续转换模式
: J! E! P1 W- \" w9 |: {        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;   //外部触发转换关闭- ^. C, @7 j& O' _8 ]/ p. Z
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐6 ^8 p6 ~( e, V- Q) r7 X6 l) P
        ADC_InitStructure.ADC_NbrOfChannel = M;        //顺序进行规则转换的ADC通道的数目) x8 N1 F5 d3 r) b6 Q
        ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器; f( h& j2 ^4 [3 i$ P) O# D" N# `
        
# {7 d- }3 J' N5 z        /* ADC1 regular channel11 configuration */ 1 {: {# z; g" l
        //设置指定ADC的规则组通道,设置它们的转化顺序和采样时间
! R6 Z+ f+ S+ T9 Z, M5 S& t7 `& J        //ADC1,ADC通道x,规则采样顺序值为y,采样时间为239.5周期
- N5 L: }: s/ y( t" N        ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 );
" w  W$ m( T, C# w! ]# u5 D        ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5 );                
$ o5 q4 Q9 M- D: }  N* _$ q' u                ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5 );        & M7 _5 B1 i6 F% X3 F1 U1 w
        ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5 );
* o/ t# i  J3 t, x5 ~' ]        ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 5, ADC_SampleTime_239Cycles5 );                7 d1 ~3 B- c8 F" ~' H( D: E
                ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 6, ADC_SampleTime_239Cycles5 );
9 M5 Q1 y: g- \! W        ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 7, ADC_SampleTime_239Cycles5 );
- v* Q  w& v! f! _$ j        ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 8, ADC_SampleTime_239Cycles5 );% a! i2 {% Z' A9 K' V' L
        ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 9, ADC_SampleTime_239Cycles5 );
  o5 ?, G: g6 Q. r8 |( w" t        ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 10, ADC_SampleTime_239Cycles5 );+ m' a& s* y+ @7 I: P
        ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 11, ADC_SampleTime_239Cycles5 );
& C, r* K0 @' `- t        ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 12, ADC_SampleTime_239Cycles5 );
1 o5 m# r7 C3 F0 ]1 d" F        % }, E1 H  @) w5 |4 o+ M' D
         // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)
; N3 ~1 j" A; j0 H5 C. C           ADC_DMACmd(ADC1, ENABLE);        
3 B& B1 ]8 B; Q        
# u2 P7 r1 C* @% Y* {         /* Enable ADC1 */+ I, Y, _% |. T2 e5 Y. m9 {
         ADC_Cmd(ADC1, ENABLE);           //使能指定的ADC1) x# t7 Y) z* e! r
         /* Enable ADC1 reset calibaration register */   8 \. P9 e/ h5 ~  e0 u. _9 Y
         ADC_ResetCalibration(ADC1);          //复位指定的ADC1的校准寄存器
( p# z8 I: l: D5 q6 f6 U         /* Check the end of ADC1 reset calibration register */
* s3 F. X6 g5 @4 j0 E  `         while(ADC_GetResetCalibrationStatus(ADC1));        //获取ADC1复位校准寄存器的状态,设置状态则等待
! u' v/ L+ A- W1 L# X  W5 N        * z* C- @: @8 m. N+ e
         /* Start ADC1 calibaration */5 K! [" J: t$ t* h
         ADC_StartCalibration(ADC1);                //开始指定ADC1的校准状态/ l" C7 R- `. K
         /* Check the end of ADC1 calibration */
6 X/ d, X- [7 R1 @* u3 s, u         while(ADC_GetCalibrationStatus(ADC1));                //获取指定ADC1的校准程序,设置状态则等待' y' a( [7 ^! _8 J
        & @+ u* S# _: s, i% _  T
        
4 {7 u, h" `5 c9 T9 k# c3 Z}1 t+ Y3 p, }; F# ?9 b
 
3 B0 y7 a2 ^9 L7 @/ E/*配置DMA*/
" V( B" \% ^7 f% ^4 l! @6 i8 Vvoid DMA_Configuration(void)
7 B( A+ G7 `3 f! R2 W; ^        {
9 |- X2 h4 b* n* d4 S* b        /* ADC1  DMA1 Channel Config */
$ [% c9 N$ W- D8 w        DMA_InitTypeDef DMA_InitStructure;$ s2 G! y0 |* a* V/ k
        DMA_DeInit(DMA1_Channel1);   //将DMA的通道1寄存器重设为缺省值
2 D. s6 h2 n4 F8 K/ z$ g' c% r        DMA_InitStructure.DMA_PeripheralBaseAddr =  (u32)&ADC1->DR;  //DMA外设ADC基地址* Q5 r) O! b* t* i
        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value;  //DMA内存基地址9 R+ _( n; O1 v* w& n0 x( `
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //内存作为数据传输的目的地
) h2 |: \0 N8 J' z        DMA_InitStructure.DMA_BufferSize = N*M;  //DMA通道的DMA缓存的大小
; c2 C0 V6 N0 f2 n! {$ Y& i1 M        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
# @, Y5 F, |0 d1 c, {0 ~  @        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
& [, R$ f  ]7 a        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  //数据宽度为16位5 g( A* q' j" r
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位0 B% j4 G9 q" P  R. r8 q/ V7 `
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  //工作在循环缓存模式( @0 t. w2 G0 w, h% d; J; \' X
        DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道 x拥有高优先级 ' _& e+ v8 I; S8 K$ K
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
9 [$ h7 K+ U$ R8 x3 X. m9 Z9 {* S        DMA_Init(DMA1_Channel1, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道/ k  Z/ |! S* h" W) ~5 z
 ) D! y1 f1 y, p1 \6 F: X7 o
        }
* q: V4 @+ g' G0 g% S 
. _: U. L+ r  x+ z8 N( Z 
" a' x2 L1 A2 ~0 H! N//配置所有外设
: p: {6 Z9 l; ivoid Init_All_Periph(void)
( T3 Q! h/ d; Y# x$ W0 e; i) y: W        {  Q: `: W" q" H' Q' @' K$ |
        ( p) K9 O/ `* L2 v
        RCC_Configuration();        + m: k) m0 C; t& L
                
' c9 M% @# w' y3 |        GPIO_Configuration();. A. c$ z: t1 H2 U& o9 g5 D
 
; g0 @  B: L7 ^# W2 w# h, O' }        ADC1_Configuration();5 \( }& k4 v% U! b! a, P
 
9 e' U/ h) B, |3 a; S( u4 _9 \8 B        DMA_Configuration();' \) a1 h# O# o7 ~. \4 d5 @7 M
 : k" w% c) K. y8 H
        //USART1_Configuration();
+ `8 Q) B/ d$ y        USART_Configuration(9600);
6 c( }% w  X0 s0 I- z 5 r4 y( _: r9 @7 ~3 S! Z$ X  S
         1 a- I5 L0 U% |3 O0 b3 V
        }
) k! j* K% ]! H, T$ O; s/ i6 U # x. E0 ?, t( T$ V: @6 T6 O9 k! |2 y
 
) J2 C, ]9 }( W/ O" \/*获取ADC的值,将二进制换算为十进制*/
$ [" o" S, o" F, P0 p4 Z9 @. x& l4 s. nu16 GetVolt(u16 advalue)   & i2 z6 U! }  R$ y1 @  C
 
2 X. C7 U5 c3 i  e/ L  {- X) I' r9 d5 U0 j
   
" B# c7 N. A# q   return (u16)(advalue * 330 / 4096);   //求的结果扩大了100倍,方便下面求出小数/ \4 x0 q, V' A. f
 
& w# e5 M- W) p/ C: N# U( L- Z! `2 x  }  y) f/ ~% n& P, {( U# m
 ; V0 T- Y. Y# p3 M
 
/ ~/ k8 g7 X& | 
* L& {$ _9 b. l7 G- L; p; ?/*求平均值函数*/
2 ^" X8 t, E$ b& K& k0 tvoid filter(void)4 R( F& T/ _- A. X
{0 P3 g/ x& p1 u  E
          int  sum = 0;
, V4 Y- L/ R( D! S% R/ ?' ]' s3 D. y        u8  count;    ( k  @1 ^! \' a: X
          for(i=0;i
赞 收藏 评论0 发布时间:2014-4-23 12:06

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版