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

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

[复制链接]
攻城狮Melo 发布时间:2023-3-14 11:26
ADC1DMA_Handler.Init.Mode
+ A" G% O2 k4 qDMA的正常模式(DMA_NORMAL):采集到DMA_BufferSize 的个数后,DMA停止。
# P2 B: J  g* kDMA的循环模式(DMA_CIRCULAR):采集到DMA_BufferSize 的个数后,重新回到设置的RAM的起点位置,如此循环。
' N% W0 o- P8 {- r* R  Y虽然道理很好理解,但个人感觉要配合触发信号来用,通过HAL_ADC_Start_DMA软件触发需要设置起点位置和长度,否则这个参数是没有意义的。3 d2 d; P8 ?+ T: Y
9 l8 O* X# J; v
ADC1_Handler.Init.ScanConvMode
% D0 ?) ]) e9 F2 c' G; C2 _
扫描模式(ENABLE):ADC会依次扫描设置的各个rank2 t, z3 [% c/ W: d+ n
非扫描模式(DISABLE):ADC只会读取rank1,即使设置的DMA_BufferSize大于2,也只会读取第一个;如果没设置rank1(此时我的设置里rank2接的3V3,rank3接的gnd),读出来的结果是516这种奇怪的东西,我也不知道是个什么鬼东西……3 g3 Y) K" C( @) D5 R' G7 ]
即使需要只读取rank1的值,把NbrOfConversion不就可以了嘛~; S3 {3 ]0 }# y  O  r% e% I5 g3 T
所以这个参数我建议设置成ENABLE,我也不知道什么时候该用DISABLE。
+ o3 G3 H* v) c# @2 t- }" ]4 s4 }
7 C/ O' |; ?6 L8 z
ADC1_Handler.Init.ContinuousConvMode+ ]/ p/ R; O+ U* N+ f
开启连续转换:开启了连续转换后,adc会一直转换,直到DMA_BufferSize大小,如图是HAL_ADC_Start_DMA 64个长度的结果。
( X' t' Y& I! u, v- [: l+ B* o  C3 Z; y: {5 L
20200419192759329.png 4 u4 X4 R" q4 A
+ `: o7 v& ~3 o% j+ l0 F) g6 p
而不开启连续转换,长度为64的同时,DMA的传输中断都不会进。
( O8 C$ Z# L( v" A$ v0 j5 q+ ^+ Z
20200419192936345.png
8 I2 A3 h' h2 S/ m/ \8 J" P, B6 a1 \; g: R# j9 y! c
而将传输长度设置为3的时候,就进入了传输完成过半的中断。- n( P0 ~! |5 r" R! Z
20200419194129548.png
5 W: l( @+ _0 w8 O

- _6 S! }$ T: P' v7 s6 [& t1 Z8 k如果我们需要采集连续的N个次结果求平均值,用这个连续转换会很方便。" P' J2 C0 s+ l; Q
也从侧面说明,dma的传输中断是一定要有那么长的真实采集数据来才能进的。$ ], Z+ K+ Z2 @8 j4 y
, R/ _. _, l9 t; ^) V
在另外一篇博文里看到了这么一个表格,希望能够辅助大家理解:  U% y0 x; h4 e% f( p; ]
, _6 w7 E! ]; h! x+ f: J8 ~1 I
20200421214739891.png
& Q/ {" O2 n9 E" K, w% K, K' T

' |$ B8 U* a$ p8 o# ^ADC1_Handler.Init.DMAContinuousRequests- W; n9 u" [6 [5 x  D
当设置了定时器触发DMA之后,这个参数如果设置为DISABLE,就只会采集一轮数据,然后结束。  ^* M5 s+ p% m
这个数据设置成了ENABLE之后,这个参数设置为ENABLE,一轮采集完成之后,感觉就会自动调用一次HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);,触发DMA请求,以实现不停采集。% K0 {% c8 d' m, S
2 l9 u' n" P5 |/ s; ?) U
但是需要注意,如果开启了连续转换,又开启了DMA连续请求,adc将一直进行采集,一刻也不停歇……1 A; e$ @9 C5 |" `+ p+ L
5 Y/ K' Y  e3 U
ADC1_Handler.Init.EOCSelection
6 Q5 x# F4 U" Y, ^1 @6 t8 z+ ]偶然看到一个帖子的回复:" h+ \8 q* X# e; |+ n& ^
当有CPU和其它主设备【如DMA】共同访问某可缓存的二级存储器比方SRAM1,同时该存储器又具有回写属性,此时就可能发生数据一致性问题。因为该存储器的回写属性,导致通过CPU欲写入存储器的数据只是缓冲在CACHE里,而没有及时写入存储器。如果此时DMA访问该二级存储器的话,读到的数据可能跟预期不一致。0 ^3 r/ u- E8 m* \- n* L
为了避免数据不一致的问题,我们需要做D-CACHE维护操作。一般有如下四种方法: 1、当对一个可缓存的二级存储器做了写数据操作之后,通过软件对D-CACHE进行清除操作,即运行SCB_CleanDCache()。这样将CACHE里的缓存内容写回到二级存储器,比如把那些DIRTY
) U/ l# ]9 F. ~8 CCACHE行的数据写进SRAM1。
# T1 S" O* r# m3 g' Q( E- r2、通过MPU调整可缓存存储器的存储属性,将其CACHE使用方式改为透写模式。这样保证每次写入CACHE里的内容也同时写入二级存储器,比如写进SRAM1。4 M) T  @# B# d
3、通过MPU调整可缓存存储器的存储属性,将其共享属性改为可共享的【SHAREABLE】。此后该二级存储器将变为不可缓存。
& v& O/ C2 @5 b4、通过配置CACR寄存器中的D-CACHE位,强制将所有写操作配置为透写属性。4 w" h; y* F* K5 S/ [. l$ y1 x

: Z" T2 W! T8 R- E, d7 P! Q在main函数中关闭cache,DMA采集的数据就可以更新了。$ ?0 e' Q3 `7 r  C
& W  h1 s& \2 f- I" ?
20200419215859139.png 1 }- ^, Q" e1 }! k7 |
3 P% K" J# X! @3 W
附上成功时候的配置,注释掉HAL_NVIC_EnableIRQ是因为中断服务函数里的打印会导致main函数无法继续执行。
9 g* T. b; c2 v5 O5 N
  1. #include "adc.h"
    + @" s& c3 q+ l* T3 z
  2. #include "delay.h"
    & U& a! {& K* O9 e( A  m5 ^0 I
  3. ; A2 Y# v: I/ m, ?8 q
  4. ADC_HandleTypeDef ADC1_Handler;//ADC句柄
      V' g* _. e$ L9 e! ^
  5. DMA_HandleTypeDef ADC1DMA_Handler;" G( Q6 o) L; s6 L/ k
  6. ADC_ChannelConfTypeDef ADC1_ChanConf;# r/ o0 K- V& M: y. X
  7. & q) N! j- L1 Y% r3 T, Z
  8. uint16_t buffer[128];- x& u* S% ^1 ^% I7 T* ]
  9. 8 f* b9 X5 U, N) \7 @" a4 l1 k

  10. / `; i. E. w9 D+ `& ~- B
  11. //初始化ADC/ [% Z- R; ?- s* I6 w
  12. //ch: ADC_channels! {6 K' O8 Y0 J! v2 G/ z; c
  13. //通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_166 z  e1 m+ f% {/ f
  14. void MY_ADC_Init(void)) N$ E/ M# H. e( t2 U. m- q
  15. {$ [' K9 S) ~) ?
  16.     __HAL_RCC_DMA2_CLK_ENABLE();9 B8 n- K- W1 a' n: {/ [& i5 x
  17.     HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);: H% V& \: x7 ?( R
  18.     //HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);# J2 o4 Z8 R, H/ M/ w& g2 ?
  19. / v8 f2 W- _$ _  c, y) b8 X
  20.     ADC1DMA_Handler.Instance = DMA2_Stream0;
    * D1 ?# X% [3 Z
  21.     ADC1DMA_Handler.Init.Channel = DMA_CHANNEL_0;
    1 I4 _! h! a: v) b! e2 c& t  G+ |
  22.     ADC1DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;9 E/ l3 }, s( i9 t$ s; h4 O! f) U. \
  23.     ADC1DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;               //外设非增量模式2 V/ q" z3 V% V& u1 I1 _1 B
  24.     ADC1DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;                   //存储器增量模式
    ; l1 h) k" J) C0 B
  25.     ADC1DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设数据长度:16位
      _( K5 O% b* y
  26.     ADC1DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //存储器数据长度:16位; i) B! d* y, K1 k5 i; J
  27.     ADC1DMA_Handler.Init.Mode = DMA_CIRCULAR;                          //传输一次就结束9 \+ P: v: k& c, v, l2 f
  28.     ADC1DMA_Handler.Init.Priority = DMA_PRIORITY_LOW;             //中等优先级* `6 K0 Q+ P, J/ S2 {* U7 v6 N
  29.     ADC1DMA_Handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;            /* 禁止FIFO*/
    8 F% x1 b& f9 K

  30. 7 p( \' O# d) }6 z8 v4 W
  31.     HAL_DMA_Init(&ADC1DMA_Handler);1 k$ P( u# f# N+ {

  32. 3 J3 x5 ^2 T% M, g+ v8 t
  33.     __HAL_LINKDMA(&ADC1_Handler, DMA_Handle, ADC1DMA_Handler);                //将DMA与ADC联系起来0 U- ^% D/ |1 C3 M# q7 A

  34. 0 k* i/ L) L) K8 F& {6 G
  35. # \5 l2 z9 o5 T. n( _, m. i  N
  36.     ADC1_Handler.Instance = ADC1;/ [9 K2 ^1 p& a
  37.     ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
    " ^( H/ ^3 R; h- y) }6 R
  38.     ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B;           //12位模式
    # W5 w# _- p) F' m& J6 y" \
  39.     ADC1_Handler.Init.ScanConvMode = ENABLE;                    //非扫描模式
    ( o7 U" T0 ?) D9 v
  40.     ADC1_Handler.Init.ContinuousConvMode = ENABLE;              //关闭连续转换% d$ N' a* g* H( P5 V
  41.     ADC1_Handler.Init.DiscontinuousConvMode = DISABLE;           //禁止不连续采样模式; J% v; |2 n; Q
  42.     ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发
    ( I2 ]2 Z: u, x+ A& t( ^
  43.     ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;     //软件触发! @5 t- S7 x# |# |$ D
  44.     ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;           //右对齐
    # ^5 ^1 t/ b  ?9 Q" o
  45.     ADC1_Handler.Init.NbrOfConversion = 2;                       //1个转换在规则序列中 也就是只转换规则序列1
    5 H8 |; E1 R1 N1 @; P! i" o* x9 o
  46.     ADC1_Handler.Init.DMAContinuousRequests = ENABLE;           //关闭DMA请求
    / c2 t, a/ f( V/ o5 t$ r
  47.     ADC1_Handler.Init.EOCSelection = ADC_EOC_SINGLE_CONV;        * j& ]: I- K' G% j% B9 u* }
  48.     HAL_ADC_Init(&ADC1_Handler);0 ~6 D8 e3 |+ |/ t- x% B2 |' \
  49. , i! K/ o" Z; Y/ G0 t& \; y
  50.     ADC1_ChanConf.Channel = ADC_CHANNEL_5;                                 //通道
    * j3 d. A& [) P3 \6 Z2 q8 r
  51.     ADC1_ChanConf.Rank = 1;                                     //序列1
    ( J+ ~. k3 b( {0 S1 S- V6 f
  52.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
    + y8 s6 t! S  S" O3 J7 R. n* S
  53.     ADC1_ChanConf.Offset = 0;
    4 N' w7 n4 [  y$ F, U& Q
  54.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置) i/ {; J& Z& j  P2 l8 @& i
  55. ( q8 [2 n) q4 x+ v, a. l
  56.     ADC1_ChanConf.Channel = ADC_CHANNEL_6;                                 //通道6 x0 a3 {7 H5 C1 h% }  e
  57.     ADC1_ChanConf.Rank = 2;                                     //序列2/ i* y, X* }7 @; X6 ?) x7 u2 g
  58.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
    # z; }- S) i# C+ w
  59.     ADC1_ChanConf.Offset = 0;
    $ X' V7 f. l7 ?& T! S# n# ]: {
  60.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置5 {7 f& k, M9 X: v8 E

  61. 2 M! v* W2 F5 _
  62.                 HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);6 q6 \" q1 I, a3 q, I
  63. }7 ?% W9 j0 K9 B+ f% v4 x! m
  64. * O% k. l4 C; `. X& @5 ~2 D
  65. //ADC底层驱动,引脚配置,时钟使能
    ( Y! L* P8 r- A. w" l; \2 ?; D
  66. //此函数会被HAL_ADC_Init()调用
    : f' }. E  g- e% A* `4 U: ?
  67. //hadc:ADC句柄1 v0 U2 n2 k/ I0 `0 O* K
  68. void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)' t! W, ?; q6 }  j- h6 \
  69. {9 E, a) t. Q% ?- S1 }
  70.     GPIO_InitTypeDef GPIO_Initure;3 H$ l- ?* p& J- @6 b
  71.     __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1时钟
    . K9 c+ V9 a  S' R1 Q
  72.     __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟
    7 _1 ?* j2 O% ]9 [1 H; z0 c
  73. % z9 B9 ]& @- A
  74.     GPIO_Initure.Pin = GPIO_PIN_5|GPIO_PIN_6;          //PA5; k! |% [4 g* F8 E9 V" E2 n
  75.     GPIO_Initure.Mode = GPIO_MODE_ANALOG;   //模拟
    ; q) h% g4 x% R/ d3 @# Y. E+ |
  76.     GPIO_Initure.Pull = GPIO_NOPULL;        //不带上下拉1 L4 s% F. N9 c8 I. Z% G; O
  77.     HAL_GPIO_Init(GPIOA, &GPIO_Initure);
    6 P; q; e$ Y7 [3 N
  78. }7 _% d4 e. _4 u7 S

  79. % X" V# U, E* r
  80. void DMA2_Stream0_IRQHandler(void)
    0 ^+ }4 C; p0 Q2 u: O
  81. {+ b: G. I. ~9 s! W9 {+ ^! X* L
  82.     HAL_DMA_IRQHandler(&ADC1DMA_Handler);
    + E6 E& b/ g- ]
  83. }; f& p/ R% U: Q+ y$ x2 I# {

  84. 8 S2 V0 r7 n: D7 m9 p( C3 [
  85. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
    3 A; \# I$ E7 _, m8 {8 C  q
  86. {$ {1 [" |9 N: {9 R9 j1 o
  87.         printf("DMA transfer complete\r\n");
    ( F: h$ \) R+ j1 P! E' W3 J; v
  88. }5 {6 p4 x, r5 y, m$ ?+ l7 i' Q
  89. void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)& h+ D6 f, F9 P/ t% M; x
  90. {5 [% m5 L( o6 d3 o/ B
  91.         printf("DMA Half transfer complete\r\n");
    - h) C! j2 @3 A4 Q
  92. }, f+ _: [$ X1 [0 ^6 O

  93. & |$ D( L6 D0 A
  94. void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
    % q! z$ ~5 g1 v+ ~( d
  95. {" Q% ?  R' D. f9 a9 s5 U
  96.         printf("DMA transfer error\r\n");. b# a- ^% M- _+ C( Y7 p, u6 d2 o
  97. }' n; I7 T7 j9 l0 }/ {* `; o0 e
复制代码
  1. #include "sys.h"6 Q; v( z: g/ C' @
  2. #include "delay.h"
    4 P; f6 W3 e  d) J
  3. #include "usart.h": E# p1 u0 Q' K4 B: H+ `
  4. $ s7 d: c" x: i3 c
  5. #include "adc.h"# t% @) H2 K6 O2 A
  6. - _. [# K# f3 ?: H6 H: k9 a9 L/ n
  7. extern uint16_t buffer[128];2 p6 M1 k" c2 x$ f$ F6 x

  8. 3 I% i6 [& n  V4 Z
  9. void show(); w. M8 Q( X/ ]1 l! B
  10. {6 r4 W6 F2 b, @7 ]( J  p+ u) x  C( Z
  11.     int i;
    % B- ^/ H; S' R& i. [6 T
  12.     printf("\r\ndata:");( P& w2 \% _* X
  13.     for (i = 0; i < 128; i++)
    + U3 h6 a* `5 y  {! v2 f. {8 V* r  _3 `
  14.     {' U& n$ `5 @  [) k$ {
  15.         if (i % 16 == 0) printf("\r\n");
    0 T) A; {2 w. l+ c: }3 |
  16.         printf("%6d", buffer[i]);
    1 L* h3 S4 G9 Z# W) x
  17.                         buffer[i]=0;3 P, m2 o' [$ s2 O& p7 K
  18. ' t* F3 F' T6 F; [
  19.     }
    0 N' _" i0 u7 G1 S" i- q  M$ ~  A
  20.     printf("\r\n");: z7 H  c) K# V& M
  21. }
    , K: V  b2 N8 D8 F( T9 u- o! V
  22. 5 z4 u6 ?: m- ~6 Q
  23. 9 s8 U9 M3 P: X0 B; o2 Q
  24. int main(void)) T6 `0 x. p$ f" h* f0 \. r5 D
  25. {
    6 r% g) X5 K! g  }) W: |
  26.     //Cache_Enable();                 //打开L1-Cache9 B- p* a+ q& c9 Q4 z7 A) A
  27.     HAL_Init();                     //初始化HAL库
    ( X/ U3 @1 ]/ p6 o7 x- J
  28.     Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz
    " R$ C2 I; {  d7 l
  29.     delay_init(216);                //延时初始化
    # [% v+ c- Z$ c* X3 q) j6 V" P+ m
  30.     uart_init(115200);              //串口初始化7 v2 g/ G7 m) @4 m# e" t* W. [' ^9 Z
  31. + p' |' c; [, v" ]8 j
  32.     printf("start\r\n");
    ) b, N; `% z" W+ V1 M
  33.     MY_ADC_Init();                  //初始化ADC1通道5: [" Y3 i3 q# F  h+ q# H' Q
  34.     " {9 V, c0 P8 l" j7 W: J$ x
  35.     while (1)
    5 V& ]# Z: `% A, V8 h
  36.     {
    - o4 `& G9 i% E% F$ Y' ]
  37.         show();9 ^% v  ]7 R; e
  38.         delay_ms(1000);+ m6 n7 c- T6 V' p
  39.     }
    $ k1 Y* z, }0 F2 [% V6 B/ W
  40. }
复制代码

4 G5 U/ k( j( v. ]; T————————————————' k4 T$ c1 J5 m3 I2 ~
版权声明:小盼你最萌哒/ C# E9 O: w$ [' L
如有侵权请联系删除+ U; N+ n+ ]! I

/ Y8 M& S# P# h# |/ A/ i
收藏 评论0 发布时间:2023-3-14 11:26

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版