基于HAL库,实现最简单ADC采集。
& T/ W# [$ ?) Q7 M" r$ n$ _' G第一步,使用CubeMX配置时钟。1 d5 n; O* m @
6 \! _4 j# q: ?) N
6 M$ D3 r* ^+ l% M4 M( C" z7 z3 A: u
然后是adc的配置:$ v+ x4 Q' n8 C Y. c7 j
9 B- N5 ~- K9 L/ T2 k% l6 y
, _2 }- G* U0 h* T
, H4 m# S( B7 M9 W将,稍微修改一下风格,并手写头文件和源文件。
( d- j+ e3 B9 k' T8 G9 i- m7 t4 v$ Y
adc.h很简单,就不说了。. k+ @+ R) `7 v/ R
2 W% {! v% B H" L8 Q; r
- #ifndef __ADC_H
7 b6 V9 O6 J* N: P1 x/ Z - #define __ADC_H
3 q/ q/ N" u$ l+ ?5 ~ - #include "sys.h"4 ^) m% G7 {; T( l
- : M. e/ }. B$ Q# Q
- void MY_ADC_Init(void); //ADC通道初始化
) _# B7 L$ v* |7 f7 B5 m - u16 Get_Adc(void); //获得某个通道值
6 Q. I2 V8 N$ }. V1 [, z - #endif
复制代码 ; U% n. U- V& ?6 p
其中,MY_ADC_Init和HAL_ADC_MspInit的内容完全是根据CubeMX生成的代码写的,就改了一个变量名字。Get_Adc则简单了,当我们需要获取adc的值的时候,先HAL_ADC_Start启动ADC,然后HAL_ADC_PollForConversion等待转换完成,最后HAL_ADC_GetValue返回结果。3 j% B$ X4 M) i) G. ~
! b" P k: U% a- Q: _# g- #include "adc.h"
2 v4 M* [1 E- n! ~% | - #include "delay.h"8 q0 d% j2 U& o t. V0 P# F
- # G6 X) }" W0 J8 r& \
: ~- R4 S' y& R- ADC_HandleTypeDef ADC1_Handler; //ADC句柄
* A# n# L: S1 W6 H - ADC_ChannelConfTypeDef ADC1_ChanConf; //ADC通道配置句柄
9 F* A# \" z: x8 _) P& J6 [
* }( e8 A8 s4 o) S) p- 3 r# _3 ~) |; c% Y
- //初始化ADC
& }5 P( A% F% T( S; ]) }0 ? - void MY_ADC_Init(void)
3 U6 w! o3 R7 ^' K) |, @$ s - {
- h' K& w; H* B7 P - ADC1_Handler.Instance = ADC1;
$ v6 l" ~2 \ J8 M1 w( k# X - ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ( x# {1 L3 L# `/ |, E
- ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B; //12位模式
! w- e% K u4 N - ADC1_Handler.Init.ScanConvMode = DISABLE; //非扫描模式* o) `$ q: G& p8 T1 g! Y/ K
- ADC1_Handler.Init.ContinuousConvMode = DISABLE; //关闭连续转换
2 O9 ]; r0 K- V) a( E - ADC1_Handler.Init.DiscontinuousConvMode = DISABLE; //禁止不连续采样模式
& ^. q. k. k: h& ?( }9 ~: W/ C - ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发7 z( h. d6 N3 y9 V
- ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; //软件触发( S8 L- [: x% F9 f7 o+ @. g r9 \" o
- ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; //右对齐* T& @- Q) p) l( K2 h3 Q
- ADC1_Handler.Init.NbrOfConversion = 1; //1个转换在规则序列中 也就是只转换规则序列1
% l2 G1 e T7 a. ~0 C5 I - ADC1_Handler.Init.NbrOfDiscConversion = 0; //不连续采样通道数为0
4 M9 |5 W8 s& y6 a - ADC1_Handler.Init.DMAContinuousRequests = DISABLE; //关闭DMA请求5 ?& X' r5 ?* v5 v# u
- ADC1_Handler.Init.EOCSelection = DISABLE; //关闭EOC中断3 p) A5 G1 f+ s0 _2 I* }2 M
- HAL_ADC_Init(&ADC1_Handler); //初始化
2 z6 O/ R% ?1 {6 P - 8 l* M" H% O( e$ o1 X) M' W
- ADC1_ChanConf.Channel = ADC_CHANNEL_5; //通道5 PA5
/ A' O! y: U( _. J - ADC1_ChanConf.Rank = 1; //1个序列
* E/ A2 s/ i) d9 _; D- @( z0 L; _ - ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES; //采样时间
; X3 B) J3 s3 n, x, ^ - ADC1_ChanConf.Offset = 0;9 d* K4 \% z) `. H9 c6 ]* R
- HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf); //通道配置
( _8 R' Q) ^/ `- J7 D* P* ]& G& B5 Y
( H* U* _/ b2 D( v- K- i- }
0 v& Y% Z* R: S/ x$ l2 Y! a5 d1 M - ' a- `2 H; v t7 n4 ?0 X+ Y i
- //ADC底层驱动,引脚配置,时钟使能
/ K+ k2 g- M0 |! n) j - //此函数会被HAL_ADC_Init()调用2 U/ I$ n+ B8 j1 s2 z; r7 P
- //hadc:ADC句柄
* Y; u1 ^9 ?7 a: a. t1 _ - void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
# N2 S. c& H, m p( S! g - {. j4 L; s6 V% {. {
- GPIO_InitTypeDef GPIO_Initure;& k" u1 M6 p7 N! a( r( D
- __HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟. H, v9 \2 m7 i+ N" m6 Z5 X- M
- __HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
6 b. ^3 {/ l3 B9 N: n% H- P4 `
: v% Y/ Q8 U. \2 s' g3 ]2 K& t5 c- GPIO_Initure.Pin = GPIO_PIN_5; //PA5
# P2 R+ y1 |7 n* _1 b7 ~: w, B7 w! @ - GPIO_Initure.Mode = GPIO_MODE_ANALOG; //模拟
6 x+ m2 g0 a. j: F - GPIO_Initure.Pull = GPIO_NOPULL; //不带上下拉
5 q8 l$ o y: r/ ~* i - HAL_GPIO_Init(GPIOA, &GPIO_Initure);
$ ]. O9 `' {% |' y# x# j/ K1 f! K - }
0 b Q( p* y( w& V7 Q( g - - [8 U9 ]- _" i1 B( {7 F- `
- //获得ADC值0 T8 v# Y: R# C
- //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
1 g& O `+ K4 F. U" i, P, t$ S) V/ B; m - //返回值:转换结果
3 z1 y& A L6 d- j* Y( T V - u16 Get_Adc()
5 s. ^8 ^' y/ V; s0 L! X - { |+ C5 B3 v0 n+ W: K, P& o
- HAL_ADC_Start(&ADC1_Handler); //开启ADC. J g, X# F0 l
- HAL_ADC_PollForConversion(&ADC1_Handler, 10); //轮询转换
2 ~) W2 O }: y! `5 R5 W - return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果
: `- u* b5 c9 L/ t8 t5 L - }
复制代码
" |7 A. L$ U. [2 X7 l4 V8 Rmain.c中,主函数初始化之后,直接读取adc的值,并打印。
) D. `4 i( H! }7 x
1 S* ~+ r% b3 o$ j- #include "sys.h"
& x3 |+ x4 I1 T - #include "delay.h"# n9 k/ q. V) c* R+ N% _; K$ @; a
- #include "usart.h"
! K" u3 c5 E- T; j c9 \" _ - #include "adc.h"
; g# f5 e( p3 q. n0 t
$ w2 Y6 M; j. \- int main(void)
% A: f' `0 l: L9 G; ?: \ - {
- h4 w: }& ]* @" P/ w# Q% e - u16 adcx;# M; S* l6 ~6 T3 K: c3 q' G
- Cache_Enable(); //打开L1-Cache
, |9 H0 a- R& c; s' e( E8 t - HAL_Init(); //初始化HAL库
2 C, \: U: l; Q+ d7 ^* B/ ` - Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz
+ t! G5 Y# Z. h( |1 w - delay_init(216); //延时初始化5 l2 o& v: a _: A9 `+ @
- uart_init(115200); //串口初始化
. I! ~; l% ]4 E* b - MY_ADC_Init(); //初始化ADC1通道52 V+ [4 k' p: s3 Q) e
-
$ Y0 m e1 x" h7 e, p* m- J - while (1)3 Q. y) ?) v1 p* P
- {
: ?( Z! n' L2 V$ H - adcx = Get_Adc(); //获取通道5的转换值,20次取平均/ r! ], S8 e. E) r: u5 Y
- printf("%d\r\n", adcx);8 ]$ Z$ R: A j, Y$ {
- delay_ms(250);
/ @: d3 a7 T; U. n - }+ f# K% A; Y4 X3 ?& d9 C
- }
复制代码
6 @; A# `, d6 b9 H0 x+ v$ n* V如果需要对多个通道进行轮询读取,可以稍微修改一下函数Get_Adc,在每次读取之前设置一下需要转换的通道:; `" X' |( Y, `6 J7 h
+ E3 E2 y9 w* k- //获得ADC值
" K( i* Q$ O6 F5 s$ s1 u- B - //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16# f$ J3 L5 u: l/ v" Q) ]
- //返回值:转换结果0 n9 z G- w0 I+ a8 n1 A* a" S
- u16 Get_Adc(u32 ch) ; S* L- t1 W( M. F+ K( |, g
- {! J+ d( K# B4 Z, E
- ADC_ChannelConfTypeDef ADC1_ChanConf;
: t& |2 e, U! J4 H6 H# G1 s
, O2 T. m- n% M. s( j$ |- ADC1_ChanConf.Channel=ch; //通道 r" t( a. s- F2 N: j7 v: t: q
- ADC1_ChanConf.Rank=1; //1个序列7 N7 T D0 @9 m. D$ S
- ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间
/ m8 b% M2 v$ n' C# u2 a - ADC1_ChanConf.Offset=0; 3 \6 d8 I, _9 A; H0 {$ a
- HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置
! r2 p9 Y- X2 G -
! @% Q- l+ A" ]/ u' e% P - HAL_ADC_Start(&ADC1_Handler); //开启ADC5 A0 W# h/ i9 g" P
- 8 \% c, I# C* U- s
- HAL_ADC_PollForConversion(&ADC1_Handler,10); //轮询转换+ Q' a) _# N1 w, _9 ~3 M* m( r) V
- * I! s5 |8 e$ ^
- return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果
* N5 f. T* ^; F! k - }/ R; D4 V# o$ m, ^, A
复制代码
( g' d5 s1 W1 F8 X- I
# [2 Q. W/ O+ a4 K, l6 R5 M3 ~2 C" i+ ~4 P9 B* w) P+ V
|