基于HAL库,实现最简单ADC采集。
0 f5 Y9 e5 G9 ]# D3 P0 C第一步,使用CubeMX配置时钟。& ]' A* K' ^: p/ Z: q
# w! T% p& ?, s+ ~
, ^: o q _0 V1 c9 y
然后是adc的配置:
+ }6 O5 V6 O9 `7 p& l: W
/ l' U4 m7 E1 J$ i* W0 S
4 m+ `9 T. [0 j' V1 R; z0 u, } X
! [5 ?$ @2 \) R7 X) V% n; @. x. y将,稍微修改一下风格,并手写头文件和源文件。7 }3 \4 K6 Y% o- ^- F) `6 a% B
% }( X0 d0 h) `0 F3 J( s0 q& t# @adc.h很简单,就不说了。9 E2 D1 l; V7 B8 F1 v2 g
; R r. v4 f# Y. V/ `. d
- #ifndef __ADC_H
! Z9 h9 W' B& N - #define __ADC_H1 T/ g2 ~) W. w- b- f0 m
- #include "sys.h"
) r1 Z- v4 Q% b7 o3 O
7 H4 H5 [2 L* k. O- void MY_ADC_Init(void); //ADC通道初始化
6 L/ q! s+ J' P) a# t - u16 Get_Adc(void); //获得某个通道值
- m X8 b8 M+ | - #endif
复制代码 1 [) o: w1 m" U7 T% b2 T
其中,MY_ADC_Init和HAL_ADC_MspInit的内容完全是根据CubeMX生成的代码写的,就改了一个变量名字。Get_Adc则简单了,当我们需要获取adc的值的时候,先HAL_ADC_Start启动ADC,然后HAL_ADC_PollForConversion等待转换完成,最后HAL_ADC_GetValue返回结果。
3 }' ^" b i4 L, M* Y; y0 b! ]
0 G3 n. B4 B5 @8 J& z- #include "adc.h"
7 L+ k' {2 K E# ? - #include "delay.h"7 p6 j3 d. z) W% E4 s3 O3 U% n* H
- % i: r- B7 S/ z. H* v8 X
- * X1 Q8 j2 O0 Y3 s
- ADC_HandleTypeDef ADC1_Handler; //ADC句柄0 n1 w7 i3 T9 b
- ADC_ChannelConfTypeDef ADC1_ChanConf; //ADC通道配置句柄; D! P8 t2 B2 T$ ]5 j" H
- ' e$ S+ Y4 \$ V- C
- % d9 _) T) o; {9 ^
- //初始化ADC9 p0 c. |, e% h( O# ~2 O
- void MY_ADC_Init(void)$ i+ _8 N- d: }5 Y" B8 F$ C
- {0 b6 V* g. l# A% W5 Q' _3 I
- ADC1_Handler.Instance = ADC1;
' h4 C+ c' j' e5 E - ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
X. J! z1 w Q; R" [ - ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B; //12位模式; o1 a3 F7 d5 o! k" L
- ADC1_Handler.Init.ScanConvMode = DISABLE; //非扫描模式9 H/ ~% ?' _4 |/ y+ l
- ADC1_Handler.Init.ContinuousConvMode = DISABLE; //关闭连续转换! i2 f/ V8 x0 {0 y; H3 ~& _
- ADC1_Handler.Init.DiscontinuousConvMode = DISABLE; //禁止不连续采样模式
# p% w! b$ e; F( w9 T - ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发- p' d, K! L! O, m7 j
- ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; //软件触发
2 I( o2 l; `# x) j8 e8 t" E6 p2 y( b - ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; //右对齐 h+ h; F8 S8 f: a+ y
- ADC1_Handler.Init.NbrOfConversion = 1; //1个转换在规则序列中 也就是只转换规则序列19 S T+ q; m% H0 D7 T5 j7 ~6 z
- ADC1_Handler.Init.NbrOfDiscConversion = 0; //不连续采样通道数为0" [' I- E7 W/ q
- ADC1_Handler.Init.DMAContinuousRequests = DISABLE; //关闭DMA请求( f5 X4 z) K# T* q1 o# o
- ADC1_Handler.Init.EOCSelection = DISABLE; //关闭EOC中断1 f' I0 W1 m% L9 I
- HAL_ADC_Init(&ADC1_Handler); //初始化
8 z5 p1 _7 d; I* E0 z/ L
. M3 ~; p* J. {8 m5 D1 R# o0 J4 b- ADC1_ChanConf.Channel = ADC_CHANNEL_5; //通道5 PA5! f. z9 H% g" T& J# e
- ADC1_ChanConf.Rank = 1; //1个序列! l3 U, E9 K$ k
- ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES; //采样时间2 N' L+ ^0 v9 F& M" F9 B& b. J- y+ \
- ADC1_ChanConf.Offset = 0;
1 }+ g; l2 j9 A2 E - HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf); //通道配置
' c' f0 p; n+ w! _( f3 e1 ?3 I
5 L( p. F' \6 g4 v- }
E& O' W( M! j0 X. [6 g - 4 P' T, p4 [/ N; l3 O1 L+ r
- //ADC底层驱动,引脚配置,时钟使能5 C! ^& Y" g- o. Q4 ^1 k
- //此函数会被HAL_ADC_Init()调用
$ `$ m0 P0 h. H - //hadc:ADC句柄" i: X& h" b9 b7 ?
- void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
" p6 G# N# a' L2 i% G - {6 {1 E3 [2 K5 ?' m
- GPIO_InitTypeDef GPIO_Initure;
! L; p) F1 Q) `2 P# L$ q- D - __HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟
3 `3 @9 M6 X, v7 [$ ^- J - __HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
. ]& \( `7 S* r6 J! _8 D8 i
( h+ i. [3 V+ m- GPIO_Initure.Pin = GPIO_PIN_5; //PA5
5 O0 P4 {, F4 U, L0 l - GPIO_Initure.Mode = GPIO_MODE_ANALOG; //模拟
+ b' z+ z; D- T5 n - GPIO_Initure.Pull = GPIO_NOPULL; //不带上下拉9 X2 w& I7 v+ U' d
- HAL_GPIO_Init(GPIOA, &GPIO_Initure);
4 j& S4 Z3 i3 }3 f/ K& E; x - }# @* b8 F0 ?( l7 c2 k' a6 l" S
- : n& R; J: E7 `; D8 X- z
- //获得ADC值1 s( g7 X8 | d, B0 v; l+ y7 L2 r
- //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16, T" E- t! r9 q
- //返回值:转换结果
0 M, |/ C, D4 d. j - u16 Get_Adc()' ^, S" a0 ^ ]* U2 y
- {; u1 U f5 i9 f" e0 h5 Q8 V( r1 d
- HAL_ADC_Start(&ADC1_Handler); //开启ADC
- K$ h: S5 w/ q0 u' p9 i3 h; {- c - HAL_ADC_PollForConversion(&ADC1_Handler, 10); //轮询转换+ k& F% [: Q9 m! w/ h4 o) ~# p
- return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果
6 u- }5 ]( A6 M- X0 F - }
复制代码 $ ?& r- h0 v0 X0 d A$ A7 ?
main.c中,主函数初始化之后,直接读取adc的值,并打印。
4 F' u9 [4 U) \, R
5 b1 l; E7 l, J: _6 R2 {1 \' \1 a& \- #include "sys.h"
5 [6 R' M# ^8 I - #include "delay.h"& {' d( c/ }" L! p' u, d) I- @2 c
- #include "usart.h"- w5 X4 F {( S( s' ?
- #include "adc.h"# W# u! v) W$ S9 L- u
- , {6 n! c& ~3 F8 x
- int main(void)# C8 i) G! r3 }% g. L! h
- {
/ i, f4 i# T0 L) A( Z. S! r - u16 adcx;
8 a7 a; g; u; l0 _0 I3 x* H - Cache_Enable(); //打开L1-Cache( J- T' x/ C" f- {& U
- HAL_Init(); //初始化HAL库
& ]4 @) m- P7 e. S: L0 K5 I - Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz
$ P1 n; o* s3 J! B' I- m' T" ~/ o - delay_init(216); //延时初始化
! l7 E# s+ n2 F! |8 @6 g - uart_init(115200); //串口初始化
. T: U- Z2 x! }8 b: \; p - MY_ADC_Init(); //初始化ADC1通道5
4 x# }) z2 X% t" F% X& G3 v( `% ~ -
: X" [; L4 k3 T* }# O, c - while (1)6 l. Z# {$ T$ n- e: O1 i
- {6 N* }3 ?/ d4 M
- adcx = Get_Adc(); //获取通道5的转换值,20次取平均
( b G0 M5 z# I1 \9 x$ V - printf("%d\r\n", adcx);, B1 o" a( n L+ x
- delay_ms(250);
1 d! ?4 |7 R a- @( G - }
2 N+ n! B* @* ^$ u% f - }
复制代码
( C+ T! o# G& O7 K" L+ U如果需要对多个通道进行轮询读取,可以稍微修改一下函数Get_Adc,在每次读取之前设置一下需要转换的通道:/ L7 K; I' i: R$ T8 P& t# {
, o _# N% r6 I7 Q. `1 x. R0 D' m: o- //获得ADC值
9 X8 `- _/ e! \" p9 r2 i: f0 a - //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
* u h5 f$ ?1 X: _ - //返回值:转换结果0 {+ |) C+ y( Y
- u16 Get_Adc(u32 ch)
k+ e! f& f8 q3 k& y" W - {
- t& v+ H% G0 L' O% u3 E - ADC_ChannelConfTypeDef ADC1_ChanConf;! n U. @: u, O8 W o* f, a) M! V
+ K; O; ]+ Q% e l; F/ W: B% S- ADC1_ChanConf.Channel=ch; //通道* S) w$ f# Z2 d; @+ _; C9 x
- ADC1_ChanConf.Rank=1; //1个序列0 i6 k- ^2 [& g$ G2 M7 P2 X
- ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间% u( M+ Z/ P3 A1 s" A/ N T( B& U; o
- ADC1_ChanConf.Offset=0;
& |9 c0 N- r, x. X3 d* Q- i$ h - HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置
4 r: W: f9 d9 M5 b% s: F3 D9 R - 5 l2 d" a: F. V3 S2 @* c
- HAL_ADC_Start(&ADC1_Handler); //开启ADC
$ q& ^# B+ F) h5 r - 6 S- O3 j5 M2 o* ]5 a( {9 B! d
- HAL_ADC_PollForConversion(&ADC1_Handler,10); //轮询转换
9 U) e# ?) _; I! x! s; B+ }
2 v6 I! H. z, i; V! p* Y- return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果
* a( B+ f9 p W0 L' t( Y: ~8 ?0 d - }
6 P3 K: w$ d; S4 k. v
复制代码 ' j) X+ X3 M# j" u! m5 v4 a& ~
( \0 b8 v8 w( z% H3 g+ H) p' ~
1 V1 ~! d4 m8 Z. h; v6 f |