基于HAL库,实现最简单ADC采集。7 p! {/ r% O) e$ M6 Q9 L8 B
第一步,使用CubeMX配置时钟。
* A6 U7 c5 Q/ d
2 Z; a0 \ Y- M' x7 R' s) ~$ L; h% I
) e3 K# h$ O4 J然后是adc的配置:" V( Z/ R* E, Q
8 _# Q @- [6 }$ I+ r: ~+ y% }( H7 C2 H9 `! B: A- H, q4 I! }
5 N& I( s% T+ r" E
将,稍微修改一下风格,并手写头文件和源文件。
9 f% g! e0 u2 L3 X# m8 R' l) Q) ]2 p9 M; U4 o
adc.h很简单,就不说了。
2 r8 x6 S1 U5 l6 r' ~6 w
. s# B% _) M0 e# {: C/ A3 t- #ifndef __ADC_H
" d7 ?$ \4 U$ ~! i - #define __ADC_H
* w0 s) M# `" z - #include "sys.h"
W0 N2 Z: q/ v. Z; d7 z; S: o - 0 E. I& _( y" Z3 V: g* V
- void MY_ADC_Init(void); //ADC通道初始化* s7 K# Y$ A# D
- u16 Get_Adc(void); //获得某个通道值
" C8 m* B2 G' n" M" _ - #endif
复制代码 . Y. _$ G O7 Z( \ N2 o
其中,MY_ADC_Init和HAL_ADC_MspInit的内容完全是根据CubeMX生成的代码写的,就改了一个变量名字。Get_Adc则简单了,当我们需要获取adc的值的时候,先HAL_ADC_Start启动ADC,然后HAL_ADC_PollForConversion等待转换完成,最后HAL_ADC_GetValue返回结果。1 n, \2 |. o; S) s N
7 L- R) D# V+ Z
- #include "adc.h"
* V& Y+ _/ [& u* G0 C% H# z( s5 P - #include "delay.h"
" \+ _- ?5 ]! N9 w. c - # \1 d" ^' ~( G( G# N7 U' n
- 9 W. L8 C" G" A7 g! b% \9 w s
- ADC_HandleTypeDef ADC1_Handler; //ADC句柄" K2 [# ]8 \8 c5 O( S5 @
- ADC_ChannelConfTypeDef ADC1_ChanConf; //ADC通道配置句柄
" W/ @' s; G/ j4 {" J/ P) n - # o! e d* R& P% @% o
- * F* G" c4 d5 ~4 z# J
- //初始化ADC9 S- b9 x6 H, c1 C9 i/ h M7 O' |
- void MY_ADC_Init(void)
$ E4 Q! d8 k. ?4 C* @: N - {
, v9 Y4 _0 w" I7 P* ^3 m3 ] - ADC1_Handler.Instance = ADC1;
: y5 a1 j( d; b - ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ9 ^* _+ R; N5 l/ z
- ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B; //12位模式
' V7 l5 |$ t0 }# X( r - ADC1_Handler.Init.ScanConvMode = DISABLE; //非扫描模式
; ]. O0 Z5 L1 H. M4 \ - ADC1_Handler.Init.ContinuousConvMode = DISABLE; //关闭连续转换7 T- @ _9 s4 K: v1 ]
- ADC1_Handler.Init.DiscontinuousConvMode = DISABLE; //禁止不连续采样模式5 Z c- x, s* V4 Q3 i
- ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发 R8 w% R- c* O9 Z M# U. ~
- ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; //软件触发
" L. M" O) i% k% W - ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; //右对齐4 E7 |* G+ Y3 t( b3 |) T3 Q
- ADC1_Handler.Init.NbrOfConversion = 1; //1个转换在规则序列中 也就是只转换规则序列14 l! _/ t/ q# _. Q5 e
- ADC1_Handler.Init.NbrOfDiscConversion = 0; //不连续采样通道数为0! M3 `4 Y* V' r9 ]! A1 J b) j
- ADC1_Handler.Init.DMAContinuousRequests = DISABLE; //关闭DMA请求
7 g+ L) x4 ^, h - ADC1_Handler.Init.EOCSelection = DISABLE; //关闭EOC中断5 o) }% ^7 _. r" x/ @* n3 _# Y
- HAL_ADC_Init(&ADC1_Handler); //初始化
; |0 a% C: m. V - 5 z2 v, U5 B' [- f
- ADC1_ChanConf.Channel = ADC_CHANNEL_5; //通道5 PA5
$ Q" d z+ }) F; g+ G9 c - ADC1_ChanConf.Rank = 1; //1个序列" s; P$ X- z2 x8 j+ k$ P
- ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES; //采样时间
! {& m4 L1 M) K9 R' b3 F - ADC1_ChanConf.Offset = 0;3 }0 u1 \( V. }% O' C# |
- HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf); //通道配置
, y5 n! i6 K3 b. |% |+ S, I
3 B* |, v' T5 b$ V1 N* V- }: U! B! U) X: X+ X+ N+ `
- ! L2 k9 {- N% t' f
- //ADC底层驱动,引脚配置,时钟使能
# Y. t6 V$ o( V- U6 V6 K - //此函数会被HAL_ADC_Init()调用
- \% t: H6 B8 P E; _3 M - //hadc:ADC句柄& e% R6 _; s% T( ~/ V# C; k3 B
- void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc); P7 X- r0 h0 ]7 ^
- {2 w: O& p* h4 _ l) j
- GPIO_InitTypeDef GPIO_Initure;9 [/ |, D- O. L. V0 c
- __HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟. e: A9 m. c- F/ [0 T
- __HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
+ E7 W+ d9 O, A& E - ! j! Z- v k5 {1 E, u ~
- GPIO_Initure.Pin = GPIO_PIN_5; //PA5
( f+ G; D$ E) i4 z - GPIO_Initure.Mode = GPIO_MODE_ANALOG; //模拟; h# ~4 j6 y+ T r& Q
- GPIO_Initure.Pull = GPIO_NOPULL; //不带上下拉
0 G2 d9 a( t8 N" \. F" e- J - HAL_GPIO_Init(GPIOA, &GPIO_Initure);
: Y5 \' P" p/ S. O H - }6 u; L u6 _% E# r3 ]. j
/ H0 P7 b( G4 i) i* H1 h) a- ]- //获得ADC值+ }8 g3 e& j, V8 ]
- //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
* n+ @9 K# x0 J$ P. T C$ G' a - //返回值:转换结果$ D( ]3 \7 c3 i# P; k/ d( [
- u16 Get_Adc()$ ~- l) Y8 Q4 x9 z) i
- {
B- I- Z( W" d/ }8 E# P - HAL_ADC_Start(&ADC1_Handler); //开启ADC
Q7 {4 i; {2 Y3 z - HAL_ADC_PollForConversion(&ADC1_Handler, 10); //轮询转换
7 b) v! I' ?/ R - return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果
: t( I/ g6 ?9 {- e$ ]$ ?9 Q - }
复制代码 / j/ j4 t4 S1 v8 W& c9 t
main.c中,主函数初始化之后,直接读取adc的值,并打印。
; D: P3 {2 O8 K' |* D2 k6 d- G* y+ y$ U1 o. l* h3 n4 f/ Q h
- #include "sys.h"
1 S, d8 @* q& V* r6 k" X - #include "delay.h") b/ M6 Q* [: z+ X4 i# B, N
- #include "usart.h"& k5 E# V$ A7 b
- #include "adc.h"- E- F8 L0 O8 w/ l
+ B% G. S0 T: W+ |) e- int main(void)
9 C3 l* Y) a1 V# J, B - {9 @" J( _$ B! a5 W8 d. J/ q2 p
- u16 adcx;
& K" o9 k. S% d$ G2 \ - Cache_Enable(); //打开L1-Cache; @+ H. z# j; q0 P2 l. L/ C
- HAL_Init(); //初始化HAL库 j: k/ h5 B( h: B' M; t. f$ e! ]
- Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz( r% }! U$ U3 z- Z. d
- delay_init(216); //延时初始化
: M% I& A0 d* P( ~/ p- Q6 O - uart_init(115200); //串口初始化
, ~$ M/ U7 T* ]0 N+ X8 `6 X8 S( c - MY_ADC_Init(); //初始化ADC1通道5
6 V: @) [) C( J9 [( m, l |2 ~ - - e, D; p& p$ k2 B k
- while (1)
" L( c) @% r; F* R9 w" [0 U# I - {- F+ a# g, U* o5 ]7 i3 E7 j5 \8 N
- adcx = Get_Adc(); //获取通道5的转换值,20次取平均
8 i2 u4 j5 A4 `( S9 g8 J - printf("%d\r\n", adcx);
) G8 D. U- I; q( E$ e* @ - delay_ms(250);4 M: y4 U. I- U& p$ m1 t9 A# H3 d
- }
6 f* [+ r- z0 i - }
复制代码 " E9 S4 h4 \9 n! P! |6 W4 y F, R
如果需要对多个通道进行轮询读取,可以稍微修改一下函数Get_Adc,在每次读取之前设置一下需要转换的通道:1 w! L* b; Q& S" u
; W' ?3 \* w6 X% y; K- //获得ADC值
4 h* W& E6 A, L3 m6 Q4 m - //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_166 x+ c6 Q& x3 ]; j( c4 v
- //返回值:转换结果- H1 r- D# s% {. H
- u16 Get_Adc(u32 ch)
1 o5 U U( l8 Y( N! K - {, T9 u# t" K# v9 O; d
- ADC_ChannelConfTypeDef ADC1_ChanConf;- X L; F3 t4 T1 S7 l5 C" c) X( o
8 [9 m: o- B4 M& J1 l: e# d- ADC1_ChanConf.Channel=ch; //通道9 s% Z1 W. a' q/ Z9 E
- ADC1_ChanConf.Rank=1; //1个序列
. W" O2 s7 z) y; [) d. Z; L" W( z - ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间
, S: b5 V& H3 E( ]- a, x - ADC1_ChanConf.Offset=0; * F) A8 P/ R4 ^: K
- HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置
$ s; V! b i. E - 9 j1 q5 a1 X" ^' S4 D6 ?
- HAL_ADC_Start(&ADC1_Handler); //开启ADC8 u& Z! o% W0 t& Y, l1 ~& Y K, C
- 9 v* I* E/ O8 c0 C z) ?9 n9 Z
- HAL_ADC_PollForConversion(&ADC1_Handler,10); //轮询转换
* O i [% C$ S" K' J' B H2 m( p - 4 ?" ?7 D W2 E& V' }/ L& d; P
- return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果2 ^8 i1 T3 ]! {8 D. m# R7 S
- }* y. E+ r% @5 }- S9 O( h+ e, U+ A3 Y" L
复制代码 5 |- G; ^& f- e# _6 \$ D }
- y5 j. p1 b# m3 C7 c8 z
- t" F+ M, v) k% I/ r |