基于HAL库,实现最简单ADC采集。! h+ t+ h1 z5 _% o4 d' _& b5 ]
第一步,使用CubeMX配置时钟。
% I3 o% C F+ R
" ~9 w$ [! Y0 H: ~5 R) d H. h4 D8 [5 W* i
然后是adc的配置:
# S/ f0 e) n z& n
* k2 D A& h9 K6 p
2 d/ n6 V. \& ~$ b; h# Y/ x8 k" I G
将,稍微修改一下风格,并手写头文件和源文件。1 S+ Z8 b [# a) N1 `) x5 C& _1 d
" O* ~- Z2 q# p. A C1 V1 f% @
adc.h很简单,就不说了。& y. U" w& ^8 R( \9 c
^7 L: f% A: F4 M1 l- #ifndef __ADC_H
8 o! |+ W5 {6 L, @( G, I - #define __ADC_H
( G# W$ V; @5 _5 S - #include "sys.h"
& z$ O7 Z" U* k9 a4 D
0 ?6 i9 h* n5 Z) X# r, e- void MY_ADC_Init(void); //ADC通道初始化
9 t, m$ v3 L& w6 D - u16 Get_Adc(void); //获得某个通道值
) u$ I! c5 [: r. c7 N - #endif
复制代码 * h. J+ ]+ F5 X9 p$ {
其中,MY_ADC_Init和HAL_ADC_MspInit的内容完全是根据CubeMX生成的代码写的,就改了一个变量名字。Get_Adc则简单了,当我们需要获取adc的值的时候,先HAL_ADC_Start启动ADC,然后HAL_ADC_PollForConversion等待转换完成,最后HAL_ADC_GetValue返回结果。- r2 k" I {4 t- G! Q
! D, O2 m8 R: [
- #include "adc.h"2 m& E" a/ i& A% |
- #include "delay.h": }% P' [5 n0 z, X# T
3 Z$ C# f, x- D/ u# j1 {- 4 C& ~' v* N4 }% v
- ADC_HandleTypeDef ADC1_Handler; //ADC句柄
- m0 [1 K- U( o+ m - ADC_ChannelConfTypeDef ADC1_ChanConf; //ADC通道配置句柄9 }/ v# ]+ E0 f* z% g
0 A: C$ }. V* [/ X
7 f' x* X; M) d0 E- //初始化ADC
- G% A/ @6 a. f2 @% S9 U/ s# I - void MY_ADC_Init(void)6 c( B5 o! h' c( B* `5 q
- {
% q) C! i$ @+ j - ADC1_Handler.Instance = ADC1;' X" s( W/ A ]
- ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
) {3 A! N0 C# a* }) f5 L, A" M - ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B; //12位模式
4 L" M' m+ h& b$ n% `$ Q/ S - ADC1_Handler.Init.ScanConvMode = DISABLE; //非扫描模式 y* Z/ |) k2 Y) }# e- l/ n/ u7 @3 |
- ADC1_Handler.Init.ContinuousConvMode = DISABLE; //关闭连续转换
- Z r N: a% J4 _9 Z' y - ADC1_Handler.Init.DiscontinuousConvMode = DISABLE; //禁止不连续采样模式
( o% l% g' B9 k - ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发9 y. @9 X$ B0 U' _1 e9 w9 G
- ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; //软件触发. [5 F- [+ t5 U1 O& t/ i
- ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; //右对齐
* [1 ~3 n8 w# Q- s2 H - ADC1_Handler.Init.NbrOfConversion = 1; //1个转换在规则序列中 也就是只转换规则序列1: X, g& ~* X7 O/ x$ {; J& k2 J
- ADC1_Handler.Init.NbrOfDiscConversion = 0; //不连续采样通道数为0: c; e1 i$ o% Y0 Z. v e
- ADC1_Handler.Init.DMAContinuousRequests = DISABLE; //关闭DMA请求
z/ m) O1 Z0 A% p - ADC1_Handler.Init.EOCSelection = DISABLE; //关闭EOC中断
' ^2 O, {3 }1 z% m - HAL_ADC_Init(&ADC1_Handler); //初始化
$ s/ g' q5 |- T! R1 k7 o - & x- p1 u5 n# b% S6 j
- ADC1_ChanConf.Channel = ADC_CHANNEL_5; //通道5 PA5
8 H, k" I, N7 A: d8 u7 K: E6 Z - ADC1_ChanConf.Rank = 1; //1个序列# ]$ D0 @2 N* |- e
- ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES; //采样时间
- p5 M6 E4 A# `2 T3 E - ADC1_ChanConf.Offset = 0;
: t0 ^4 [& t; d; d: }; A/ a+ G! I - HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf); //通道配置$ S; h6 D1 R: n# M0 j0 s
- $ k# f1 M( l! \: `/ o7 F
- }
% E; p* y; J2 [. s1 _2 g
9 P' |& @* p" j7 |- //ADC底层驱动,引脚配置,时钟使能
5 N5 `( i, \! x* E& b: Q8 F) J - //此函数会被HAL_ADC_Init()调用
) P% l# Q+ r! N3 `" g! L I, K2 s% B - //hadc:ADC句柄5 A2 G2 n- r% `1 W5 e2 ?3 a# Y$ m7 U
- void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)2 B# f# ~- t B7 I, H2 e5 G/ U T
- {0 M6 E1 o0 Z1 h0 [# s1 W$ }1 D$ g: E
- GPIO_InitTypeDef GPIO_Initure;
$ o4 m' @ X! g H% _! q1 `7 }, i1 F - __HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟
) M* [# H8 t. }' g - __HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
& {- `6 J9 s* U7 d0 v' |- p" T - 4 ^% J: `/ h( x: w& E
- GPIO_Initure.Pin = GPIO_PIN_5; //PA5- U( m, n* N- M% k+ @
- GPIO_Initure.Mode = GPIO_MODE_ANALOG; //模拟2 A! X; m( A* k0 d1 h7 x, X
- GPIO_Initure.Pull = GPIO_NOPULL; //不带上下拉. `* d8 z+ V5 ]& R6 b9 e1 G" c( Z* D1 \
- HAL_GPIO_Init(GPIOA, &GPIO_Initure);
* t1 W. H9 k4 G% `7 }7 J9 Q; D - }
9 A. H' H% l( L& y" F l; Y - ! ?& c1 C+ n7 Z& A
- //获得ADC值# m9 y4 }' W$ S, e# m
- //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
' z) y [1 [" B4 E - //返回值:转换结果
! D2 [/ E# j( {+ j& T6 }6 l - u16 Get_Adc()
" n0 t, M0 I5 v2 ^7 G' c: k! A" K - {
! b, d8 L6 _3 \ I5 w5 ]: { - HAL_ADC_Start(&ADC1_Handler); //开启ADC& H- ^% b. m+ W* q. x4 ^. W3 T
- HAL_ADC_PollForConversion(&ADC1_Handler, 10); //轮询转换
8 B0 D2 m/ v- T2 U: V - return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果+ B4 k( `9 C, }; L* O& J6 F
- }
复制代码 0 X9 l* i8 E; X1 ^( @' S& Y+ N' Z: e4 _
main.c中,主函数初始化之后,直接读取adc的值,并打印。1 I7 o4 N9 h8 i% H1 |
9 D+ `) p4 Y' {, H4 `
- #include "sys.h"
+ L0 C( Q* X: P& e) w - #include "delay.h"
% U$ _+ a @6 j$ f0 U - #include "usart.h"% {/ x9 _" o" W+ P" S: N4 R" F
- #include "adc.h"
) d$ K* U9 R+ o6 a! Y - & s' W% x- z) ~1 e% T4 q: T
- int main(void)
# N8 E# J% D) B. K9 \+ n - {
1 A R/ c- X9 X* b - u16 adcx;
! f7 @. [# o6 G3 k+ Z - Cache_Enable(); //打开L1-Cache9 E$ N- V4 z* Q
- HAL_Init(); //初始化HAL库" n/ I# h& g6 I9 I* l5 `8 h) x
- Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz
4 J. O8 s4 v* f! \: Z5 [+ E - delay_init(216); //延时初始化; P1 }- m' R# Z* w% k+ ]
- uart_init(115200); //串口初始化
6 v, x4 @: L- I! D6 a. `" y; i - MY_ADC_Init(); //初始化ADC1通道5% \+ ~0 ^- r6 }6 Q
- : V' l$ {4 N- ?2 m
- while (1)/ p& w# S) M4 }+ ~) h+ t1 j
- {
# k( y( O. e* C( N+ X - adcx = Get_Adc(); //获取通道5的转换值,20次取平均 l3 H8 X$ p- }- D. z* x3 E' B
- printf("%d\r\n", adcx);
1 Q+ @3 d$ X; b" H# n2 e; V - delay_ms(250);
7 A% N, C4 h7 U# Q - }5 @2 e6 s! \% w3 K
- }
复制代码
' P- n; r* b. o如果需要对多个通道进行轮询读取,可以稍微修改一下函数Get_Adc,在每次读取之前设置一下需要转换的通道:' g, j I: Q4 W4 F/ H" S
1 t& x8 U5 A% P- //获得ADC值 ~0 }% _3 C! L! \. P2 ?3 |
- //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
) I$ ^% |6 n2 \. P9 n8 R) i* U - //返回值:转换结果
. ?( T: t+ h. L+ }% P( A) d* N/ h - u16 Get_Adc(u32 ch) : z+ g5 I" u8 m% D5 P3 _) J- F
- {( n- j# k- n0 a. F9 S
- ADC_ChannelConfTypeDef ADC1_ChanConf;
& S4 U/ u" B6 O& L+ F - 5 X/ M4 X4 _! E6 F4 o# [# J0 j
- ADC1_ChanConf.Channel=ch; //通道1 W( F# Y ? ?5 h; q1 e: R
- ADC1_ChanConf.Rank=1; //1个序列
( V% u' K8 k' p - ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间
# k7 J: m6 g1 c$ J, h; Z+ t - ADC1_ChanConf.Offset=0;
, v! a" q1 Q! V+ U, z; g - HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置) U5 j( r9 ^* v( {
- ! I ~3 v' o$ C! I
- HAL_ADC_Start(&ADC1_Handler); //开启ADC
5 a/ _! x: W$ P6 s+ [+ H* v -
$ u6 }3 n! m8 z) C2 b a6 j$ \/ P - HAL_ADC_PollForConversion(&ADC1_Handler,10); //轮询转换
7 N/ `5 A* @; F7 T+ J' q7 b - % k0 }3 m! D3 T9 D* @
- return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果7 c- Z: v; X% A9 {" b* q
- }
8 ~' e3 q/ o/ f) |5 J4 B* x
复制代码 % Q' b, E/ M3 C0 B1 x% t5 h0 p* F- D
1 z n3 M/ v5 D2 h1 |
0 ?& C' D' E, v u1 u/ x |