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

基于STM32F7进行ADC采集解决更新问题

[复制链接]
攻城狮Melo 发布时间:2023-3-14 11:26
ADC1DMA_Handler.Init.Mode6 D4 m- H7 u0 f' V& J
DMA的正常模式(DMA_NORMAL):采集到DMA_BufferSize 的个数后,DMA停止。2 ^9 r2 }$ F/ f7 e: N. v; r
DMA的循环模式(DMA_CIRCULAR):采集到DMA_BufferSize 的个数后,重新回到设置的RAM的起点位置,如此循环。0 Z# w  C% y; H3 z' Z! j
虽然道理很好理解,但个人感觉要配合触发信号来用,通过HAL_ADC_Start_DMA软件触发需要设置起点位置和长度,否则这个参数是没有意义的。) n! D4 P0 u* Q- e3 u
* p: ]$ |6 e% ?1 m/ y
ADC1_Handler.Init.ScanConvMode

. e- A, d# c) _9 w' t0 }: L扫描模式(ENABLE):ADC会依次扫描设置的各个rank
0 W$ M" D2 N# o- z非扫描模式(DISABLE):ADC只会读取rank1,即使设置的DMA_BufferSize大于2,也只会读取第一个;如果没设置rank1(此时我的设置里rank2接的3V3,rank3接的gnd),读出来的结果是516这种奇怪的东西,我也不知道是个什么鬼东西……0 N* U) t, D, S- m
即使需要只读取rank1的值,把NbrOfConversion不就可以了嘛~% z  O+ g8 y. }0 v/ j/ x& s$ n
所以这个参数我建议设置成ENABLE,我也不知道什么时候该用DISABLE。. e0 a0 H* A. G

; Y+ F* z. I  EADC1_Handler.Init.ContinuousConvMode9 w2 m0 q  V3 V8 ^( g' D
开启连续转换:开启了连续转换后,adc会一直转换,直到DMA_BufferSize大小,如图是HAL_ADC_Start_DMA 64个长度的结果。, k' T6 q/ w9 O5 T4 U* g. J; f
9 P' u# j% u  l/ |7 {) N: O
20200419192759329.png 4 z. {8 v$ Z; t" G* a/ E$ ]

- x; v! ~: I. {+ l而不开启连续转换,长度为64的同时,DMA的传输中断都不会进。
7 b+ ^+ L# k  u" J8 m, [4 R- O1 n4 V% V: [3 T
20200419192936345.png
2 ~4 o, M# h+ h: D+ u! y; s5 @/ i, A0 U) Z! M% ~0 I
而将传输长度设置为3的时候,就进入了传输完成过半的中断。
$ h, v- Z: e/ Z1 x
20200419194129548.png
* W# _5 _( h8 x! s/ W4 m; e

5 T4 w9 u$ z; E6 D# B5 t如果我们需要采集连续的N个次结果求平均值,用这个连续转换会很方便。' F" V4 Q  b) w6 K7 c! n+ [
也从侧面说明,dma的传输中断是一定要有那么长的真实采集数据来才能进的。
, ~, N+ k" w, v9 |7 ^# S

3 J9 ~6 {) w& F  e9 }在另外一篇博文里看到了这么一个表格,希望能够辅助大家理解:
; ]+ T4 z2 J1 R! z! q4 y& Q
4 B6 }9 j5 w& D/ e
20200421214739891.png % g. s: c! B9 s' T8 s
8 k/ I4 y, J7 w, Z; W! N' p! {; y
ADC1_Handler.Init.DMAContinuousRequests- o! L. n$ @) M% Q5 n
当设置了定时器触发DMA之后,这个参数如果设置为DISABLE,就只会采集一轮数据,然后结束。) p4 N7 ^4 u0 M+ c1 \
这个数据设置成了ENABLE之后,这个参数设置为ENABLE,一轮采集完成之后,感觉就会自动调用一次HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);,触发DMA请求,以实现不停采集。% w; P2 H& W( ]; g; J7 m4 J* F
: i( ^3 N' N& J( i6 K* V/ ]4 c
但是需要注意,如果开启了连续转换,又开启了DMA连续请求,adc将一直进行采集,一刻也不停歇……( R. E# i/ E6 U& C

5 y; Q1 t4 x, C: LADC1_Handler.Init.EOCSelection; r! ?3 `. U4 p( M* [# P2 {
偶然看到一个帖子的回复:
: `. ], x6 u0 E" ]! I: e: R9 H当有CPU和其它主设备【如DMA】共同访问某可缓存的二级存储器比方SRAM1,同时该存储器又具有回写属性,此时就可能发生数据一致性问题。因为该存储器的回写属性,导致通过CPU欲写入存储器的数据只是缓冲在CACHE里,而没有及时写入存储器。如果此时DMA访问该二级存储器的话,读到的数据可能跟预期不一致。
0 u! h" X- l; u! ~5 v) \" ?为了避免数据不一致的问题,我们需要做D-CACHE维护操作。一般有如下四种方法: 1、当对一个可缓存的二级存储器做了写数据操作之后,通过软件对D-CACHE进行清除操作,即运行SCB_CleanDCache()。这样将CACHE里的缓存内容写回到二级存储器,比如把那些DIRTY
  D% B6 y3 w$ B" {6 [CACHE行的数据写进SRAM1。
# q) O+ _/ |' ]( u2、通过MPU调整可缓存存储器的存储属性,将其CACHE使用方式改为透写模式。这样保证每次写入CACHE里的内容也同时写入二级存储器,比如写进SRAM1。% ?% @2 j* N. X5 \
3、通过MPU调整可缓存存储器的存储属性,将其共享属性改为可共享的【SHAREABLE】。此后该二级存储器将变为不可缓存。7 k3 d% t/ i" N; I' I. t/ q
4、通过配置CACR寄存器中的D-CACHE位,强制将所有写操作配置为透写属性。- _; }7 ?7 g& C/ c5 a' V
+ e5 m& h* b2 ~# `( t8 C4 s
在main函数中关闭cache,DMA采集的数据就可以更新了。
1 l8 G& ?! ~: A0 l( Z
9 [/ X3 k# m0 F* G  P
20200419215859139.png
$ L: \: x0 Y6 p3 H2 |) f( ~
+ J/ D, @* X2 I; y
附上成功时候的配置,注释掉HAL_NVIC_EnableIRQ是因为中断服务函数里的打印会导致main函数无法继续执行。. k$ d. Q# {4 I5 `- H! P" v( l1 L
  1. #include "adc.h"' ^1 I/ c: t- z% q# k9 K
  2. #include "delay.h"
    - p( J4 z$ D  J, y/ `8 h

  3. ; s4 K$ @4 y$ U7 E
  4. ADC_HandleTypeDef ADC1_Handler;//ADC句柄
    7 o' d/ h5 I: A9 {4 N" i
  5. DMA_HandleTypeDef ADC1DMA_Handler;- [7 @; W- A: ^9 ]% R" F$ Y' y  F
  6. ADC_ChannelConfTypeDef ADC1_ChanConf;) E9 q; L. R3 W% F: u$ o% t
  7. & K2 T) B. e( i, F, ^0 M
  8. uint16_t buffer[128];, c1 s& ]+ d9 h5 M9 }  A& y

  9. - ^7 w5 E6 h9 L6 m; U- J7 M! g
  10. + N- v4 D0 w( h& q
  11. //初始化ADC
    & I5 k" _6 A* m) A( j
  12. //ch: ADC_channels/ e. h% M7 A, k; ~% D
  13. //通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
    7 A$ V1 ]/ F9 L0 B8 c$ i
  14. void MY_ADC_Init(void)
    ' p6 t+ H7 q. t$ y/ C6 R; K$ P: J! O
  15. {0 _5 ^! f3 Q5 g& P
  16.     __HAL_RCC_DMA2_CLK_ENABLE();+ O& t5 i) t5 L. _/ U$ y
  17.     HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
    & k. r# W% L! ?
  18.     //HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);/ R! ~. Z" k, K& i" g; b% p- t
  19. 7 l0 D2 E1 @9 O& r6 E# ^# v
  20.     ADC1DMA_Handler.Instance = DMA2_Stream0;
    & C6 g$ X0 g; z' G) f# ~# p
  21.     ADC1DMA_Handler.Init.Channel = DMA_CHANNEL_0;
    / d' X" Q3 ]" R' i
  22.     ADC1DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
    - E% ~- ~' e1 ~, K/ M7 ?( m1 E! ]3 r
  23.     ADC1DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;               //外设非增量模式1 [0 ^% r+ G1 ~3 y& D! v/ p
  24.     ADC1DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;                   //存储器增量模式3 k/ q8 x) {. R) W" p2 k$ r* K
  25.     ADC1DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设数据长度:16位
    0 p( f6 Y: i. X  x) d1 k8 I
  26.     ADC1DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //存储器数据长度:16位
    ; S0 V) u; Y. L9 @* Z* I) z0 z" H
  27.     ADC1DMA_Handler.Init.Mode = DMA_CIRCULAR;                          //传输一次就结束9 b6 ^. e0 [9 {& }$ t
  28.     ADC1DMA_Handler.Init.Priority = DMA_PRIORITY_LOW;             //中等优先级5 a; T1 p4 H& @, y
  29.     ADC1DMA_Handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;            /* 禁止FIFO*/$ p# m# Q' R( `1 [, X1 e
  30. ! j. N- P2 b- V  ?0 k
  31.     HAL_DMA_Init(&ADC1DMA_Handler);3 e' u8 V* v. p2 {
  32. ) p6 C, S# z' X1 ^+ C5 u4 C
  33.     __HAL_LINKDMA(&ADC1_Handler, DMA_Handle, ADC1DMA_Handler);                //将DMA与ADC联系起来
    " _5 X: @6 P+ A
  34. $ f3 e3 {0 d+ i* _* n
  35. 2 E3 p, D5 F& B: @% s
  36.     ADC1_Handler.Instance = ADC1;+ y; D9 h2 X1 b5 J: p1 @4 X3 C+ i
  37.     ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
    5 K% V5 z* d& J6 A
  38.     ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B;           //12位模式: E1 o- s" N- S1 Y: ~1 f
  39.     ADC1_Handler.Init.ScanConvMode = ENABLE;                    //非扫描模式
    1 U" y- R. S* v0 u4 {
  40.     ADC1_Handler.Init.ContinuousConvMode = ENABLE;              //关闭连续转换, i4 M+ k- }% k" a" U
  41.     ADC1_Handler.Init.DiscontinuousConvMode = DISABLE;           //禁止不连续采样模式
    7 H+ L+ o5 \. b5 o% b+ G, R0 K5 U
  42.     ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发1 }8 B9 f# @- U0 X' y, H
  43.     ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;     //软件触发( c. l: l* |, S- d9 n
  44.     ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;           //右对齐% @* S; T' A3 V# C$ @- y2 ?
  45.     ADC1_Handler.Init.NbrOfConversion = 2;                       //1个转换在规则序列中 也就是只转换规则序列1
    + F+ F% O. z( u7 A% u3 G- w
  46.     ADC1_Handler.Init.DMAContinuousRequests = ENABLE;           //关闭DMA请求
    ; V1 \2 [& u# S
  47.     ADC1_Handler.Init.EOCSelection = ADC_EOC_SINGLE_CONV;        
    / C+ O: ^9 r3 x- P) ]! F$ [
  48.     HAL_ADC_Init(&ADC1_Handler);
    0 U4 n1 L# g! @0 B# I& {* K
  49. * {1 N: }) c: I+ o6 U
  50.     ADC1_ChanConf.Channel = ADC_CHANNEL_5;                                 //通道
    5 r. `$ Z( n- |  W# A
  51.     ADC1_ChanConf.Rank = 1;                                     //序列18 a" ?, I- R5 |/ Y' `6 E3 x
  52.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
    7 X& |7 ]0 R) ]6 m( _# \
  53.     ADC1_ChanConf.Offset = 0;
    6 L! D7 Z  D5 X1 z  \* U1 j* X
  54.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置$ t9 Q5 Q  ?  ?9 {, M; Y
  55. 2 q  d; x8 J" ]& z/ d# o4 _, H7 S
  56.     ADC1_ChanConf.Channel = ADC_CHANNEL_6;                                 //通道
    9 n2 T8 x% Z/ c) a& k% c+ U
  57.     ADC1_ChanConf.Rank = 2;                                     //序列2
    5 l) }5 D, J0 x" a3 N5 B
  58.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间, i" ?' g2 M5 X8 o. L1 X( t
  59.     ADC1_ChanConf.Offset = 0;0 T! u1 h3 Y2 A" Z4 Y
  60.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置
    # B1 G1 q/ k* b, y8 o) S4 c

  61. ; q# J3 Q2 e  \) X  D( B
  62.                 HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);* M. {9 B! X( r8 u- y' H# `
  63. }" S/ q' c2 s& L! x
  64. : ^; J# U: Z& S
  65. //ADC底层驱动,引脚配置,时钟使能
    7 n6 g, T6 ^' ^; V
  66. //此函数会被HAL_ADC_Init()调用
    ( t+ ?- m9 e* W* Q! B& Q. c
  67. //hadc:ADC句柄
    , I3 p$ ~" b! J4 [& s; n; s* x% S: {
  68. void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
    / }: a. C+ K; ?3 I% p
  69. {
    ! @1 [# V( a' I2 z
  70.     GPIO_InitTypeDef GPIO_Initure;; y& [$ n  H& q( O: O$ T8 Q0 D
  71.     __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1时钟. J, d0 M0 I: u6 S0 ^1 x
  72.     __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟7 v: q# q1 B6 _- y3 \7 H+ `

  73. : `, A0 L( w: p7 p
  74.     GPIO_Initure.Pin = GPIO_PIN_5|GPIO_PIN_6;          //PA5
    3 m- P& T2 m! {9 x6 [& @
  75.     GPIO_Initure.Mode = GPIO_MODE_ANALOG;   //模拟
    7 y/ F2 G+ P% D
  76.     GPIO_Initure.Pull = GPIO_NOPULL;        //不带上下拉
    + S7 S  M% d- o2 Y6 j
  77.     HAL_GPIO_Init(GPIOA, &GPIO_Initure);9 k7 F& q$ C0 _: f; Z" ?& N
  78. }( K; P- y0 ?( r7 w7 @3 _: e9 m

  79. / q% f2 q% S# U1 z4 `: I% G
  80. void DMA2_Stream0_IRQHandler(void)
    , T$ ~* k( {) G) _% V) M
  81. {
      @( E3 Q+ `8 {) o
  82.     HAL_DMA_IRQHandler(&ADC1DMA_Handler);% Q! l6 [  |, v4 H; r
  83. }' h. Y, u0 Z6 L# a! k/ `

  84. ) H7 ]4 m6 G% l, [
  85. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
    % i! P4 n6 X) n# ?
  86. {
      e6 ]  E4 w- V+ p* y  w9 E# q
  87.         printf("DMA transfer complete\r\n");# W4 B5 l; F8 c  r2 ?
  88. }; e; G" L2 \9 u/ N
  89. void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)
    , t# l; F4 G! \' b
  90. {" b  H7 A# t( _3 z5 f( l
  91.         printf("DMA Half transfer complete\r\n");
    4 b, k: e8 {; `& X0 q. @7 z
  92. }
    * ]% P3 k5 t; r$ {% s, [# r# ?
  93. , x: Y9 e2 m/ x+ a. H
  94. void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)( V, L3 |$ ^6 G) I( `
  95. {5 j  H5 p8 A3 V1 s, V) \5 H
  96.         printf("DMA transfer error\r\n");
    + R$ q3 E1 E% ~' r$ Y" a4 X* d$ M
  97. }, K, X9 L0 G$ x3 d1 C4 }& A7 g
复制代码
  1. #include "sys.h"
    $ p( W9 B. |( n' s  X2 J
  2. #include "delay.h": J% i2 C: s( l
  3. #include "usart.h"
    3 C# L. |  V% D1 M
  4. ; e: R9 x, ~& }1 X! S# b: H4 f
  5. #include "adc.h"
    : u6 u5 ^! |% u: Q, ]$ K; C

  6. 4 c) J" Z+ O" E% v0 @4 V
  7. extern uint16_t buffer[128];  q3 a6 ]- k* Q: g* q. T( X/ H" H
  8. 4 O5 G1 T* W2 H' l8 n
  9. void show()8 ^0 z4 g8 U6 l9 q6 p& H% ]
  10. {; I: b2 C% C3 q' H; }9 y
  11.     int i;& ~7 q% _8 \  W* v: P+ U; ]- e. [; B! S
  12.     printf("\r\ndata:");4 L. s: A5 c3 Z2 g" [
  13.     for (i = 0; i < 128; i++). u, R/ ?; N% }$ J/ c. H3 l1 j
  14.     {. {; ~6 D4 G8 B. d/ L0 F
  15.         if (i % 16 == 0) printf("\r\n");1 Z  k% ~  `* ?# e& `! S2 b
  16.         printf("%6d", buffer[i]);4 G# s4 [& s7 o
  17.                         buffer[i]=0;
    ; N( Q- _: d" ~3 W& d$ |1 f: K4 X
  18. 8 Z7 X( m; p8 ^( U) w7 _. N6 Q' v( H
  19.     }2 h0 c1 ]7 R% d; b: y
  20.     printf("\r\n");+ a4 O3 ^, i0 ~7 t9 M( B# a1 H, y
  21. }2 l0 V. V- u# M1 y0 o( F8 V/ _- b7 G
  22.   d, P  ?* P# W6 q2 @

  23. , q; N. V8 Z6 p" y3 ?
  24. int main(void)
    3 k8 o: d" _) o5 M2 p
  25. {5 ]9 E3 J* N; @& i2 V) S; {
  26.     //Cache_Enable();                 //打开L1-Cache7 |( l1 X% K; o: F7 }: b# L
  27.     HAL_Init();                     //初始化HAL库
    : K7 D5 P; m% Z& d
  28.     Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz% J* m7 O' W8 D' S6 Y6 s
  29.     delay_init(216);                //延时初始化
    * h  M7 E1 o8 g0 G6 ^7 @- @
  30.     uart_init(115200);              //串口初始化# q6 C; |1 u. I& h. U3 A* j6 I
  31. % x# k  D  c/ \7 E8 u  ^
  32.     printf("start\r\n");, K* Q" t- P/ q& |- K- I4 \
  33.     MY_ADC_Init();                  //初始化ADC1通道54 y+ d# A) s5 e5 F
  34.    
    / K$ @% b0 l7 l  w* V4 f& {$ v
  35.     while (1)$ p- H2 l+ ?% Y0 @. H
  36.     {
    / b+ U0 s1 Y- K) F( O
  37.         show();
    * D9 C# D0 u3 X0 a5 g; J
  38.         delay_ms(1000);$ E: Z  N3 N! ^& L
  39.     }7 f" |5 D4 y7 U7 d: F7 Y
  40. }
复制代码

: u) p2 {: k. H————————————————
" V7 I1 m& p7 p$ S7 O版权声明:小盼你最萌哒! N9 I: C+ u5 @# X. S& B8 a
如有侵权请联系删除- E4 n3 k+ w% r& K5 a; B

& }' y4 U$ h4 k% j. q2 U% t0 @6 Q
收藏 评论0 发布时间:2023-3-14 11:26

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版