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

【经验分享】STM32F103单片机使用DMA功能读取ADC采样数据

[复制链接]
STMCU小助手 发布时间:2022-3-20 13:03
  使用DMA功能操作外设时,可以极大的简化代码,提高程序的执行效率。特别是在需要频繁操作的外设上。比如现在要采集单片机16个ADC通道的电压值,就可以使用DMA功能,直接将ADC通道转换好的值,传输到数组中。需要操纵ADC的值时,直接去数组中拿数据就行。不需要再去判断ADC数据转换是否结束。下面直接通过代码来实现。
+ B- q, c( {- |+ Q1 Y- u9 x" Y! X7 ~% x3 c6 }
  首先初始化ADC,这里将ADC的16个采样通道全部开启。
8 ^" n& q* H$ |' ^/ [* n
! U" Z; ^6 S' X) Y( b8 W
  1. 8 q  T, `1 E  t7 o  A1 b, F
  2. void ADC1_Init ( void )
    " r5 r4 Z0 ]6 P  H( g% @
  3. {4 z2 ^' i+ E! j- l* z
  4.     GPIO_InitTypeDef GPIO_InitStructure;* `7 ]& ?. S0 y% c% ^' z9 v
  5.     ADC_InitTypeDef  ADC_InitStructure;  : r; X) x2 |2 C  R3 k0 Q
  6.         ; y# Q2 C( W# h1 @( k
  7.     RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO, ENABLE );& r: k  I" k9 C6 D: y9 Y& z
  8.     RCC_ADCCLKConfig ( RCC_PCLK2_Div6 );                // 72M / 6 = 12M  ADC最大不能超过14M
    ; T' w" w4 [1 Z$ h" g1 v

  9. 3 H& M+ X# m0 f! n/ g* s4 l: |
  10.     // ADC1 --- ADC8
    ) N9 t/ H& |% D7 E1 A, D! ~
  11.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;' }- O- g$ u( C: Q6 @9 v3 Y% V3 S
  12.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
      B) a! Y3 Q0 V$ P
  13.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;2 J9 t3 s9 Y9 r  r& i1 B2 G) V
  14.     GPIO_Init ( GPIOA, &GPIO_InitStructure );3 L7 |4 p6 [% U* l  D5 R5 b) @
  15.     // ADC9 ADC10- j  V& O; ?! ^& t6 w5 K
  16.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    8 }/ I6 m6 h/ u
  17.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    " ]5 \( s2 K0 d$ g3 u( v
  18.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    3 W. F$ L) f8 _% y6 B
  19.     GPIO_Init ( GPIOB, &GPIO_InitStructure );
    / n2 @1 ?& i8 k" M6 |5 w
  20.    // ADC11 --- ADC 16( ^" O; H1 N2 T9 N- \
  21.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
    0 O9 V1 |& g+ q1 r0 q) W
  22.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    ! \* m" {. f) C6 L
  23.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    . U/ q& _/ C6 ]) b$ a  L
  24.     GPIO_Init ( GPIOC, &GPIO_InitStructure );9 G5 r+ P4 C3 x, p
  25. / L" Q. A- [. a& R3 ~1 t! |! ~
  26.     ADC_DeInit ( ADC1 );
    ( c) M; p- I/ E' i; I

  27. 8 `/ Z" [5 y) L* T: A
  28.     ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                                        //独立模式
    % p* s5 {. S  \4 o
  29.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                                //扫描模式
    " D/ A+ R: @' r/ {7 c: ^
  30.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                                        //连续转换0 R( t* Z. [! y+ b3 {7 H3 C
  31.     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //不使用外部触发
    7 W  s9 }* O- f: r0 H4 ~2 [1 e9 S# m
  32.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                                //数据右对齐. }: d( y/ L5 t2 [8 e
  33.     ADC_InitStructure.ADC_NbrOfChannel = 16;                                                                //ADC通道数
    ; ~4 d+ l7 ^/ M3 X9 y
  34.     ADC_Init ( ADC1, &ADC_InitStructure );) x% X+ |! R2 I% |
  35. 3 y7 n, v3 r$ ?& t7 E" h1 ^
  36.     //规则通道配置7 ~/ Z- d* ]: w6 q) D  i8 ?& i
  37.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 );
    - N. p% a( V- R9 D) h
  38.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5 );
    * f% I9 q+ A; k: S" p9 h5 ^
  39.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5 );2 c) t: Y* A( U
  40.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5 );9 s5 N+ S* D! ^, v
  41.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_4, 5, ADC_SampleTime_239Cycles5 );
    1 |8 `  _& Q5 `1 g" O  _1 q$ H
  42.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_5, 6, ADC_SampleTime_239Cycles5 );0 s7 P+ O0 A' H0 ?" @
  43.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_6, 7, ADC_SampleTime_239Cycles5 );- z* h3 s5 F  g& h8 e3 ~
  44.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_7, 8, ADC_SampleTime_239Cycles5 );
    # T* S- A7 g. b9 P, X0 y# i
  45.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_8, 9, ADC_SampleTime_239Cycles5 );0 C! s7 e. ]% L' v4 f& z
  46.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_9, 10, ADC_SampleTime_239Cycles5 );
    9 q7 C  e- W7 n! M/ W" \3 q- l1 {
  47.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_10, 11, ADC_SampleTime_239Cycles5 );
    % W. J; U0 u: S* e
  48.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_11, 12, ADC_SampleTime_239Cycles5 );  D' Z6 `+ l6 F
  49.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_12, 13, ADC_SampleTime_239Cycles5 );
    . t- C- s) [0 j$ S% s! L1 L
  50.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_13, 14, ADC_SampleTime_239Cycles5 );  Z0 a7 _+ ]* Q- J$ ?* K; w
  51.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_14, 15, ADC_SampleTime_239Cycles5 );% A: O- t5 u, |
  52.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_15, 16, ADC_SampleTime_239Cycles5 );& W1 y( b3 ]: M' `0 O
  53. 0 v* W7 l( [$ v5 @
  54.    ADC_DMACmd ( ADC1, ENABLE );                                        //使能ADC DMA传输8 _; y5 k& E. r% A7 b
  55. 9 G( n7 b/ B# w4 x1 Q9 x7 G, p
  56.     ADC_Cmd ( ADC1, ENABLE );                                                //使能ADC1
    4 {! X3 \6 d/ [) d. V, `
  57.         ( p6 l0 ^) v; J2 C- v( j; \( N
  58.     ADC_ResetCalibration ( ADC1 );                                        //使能复位校准
    6 s, v; M8 K( o
  59.     while ( ADC_GetResetCalibrationStatus ( ADC1 ) );        //等待复位校准结束1 s8 B& x$ n3 @
  60.         . Q& E1 b- ~. L' q" Y! L# N
  61.     ADC_StartCalibration ( ADC1 );                                        //开启AD校准0 b( D# l  ^& P3 p* M6 ]. k
  62.     while ( ADC_GetCalibrationStatus ( ADC1 ) );        //等待校准结束
    9 N. V9 X  @, g8 m8 X4 J& R
  63. //    ADC_SoftwareStartConvCmd ( ADC1, ENABLE );        //启动转换8 s+ |* Z9 Q' u: ~1 p  r9 q
  64. }
复制代码

$ s- s% v1 g; H/ P6 C9 t% |ADC设置为扫描模式,连续转换,16个通道依次扫描采样,一轮采样结束后,接着开启下一轮采样。8 p. Q& y, Y# B3 {) M2 b  b0 s
6 X% c; \; ^, E
  下面初始化DMA功能。7 a7 o4 u& `# F8 N

/ k; O! _' K, n) M' _7 J
  1. void MYDMA_Config ( DMA_Channel_TypeDef *DMA_CHx, u32 cpar, u32 cmar, u16 cndtr )
    ! S+ e: |  l$ t2 x
  2. {
    " Y/ y9 s- u/ }  r9 R. a. B# J4 Q2 E
  3.     DMA_InitTypeDef DMA_InitStructure;
    : S! v3 P8 @% I: E+ K
  4.     RCC_AHBPeriphClockCmd ( RCC_AHBPeriph_DMA1, ENABLE );
    ! i; |* z3 X7 l, G: X
  5.         $ _$ A/ U/ u0 c
  6.     DMA_DeInit ( DMA_CHx );
      n7 R( p* D8 q7 P& P
  7.         
    1 X, C5 ^/ {; b- b3 \8 a
  8.     DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;                        //外设基地址
      o5 E3 A* M: s1 ^: y' V$ [
  9.     DMA_InitStructure.DMA_MemoryBaseAddr = cmar;                                //内存基地址# d1 [1 e- E: m$ K# Z9 V$ Q
  10.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                        //数据传输从外设到内存4 k5 x" t! n% ~* |) C. s
  11.     DMA_InitStructure.DMA_BufferSize = cndtr;                                        //DMA缓存; |# q' p+ J; C/ l
  12.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        //外设地址不变! N& e5 E9 T6 i- p% h9 h
  13.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                //内存地址递增
    ' Y2 m4 w4 V! r
  14.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据16位
    9 L' x# f7 f8 B
  15.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                        //内存地址1位# e, Z) o6 d8 }( T' U" ~) D
  16.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                //循环工作模式, V; J8 g! E" i. _
  17.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;                        //高优先级9 l3 }+ K" d; @. v1 c
  18.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                //没有设置内存到内存传输( i+ B  d" \8 _( d
  19.         1 \7 r% n- q1 q9 j1 E: L. d" y
  20.     DMA_Init ( DMA_CHx, &DMA_InitStructure );
    4 J% p# l, F2 `/ v" @# I
  21. }
复制代码
* I9 P; A% v+ U& j; O/ q( X
这里DMA的数据方向要设置为从外设到内存,也就是将外设ADC采样的数据结果保存到内部存储空间中。6 q) E/ t+ i1 }0 a$ M. p, ?

& j  O4 I; K% K9 \. F初始化完成之后,在主函数中直接启动DMA转换功能。% ]' Y0 Q& m( l1 X% z8 |* m
- @# U6 E* L* p( M6 e& m( q# }
  1. #define ADC1_DR_Address    ((uint32_t)0x4001244C)
    # s  ^6 U8 A) n
  2. u16 AD_Value[6];
    : \. G3 D9 W6 H2 x: j% ~/ ^' J  ~
  3. float volta[16];+ H& A# E# ]9 r4 p( k: q
  4. u8 i, j;! E6 J+ q+ d4 u
  5. uint16_t ADC1ConvertedValue[10][16];
    9 S) {) w4 |( W$ k. \8 \" F
  6. uint32_t ADC1ConvertedVoltage[16];
    & c6 B6 g' _, G' S& k% S+ r
  7. int main ( void )& |" y; ?5 r1 G% o$ O" h4 B. Y3 s, I
  8. {- [2 u+ u# W7 a/ a3 H
  9.     delay_init();       //延时函数初始化
    ! V$ G/ b0 a, Y8 g$ S0 W: W& E1 R
  10.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 );9 c" [* d: ^0 o+ g9 v
  11.     uart_init ( 115200 );
    * ?! @/ B. v7 i# M* b0 u/ {
  12.     LED_Init();         //初始化与LED连接的硬件接口
      X5 {/ k4 X6 j- o
  13.     MYDMA_Config ( DMA1_Channel1, ( u32 ) &ADC1->DR, ( u32 ) &ADC1ConvertedValue, 160 );6 t  n5 D5 p# V3 [
  14.     ADC1_Init();
    1 `9 v# |; H) b& ?
  15.     DMA_Cmd ( DMA1_Channel1, ENABLE );          //启动DMA通道
    . E0 F" X7 C; @& }/ v
  16.     ADC_SoftwareStartConvCmd ( ADC1, ENABLE );  //启动ADC1软件转换. J, w+ A) b6 Y5 F% I
  17.     while ( 1 )" A! B: t% P+ F4 s$ m* w
  18.     {
    1 S( b, k9 S9 L: ?) D4 Z0 ~2 `0 v8 Z
  19.         ADC1ConvertedVoltage[0] = 0;
    & M& \6 \0 a) }( e
  20.         for ( i = 0; i < 16; i++ )
      Q& [. m5 o4 ~4 B0 s# w; Z
  21.         {
    9 D  z0 }6 `* D' W, m) _0 b
  22.             ADC1ConvertedVoltage= 0;
    3 u% x% ^' k) K0 G" Q- m
  23.             for ( j = 0; j < 10; j++ )                        //采样10次取平均值! a! i$ U/ N1 ^, U, \2 k
  24.             {
    0 q, D2 U+ j! C+ A& x1 p7 D
  25. ADC1ConvertedVoltage += ADC1ConvertedValue[j];
    % v3 z4 ?/ ]" [7 `
  26.             }
      C# O  i7 Q. d0 ?
  27.             ADC1ConvertedVoltage = ADC1ConvertedVoltage / 10;
    9 B% @' @# t& ~( x3 J
  28.         }
      l" _' E1 d9 {# M, [5 A$ v$ S# p
  29.                 for(i=0;i<16;i++)# `9 B6 F( z' {% g
  30.                 {  F  h' Y: w: W% G9 D
  31.                         volta = ADC1ConvertedVoltage * 3.3 / 4096;
    * @8 \, [/ k1 R$ s, [
  32.                         printf("AD%2d:  value: %4d  vol: %f\r\n",i,ADC1ConvertedVoltage,volta);
    ) _7 f( F% ]/ ?/ |
  33. ( z% ~( M+ P7 @1 m$ f( R8 s/ @+ f- n
  34.                 }- _" K* H1 d; Q, n% K& L! V/ @
  35.                  printf ( "\r\n\r\n" );
    * ]/ c4 L6 C( M5 _. i% h0 K
  36. ' y6 n% G5 F. E! _8 P* |! H
  37.         LED0 = 0;& U6 o, ?1 N$ X) ]& ?
  38.         LED1 = 1;
    $ E% r7 {9 h# i5 R! O
  39.         delay_ms ( 500 ); //延时300ms3 T1 g# `$ _/ i9 n: e
  40.         LED0 = 1;
    # Z4 m; F$ C; h) c% u
  41.         LED1 = 0;+ D% i7 T" U' q; L0 y; p/ }
  42.         delay_ms ( 500 ); //延时300ms
    + K3 ?0 K% [3 B5 j3 g
  43.     }! }+ N2 A) k) Z3 i/ S5 D
  44. }8 R' L0 I& b6 W8 V% T- X# F
复制代码

& w! P( N" f- Z4 m' N4 R  m5 A, ?  n通过一个二维数据存储16个通道的转换值,每个通道存储10个数据然后取平均值。最后将采样的16个通道值依次打印出来。
$ M- \; s6 |  a0 b& A6 ~. B$ p- e# e( r. a. x, u( h

: F% ^4 b: ]/ l+ {: N$ i( ~0 f
赞 收藏 评论0 发布时间:2022-3-20 13:03

举报

0个回答

所属标签

相似技术帖

官网相关资源

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