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

【STM32F769I-DISC1】测评04:使用ADC通道制作的位移采集模块,上传数据到PC端

[复制链接]
〃聪聪哥哥 发布时间:2025-3-14 17:27
今天和大家分享一下使用STM32F769制作的位移采集装置
. t; `, T! s3 s) S/ d一:STM32F769 ADC 知识分享:% b& v" D0 O; Z6 j
) r: r  t# L. A
STM32F769xx 系列有3个 ADC,这些 ADC 可以独立使用,也可以使用双重/三重模式(提高采样率)。STM32F769 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有 19 个通道,可测量 16 个外部源、2 个内部源和 Vbat 通道的信号。这些通道的 A/D 转换可以单次、连续、扫描或间断模式执行。ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。 模拟看门
+ _# y4 t1 i1 u狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。STM32F769IGT6 包含有3个ADC。STM32F769的 ADC 最大的转换速率为2.4Mhz,也就是转换时间为 0.41us(在 ADCCLK=36M,采样周期为3个 ADC 时钟下得到),不要让 ADC 的时钟超过 36M,否则将导致结果准确度下降。# B3 r1 ^$ D' Q. s
STM32F769将ADC的转换分为2个通道组:规则通道组和注入通道组。规则通道相当于你正常运行的程序,而注入通道呢,就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换, 在注入通道被转换完成之后,规则通道才得以继续转换。" ~8 P' a5 W. P- m

; V* V) S/ {: U8 u, {' Q; P) b3 \  i
ADC 的主要特征:' ^3 p2 W$ O3 B! ]+ N' |9 b
5 c# {# v3 `# m8 Z& e: K
可配置 12 位、10 位、8 位或6 位分辨率/ W4 i% {# k1 h; J- S4 Q; Y2 `
在转换结束、注入转换结束以及发生模拟看门狗或溢出事件时产生中断
# N4 b$ F) }, C( B1 P: x单次和连续转换模式
2 y' Q% D* X6 Z3 x  O( J扫描模式,自动转化通道 0到通道 n数据6 O2 G9 s! c4 A
数据对齐以保持内置数据一致性0 x1 z$ A( y' S* s3 c0 H
可独立设置各通道采样时间! _: }, L  V" z; p, D4 L, z4 e: f
外部触发器选项,可为常规转换和注入转换配置极性
! S3 H# ]8 i1 R7 i8 K不连续采样模式7 n# C' y" k/ _( ?8 {( a5 B& ^; H3 [( E
双重/三重模式(具有2个或更多 ADC 的器件提供)7 S. L/ O: L4 q- r, H/ v
双重/三重 ADC 模式下可配置的 DMA 数据存储( y2 R+ P2 o  E! ~
双重/三重交替模式下可配置的转换间延迟
) P$ _1 ^) U8 P2 A# n, EADC转换类型(参见数据手册)
4 k+ d/ B/ D2 k) k" RADC 电源要求:供电在 2.4V 到 3.6V 下可全速运行,供电低至 1.8V 时为慢速运行
+ y! q: s& D! q7 x+ |8 {7 Y/ u. BADC 输入范围:VREF-≤VIN≤ VREF+
' i4 b# x! ]! T6 w. @" k  K6 I常规通道转换期间可产生 DMA 请求* n( `# b8 J) p/ q4 C, Z
: E& [9 B4 C$ ]/ z- q: `

4 y' K' V4 H: a  L% t4 i二:STM32 cube MX 软件的配置如下所示:& K2 }9 F8 R5 l3 h
1.png 2.png 8 j0 C; I4 Y  j% W/ e" o: s8 F8 l

# Z; `' Z; X+ b. x4 r三:STM32 cube MX 软件生成代码如下所示:
- }/ T; y  a. b% z; o4 s
9 Q: g7 r' V  k, y
  1.   hadc1.Instance = ADC1;
    , {9 b3 b5 ^; y2 E( D' K
  2.   hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
    ) B8 _$ {7 }6 c
  3.   hadc1.Init.Resolution = ADC_RESOLUTION_12B;
    % A- U# L) I! O; p: e
  4.   hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;; r1 |& F% ^- d" \/ T
  5.   hadc1.Init.ContinuousConvMode = ENABLE;
    # X" ~- a" m0 @" m/ U
  6.   hadc1.Init.DiscontinuousConvMode = DISABLE;
    - |0 C) `' p( K0 ?
  7.   hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;( ]2 U5 n! T" e9 q
  8.   hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
    ' x' y! `/ I" ?1 g# C, @6 P
  9.   hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;; M- g3 @4 L( m7 Z* f3 E
  10.   hadc1.Init.NbrOfConversion = 1;
    8 E2 |$ a1 N6 c2 r  |. y+ t$ f
  11.   hadc1.Init.DMAContinuousRequests = ENABLE;
    9 |4 ?. ~8 @# x. l, n- R0 i6 b8 C
  12.   hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;# Z$ y+ Z5 H2 j% h: k
  13.   if (HAL_ADC_Init(&hadc1) != HAL_OK)
    3 ~) E3 v4 N( K1 A) G/ Y
  14.   {3 ?6 t3 [, F7 [  j) S
  15.     Error_Handler();
    . \4 x  O2 U6 `0 J+ ^
  16.   }
复制代码
上述软件代码是软件配置之后,自动生成的功能,然后我下载之后,发现代码进入的 void NMI_Handler(void) 错误,由于我使用的是DMA的方式接收的ADC的数据,所以DMA还在正常运行,也是搞不懂为什么,串口输出也不正常。; Y6 S* Z- {: C: R  Q# ~
然后我查询了下代码,将ADC的初始化修改如下所示代码:+ k& I- R0 x7 b$ `6 |7 k
  1.   hadc1.Instance = ADC1;
    : A7 A, X/ z0 S+ ?' D. j  a# r
  2.   hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
    7 V, P6 ~; Z! B2 z/ ]7 r
  3.   hadc1.Init.Resolution = ADC_RESOLUTION_12B;
    / t  f* m% s! d  z) C
  4.   hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;% @! Y5 b; ]1 {) m+ V/ g
  5.   hadc1.Init.ContinuousConvMode = ENABLE;
    ( G5 B/ l4 D( }. S+ A( T# y1 g
  6.   hadc1.Init.DiscontinuousConvMode = DISABLE;. ~; t- Y; {1 U; R& B- y
  7.   hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
    $ Y8 c+ O8 A, P5 |9 `; {8 ]. v
  8.   hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
    : K! r9 R: Q' q. j" F8 g
  9.   hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    9 `( O( O; a5 O7 Z& ^
  10.   hadc1.Init.NbrOfConversion = 1;
    5 d2 O. z' L+ H* ~
  11.   hadc1.Init.DMAContinuousRequests = ENABLE;
    , j; P: {! Q8 h+ b4 r! p. `' ]0 {8 w
  12.   hadc1.Init.EOCSelection = DISABLE;9 d# B( I2 z: {; C0 i) Z
  13.   if (HAL_ADC_Init(&hadc1) != HAL_OK)
    $ U4 t6 X" j9 }0 H
  14.   {
    0 l9 p% X0 j9 r/ P: v8 r" p
  15.     Error_Handler();
    " X4 Q( W! }; ]
  16.   }
复制代码
下面是ADC 结构体的的变量解释
$ }' Q9 A  L5 N8 s% ]8 [6 d8 }$ H
  1. typedef struct{4 N+ I. o; D" @$ |  s! j4 H/ p
  2. uint32 t ClockPrescaler;//分频系数 2/4/6/8 分频
复制代码
这里发现是 cube MX 软件配置中对下述变量配置不太一样:' d/ e' R& e. E: O, u/ V% G% N/ v" A
  1. hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV; 9 I' d! p) P0 p$ R$ l$ M
  2. hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; 
复制代码
配置好ADC代码后,我们就直接读取ADC的数据就可以了- S  Y9 e: \+ L; i/ _
主程序代码如下:, }7 H5 Q- y3 s# |5 i: M; t: b/ _
  1.   HAL_Delay(200) ;
    4 C" Z. L  k  T& g3 U, L# ~' J
  2.                 HAL_GPIO_TogglePin(GPIOJ,GPIO_PIN_13) ;
    + k: k3 C. c9 o! l( e# w* L) @6 q
  3. //                HAL_Delay(200) ;
    ' F" z4 R% L' j; V2 w- r
  4. //                HAL_GPIO_TogglePin(GPIOJ,GPIO_PIN_5) ;
    - G: C' w# z& \: u  |" k* o! c
  5. //                HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_4) ;
    , @9 ~* P4 C' y1 Z# c% Z
  6. //                HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_12) ;
    ' H0 W  ?$ I$ I7 ^+ a4 S
  7.                 if(usart1_flag == 1)+ `. H; P, ?7 T3 W( U2 n
  8.                 {- m3 }% i5 g$ a8 f
  9.                         usart1_flag = 0 ;) {3 I+ D9 B4 r4 T( G
  10.                         HAL_UART_Transmit(&huart1,Usart1_DEAL_RX_Buf,usart1_rx_len,100);
    / \/ o/ ~3 P! r5 D  t
  11. //                        printf("Hello STM32! Hello congcong! Hello STM32f769!\r\n");8 g6 x6 W4 O( R5 b$ B8 t9 t

  12. ' S5 p! b2 f7 i1 S: b- r. x8 ?
  13.                         printf("Hello STM32! Hello congcong! Hello STM32f769!\r\n" );
    , b% R- r3 G: Y' Y
  14.                 }6 j* d. @/ }3 G% y, E; q
  15. 7 [& M* N0 \2 e
  16.                 printf("ubADCSample data = %5d\r\n" ,ubADCSample);
复制代码
PC截图如下所示:
4 L$ I- e  O7 K- G; d7 A2 ^! y) S- z: u 3.png 3 Z: }7 T6 h+ M7 R5 r. l. s) o  L

) ^2 U& U7 f- e9 i% H1 u调试感想如下:
- ?* H) i# ]5 N- `4 @虽然使用STM32 读取了ADC的数据,但是数据飘动还是比较大了,对于工业控制并不是很好,所以这里我推荐以下几种处理方式:
+ k: D. A. m2 e2 ?  J1:中值滤波方式:+ r5 H, E# K  l2 N) I2 ]7 b
主要是程序在执行的时候,连续采集N次(需要注意下这里下,这里的N必须取值奇数),程序需要按大到小或者从小到达的顺序进行排序,然后取中间数值做为有效值。
4 A. k. u2 Y# A0 D) @  O
  1. int MidValueDeal(int N)
    - V- y+ F0 q5 g0 `6 N
  2. {      
    % ?) u  ]4 [/ z: Y4 a7 L
  3.     int value_buf[N];      int i,j,k,temp;      
    & ?, Z$ l0 U! |  c0 l
  4.     for( i = 0; i < N; ++i)      
    $ z- ~8 p+ |) C+ q
  5.     {        / F5 D: @$ E% T) k- _/ X! R
  6.      value_buf[i] = HAL_ADC_GetValue(&hadc1);  
      g7 ~3 v: b7 ~& s6 \$ `' g% H
  7.     }
    # M4 E4 z) ?; N; U
  8.       for(j = 0 ; j < N-1; ++j)      
    ( I6 O) k5 q, ?7 ]/ ~2 z8 i! o+ D
  9.       {         
    1 S* I( I) |' r, T" I( v6 W; B
  10.           for(k = 0; k < N-j-1; ++k)          3 z) v+ N5 h0 A+ ^( k
  11.           {              //从小到大排序,冒泡法排序              
    * @2 j) K& [4 b: h3 }- s" u# J8 w! e. I) G
  12.               if(value_buf[k] > value_buf[k+1])              
    4 c9 ^' z- w' m+ b, Z1 J+ z
  13.               {               
    2 a' b: `+ @. l3 h5 x) i9 ^- ~6 d$ |
  14.                   temp = value_buf[k];                ( p; u( s: [0 l- v
  15.                   value_buf[k] = value_buf[k+1];               
    " L. r9 e# N4 i* Z- x7 O. n" H: C
  16.                   value_buf[k+1] = temp;              * w  X$ q' T' O; J
  17.               }         
    3 E4 i: Z% p4 j3 t( y. p7 E
  18.           }      - O3 e1 d0 h8 b  z. W, m) ?( Y
  19.       }
    - S& \* m8 u% `  j7 j2 S& s& W2 m1 g
  20.       return value_buf[(N-1)/2];
    9 T6 [6 Y; f# `: k
  21.   }
复制代码
2:算术平均数滤波:连续取值N个数据,对所有的数据进行取平均值;9 Y) ^. W( d7 w- ]4 W# o4 f
  1. int AverValueDeal(int N)
    0 ?6 h0 w0 j/ }9 d, d
  2. {    + a( V$ w& v. c; r6 n
  3.     int sum = 0;     
    9 i$ ?4 O) j0 P+ y. \' w6 K* I& n
  4.     unsinged short i;   
      d( m( I1 _7 w9 {( z; B
  5.     for(i = 0; i < N; ++i)     0 }6 x) n: D  Y5 D4 O
  6.     {        7 Z7 J/ r7 W3 }1 f8 v
  7.         sum += HAL_ADC_GetValue(&hadc1);      ( ]' i. |+ w& E3 b/ a5 P7 S( |
  8.     }     
    2 K# Z$ z+ K4 ]2 J8 O8 k! {3 d% t8 E
  9.     return sum/N;( l" b% D6 N! e) |5 Q0 @- i
  10. }
复制代码
相比之下:STM32F769的硬件上面没有过采样的硬件配置,对于STM32U083单片机,已经支持硬件的过采样功能。当时测试时候发现,经过硬件处理之后,数据稳定性得到提高。
) s$ T: F# z9 V+ S! W不过即使没有硬件的过采样,我们依然可以使用软件模拟过采样、滤波采样的功能,对数据进行处理。
- F/ P; Q" R1 S9 N, y# F& E9 ]
" ]7 r* b4 v2 T$ ?0 Z: o* A8 _. @5 E7 I6 S' r
最后,大家在调试ADC时候有什么好的建议和想法,麻烦评论区留言。
' {) f" v, W9 k
5.png
4.png
收藏 评论5 发布时间:2025-3-14 17:27

举报

5个回答
lugl 回答时间:2025-3-15 09:20:02

用标准的基准源进行观察。打印出ADC的值,使用分析软件进行分析评估。

〃聪聪哥哥 回答时间:2025-3-16 12:36:37

lugl 发表于 2025-3-15 09:20
用标准的基准源进行观察。打印出ADC的值,使用分析软件进行分析评估。
...

不知道是不是我配置的问题,这个AD的数据,感觉还没有U083单片机的采集稳定

lugl 回答时间:2025-3-16 19:41:05

〃聪聪哥哥 发表于 2025-3-16 12:36
不知道是不是我配置的问题,这个AD的数据,感觉还没有U083单片机的采集稳定
...

需要进行滤波算法进行处理吧。这么高的主频处理起来应该不难。但是这个12bit的ADC,他的应用场景不是高精度的ADC采集。如果想稳定,最好使用专业的ADC吧。

〃聪聪哥哥 回答时间:2025-3-17 19:45:18

lugl 发表于 2025-3-16 19:41
需要进行滤波算法进行处理吧。这么高的主频处理起来应该不难。但是这个12bit的ADC,他的应用场景不是 ...

[md]嗯,这个正好有个机会研究一下,,感觉不如U0系列的好呢😄

lugl 回答时间:2025-3-18 05:19:04

〃聪聪哥哥 发表于 2025-3-17 19:45
嗯,这个正好有个机会研究一下,,感觉不如U0系列的好呢😄

这个也不能这样说,F769在当年可以说是高档产品了。他还有其他的功能,综合性能比U0要强很多。但是U0的使用的内核比F769要新,在能耗性能比上要比F7xx要好。各有所长。

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