基于HAL库,实现最简单ADC采集。& r. p* h1 K. ^: |; ?
第一步,使用CubeMX配置时钟。
3 I, F; m B$ ]0 _: n U s' [
) a3 |- t" ]6 P5 g4 C
. _* A& O0 E5 B v+ A; Y然后是adc的配置:
. Y# D+ ^! ]/ z+ p% D( p0 H* L9 b: y
1 M8 c& j1 ~# N' ~
: D( j7 d' V- A2 @% Y+ @将,稍微修改一下风格,并手写头文件和源文件。
- `; R6 k! C, Y
: d' w" c7 |2 L) Z/ p S7 u- eadc.h很简单,就不说了。
/ d/ \( g1 C- a; G
2 P! `/ M2 @! ?5 ]7 Q. {- q6 p1 b- #ifndef __ADC_H! X4 K& e" I' k+ v
- #define __ADC_H1 i$ {$ ?; I9 v: {& X# r: w' c f" @
- #include "sys.h"
- Q& C% }2 b7 A6 q- X( E
3 w5 @; `# q( C1 k' s/ S. q. Q/ l- void MY_ADC_Init(void); //ADC通道初始化* Y$ K1 n( e" c+ R+ ]3 k4 ~
- u16 Get_Adc(void); //获得某个通道值 ( E! _6 Y' Y" p' p5 D& p3 e
- #endif
复制代码 4 K+ { a% v4 `% ^" R Y
其中,MY_ADC_Init和HAL_ADC_MspInit的内容完全是根据CubeMX生成的代码写的,就改了一个变量名字。Get_Adc则简单了,当我们需要获取adc的值的时候,先HAL_ADC_Start启动ADC,然后HAL_ADC_PollForConversion等待转换完成,最后HAL_ADC_GetValue返回结果。
4 @! p7 `% v" G# x: ~& P+ n0 x! _- X) \$ \6 T: G5 }
- #include "adc.h"0 j6 ~5 Q1 W# Z% N4 |* @3 e
- #include "delay.h"
, C- ]- t: X3 P. d2 g - & a J% @1 i2 R* B
/ @& f9 g* v7 L& B- H6 Y4 m" k9 ^- ADC_HandleTypeDef ADC1_Handler; //ADC句柄
$ B! e2 M! c$ p/ g2 y) _9 J- S) q7 N - ADC_ChannelConfTypeDef ADC1_ChanConf; //ADC通道配置句柄
! i1 b5 @! t X7 h& `) Q
+ e7 `0 H# G% Y8 G0 Z
6 y2 Q: }' B( t) l8 U4 g+ n; t- //初始化ADC
5 h4 K; b$ p# a. _* _" R. z - void MY_ADC_Init(void)% E. A$ S( f$ X& Q6 a" S
- {
! `) L( J' e4 ~( U8 e - ADC1_Handler.Instance = ADC1;
$ X- t1 X4 i3 T - ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ B8 X6 i, c1 L. `
- ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B; //12位模式
6 W/ g7 Q5 e; w2 y! Q" v* K - ADC1_Handler.Init.ScanConvMode = DISABLE; //非扫描模式
$ p8 {. [- \5 A - ADC1_Handler.Init.ContinuousConvMode = DISABLE; //关闭连续转换
0 G8 y- c! |& a$ e; C5 G - ADC1_Handler.Init.DiscontinuousConvMode = DISABLE; //禁止不连续采样模式
5 X' [, p# h, S2 Y; f( D: o - ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发
D3 i* ], s0 I& \ - ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; //软件触发3 Y! B, U+ E+ |2 S8 W( \0 w/ g: Q O
- ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; //右对齐
( S+ K5 i" N! Y: l" \$ t9 K% u - ADC1_Handler.Init.NbrOfConversion = 1; //1个转换在规则序列中 也就是只转换规则序列1" W* r0 K, \ G% s, N
- ADC1_Handler.Init.NbrOfDiscConversion = 0; //不连续采样通道数为0( Q- J. G% K+ B
- ADC1_Handler.Init.DMAContinuousRequests = DISABLE; //关闭DMA请求
2 t& {, D+ T3 ]6 T3 D$ A - ADC1_Handler.Init.EOCSelection = DISABLE; //关闭EOC中断1 c3 Q( |) _% y8 ?
- HAL_ADC_Init(&ADC1_Handler); //初始化6 @' C" l% `' r' M+ t. R' @
- 5 m$ ^7 ?7 Q2 Z$ `1 f
- ADC1_ChanConf.Channel = ADC_CHANNEL_5; //通道5 PA5
* m. r H! D) J - ADC1_ChanConf.Rank = 1; //1个序列
e4 Y. k% G" [( V# m% J - ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES; //采样时间5 B. r9 l9 G, ^; L* B
- ADC1_ChanConf.Offset = 0;
- ?) A$ B2 ?" n/ j, `& M z - HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf); //通道配置
+ r/ w0 P4 n; r6 l4 B/ T6 n9 F - 6 K' M: t& Q* H$ ^7 p8 X" n' p
- }' ]' c# _+ [( W1 z' ]0 c
- 0 V- t% m( O* o9 i3 L- n0 y: z5 W2 _
- //ADC底层驱动,引脚配置,时钟使能
* F) {8 @/ {2 K1 v7 R - //此函数会被HAL_ADC_Init()调用/ G7 }- x$ s: N# F/ C! }
- //hadc:ADC句柄
) X" n9 V+ b. g! [/ Z - void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
" E. p0 M" v" x) s% E - {* b7 ?, j7 D* R5 n
- GPIO_InitTypeDef GPIO_Initure;
_) g, z# r% i! W% s - __HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟
. r5 H2 k, a1 q7 j4 a0 a - __HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟, V5 G! \# F5 C) x7 _
) N0 W9 @: [( r/ j1 j- _- GPIO_Initure.Pin = GPIO_PIN_5; //PA5
' M' C% x6 e0 b6 x - GPIO_Initure.Mode = GPIO_MODE_ANALOG; //模拟
0 T9 P i, O% F1 {" H) R - GPIO_Initure.Pull = GPIO_NOPULL; //不带上下拉
/ |! a" d; A" \/ ]6 @& \. F1 v - HAL_GPIO_Init(GPIOA, &GPIO_Initure);9 P" ^& K$ d4 S) S+ H2 [- B
- }
$ N( V3 V& A7 j, S4 B3 g - k# I3 b& b( H" a
- //获得ADC值 |6 h! T* V" j
- //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16% c+ v/ J4 S2 W5 L1 d* c0 Q6 C" V
- //返回值:转换结果
$ \: a" ^% o$ G# L$ b4 l - u16 Get_Adc()
6 F& S% N, r+ h' f$ J. P - {
0 g0 x6 \: ~( j' p2 s - HAL_ADC_Start(&ADC1_Handler); //开启ADC
7 v0 b9 P0 U" U) q - HAL_ADC_PollForConversion(&ADC1_Handler, 10); //轮询转换
! J5 O* T( p9 Y - return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果
- N- x/ h) L2 m# e - }
复制代码
$ C3 e+ ^3 Q1 q6 nmain.c中,主函数初始化之后,直接读取adc的值,并打印。
8 o/ E( i( K+ m/ a k; a7 o
3 O" z4 ~2 _; t ~2 _- #include "sys.h"- q7 q! F. h7 p. f- `7 ^8 b
- #include "delay.h"
+ A, K/ D" l* o N& C - #include "usart.h"
/ ^ o' l1 w% ? - #include "adc.h"
: F8 W' g4 h2 ]" r a
( {0 Y+ F, }/ s- int main(void)
3 h2 a1 h& K) H+ f) `9 P - {
0 K- ~$ [' z! |5 A0 d$ ~: S - u16 adcx;
2 n2 m% J% Y! S ^; a - Cache_Enable(); //打开L1-Cache, Z& ?" Y" T( S! |0 g
- HAL_Init(); //初始化HAL库$ L1 c0 h" C( z' y6 K7 N
- Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz6 E2 {' y* Z D' m! z; x3 \
- delay_init(216); //延时初始化% [1 ?* `! ?+ C" v5 g
- uart_init(115200); //串口初始化( t8 o [3 k0 E/ x6 x, d. A) h8 {) f7 c
- MY_ADC_Init(); //初始化ADC1通道5+ a' S/ _3 x4 M0 ~+ @% O, j
-
' `. [- Z2 f' U3 t+ W - while (1)# |# ?4 t) f5 C; v6 Z6 v1 w
- {
9 Q7 X5 @7 u1 Q3 i* r4 r) `5 X - adcx = Get_Adc(); //获取通道5的转换值,20次取平均6 P$ y2 |* H! R+ E2 a
- printf("%d\r\n", adcx);; M/ n. ^% W* r* S4 t4 |
- delay_ms(250); H. _; j0 q* K% F7 i
- }& ^5 L% m" ~4 K4 @
- }
复制代码
7 o9 a) G- E7 Q, ]1 U- u如果需要对多个通道进行轮询读取,可以稍微修改一下函数Get_Adc,在每次读取之前设置一下需要转换的通道:, p7 w6 X/ H1 a) z; p7 y( A
3 t2 z) X% v3 |+ Y) ]8 A
- //获得ADC值
$ j4 N& r1 k( B* t! O - //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
0 P3 s0 k) Z. T( D% {1 N - //返回值:转换结果 Q8 J; ~0 P+ X( j3 I a. w u
- u16 Get_Adc(u32 ch)
5 n; i8 e& C) b& U- y& b/ l - {! K5 m9 V' b: c2 A W- G
- ADC_ChannelConfTypeDef ADC1_ChanConf;
" T+ u, ]+ K) c& N' M& |
. A2 G& b8 k: D! W' O- ADC1_ChanConf.Channel=ch; //通道
* ~' [0 y t/ s& V. i- z6 e; _ - ADC1_ChanConf.Rank=1; //1个序列5 @8 d: o* B3 C5 \
- ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间% N) x, ]0 b8 F3 `
- ADC1_ChanConf.Offset=0; ' C3 A# w( Z* A1 I# E6 e4 X/ C
- HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置
0 Y3 L' G; Y$ o8 N# S" W2 Z - & D8 j; x3 o2 s' V# j; T
- HAL_ADC_Start(&ADC1_Handler); //开启ADC% s; h$ R0 X+ n* x9 ?+ F1 O5 U
- ; f9 i3 k% k, a' S
- HAL_ADC_PollForConversion(&ADC1_Handler,10); //轮询转换! a# { u9 E9 U0 C" z; f
- 9 S; [& E- ~% q' i( m5 e% l
- return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果
* ^2 n! _2 ^; Y9 E3 f& P! B- R - }, G, D9 v1 I' V6 s% d! i
复制代码
" J! s% P7 U* j/ X9 m4 X
" g4 n2 G" J$ ^7 W
6 {" r9 v$ _8 O- S" y |